diff --git a/CMakeExternals/Boost.cmake b/CMakeExternals/Boost.cmake index bf50d36881..323448f549 100644 --- a/CMakeExternals/Boost.cmake +++ b/CMakeExternals/Boost.cmake @@ -1,343 +1,343 @@ #----------------------------------------------------------------------------- # Boost #----------------------------------------------------------------------------- include(mitkFunctionGetMSVCVersion) #[[ Sanity checks ]] -if(DEFINED BOOST_ROOT AND NOT EXISTS ${BOOST_ROOT}) - message(FATAL_ERROR "BOOST_ROOT variable is defined but corresponds to non-existing directory") +if(DEFINED Boost_ROOT AND NOT EXISTS ${Boost_ROOT}) + message(FATAL_ERROR "Boost_ROOT variable is defined but corresponds to non-existing directory") endif() string(REPLACE "^^" ";" MITK_USE_Boost_LIBRARIES "${MITK_USE_Boost_LIBRARIES}") set(proj Boost) set(proj_DEPENDENCIES ) set(Boost_DEPENDS ${proj}) -if(NOT DEFINED BOOST_ROOT AND NOT MITK_USE_SYSTEM_Boost) +if(NOT DEFINED Boost_ROOT AND NOT MITK_USE_SYSTEM_Boost) #[[ Reset variables. ]] set(patch_cmd "") set(configure_cmd "") set(install_cmd "") - set(BOOST_ROOT ${ep_prefix}) - set(Boost_DIR "${BOOST_ROOT}/lib/cmake/Boost-1.82.0") + set(Boost_ROOT ${ep_prefix}) + set(Boost_DIR "${Boost_ROOT}/lib/cmake/Boost-1.82.0") if(WIN32) - set(BOOST_LIBRARYDIR "${BOOST_ROOT}/lib") + set(BOOST_LIBRARYDIR "${Boost_ROOT}/lib") endif() #[[ If you update Boost, make sure that the FindBoost module of the minimum required version of CMake supports the new version of Boost. In case you are using a higher version of CMake, download at least the source code of the minimum required version of CMake to look into the right version of the FindBoost module: /share/cmake-/Modules/FindBoost.cmake Search for a list called _Boost_KNOWN_VERSIONS. If the new version is not included in this list, you have three options: * Update the minimum required version of CMake. This may require adaptions of other parts of our CMake scripts and has the most impact on other MITK developers. Yet this is the safest and cleanest option. * Set Boost_ADDITIONAL_VERSIONS (see the documentation of the FindBoost module). As Boost libraries and dependencies between them are hard-coded in the FindBoost module only for known versions, this may cause trouble for other MITK developers relying on new components of Boost or components with changed dependencies. * Copy a newer version of the FindBoost module into our CMake directory. Our CMake directory has a higher precedence than the default CMake module directory. Doublecheck if the minimum required version of CMake is able to process the newer version of the FindBoost module. Also, DO NOT FORGET to mention this option right above the call of cmake_minimum_required() in the top-level CMakeLists.txt file AND in this file right above the set(url) command below so if we update the minimum required version of CMake or use another option in the future, we do not forget to remove our copy of the FindBoost module again. ]] set(url "${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/boost_1_82_0.tar.gz") set(md5 f7050f554a65f6a42ece221eaeec1660) if(MITK_USE_Boost_LIBRARIES) #[[ Boost has a two-step build process. In the first step, a bootstrap script is called to build b2, an executable that is used to actually build Boost in the second step. The bootstrap script expects a toolset (compiler) argument that is used to build the b2 executable. The scripts and their expected argument format differ between Windows and Unix. ]] if(WIN32) mitkFunctionGetMSVCVersion() if(VISUAL_STUDIO_VERSION_MINOR EQUAL 0) #[[ Use just the major version in the toolset name. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}) elseif(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR LESS 20) #[[ Assume Visual Studio 2017. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}1) elseif(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR LESS 30) #[[ Assume Visual Studio 2019. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}2) elseif(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR LESS 40) #[[ Assume Visual Studio 2022. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}3) else() #[[ Fallback to the generic case. Be prepared to add another elseif branch above for future versions of Visual Studio. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}) endif() else() #[[ We support GCC and Clang on Unix. On macOS, the toolset must be set to clang. The actual compiler for all of these toolkits is set further below, after the bootstrap script but before b2. ]] if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) set(toolset gcc) elseif(CMAKE_CXX_COMPILER_ID STREQUAL Clang OR APPLE) set(toolset clang) endif() if(toolset) set(bootstrap_args --with-toolset=${toolset}) endif() #[[ At least give it a shot if the toolset is something else and let the bootstrap script decide on the toolset by not passing any argument. ]] endif() #[[ The call of b2 is more complex. b2 arguments are grouped into options and properties. Options follow the standard format for arguments while properties are plain key-value pairs. ]] set(b2_options --build-dir= --stagedir= --ignore-site-config #[[ Build independent of any site.config file ]] -q #[[ Stop at first error ]] ) if(APPLE AND CMAKE_OSX_SYSROOT) #[[ Specify the macOS platform SDK to be used. ]] list(APPEND b2_options --sysroot=${CMAKE_OSX_SYSROOT}) endif() foreach(lib ${MITK_USE_Boost_LIBRARIES}) list(APPEND b2_options --with-${lib}) endforeach() set(b2_properties threading=multi runtime-link=shared "cxxflags=${MITK_CXX${MITK_CXX_STANDARD}_FLAG} ${CMAKE_CXX_FLAGS}" ) if(CMAKE_SIZEOF_VOID_P EQUAL 8) list(APPEND b2_properties address-model=64) else() list(APPEND b2_properties address-model=32) endif() if(BUILD_SHARED_LIBS) list(APPEND b2_properties link=shared) else() list(APPEND b2_properties link=static) endif() list(APPEND b2_properties "\ $<$:variant=debug>\ $<$:variant=release>\ $<$:variant=release>\ $<$:variant=release>") if(WIN32) set(bootstrap_cmd if not exist b2.exe \( call bootstrap.bat ${bootstrap_args} \)) set(b2_cmd b2 ${b2_options} ${b2_properties} stage) else() set(bootstrap_cmd #[[ test -e ./b2 || ]] ./bootstrap.sh ${bootstrap_args}) set(b2_cmd ./b2 ${b2_options} ${b2_properties} stage) #[[ We already told Boost if we want to use GCC or Clang but so far we were not able to specify the exact same compiler we set in CMake when configuring the MITK superbuild for the first time. For example, this can be different from the system default when multiple versions of the same compiler are installed at the same time. The bootstrap script creates a configuration file for b2 that should be modified if necessary before b2 is called. We look for a line like using gcc ; and replace it with something more specific like using gcc : : /usr/bin/gcc-7.3 ; We use the stream editor sed for the replacement but since macOS is based on BSD Unix, we use the limited but portable BSD syntax instead of the more powerful GNU syntax. We also use | instead of the more commonly used / separator for sed because the replacement contains slashes. 2021/06/15: The custom project-config.jam does not work well with SDK paths on macOS anymore, so we use a custom project-config.jam only on Linux for now. ]] if(toolset AND NOT APPLE) set(configure_cmd sed -i.backup "\ s|\ using[[:space:]][[:space:]]*${toolset}[[:space:]]*$|\ using ${toolset} : : ${CMAKE_CXX_COMPILER} $|\ g" /project-config.jam ) endif() endif() endif() if(WIN32) set(dummy_cmd cd .) else() set(dummy_cmd true) #[[ "cd ." does not work reliably ]] endif() if(NOT patch_cmd) set(patch_cmd ${dummy_cmd}) #[[ Do nothing ]] endif() if(NOT configure_cmd) set(configure_cmd ${dummy_cmd}) #[[ Do nothing ]] endif() if(WIN32) set(install_cmd if not exist $ \( ${CMAKE_COMMAND} -E copy_directory /boost /include/boost \) ) else() set(install_cmd # test -e /include/boost/config.hpp || ${CMAKE_COMMAND} -E copy_directory /boost /include/boost ) endif() ExternalProject_Add(${proj} URL ${url} URL_MD5 ${md5} PATCH_COMMAND ${patch_cmd} CONFIGURE_COMMAND ${configure_cmd} BUILD_COMMAND "" INSTALL_COMMAND ${install_cmd} ) ExternalProject_Add_Step(${proj} bootstrap COMMAND ${bootstrap_cmd} DEPENDEES patch DEPENDERS configure WORKING_DIRECTORY ) ExternalProject_Add_Step(${proj} b2 COMMAND ${b2_cmd} DEPENDEES bootstrap DEPENDERS build WORKING_DIRECTORY ) if(WIN32) #[[ Reuse already extracted files. ]] set(stamp_dir ${ep_prefix}/src/Boost-stamp) configure_file( ${CMAKE_CURRENT_LIST_DIR}/extract-Boost.replacement.cmake ${stamp_dir}/extract-Boost.replacement.cmake COPYONLY) ExternalProject_Add_Step(${proj} pre_download COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-pre_download.cmake DEPENDEES mkdir DEPENDERS download WORKING_DIRECTORY ${stamp_dir} ) endif() set(install_manifest_dependees install) if(MITK_USE_Boost_LIBRARIES) if(WIN32) #[[ Move DLLs from lib to bin directory. ]] ExternalProject_Add_Step(${proj} post_install COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-post_install-WIN32.cmake DEPENDEES install WORKING_DIRECTORY /lib ) set(install_manifest_dependees post_install) elseif(APPLE) #[[ Boost does not follow the common practice of either using rpath or absolute paths for referencing dependencies. We have to use the install_name_tool to fix this. ]] ExternalProject_Add_Step(${proj} post_install COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-post_install-APPLE.cmake DEPENDEES install WORKING_DIRECTORY /lib ) set(install_manifest_dependees post_install) endif() endif() ExternalProject_Add_Step(${proj} install_manifest COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-install_manifest.cmake DEPENDEES ${install_manifest_dependees} WORKING_DIRECTORY ${ep_prefix} ) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/Poco.cmake b/CMakeExternals/Poco.cmake index 9a3ccd0794..e81f01376e 100644 --- a/CMakeExternals/Poco.cmake +++ b/CMakeExternals/Poco.cmake @@ -1,103 +1,103 @@ #----------------------------------------------------------------------------- # Poco #----------------------------------------------------------------------------- if(MITK_USE_Poco) # Sanity checks if(DEFINED Poco_DIR AND NOT EXISTS ${Poco_DIR}) message(FATAL_ERROR "Poco_DIR variable is defined but corresponds to non-existing directory") endif() set(proj Poco) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED ${proj}_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() set(ssl_args -DENABLE_CRYPTO:BOOL=OFF -DENABLE_NETSSL:BOOL=OFF -DENABLE_NETSSL_WIN:BOOL=OFF ) if(OpenSSL_FOUND) set(ssl_args -DENABLE_CRYPTO:BOOL=ON -DENABLE_NETSSL:BOOL=ON -DFORCE_OPENSSL:BOOL=ON ) if(OPENSSL_ROOT_DIR) list(APPEND ssl_args "-DOPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR}" ) endif() endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - GIT_REPOSITORY https://github.com/pocoproject/poco.git - GIT_TAG poco-1.12.4-release + GIT_REPOSITORY https://github.com/mitk/poco.git + GIT_TAG 7a7d81fd049088d93e42d0f7b8f7f7d5d1af3708 # poco-1.12.4-patched CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} ${ssl_args} -DENABLE_ACTIVERECORD:BOOL=OFF -DENABLE_ACTIVERECORD_COMPILER:BOOL=OFF -DENABLE_APACHECONNECTOR:BOOL=OFF -DENABLE_CPPPARSER:BOOL=OFF -DENABLE_DATA:BOOL=OFF -DENABLE_DATA_MYSQL:BOOL=OFF -DENABLE_DATA_ODBC:BOOL=OFF -DENABLE_DATA_POSTGRESQL:BOOL=OFF -DENABLE_DATA_SQLITE:BOOL=OFF -DENABLE_ENCODINGS:BOOL=OFF -DENABLE_ENCODINGS_COMPILER:BOOL=OFF -DENABLE_FOUNDATION:BOOL=ON -DENABLE_JSON:BOOL=ON -DENABLE_JWT:BOOL=OFF -DENABLE_MONGODB:BOOL=OFF -DENABLE_NET:BOOL=ON -DENABLE_PAGECOMPILER:BOOL=OFF -DENABLE_PAGECOMPILER_FILE2PAGE:BOOL=OFF -DENABLE_PDF:BOOL=OFF -DENABLE_POCODOC:BOOL=OFF -DENABLE_PROMETHEUS:BOOL=OFF -DENABLE_REDIS:BOOL=OFF -DENABLE_SEVENZIP:BOOL=OFF -DENABLE_TESTS:BOOL=OFF -DENABLE_UTIL:BOOL=ON -DENABLE_XML:BOOL=ON -DENABLE_ZIP:BOOL=ON ${${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(${proj}_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index dd5ce7718a..704c4e583e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1418 +1,1422 @@ #[[ When increasing the minimum required version, check if Boost_ADDITIONAL_VERSIONS in CMake/PackageDepends/MITK_Boost_Config.cmake can be removed. See the first long comment in CMakeExternals/Boost.cmake for details. ]] set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.18) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND CMAKE_VERSION VERSION_LESS 3.19.2) message(FATAL_ERROR "\ CMake v${CMAKE_VERSION} is defective [1]. \ Please either downgrade to v3.18 or upgrade to at least v3.19.2.\n\ [1] https://gitlab.kitware.com/cmake/cmake/-/issues/21529") endif() #----------------------------------------------------------------------------- # Policies #----------------------------------------------------------------------------- #[[ T28060 https://cmake.org/cmake/help/v3.18/policy/CMP0091.html https://cmake.org/cmake/help/v3.18/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html We pass CMP0091 to all external projects as command-line argument: -DCMAKE_POLICY_DEFAULT_CMP0091:STRING=OLD ]] cmake_policy(SET CMP0091 OLD) +if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) # https://cmake.org/cmake/help/v3.24/policy/CMP0135.html +endif() + #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Build MITK and the projects it depends on via SuperBuild.cmake." ON) if(MITK_USE_SUPERBUILD) project(MITK-superbuild) set(MITK_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(MITK_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(MITK VERSION 2023.04.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") unset(MITK_ABSOLUTE_EXTENSION_DIRS) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) get_filename_component(MITK_ABSOLUTE_EXTENSION_DIR "${MITK_EXTENSION_DIR}" ABSOLUTE) list(APPEND MITK_ABSOLUTE_EXTENSION_DIRS "${MITK_ABSOLUTE_EXTENSION_DIR}") endforeach() set(MITK_DIR_PLUS_EXTENSION_DIRS "${MITK_SOURCE_DIR}" ${MITK_ABSOLUTE_EXTENSION_DIRS}) #----------------------------------------------------------------------------- # Update CMake module path #----------------------------------------------------------------------------- set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMake") if(EXISTS "${MITK_CMAKE_EXTENSION_DIR}") list(APPEND CMAKE_MODULE_PATH "${MITK_CMAKE_EXTENSION_DIR}") endif() endforeach() #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- # Standard CMake macros include(FeatureSummary) include(CTest) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) include(mitkFunctionEnableBuildConfiguration) include(mitkFunctionWhitelists) include(mitkFunctionAddExternalProject) include(mitkFunctionAddLibrarySearchPaths) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 17) set(CMAKE_CXX_EXTENSIONS 0) set(CMAKE_CXX_STANDARD ${MITK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED 1) # This is necessary to avoid problems with compile feature checks. # CMAKE_CXX_STANDARD seems to only set the -std=c++ flag for targets. # However, compile flag checks also need to be done with -std=c++. # The MITK_CXX_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++${MITK_CXX_STANDARD}" MITK_CXX${MITK_CXX_STANDARD}_FLAG) #----------------------------------------------------------------------------- # Warn if source or build path is too long #----------------------------------------------------------------------------- if(WIN32) set(_src_dir_length_max 50) set(_bin_dir_length_max 50) if(MITK_USE_SUPERBUILD) set(_src_dir_length_max 34) # _src_dir_length_max - strlen(ep/src/ITK-build) set(_bin_dir_length_max 40) # _bin_dir_length_max - strlen(MITK-build) endif() string(LENGTH "${MITK_SOURCE_DIR}" _src_n) string(LENGTH "${MITK_BINARY_DIR}" _bin_n) # The warnings should be converted to errors if(_src_n GREATER _src_dir_length_max) message(WARNING "MITK source code directory path length is too long (${_src_n} > ${_src_dir_length_max})." "Please move the MITK source code directory to a directory with a shorter path." ) endif() if(_bin_n GREATER _bin_dir_length_max) message(WARNING "MITK build directory path length is too long (${_bin_n} > ${_bin_dir_length_max})." "Please move the MITK build directory to a directory with a shorter path." ) endif() endif() #----------------------------------------------------------------------------- # Additional MITK Options (also shown during superbuild) #----------------------------------------------------------------------------- # ----------------------------------------- # General build options option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) option(MITK_FAST_TESTING "Disable long-running tests like packaging" OFF) option(MITK_XVFB_TESTING "Execute test drivers through xvfb-run" OFF) option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) option(MITK_BUILD_EXAMPLES "Build the MITK Examples" OFF) mark_as_advanced( MITK_XVFB_TESTING MITK_FAST_TESTING MITK_BUILD_ALL_APPS ) #----------------------------------------------------------------------------- # Set UI testing flags #----------------------------------------------------------------------------- if(MITK_XVFB_TESTING) set(MITK_XVFB_TESTING_COMMAND "xvfb-run" "--auto-servernum" CACHE STRING "Command and options to test through Xvfb") mark_as_advanced(MITK_XVFB_TESTING_COMMAND) endif(MITK_XVFB_TESTING) # ----------------------------------------- # Other options set(MITK_CUSTOM_REVISION_DESC "" CACHE STRING "Override MITK revision description") mark_as_advanced(MITK_CUSTOM_REVISION_DESC) set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") include(CMakeExternals/ExternalProjectList.cmake) foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMakeExternals") if(EXISTS "${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake") include("${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake") endif() endforeach() # ----------------------------------------- # Other MITK_USE_* options not related to # external projects build via the # MITK superbuild option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) option(MITK_USE_OpenMP "Use OpenMP" OFF) option(MITK_USE_Python3 "Use Python 3" OFF) #----------------------------------------------------------------------------- # Build configurations #----------------------------------------------------------------------------- set(_buildConfigs "Custom") file(GLOB _buildConfigFiles CMake/BuildConfigurations/*.cmake) foreach(_buildConfigFile ${_buildConfigFiles}) get_filename_component(_buildConfigFile ${_buildConfigFile} NAME_WE) list(APPEND _buildConfigs ${_buildConfigFile}) endforeach() foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) file(GLOB _extBuildConfigFiles "${MITK_EXTENSION_DIR}/CMake/BuildConfigurations/*.cmake") foreach(_extBuildConfigFile ${_extBuildConfigFiles}) get_filename_component(_extBuildConfigFile "${_extBuildConfigFile}" NAME_WE) list(APPEND _buildConfigs "${_extBuildConfigFile}") endforeach() list(REMOVE_DUPLICATES _buildConfigs) endforeach() set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations") set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs}) mitkFunctionEnableBuildConfiguration() mitkFunctionCreateWhitelistPaths(MITK) mitkFunctionFindWhitelists(MITK) # ----------------------------------------- # Qt version related variables option(MITK_USE_Qt5 "Use Qt 5 library" ON) if(MITK_USE_Qt5) if(WIN32) set(MITK_QT5_MINIMUM_VERSION 5.12.9) else() set(MITK_QT5_MINIMUM_VERSION 5.12) endif() set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets Xml XmlPatterns WebEngineWidgets UiTools Help LinguistTools) if(APPLE) list(APPEND MITK_QT5_COMPONENTS DBus) elseif(UNIX) list(APPEND MITK_QT5_COMPONENTS X11Extras) endif() # Hint at default install locations of Qt if(NOT Qt5_DIR) if(MSVC) set(_dir_candidates "C:/Qt") if(CMAKE_GENERATOR MATCHES "^Visual Studio [0-9]+ ([0-9]+)") set(_compilers "msvc${CMAKE_MATCH_1}") elseif(CMAKE_GENERATOR MATCHES "Ninja") include(mitkFunctionGetMSVCVersion) mitkFunctionGetMSVCVersion() if(VISUAL_STUDIO_PRODUCT_NAME MATCHES "^Visual Studio ([0-9]+)") set(_compilers "msvc${CMAKE_MATCH_1}") endif() endif() if(_compilers MATCHES "[0-9]+") if (CMAKE_MATCH_0 EQUAL 2022) list(APPEND _compilers "msvc2019" "msvc2017") # Binary compatible elseif (CMAKE_MATCH_0 EQUAL 2019) list(APPEND _compilers "msvc2017") # Binary compatible endif() endif() else() set(_dir_candidates ~/Qt) if(APPLE) set(_compilers clang) else() list(APPEND _dir_candidates /opt/Qt) set(_compilers gcc) endif() endif() if(CMAKE_SIZEOF_VOID_P EQUAL 8) foreach(_compiler ${_compilers}) list(APPEND _compilers64 "${_compiler}_64") endforeach() set(_compilers ${_compilers64}) endif() foreach(_dir_candidate ${_dir_candidates}) get_filename_component(_dir_candidate ${_dir_candidate} REALPATH) foreach(_compiler ${_compilers}) set(_glob_expression "${_dir_candidate}/5.*/${_compiler}") file(GLOB _hints ${_glob_expression}) list(SORT _hints) list(APPEND MITK_QT5_HINTS ${_hints}) endforeach() endforeach() endif() find_package(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS} REQUIRED HINTS ${MITK_QT5_HINTS}) endif() # ----------------------------------------- # Custom dependency logic if(WIN32 AND Qt5_DIR) set(_dir_candidate "${Qt5_DIR}/../../../../../Tools/OpenSSL/Win_x64") get_filename_component(_dir_candidate ${_dir_candidate} ABSOLUTE) if(EXISTS "${_dir_candidate}") set(OPENSSL_ROOT_DIR "${_dir_candidate}") endif() endif() find_package(OpenSSL) option(MITK_USE_SYSTEM_Boost "Use the system Boost" OFF) set(MITK_USE_Boost_LIBRARIES "" CACHE STRING "A semi-colon separated list of required Boost libraries") if(MITK_USE_cpprestsdk OR MITK_USE_httplib) if(NOT OpenSSL_FOUND) set(openssl_message "Could not find OpenSSL (dependency of C++ REST SDK and cpp-httplib).\n") if(UNIX) if(APPLE) set(openssl_message "${openssl_message}Please install it using your favorite package management " "system (i.e. Homebrew or MacPorts).\n") else() set(openssl_message "${openssl_message}Please install the dev package of OpenSSL (i.e. libssl-dev).\n") endif() else() set(openssl_message "${openssl_message}Please either install Win32 OpenSSL:\n" " https://slproweb.com/products/Win32OpenSSL.html\n" "Or use the Qt Maintenance tool to install (recommended):\n" " Developer and Designer Tools > OpenSSL Toolkit > OpenSSL 64-bit binaries\n") endif() set(openssl_message "${openssl_message}If it still cannot be found, you can hint CMake to find OpenSSL by " "adding/setting the OPENSSL_ROOT_DIR variable to the root directory of an " "OpenSSL installation. Make sure to clear variables of partly found " "versions of OpenSSL before, or they will be mixed up.") message(FATAL_ERROR ${openssl_message}) endif() list(APPEND MITK_USE_Boost_LIBRARIES date_time regex system) if(UNIX) list(APPEND MITK_USE_Boost_LIBRARIES atomic chrono filesystem random thread) endif() list(REMOVE_DUPLICATES MITK_USE_Boost_LIBRARIES) set(MITK_USE_Boost_LIBRARIES ${MITK_USE_Boost_LIBRARIES} CACHE STRING "A semi-colon separated list of required Boost libraries" FORCE) endif() if(MITK_USE_Python3) set(MITK_USE_ZLIB ON CACHE BOOL "" FORCE) if(APPLE AND CMAKE_FRAMEWORK_PATH AND CMAKE_FRAMEWORK_PATH MATCHES "python3\\.?([0-9]+)") find_package(Python3 3.${CMAKE_MATCH_1} EXACT REQUIRED COMPONENTS Interpreter Development NumPy) else() find_package(Python3 REQUIRED COMPONENTS Interpreter Development NumPy) endif() if(WIN32) string(REPLACE "\\" "/" Python3_STDARCH "${Python3_STDARCH}") string(REPLACE "\\" "/" Python3_STDLIB "${Python3_STDLIB}") string(REPLACE "\\" "/" Python3_SITELIB "${Python3_SITELIB}") endif() endif() if(BUILD_TESTING AND NOT MITK_USE_CppUnit) message("> Forcing MITK_USE_CppUnit to ON because BUILD_TESTING=ON") set(MITK_USE_CppUnit ON CACHE BOOL "Use CppUnit for unit tests" FORCE) endif() if(MITK_USE_BLUEBERRY) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) mark_as_advanced(MITK_BUILD_ALL_PLUGINS) if(NOT MITK_USE_CTK) message("> Forcing MITK_USE_CTK to ON because of MITK_USE_BLUEBERRY") set(MITK_USE_CTK ON CACHE BOOL "Use CTK in MITK" FORCE) endif() endif() #----------------------------------------------------------------------------- # Pixel type multiplexing #----------------------------------------------------------------------------- # Customize the default pixel types for multiplex macros set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") mark_as_advanced(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS ) # consistency checks if(NOT MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES) set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES) set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES) set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) string(REPLACE "," ";" _integral_types ${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES}) string(REPLACE "," ";" _floating_types ${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES}) foreach(_scalar_type ${_integral_types} ${_floating_types}) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}itk::VariableLengthVector<${_scalar_type}>,") endforeach() string(LENGTH "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" _length) math(EXPR _length "${_length} - 1") string(SUBSTRING "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" 0 ${_length} MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES ${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES} CACHE STRING "List of vector pixel types used in AccessByItk and InstantiateAccessFunction macros for itk::VectorImage types" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() find_package(Git REQUIRED) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") # Print configuration summary message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL) return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # Organize MITK targets in folders #----------------------------------------------------------------------------- set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(MITK_ROOT_FOLDER "MITK" CACHE STRING "") mark_as_advanced(MITK_ROOT_FOLDER) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(GenerateExportHeader) include(mitkFunctionAddManifest) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionCreateBlueBerryApplication) include(mitkFunctionCreateCommandLineApp) include(mitkFunctionCreateModule) include(mitkFunctionCreatePlugin) include(mitkFunctionCreateProvisioningFile) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionUseModules) if( ${MITK_USE_MatchPoint} ) include(mitkFunctionCreateMatchPointDeployedAlgorithm) endif() include(mitkMacroConfigureItkPixelTypes) include(mitkMacroCreateExecutable) include(mitkMacroCreateModuleTests) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroMultiplexPicType) # Deprecated include(mitkMacroCreateCTKPlugin) #----------------------------------------------------------------------------- # Global CMake variables #----------------------------------------------------------------------------- if(NOT DEFINED CMAKE_DEBUG_POSTFIX) # We can't do this yet because the CTK Plugin Framework # cannot cope with a postfix yet. #set(CMAKE_DEBUG_POSTFIX d) endif() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- set(_default_LIBRARY_output_dir lib) set(_default_RUNTIME_output_dir bin) set(_default_ARCHIVE_output_dir lib) foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) else() set(CMAKE_${type}_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${_default_${type}_output_dir}) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY}) endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY} CACHE INTERNAL "Output directory for ${type} files.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- if(OpenSSL_FOUND AND WIN32) #[[ On Windows, CMake is able to locate the link libraries for OpenSSL but it does not look for the corresponding DLLs that we need to copy to our binary directories and include in packaging. Setting these paths manually is cumbersome so we try to use a simple heuristic to automatically set them: - Based on the link libraries (usually located in a lib folder), try to find the "../bin" binary directory. - Use the base file names of the link libraries to find corresponding DLLs like "*.dll", that usually are named like "-1_1-x64.dll" or similar. ]] set(openssl_ssl_dll "") set(openssl_crypto_dll "") if(OPENSSL_SSL_LIBRARY AND EXISTS "${OPENSSL_SSL_LIBRARY}") get_filename_component(openssl_bin_dir "${OPENSSL_SSL_LIBRARY}" DIRECTORY) get_filename_component(openssl_bin_dir "${openssl_bin_dir}" DIRECTORY) set(openssl_bin_dir "${openssl_bin_dir}/bin") if(EXISTS "${openssl_bin_dir}") get_filename_component(openssl_ssl_basename "${OPENSSL_SSL_LIBRARY}" NAME_WE) file(GLOB openssl_ssl_dll "${openssl_bin_dir}/${openssl_ssl_basename}*.dll") list(LENGTH openssl_ssl_dll num_findings) if(num_findings GREATER 1) set(openssl_ssl_dll "") endif() get_filename_component(openssl_crypto_basename "${OPENSSL_CRYPTO_LIBRARY}" NAME_WE) file(GLOB openssl_crypto_dll "${openssl_bin_dir}/${openssl_crypto_basename}*.dll") list(LENGTH openssl_crypto_dll num_findings) if(num_findings GREATER 1) set(openssl_crypto_dll "") endif() endif() endif() set(MITK_OPENSSL_SSL_DLL "${openssl_ssl_dll}" CACHE FILEPATH "") if(DEFINED CACHE{MITK_OPENSSL_SSL_DLL} AND NOT MITK_OPENSSL_SSL_DLL AND openssl_ssl_dll) set(MITK_OPENSSL_SSL_DLL "${openssl_ssl_dll}" CACHE FILEPATH "" FORCE) endif() set(MITK_OPENSSL_CRYPTO_DLL "${openssl_crypto_dll}" CACHE FILEPATH "") if(DEFINED CACHE{MITK_OPENSSL_CRYPTO_DLL} AND NOT MITK_OPENSSL_CRYPTO_DLL AND openssl_crypto_dll) set(MITK_OPENSSL_CRYPTO_DLL "${openssl_crypto_dll}" CACHE FILEPATH "" FORCE) endif() if(MITK_OPENSSL_SSL_DLL AND EXISTS "${MITK_OPENSSL_SSL_DLL}" AND MITK_OPENSSL_CRYPTO_DLL AND EXISTS "${MITK_OPENSSL_CRYPTO_DLL}") foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${MITK_BINARY_DIR}/bin/${config_type}") configure_file("${MITK_OPENSSL_SSL_DLL}" "${MITK_BINARY_DIR}/bin/${config_type}/" COPYONLY) configure_file("${MITK_OPENSSL_CRYPTO_DLL}" "${MITK_BINARY_DIR}/bin/${config_type}/" COPYONLY) endforeach() MITK_INSTALL(FILES "${MITK_OPENSSL_SSL_DLL}" "${MITK_OPENSSL_CRYPTO_DLL}" ) endif() endif() # Look for optional Doxygen package find_package(Doxygen) option(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) mark_as_advanced(BLUEBERRY_DEBUG_SMARTPOINTER) # Ask the user to show the console window for applications option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) if(NOT MITK_FAST_TESTING) if(MITK_CTEST_SCRIPT_MODE STREQUAL "Continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "Experimental") set(MITK_FAST_TESTING ON) endif() endif() if(NOT UNIX) set(MITK_WIN32_FORCE_STATIC "STATIC" CACHE INTERNAL "Use this variable to always build static libraries on non-unix platforms") endif() if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() # Configure pixel types used for ITK image access multiplexing mitkMacroConfigureItkPixelTypes() # Configure module naming conventions set(MITK_MODULE_NAME_REGEX_MATCH "^[A-Z].*$") set(MITK_MODULE_NAME_REGEX_NOT_MATCH "^[Mm][Ii][Tt][Kk].*$") set(MITK_DEFAULT_MODULE_NAME_PREFIX "Mitk") set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) set(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME 1) #----------------------------------------------------------------------------- # Get MITK version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK) mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK) # MITK_VERSION set(MITK_VERSION_STRING "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") if(MITK_VERSION_PATCH STREQUAL "99") set(MITK_VERSION_STRING "${MITK_VERSION_STRING}-${MITK_REVISION_SHORTID}") endif() #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on macOS all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Applications") if(EXISTS "${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake") set(MITK_APPS "") include("${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) list(GET target_info_list 0 app_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) set(MACOSX_BUNDLE_NAMES ${MACOSX_BUNDLE_NAMES} Mitk${app_name}) endif() endforeach() endif() endforeach() endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # MITK C/CXX Flags #----------------------------------------------------------------------------- set(MITK_C_FLAGS "${COVERAGE_C_FLAGS}") set(MITK_C_FLAGS_DEBUG ) set(MITK_C_FLAGS_RELEASE ) set(MITK_CXX_FLAGS "${COVERAGE_CXX_FLAGS} ${MITK_CXX${MITK_CXX_STANDARD}_FLAG}") set(MITK_CXX_FLAGS_DEBUG ) set(MITK_CXX_FLAGS_RELEASE ) set(MITK_EXE_LINKER_FLAGS ) set(MITK_SHARED_LINKER_FLAGS ) if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -DWIN32_LEAN_AND_MEAN -DNOMINMAX") mitkFunctionCheckCompilerFlags("/wd4005" MITK_CXX_FLAGS) # warning C4005: macro redefinition mitkFunctionCheckCompilerFlags("/wd4231" MITK_CXX_FLAGS) # warning C4231: nonstandard extension used : 'extern' before template explicit instantiation # the following line should be removed after fixing bug 17637 mitkFunctionCheckCompilerFlags("/wd4316" MITK_CXX_FLAGS) # warning C4316: object alignment on heap mitkFunctionCheckCompilerFlags("/wd4180" MITK_CXX_FLAGS) # warning C4180: qualifier applied to function type has no meaning mitkFunctionCheckCompilerFlags("/wd4251" MITK_CXX_FLAGS) # warning C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' endif() if(APPLE) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -DGL_SILENCE_DEPRECATION") # Apple deprecated OpenGL in macOS 10.14 endif() if(NOT MSVC_VERSION) foreach(_flag -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Wno-error=gnu -Wno-error=unknown-pragmas # The strict-overflow warning is generated by ITK template code -Wno-error=strict-overflow -Woverloaded-virtual -Wstrict-null-sentinel #-Wold-style-cast #-Wsign-promo -Wno-deprecated-copy -Wno-array-bounds -Wno-cast-function-type -Wno-maybe-uninitialized -Wno-error=stringop-overread -fdiagnostics-show-option ) mitkFunctionCheckCAndCXXCompilerFlags(${_flag} MITK_C_FLAGS MITK_CXX_FLAGS) endforeach() endif() if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionCheckCAndCXXCompilerFlags("-fstack-protector-all" MITK_C_FLAGS MITK_CXX_FLAGS) set(MITK_CXX_FLAGS_RELEASE "-U_FORTIFY_SOURCES -D_FORTIFY_SOURCE=2 ${MITK_CXX_FLAGS_RELEASE}") endif() set(MITK_MODULE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(MITK_EXE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) #----------------------------------------------------------------------------- # MITK Packages #----------------------------------------------------------------------------- set(MITK_MODULES_PACKAGE_DEPENDS_DIR ${MITK_SOURCE_DIR}/CMake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) set(MITK_PACKAGE_DEPENDS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMake/PackageDepends") if(EXISTS "${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}") list(APPEND MODULES_PACKAGE_DEPENDS_DIRS "${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}") endif() endforeach() if(NOT MITK_USE_SYSTEM_Boost) set(Boost_NO_SYSTEM_PATHS 1) endif() set(Boost_USE_MULTITHREADED 1) set(Boost_USE_STATIC_LIBS 0) set(Boost_USE_STATIC_RUNTIME 0) set(Boost_ADDITIONAL_VERSIONS 1.74 1.74.0) # We need this later for a DCMTK workaround set(_dcmtk_dir_orig ${DCMTK_DIR}) # This property is populated at the top half of this file get_property(MITK_EXTERNAL_PROJECTS GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(MITK_USE_${ep} AND _package) if(_components) find_package(${_package} COMPONENTS ${_components} REQUIRED CONFIG) else() # Prefer config mode first because it finds external # Config.cmake files pointed at by _DIR variables. # Otherwise, existing Find.cmake files could fail. if(DEFINED ${_package}_DIR) #we store the information because it will be overwritten by find_package #and would get lost for all EPs that use on Find.cmake instead of config #files. set(_temp_EP_${_package}_dir ${${_package}_DIR}) endif(DEFINED ${_package}_DIR) find_package(${_package} QUIET CONFIG) string(TOUPPER "${_package}" _package_uc) if(NOT (${_package}_FOUND OR ${_package_uc}_FOUND)) if(DEFINED _temp_EP_${_package}_dir) set(${_package}_DIR ${_temp_EP_${_package}_dir} CACHE PATH "externaly set dir of the package ${_package}" FORCE) endif(DEFINED _temp_EP_${_package}_dir) find_package(${_package} REQUIRED) endif() endif() endif() endforeach() # Ensure that the MITK CMake module path comes first set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) if(MITK_USE_DCMTK) if(${_dcmtk_dir_orig} MATCHES "${MITK_EXTERNAL_PROJECT_PREFIX}.*") # Help our FindDCMTK.cmake script find our super-build DCMTK set(DCMTK_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) else() # Use the original value set(DCMTK_DIR ${_dcmtk_dir_orig}) endif() endif() if(MITK_USE_DCMQI) # Due to the preferred CONFIG mode in find_package calls above, # the DCMQIConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMQI. # Help our FindDCMQI.cmake script find our super-build DCMQI set(DCMQI_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) find_package(DCMQI REQUIRED) endif() if(MITK_USE_OpenIGTLink) link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() if(MITK_USE_OpenCL) find_package(OpenCL REQUIRED) endif() if(MITK_USE_OpenMP) find_package(OpenMP REQUIRED COMPONENTS CXX) else() find_package(OpenMP QUIET COMPONENTS CXX) if(OpenMP_FOUND) set(MITK_USE_OpenMP ON CACHE BOOL "" FORCE) elseif(APPLE AND OpenMP_libomp_LIBRARY AND NOT OpenMP_CXX_LIB_NAMES) set(OpenMP_CXX_LIB_NAMES libomp CACHE STRING "" FORCE) get_filename_component(openmp_lib_dir "${OpenMP_libomp_LIBRARY}" DIRECTORY) set(openmp_include_dir "${openmp_lib_dir}/../include") if(EXISTS "${openmp_include_dir}") get_filename_component(openmp_include_dir "${openmp_include_dir}" REALPATH) set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${openmp_include_dir}" CACHE STRING "" FORCE) find_package(OpenMP QUIET COMPONENTS CXX) if(OpenMP_FOUND) set(MITK_USE_OpenMP ON CACHE BOOL "" FORCE) endif() endif() endif() endif() # Qt support if(MITK_USE_Qt5) find_package(Qt5Core ${MITK_QT5_MINIMUM_VERSION} REQUIRED) # at least Core required get_target_property(_qmake_exec Qt5::qmake LOCATION) execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS RESULT_VARIABLE _result OUTPUT_VARIABLE QT_BINARY_DIR ERROR_VARIABLE _error ) string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR) if(_result OR NOT EXISTS "${QT_BINARY_DIR}") message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") endif() find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt5 qhelpgenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_COLLECTIONGENERATOR_EXECUTABLE NAMES qcollectiongenerator qcollectiongenerator-qt5 qcollectiongenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_ASSISTANT_EXECUTABLE NAMES assistant assistant-qt5 assistant5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_XMLPATTERNS_EXECUTABLE NAMES xmlpatterns PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) mark_as_advanced(QT_HELPGENERATOR_EXECUTABLE QT_COLLECTIONGENERATOR_EXECUTABLE QT_ASSISTANT_EXECUTABLE QT_XMLPATTERNS_EXECUTABLE ) if(MITK_USE_BLUEBERRY) option(BLUEBERRY_USE_QT_HELP "Enable support for integrating plugin documentation into Qt Help" ${DOXYGEN_FOUND}) mark_as_advanced(BLUEBERRY_USE_QT_HELP) # Sanity checks for in-application BlueBerry plug-in help generation if(BLUEBERRY_USE_QT_HELP) set(_force_blueberry_use_qt_help_to_off 0) if(NOT DOXYGEN_FOUND) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen was not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(DOXYGEN_FOUND AND DOXYGEN_VERSION VERSION_LESS 1.8.7) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen version 1.8.7 or newer not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_HELPGENERATOR_EXECUTABLE) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because QT_HELPGENERATOR_EXECUTABLE is empty.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT MITK_USE_Qt5) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because MITK_USE_Qt5 is OFF.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_XMLPATTERNS_EXECUTABLE) message("You have enabled Qt Help support, but QT_XMLPATTERNS_EXECUTABLE is empty") set(_force_blueberry_use_qt_help_to_off 1) endif() if(_force_blueberry_use_qt_help_to_off) set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating plugin documentation into Qt Help" FORCE) endif() endif() if(BLUEBERRY_QT_HELP_REQUIRED AND NOT BLUEBERRY_USE_QT_HELP) message(FATAL_ERROR "BLUEBERRY_USE_QT_HELP is required to be set to ON") endif() endif() endif() #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch (const std::exception& e) { fprintf(stderr, \"%s\\n\", e.what()); return EXIT_FAILURE; } catch (...) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; }") set(MITK_TEST_OUTPUT_DIR "${MITK_BINARY_DIR}/test_output") if(NOT EXISTS ${MITK_TEST_OUTPUT_DIR}) file(MAKE_DIRECTORY ${MITK_TEST_OUTPUT_DIR}) endif() # Test the package target include(mitkPackageTest) endif() configure_file(mitkTestingConfig.h.in ${MITK_BINARY_DIR}/mitkTestingConfig.h) #----------------------------------------------------------------------------- # MITK_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If MITK_SUPERBUILD_BINARY_DIR isn't defined, it means MITK is *NOT* build using Superbuild. # In that specific case, MITK_SUPERBUILD_BINARY_DIR should default to MITK_BINARY_DIR if(NOT DEFINED MITK_SUPERBUILD_BINARY_DIR) set(MITK_SUPERBUILD_BINARY_DIR ${MITK_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Set C/CXX and linker flags for MITK code #----------------------------------------------------------------------------- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MITK_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MITK_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MITK_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MITK_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MITK_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MITK_C_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MITK_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MITK_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MITK_MODULE_LINKER_FLAGS}") #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Utilities) add_subdirectory(Modules) include("${CMAKE_CURRENT_SOURCE_DIR}/Modules/ModuleList.cmake") mitkFunctionWhitelistModules(MITK MITK_MODULES) set(MITK_ROOT_FOLDER_BACKUP "${MITK_ROOT_FOLDER}") foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) get_filename_component(MITK_ROOT_FOLDER "${MITK_EXTENSION_DIR}" NAME) set(MITK_MODULES_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Modules") if(EXISTS "${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake") set(MITK_MODULES "") include("${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake") foreach(mitk_module ${MITK_MODULES}) add_subdirectory("${MITK_MODULES_EXTENSION_DIR}/${mitk_module}" "Modules/${mitk_module}") endforeach() endif() set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) endforeach() set(MITK_ROOT_FOLDER "${MITK_ROOT_FOLDER_BACKUP}") add_subdirectory(Wrapping) set(MITK_DOXYGEN_OUTPUT_DIR "${PROJECT_BINARY_DIR}/Documentation/Doxygen" CACHE PATH "Output directory for doxygen generated documentation.") if(MITK_USE_BLUEBERRY) include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") mitkFunctionWhitelistPlugins(MITK MITK_PLUGINS) set(mitk_plugins_fullpath "") foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath Plugins/${mitk_plugin}) endforeach() set(MITK_PLUGIN_REGEX_LIST "") foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) set(MITK_PLUGINS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Plugins") if(EXISTS "${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake") set(MITK_PLUGINS "") include("${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake") foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath "${MITK_PLUGINS_EXTENSION_DIR}/${mitk_plugin}") endforeach() endif() endforeach() if(EXISTS ${MITK_PRIVATE_MODULES}/PluginList.cmake) include(${MITK_PRIVATE_MODULES}/PluginList.cmake) foreach(mitk_plugin ${MITK_PRIVATE_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PRIVATE_MODULES}/${mitk_plugin}) endforeach() endif() if(MITK_BUILD_EXAMPLES) include("${CMAKE_CURRENT_SOURCE_DIR}/Examples/Plugins/PluginList.cmake") set(mitk_example_plugins_fullpath ) foreach(mitk_example_plugin ${MITK_EXAMPLE_PLUGINS}) list(APPEND mitk_example_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) list(APPEND mitk_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) endforeach() endif() # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_[a-zA-Z0-9_]+$") set(re_ctkplugin_bb "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk re_ctkplugin_bb MITK_PLUGIN_REGEX_LIST OUTPUT_VARIABLE ${varname}) endmacro() # Get infos about application directories and build options set(mitk_apps_fullpath "") foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Applications") if(EXISTS "${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake") set(MITK_APPS "") include("${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 directory_name) list(GET target_info_list 1 option_name) if(${option_name}) list(APPEND mitk_apps_fullpath "${MITK_APPLICATIONS_EXTENSION_DIR}/${directory_name}^^${option_name}") endif() endforeach() endif() endforeach() if (mitk_plugins_fullpath) ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) endif() set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- set(MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS) set(MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS "${MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS} \"${MITK_EXTENSION_DIR}\"") set(MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS "${MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS} \"${MITK_EXTENSION_DIR}\"") endforeach() if(DOXYGEN_FOUND) add_subdirectory(Documentation) endif() #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables # These are the default variables, which can be overwritten ( see below ) include(mitkSetupCPack) set(use_default_config ON) set(ALL_MITK_APPS "") set(activated_apps_no 0) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Applications") if(EXISTS "${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake") set(MITK_APPS "") include("${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake") foreach(mitk_app ${MITK_APPS}) string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 directory_name) list(GET target_info_list 1 option_name) list(GET target_info_list 2 executable_name) list(APPEND ALL_MITK_APPS "${MITK_EXTENSION_DIR}/Applications/${directory_name}^^${option_name}^^${executable_name}") if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() endif() endforeach() list(LENGTH ALL_MITK_APPS app_count) if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS)) # Corner case if there is only one app in total set(use_project_cpack ON) elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS) # Only one app is enabled (no "build all" flag set) set(use_project_cpack ON) else() # Less or more then one app is enabled set(use_project_cpack OFF) endif() foreach(mitk_app ${ALL_MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) list(GET target_info_list 2 executable_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) # check whether application specific configuration files will be used if(use_project_cpack) # use files if they exist if(EXISTS "${target_dir}/CPackOptions.cmake") include("${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${target_dir}/CPackConfig.cmake") configure_file(${target_dir}/CPackConfig.cmake.in ${CPACK_PROJECT_CONFIG_FILE} @ONLY) set(use_default_config OFF) endif() endif() # add link to the list list(APPEND CPACK_CREATE_DESKTOP_LINKS "${executable_name}") endif() endforeach() # if no application specific configuration file was used, use default if(use_default_config) configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake") endif() # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- # ---------------- Export targets ----------------- set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake") file(REMOVE ${MITK_EXPORTS_FILE}) set(targets_to_export) get_property(module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) if(module_targets) list(APPEND targets_to_export ${module_targets}) endif() if(MITK_USE_BLUEBERRY) if(MITK_PLUGIN_LIBRARIES) list(APPEND targets_to_export ${MITK_PLUGIN_LIBRARIES}) endif() endif() export(TARGETS ${targets_to_export} APPEND FILE ${MITK_EXPORTS_FILE}) set(MITK_EXPORTED_TARGET_PROPERTIES ) foreach(target_to_export ${targets_to_export}) get_target_property(autoload_targets ${target_to_export} MITK_AUTOLOAD_TARGETS) if(autoload_targets) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_TARGETS \"${autoload_targets}\")") endif() get_target_property(autoload_dir ${target_to_export} MITK_AUTOLOAD_DIRECTORY) if(autoload_dir) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_DIRECTORY \"${autoload_dir}\")") endif() get_target_property(deprecated_module ${target_to_export} MITK_MODULE_DEPRECATED_SINCE) if(deprecated_module) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_MODULE_DEPRECATED_SINCE \"${deprecated_module}\")") endif() endforeach() # ---------------- External projects ----------------- get_property(MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS_CONFIG GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) set(MITK_CONFIG_EXTERNAL_PROJECTS ) #string(REPLACE "^^" ";" _mitk_external_projects ${MITK_EXTERNAL_PROJECTS}) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} set(MITK_USE_${ep} ${MITK_USE_${ep}}) set(MITK_${ep}_DIR \"${${ep}_DIR}\") set(MITK_${ep}_COMPONENTS ${_components}) ") endforeach() foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(_components) set(_components_arg COMPONENTS \${_components}) else() set(_components_arg) endif() if(_package) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} if(MITK_USE_${ep}) set(${ep}_DIR \${MITK_${ep}_DIR}) if(MITK_${ep}_COMPONENTS) mitkMacroFindDependency(${_package} COMPONENTS \${MITK_${ep}_COMPONENTS}) else() mitkMacroFindDependency(${_package}) endif() endif()") endif() endforeach() # ---------------- Tools ----------------- configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY) # ---------------- Configure files ----------------- configure_file(mitkVersion.h.in ${MITK_BINARY_DIR}/mitkVersion.h) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc) set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY) write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${MITK_VERSION_STRING} COMPATIBILITY AnyNewerVersion) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) if(MSVC AND TARGET MitkWorkbench) set_directory_properties(PROPERTIES VS_STARTUP_PROJECT MitkWorkbench) endif() foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Applications") if(EXISTS "${MITK_APPLICATIONS_EXTENSION_DIR}/CMakeLists.txt") add_subdirectory("${MITK_APPLICATIONS_EXTENSION_DIR}" "Applications") endif() endforeach() #----------------------------------------------------------------------------- # MITK Examples #----------------------------------------------------------------------------- if(MITK_BUILD_EXAMPLES) # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Examples) endif() #----------------------------------------------------------------------------- # Print configuration summary #----------------------------------------------------------------------------- message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL ) diff --git a/MITKConfig.cmake.in b/MITKConfig.cmake.in index 530ee7c6e3..4e7ef7c55b 100644 --- a/MITKConfig.cmake.in +++ b/MITKConfig.cmake.in @@ -1,314 +1,314 @@ if(CMAKE_VERSION VERSION_LESS @MITK_CMAKE_MINIMUM_REQUIRED_VERSION@) message(FATAL_ERROR "MITK requires at least CMake Version @MITK_CMAKE_MINIMUM_REQUIRED_VERSION@") endif() # The MITK version number set(MITK_VERSION_MAJOR "@MITK_VERSION_MAJOR@") set(MITK_VERSION_MINOR "@MITK_VERSION_MINOR@") set(MITK_VERSION_PATCH "@MITK_VERSION_PATCH@") set(MITK_VERSION_STRING "@MITK_VERSION_STRING@") #----------------------------------------------------------------------------- # C++ language standard #----------------------------------------------------------------------------- set(MITK_CXX_STANDARD @MITK_CXX_STANDARD@) #----------------------------------------------------------------------------- # Include required CMake scripts #----------------------------------------------------------------------------- # Update the CMake module path set(MITK_CMAKE_MODULE_PATH "@MITK_SOURCE_DIR@/CMake") list(APPEND CMAKE_MODULE_PATH ${MITK_CMAKE_MODULE_PATH}) # Standard CMake macros include(CMakeParseArguments) include(FeatureSummary) include(FindPackageHandleStandardArgs) include(GenerateExportHeader) # Include MITK macros include(MacroParseArguments) include(mitkFunctionAddManifest) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckMitkCompatibility) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionCreateBlueBerryApplication) include(mitkFunctionCreateCommandLineApp) include(mitkFunctionCreateModule) include(mitkFunctionCreatePlugin) include(mitkFunctionCreateProvisioningFile) include(mitkFunctionCreateWindowsBatchScript) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionUseModules) include(mitkMacroCreateExecutable) include(mitkMacroCreateModuleTests) include(mitkMacroFindDependency) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetPMDPlatformString) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroMultiplexPicType) #----------------------------------------------------------------------------- # MITK flags and directories #----------------------------------------------------------------------------- # MITK compiler flags set(MITK_C_FLAGS "@MITK_C_FLAGS@") set(MTTK_C_FLAGS_DEBUG "@MITK_C_FLAGS_DEBUG@") set(MITK_C_FLAGS_RELEASE "@MITK_C_FLAGS_RELEASE@") set(MITK_CXX_FLAGS "@MITK_CXX_FLAGS@") set(MTTK_CXX_FLAGS_DEBUG "@MITK_CXX_FLAGS_DEBUG@") set(MITK_CXX_FLAGS_RELEASE "@MITK_CXX_FLAGS_RELEASE@") # MITK linker flags set(MITK_EXE_LINKER_FLAGS "@MITK_EXE_LINKER_FLAGS@") set(MITK_SHARED_LINKER_FLAGS "@MITK_SHARED_LINKER_FLAGS@") set(MITK_MODULE_LINKER_FLAGS "@MITK_MODULE_LINKER_FLAGS@") # MITK specific directories set(MITK_SOURCE_DIR "@MITK_SOURCE_DIR@") set(MITK_BINARY_DIR "@MITK_BINARY_DIR@") set(MITK_CMAKE_DIR "@MITK_CMAKE_DIR@") # MITK output directories set(MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY "@MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY@") set(MITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY "@MITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY@") set(MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY "@MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY@") #----------------------------------------------------------------------------- # Miscellaneous variables #----------------------------------------------------------------------------- # Internal version numbers, used for approximate compatibility checks # of a MITK development version (non-release). set(MITK_VERSION_PLUGIN_SYSTEM 2) # dropped legacy BlueBerry plug-in CMake support set(MITK_DATA_DIR "@MITK_DATA_DIR@") set(UTILITIES_DIR "@UTILITIES_DIR@") set(REGISTER_QFUNCTIONALITY_CPP_IN "@REGISTER_QFUNCTIONALITY_CPP_IN@") set(MITK_DOXYGEN_TAGFILE_NAME "@MITK_DOXYGEN_TAGFILE_NAME@") set(MITK_LEGACY_EXPORT_MACRO_NAME 1) set(DCMTK_CMAKE_DEBUG_POSTFIX @DCMTK_CMAKE_DEBUG_POSTFIX@) # Get the canonical name of the directory to avoid potential case mismatch, # e.g. in the drive letter on Windows. get_filename_component(CMAKE_CURRENT_LIST_DIR_REALPATH ${CMAKE_CURRENT_LIST_DIR} REALPATH) if(CMAKE_CURRENT_LIST_DIR_REALPATH STREQUAL MITK_BINARY_DIR) set(MITK_EXTERNAL_PROJECT_PREFIX @MITK_EXTERNAL_PROJECT_PREFIX@) endif() set(MITK_MODULES_PACKAGE_DEPENDS_DIR "@MITK_MODULES_PACKAGE_DEPENDS_DIR@") if(MODULES_PACKAGE_DEPENDS_DIRS) list(APPEND MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) list(REMOVE_DUPLICATES MODULES_PACKAGE_DEPENDS_DIRS) else() set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) endif() #----------------------------------------------------------------------------- # External dependencies #----------------------------------------------------------------------------- list(APPEND CMAKE_PREFIX_PATH "@MITK_EXTERNAL_PROJECT_PREFIX@") # ----------------------------------------- # Qt variables and dependencies set(MITK_USE_Qt5 @MITK_USE_Qt5@) if(MITK_USE_Qt5) set(MITK_QT5_MINIMUM_VERSION @MITK_QT5_MINIMUM_VERSION@) set(MITK_QT5_COMPONENTS @MITK_QT5_COMPONENTS@) mitkMacroFindDependency(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS}) endif() # ----------------------------------------- # Special Python variables set(MITK_USE_Python3 @MITK_USE_Python3@) if(MITK_USE_Python3) set(PYTHON_EXECUTABLE "@PYTHON_EXECUTABLE@" CACHE FILEPATH "") set(PYTHON_INCLUDE_DIR "@PYTHON_INCLUDE_DIR@" CACHE PATH "") set(PYTHON_LIBRARY "@PYTHON_LIBRARY@" CACHE FILEPATH "") set(PYTHON_INCLUDE_DIR2 "@PYTHON_INCLUDE_DIR2@" CACHE PATH "") mitkMacroFindDependency(Python3 COMPONENTS Interpreter Development NumPy) endif() # ----------------------------------------- # Special Boost variables set(MITK_USE_Boost_LIBRARIES @MITK_USE_Boost_LIBRARIES@) set(MITK_USE_SYSTEM_Boost @MITK_USE_SYSTEM_Boost@) -set(BOOST_ROOT "@BOOST_ROOT@" CACHE PATH "") +set(Boost_ROOT "@Boost_ROOT@" CACHE PATH "") set(BOOST_LIBRARYDIR "@BOOST_LIBRARYDIR@" CACHE PATH "") set(Boost_ADDITIONAL_VERSIONS 1.74 1.74.0) # We need this later for a DCMTK workaround set(_dcmtk_dir_orig "@DCMTK_DIR@") # ----------------------------------------- # External dependencies from the superbuild # or injected from somewhere else via # _DIR variables. @MITK_CONFIG_EXTERNAL_PROJECTS@ # Ensure the MITK module path comes first set(CMAKE_MODULE_PATH ${MITK_CMAKE_MODULE_PATH} ${CMAKE_MODULE_PATH}) # ----------------------------------------- # Special handling for DCMTK if(MITK_USE_DCMTK) # Due to the preferred CONFIG mode in find_package calls above, # the DCMTKConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMTK. if(${_dcmtk_dir_orig} MATCHES "${MITK_EXTERNAL_PROJECT_PREFIX}.*") # Help our FindDCMTK.cmake script find our super-build DCMTK set(DCMTK_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) else() # Use the original value set(DCMTK_DIR ${_dcmtk_dir_orig}) endif() find_package(DCMTK REQUIRED MODULE) endif() # ----------------------------------------- # Special handling for DCMQI if(MITK_USE_DCMQI) # Due to the preferred CONFIG mode in find_package calls above, # the DCMQIConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMQI. # Help our FindDCMQI.cmake script find our super-build DCMQI set(DCMQI_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) find_package(DCMQI REQUIRED) endif() # ----------------------------------------- # Special handling for Boost if(MITK_USE_Boost) link_directories(${Boost_LIBRARY_DIRS}) endif() # ----------------------------------------- # Special handling for OpenIGTLink if(MITK_USE_OpenIGTLink) link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() # ----------------------------------------- # Internal project dependencies set(CppMicroServices_DIR "@CppMicroServices_DIR@") mitkMacroFindDependency(CppMicroServices) set(MITK_USE_BLUEBERRY @MITK_USE_BLUEBERRY@) if(MITK_USE_BLUEBERRY) set(MITK_PLUGIN_USE_FILE "@MITK_PLUGIN_USE_FILE@") if(MITK_PLUGIN_USE_FILE) if(EXISTS "${MITK_PLUGIN_USE_FILE}") include("${MITK_PLUGIN_USE_FILE}") endif() endif() set(MITK_PLUGIN_PROVISIONING_FILE "@MITK_EXTAPP_PROVISIONING_FILE@") set(MITK_PROVISIONING_FILES "${BLUEBERRY_PLUGIN_PROVISIONING_FILE}" "${MITK_PLUGIN_PROVISIONING_FILE}") endif() set(BLUEBERRY_USE_QT_HELP @BLUEBERRY_USE_QT_HELP@) if(BLUEBERRY_USE_QT_HELP AND DOXYGEN_VERSION VERSION_LESS "1.8.7") message("Setting BLUEBERRY_USE_QT_HELP to OFF because Doxygen version 1.8.7 or newer not found.") set(BLUEBERRY_USE_QT_HELP OFF) endif() set(BLUEBERRY_QTPLUGIN_PATH "@BLUEBERRY_QTPLUGIN_PATH@") set(QT_HELPGENERATOR_EXECUTABLE "@QT_HELPGENERATOR_EXECUTABLE@") set(QT_COLLECTIONGENERATOR_EXECUTABLE "@QT_COLLECTIONGENERATOR_EXECUTABLE@") set(QT_ASSISTANT_EXECUTABLE "@QT_ASSISTANT_EXECUTABLE@") set(QT_XMLPATTERNS_EXECUTABLE "@QT_XMLPATTERNS_EXECUTABLE@") #----------------------------------------------------------------------------- # MITK sub-project variables #----------------------------------------------------------------------------- # External SDK directories set(MITK_PMD_SDK_DIR @MITK_PMD_SDK_DIR@) # MITK ToF use variables set(MITK_TOF_PMDCAMCUBE_AVAILABLE @MITK_USE_TOF_PMDCAMCUBE@) if(MITK_TOF_PMDCAMCUBE_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_PMDCAMCUBE "Enable support for PMD Cam Cube" @MITK_USE_TOF_PMDCAMCUBE@) mark_as_advanced(MITK_USE_TOF_PMDCAMCUBE) endif() set(MITK_TOF_PMDCAMBOARD_AVAILABLE @MITK_USE_TOF_PMDCAMBOARD@) if(MITK_TOF_PMDCAMBOARD_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_PMDCAMBOARD "Enable support for PMD Cam Board" @MITK_USE_TOF_PMDCAMBOARD@) mark_as_advanced(MITK_USE_TOF_PMDCAMBOARD) endif() set(MITK_TOF_PMDO3_AVAILABLE @MITK_USE_TOF_PMDO3@) if(MITK_TOF_PMDO3_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_PMDO3 "Enable support for PMD =3" @MITK_USE_TOF_PMDO3@) mark_as_advanced(MITK_USE_TOF_PMDO3) endif() set(MITK_TOF_KINECT_AVAILABLE @MITK_USE_TOF_KINECT@) if(MITK_TOF_KINECT_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_KINECT "Enable support for Kinect" @MITK_USE_TOF_KINECT@) mark_as_advanced(MITK_USE_TOF_KINECT) endif() set(MITK_TOF_MESASR4000_AVAILABLE @MITK_USE_TOF_MESASR4000@) if(MITK_TOF_MESASR4000_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_MESASR4000 "Enable support for MESA SR4000" @MITK_USE_TOF_MESASR4000@) mark_as_advanced(MITK_USE_TOF_MESASR4000) endif() if(MITK_USE_IGT) #include("${MITK_DIR}/mitkIGTConfig.cmake") endif() #----------------------------------------------------------------------------- # Import MITK targets and set custom properties #----------------------------------------------------------------------------- if(NOT MITK_EXPORTS_FILE_INCLUDED) if(EXISTS "@MITK_EXPORTS_FILE@") set(MITK_EXPORTS_FILE_INCLUDED 1) include("@MITK_EXPORTS_FILE@") endif() endif() # Set properties on exported targets @MITK_EXPORTED_TARGET_PROPERTIES@ #----------------------------------------------------------------------------- # Install rules #----------------------------------------------------------------------------- # Install rules for ToF libraries loaded at runtime if(EXISTS "@MITK_BINARY_DIR@/mitkToFHardwareInstallRules.cmake") include("@MITK_BINARY_DIR@/mitkToFHardwareInstallRules.cmake") endif() diff --git a/Modules/Core/include/mitkBaseGeometry.h b/Modules/Core/include/mitkBaseGeometry.h index 833189965d..4d00557d8d 100644 --- a/Modules/Core/include/mitkBaseGeometry.h +++ b/Modules/Core/include/mitkBaseGeometry.h @@ -1,752 +1,763 @@ /*============================================================================ 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 mitkBaseGeometry_h #define mitkBaseGeometry_h #include "mitkOperationActor.h" #include #include #include "itkScalableAffineTransform.h" #include "mitkNumericTypes.h" #include #include #include #include #include #include class vtkMatrix4x4; class vtkMatrixToLinearTransform; class vtkLinearTransform; namespace mitk { //##Documentation //## @brief Standard 3D-BoundingBox typedef //## //## Standard 3D-BoundingBox typedef to get rid of template arguments (3D, type). typedef itk::BoundingBox BoundingBox; //##Documentation //## @brief Standard typedef for time-bounds typedef itk::FixedArray TimeBounds; typedef itk::FixedArray FixedArrayType; //##Documentation //## @brief BaseGeometry Describes the geometry of a data object //## //## The class holds //## \li a bounding box which is axes-parallel in intrinsic coordinates //## (often integer indices of pixels), to be accessed by //## GetBoundingBox() //## \li a transform to convert intrinsic coordinates into a //## world-coordinate system with coordinates in millimeters //## and milliseconds (all are floating point values), to //## be accessed by GetIndexToWorldTransform() //## \li an origin and spacing to define the geometry //## //## BaseGeometry and its sub-classes allow converting between //## intrinsic coordinates (called index or unit coordinates) //## and world-coordinates (called world or mm coordinates), //## e.g. WorldToIndex. //## In case you need integer index coordinates, provide an //## mitk::Index3D (or itk::Index) as target variable to //## WorldToIndex, otherwise you will get a continuous index //## (floating point values). //## //## An important sub-class is SlicedGeometry3D, which describes //## data objects consisting of slices, e.g., objects of type Image. //## Conversions between world coordinates (in mm) and unit coordinates //## (e.g., pixels in the case of an Image) can be performed. //## //## For more information on related classes, see \ref Geometry. //## //## BaseGeometry instances referring to an Image need a slightly //## different definition of corners, see SetImageGeometry. This //## is usually automatically called by Image. //## //## BaseGeometry have to be initialized in the method GenerateOutputInformation() //## of BaseProcess (or CopyInformation/ UpdateOutputInformation of BaseData, //## if possible, e.g., by analyzing pic tags in Image) subclasses. See also //## itk::ProcessObject::GenerateOutputInformation(), //## itk::DataObject::CopyInformation() and //## itk::DataObject::UpdateOutputInformation(). //## //## At least, it can return the bounding box of the data object. //## //## The BaseGeometry class is an abstract class. The most simple implementation //## is the subclass Geometry3D. //## //## Rule: everything is in mm (ms) if not stated otherwise. //## @ingroup Geometry class MITKCORE_EXPORT BaseGeometry : public itk::Object, public OperationActor { public: mitkClassMacroItkParent(BaseGeometry, itk::Object); itkCloneMacro(Self); // ********************************** TypeDef ********************************** typedef GeometryTransformHolder::TransformType TransformType; typedef itk::BoundingBox BoundingBoxType; typedef BoundingBoxType::BoundsArrayType BoundsArrayType; typedef BoundingBoxType::Pointer BoundingBoxPointer; // ********************************** Origin, Spacing ********************************** //##Documentation //## @brief Get the origin, e.g. the upper-left corner of the plane const Point3D GetOrigin() const; //##Documentation //## @brief Set the origin, i.e. the upper-left corner of the plane //## void SetOrigin(const Point3D &origin); //##Documentation //## @brief Get the spacing (size of a pixel). //## const mitk::Vector3D GetSpacing() const; //##Documentation //## @brief Set the spacing (m_Spacing). //## //##The spacing is also changed in the IndexToWorldTransform. void SetSpacing(const mitk::Vector3D &aSpacing, bool enforceSetSpacing = false); //##Documentation //## @brief Get the origin as VnlVector //## //## \sa GetOrigin VnlVector GetOriginVnl() const; // ********************************** other functions ********************************** //##Documentation //## @brief Get the DICOM FrameOfReferenceID referring to the //## used world coordinate system itkGetConstMacro(FrameOfReferenceID, unsigned int); //##Documentation //## @brief Set the DICOM FrameOfReferenceID referring to the //## used world coordinate system itkSetMacro(FrameOfReferenceID, unsigned int); itkGetConstMacro(IndexToWorldTransformLastModified, unsigned long); //##Documentation //## @brief Overload of function Modified() to prohibit several calls of Modified() using the ModifiedLock class. //## //## For the use of Modified(), see class ModifiedLock. void Modified() const override; friend class ModifiedLock; //##Documentation //## @brief Is this BaseGeometry in a state that is valid? //## //## This function returns always true in the BaseGeometry class. Other implementations are possible in subclasses. virtual bool IsValid() const; // ********************************** Initialize ********************************** //##Documentation //## @brief Initialize the BaseGeometry void Initialize(); void InitializeGeometry(Self *newGeometry) const; // ********************************** Transformations Set/Get ********************************** //##Documentation //## @brief Get the transformation used to convert from index //## to world coordinates mitk::AffineTransform3D *GetIndexToWorldTransform(); //##Documentation //## @brief Get the transformation used to convert from index //## to world coordinates const mitk::AffineTransform3D *GetIndexToWorldTransform() const; //## @brief Set the transformation used to convert from index //## to world coordinates. The spacing of the new transform is //## copied to m_spacing. void SetIndexToWorldTransform(mitk::AffineTransform3D *transform); //##Documentation //## @brief Convenience method for setting the ITK transform //## (m_IndexToWorldTransform) via an vtkMatrix4x4.The spacing of //## the new transform is copied to m_spacing. //## \sa SetIndexToWorldTransform void SetIndexToWorldTransformByVtkMatrix(vtkMatrix4x4 *vtkmatrix); //## @brief Set the transformation used to convert from index //## to world coordinates.This function keeps the original spacing. void SetIndexToWorldTransformWithoutChangingSpacing(mitk::AffineTransform3D *transform); //##Documentation //## @brief Convenience method for setting the ITK transform //## (m_IndexToWorldTransform) via an vtkMatrix4x4. This function keeps the original spacing. //## \sa SetIndexToWorldTransform void SetIndexToWorldTransformByVtkMatrixWithoutChangingSpacing(vtkMatrix4x4 *vtkmatrix); //## Get the Vtk Matrix which describes the transform. vtkMatrix4x4 *GetVtkMatrix(); //##Documentation //## @brief Get the m_IndexToWorldTransform as a vtkLinearTransform vtkLinearTransform *GetVtkTransform() const; //##Documentation //## @brief Set the transform to identity, the spacing to 1 and origin to 0 //## void SetIdentity(); // ********************************** Transformations ********************************** //##Documentation //## @brief Compose new IndexToWorldTransform with a given transform. //## //## This method composes m_IndexToWorldTransform with another transform, //## modifying self to be the composition of self and other. //## If the argument pre is true, then other is precomposed with self; //## that is, the resulting transformation consists of first applying //## other to the source, followed by self. If pre is false or omitted, //## then other is post-composed with self; that is the resulting //## transformation consists of first applying self to the source, //## followed by other. //## This method also changes m_spacing. void Compose(const TransformType *other, bool pre = false); //##Documentation //## @brief Compose new IndexToWorldTransform with a given vtkMatrix4x4. //## //## Converts the vtkMatrix4x4 into a itk-transform and calls the previous method. void Compose(const vtkMatrix4x4 *vtkmatrix, bool pre = false); //##Documentation //## @brief Translate the origin by a vector //## void Translate(const Vector3D &vector); //##Documentation //##@brief executes affine operations (translate, rotate, scale) void ExecuteOperation(Operation *operation) override; //##Documentation //## @brief Convert world coordinates (in mm) of a \em point to (continuous!) index coordinates //## \warning If you need (discrete) integer index coordinates (e.g., for iterating easily over an image), //## use WorldToIndex(const mitk::Point3D& pt_mm, itk::Index &index). //## For further information about coordinates types, please see the Geometry documentation void WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## For further information about coordinates types, please see the Geometry documentation void WorldToIndex(const mitk::Vector3D &vec_mm, mitk::Vector3D &vec_units) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em point to (discrete!) index coordinates. //## This method rounds to integer indices! //## For further information about coordinates types, please see the Geometry documentation template void WorldToIndex(const mitk::Point3D &pt_mm, itk::Index &index) const { typedef itk::Index IndexType; mitk::Point3D pt_units; this->WorldToIndex(pt_mm, pt_units); int i, dim = index.GetIndexDimension(); if (dim > 3) { index.Fill(0); dim = 3; } for (i = 0; i < dim; ++i) { index[i] = itk::Math::RoundHalfIntegerUp(pt_units[i]); } } //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation void IndexToWorld(const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em point to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation void IndexToWorld(const mitk::Point3D &pt_units, mitk::Point3D &pt_mm) const; //##Documentation //## @brief Convert (discrete) index coordinates of a \em point to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation template void IndexToWorld(const itk::Index &index, mitk::Point3D &pt_mm) const { mitk::Point3D pt_units; pt_units.Fill(0); int i, dim = index.GetIndexDimension(); if (dim > 3) { dim = 3; } for (i = 0; i < dim; ++i) { pt_units[i] = index[i]; } IndexToWorld(pt_units, pt_mm); } //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## @deprecated First parameter (Point3D) is not used. If possible, please use void IndexToWorld(const // mitk::Vector3D& vec_units, mitk::Vector3D& vec_mm) const. //## For further information about coordinates types, please see the Geometry documentation void IndexToWorld(const mitk::Point3D &atPt3d_units, const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## @deprecated First parameter (Point3D) is not used. If possible, please use void WorldToIndex(const // mitk::Vector3D& vec_mm, mitk::Vector3D& vec_units) const. //## For further information about coordinates types, please see the Geometry documentation void WorldToIndex(const mitk::Point3D &atPt3d_mm, const mitk::Vector3D &vec_mm, mitk::Vector3D &vec_units) const; //##Documentation //## @brief Deprecated for use with ITK version 3.10 or newer. //## Convert ITK physical coordinates of a \em point (in mm, //## but without a rotation) into MITK world coordinates (in mm) //## //## For more information, see WorldToItkPhysicalPoint. template void ItkPhysicalPointToWorld(const itk::Point &itkPhysicalPoint, mitk::Point3D &pt_mm) const { mitk::vtk2itk(itkPhysicalPoint, pt_mm); } //##Documentation //## @brief Deprecated for use with ITK version 3.10 or newer. //## Convert world coordinates (in mm) of a \em point to //## ITK physical coordinates (in mm, but without a possible rotation) //## //## This method is useful if you have want to access an mitk::Image //## via an itk::Image. ITK v3.8 and older did not support rotated (tilted) //## images, i.e., ITK images are always parallel to the coordinate axes. //## When accessing a (possibly rotated) mitk::Image via an itk::Image //## the rotational part of the transformation in the BaseGeometry is //## simply discarded; in other word: only the origin and spacing is //## used by ITK, not the complete matrix available in MITK. //## With WorldToItkPhysicalPoint you can convert an MITK world //## coordinate (including the rotation) into a coordinate that //## can be used with the ITK image as a ITK physical coordinate //## (excluding the rotation). template void WorldToItkPhysicalPoint(const mitk::Point3D &pt_mm, itk::Point &itkPhysicalPoint) const { mitk::vtk2itk(pt_mm, itkPhysicalPoint); } // ********************************** BoundingBox ********************************** /** Get the bounding box */ itkGetConstObjectMacro(BoundingBox, BoundingBoxType); // a bit of a misuse, but we want only doxygen to see the following: #ifdef DOXYGEN_SKIP //##Documentation //## @brief Get bounding box (in index/unit coordinates) itkGetConstObjectMacro(BoundingBox, BoundingBoxType); //##Documentation //## @brief Get bounding box (in index/unit coordinates) as a BoundsArrayType const BoundsArrayType GetBounds() const; #endif const BoundsArrayType GetBounds() const; //##Documentation //## \brief Set the bounding box (in index/unit coordinates) //## //## Only possible via the BoundsArray to make clear that a //## copy of the bounding-box is stored, not a reference to it. void SetBounds(const BoundsArrayType &bounds); //##Documentation //## @brief Set the bounding box (in index/unit coordinates) via a float array void SetFloatBounds(const float bounds[6]); //##Documentation //## @brief Set the bounding box (in index/unit coordinates) via a double array void SetFloatBounds(const double bounds[6]); //##Documentation //## @brief Get a VnlVector along bounding-box in the specified //## @a direction, length is spacing //## //## \sa GetAxisVector VnlVector GetMatrixColumn(unsigned int direction) const; //##Documentation //## @brief Calculates a bounding-box around the geometry relative //## to a coordinate system defined by a transform //## mitk::BoundingBox::Pointer CalculateBoundingBoxRelativeToTransform(const mitk::AffineTransform3D *transform) const; //##Documentation //## @brief Set the time bounds (in ms) // void SetTimeBounds(const TimeBounds& timebounds); // ********************************** Geometry ********************************** #ifdef DOXYGEN_SKIP //##Documentation //## @brief Get the extent of the bounding box (in index/unit coordinates) //## //## To access the extent in mm use GetExtentInMM ScalarType GetExtent(unsigned int direction) const; #endif /** Get the extent of the bounding box */ ScalarType GetExtent(unsigned int direction) const; //##Documentation //## @brief Get the extent of the bounding-box in the specified @a direction in mm //## //## Equals length of GetAxisVector(direction). ScalarType GetExtentInMM(int direction) const; //##Documentation //## @brief Get vector along bounding-box in the specified @a direction in mm //## //## The length of the vector is the size of the bounding-box in the //## specified @a direction in mm //## \sa GetMatrixColumn Vector3D GetAxisVector(unsigned int direction) const; //##Documentation //## @brief Checks, if the given geometry can be converted to 2D without information loss //## e.g. when a 2D image is saved, the matrix is usually cropped to 2x2, and when you load it back to MITK //## it will be filled with standard values. This function checks, if information would be lost during this //## procedure virtual bool Is2DConvertable(); //##Documentation //## @brief Get the center of the bounding-box in mm //## Point3D GetCenter() const; //##Documentation //## @brief Get the squared length of the diagonal of the bounding-box in mm //## double GetDiagonalLength2() const; //##Documentation //## @brief Get the length of the diagonal of the bounding-box in mm //## double GetDiagonalLength() const; //##Documentation //## @brief Get the position of the corner number \a id (in world coordinates) //## //## See SetImageGeometry for how a corner is defined on images. Point3D GetCornerPoint(int id) const; //##Documentation //## @brief Get the position of a corner (in world coordinates) //## //## See SetImageGeometry for how a corner is defined on images. Point3D GetCornerPoint(bool xFront = true, bool yFront = true, bool zFront = true) const; //##Documentation //## @brief Set the extent of the bounding-box in the specified @a direction in mm //## //## @note This changes the matrix in the transform, @a not the bounds, which are given in units! void SetExtentInMM(int direction, ScalarType extentInMM); //##Documentation //## @brief Test whether the point \a p (world coordinates in mm) is //## inside the bounding box bool IsInside(const mitk::Point3D &p) const; //##Documentation //## @brief Test whether the point \a p ((continuous!)index coordinates in units) is //## inside the bounding box bool IsIndexInside(const mitk::Point3D &index) const; //##Documentation //## @brief Convenience method for working with ITK indices template bool IsIndexInside(const itk::Index &index) const { int i, dim = index.GetIndexDimension(); Point3D pt_index; pt_index.Fill(0); for (i = 0; i < dim; ++i) { pt_index[i] = index[i]; } return IsIndexInside(pt_index); } // ********************************* Image Geometry ******************************** //##Documentation //## @brief When switching from an Image Geometry to a normal Geometry (and the other way around), you have to //change // the origin as well (See Geometry Documentation)! This function will change the "isImageGeometry" bool flag and // changes the origin respectively. virtual void ChangeImageGeometryConsideringOriginOffset(const bool isAnImageGeometry); //##Documentation //## @brief Is this an ImageGeometry? //## //## For more information, see SetImageGeometry itkGetConstMacro(ImageGeometry, bool) //##Documentation //## @brief Define that this BaseGeometry is referring to an Image //## //## A geometry referring to an Image needs a slightly different //## definition of the position of the corners (see GetCornerPoint). //## The position of a voxel is defined by the position of its center. //## If we would use the origin (position of the (center of) the first //## voxel) as a corner and display this point, it would seem to be //## \em not at the corner but a bit within the image. Even worse for //## the opposite corner of the image: here the corner would appear //## outside the image (by half of the voxel diameter). Thus, we have //## to correct for this and to be able to do that, we need to know //## that the BaseGeometry is referring to an Image. itkSetMacro(ImageGeometry, bool); itkBooleanMacro(ImageGeometry); const GeometryTransformHolder *GetGeometryTransformHolder() const; + //##Documentation + //## @brief One to one mapping of axes to world orientations. + //## + //## The result is stored in the output argument that must be an array of three int values. + //## The elements of the array will be the axis indices that correspond to the sagittal, + //## coronal and axial orientations, in this order. It is guaranteed that each axis will + //## be mapped to different orientations. + //## + //## @param axes Output argument that will store the axis indices for each orientation. + void MapAxesToOrientations(int axes[]) const; + protected: // ********************************** Constructor ********************************** BaseGeometry(); BaseGeometry(const BaseGeometry &other); ~BaseGeometry() override; itk::LightObject::Pointer InternalClone() const override = 0; void PrintSelf(std::ostream &os, itk::Indent indent) const override; static const std::string GetTransformAsString(TransformType *transformType); itkGetConstMacro(NDimensions, unsigned int); bool IsBoundingBoxNull() const; bool IsIndexToWorldTransformNull() const; void SetVtkMatrixDeepCopy(vtkTransform *vtktransform); void _SetSpacing(const mitk::Vector3D &aSpacing, bool enforceSetSpacing = false); //##Documentation //## @brief PreSetSpacing //## //## These virtual function allows a different beahiour in subclasses. //## Do implement them in every subclass of BaseGeometry. If not needed, use //## {Superclass::PreSetSpacing();}; virtual void PreSetSpacing(const mitk::Vector3D & /*aSpacing*/){}; //##Documentation //## @brief CheckBounds //## //## This function is called in SetBounds. Assertions can be implemented in this function (see PlaneGeometry.cpp). //## If you implement this function in a subclass, make sure, that all classes were your class inherits from //## have an implementation of CheckBounds //## (e.g. inheritance BaseGeometry <- A <- B. Implementation of CheckBounds in class B needs implementation in A as // well!) virtual void CheckBounds(const BoundsArrayType & /*bounds*/){}; //##Documentation //## @brief CheckIndexToWorldTransform //## //## This function is called in SetIndexToWorldTransform. Assertions can be implemented in this function (see // PlaneGeometry.cpp). //## In Subclasses of BaseGeometry, implement own conditions or call Superclass::CheckBounds(bounds);. virtual void CheckIndexToWorldTransform(mitk::AffineTransform3D * /*transform*/){}; private: GeometryTransformHolder *m_GeometryTransform; void InitializeGeometryTransformHolder(const BaseGeometry *otherGeometry); //##Documentation //## @brief Bounding Box, which is axes-parallel in intrinsic coordinates //## (often integer indices of pixels) BoundingBoxPointer m_BoundingBox; unsigned int m_FrameOfReferenceID; // mitk::TimeBounds m_TimeBounds; static const unsigned int m_NDimensions = 3; mutable TransformType::Pointer m_InvertedTransform; mutable unsigned long m_IndexToWorldTransformLastModified; bool m_ImageGeometry; //##Documentation //## @brief ModifiedLockFlag is used to prohibit the call of Modified() //## //## For the use of this Flag, see class ModifiedLock. This flag should only be set //## by the ModifiedLock class! bool m_ModifiedLockFlag; //##Documentation //## @brief ModifiedcalledFlag is used to collect calls of Modified(). //## //## For the use of this Flag, see class ModifiedLock. This flag should only be set //## by the Modified() function! mutable bool m_ModifiedCalledFlag; }; // ********************************** Equal Functions ********************************** // // Static compare functions mainly for testing // /** * @brief Equal A function comparing two geometries for being identical. * * @ingroup MITKTestingAPI * * The function compares the spacing, origin, axisvectors, extents, the matrix of the * IndexToWorldTransform (elementwise), the bounding (elementwise) and the ImageGeometry flag. * * The parameter eps is a tolarence value for all methods which are internally used for comparison. * If you want to use different tolerance values for different parts of the geometry, feel free to use * the other comparison methods and write your own implementation of Equal. * @param rightHandSide Compare this against leftHandSide. * @param leftHandSide Compare this against rightHandSide. * @param coordinateEps Tolerance for comparison of all spatial aspects (spacing, origin and grid alignment). * You can use mitk::eps in most cases. * @param directionEps Tolerance for comparison of all directional aspects (axis). You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return True, if all comparison are true. False in any other case. */ MITKCORE_EXPORT bool Equal(const mitk::BaseGeometry& leftHandSide, const mitk::BaseGeometry& rightHandSide, ScalarType coordinateEps, ScalarType directionEps, bool verbose = false); /** * @brief Equal A function comparing two geometries for being identical. * * @ingroup MITKTestingAPI * * This is an overloaded version that uses a single tolerance for spatial and directional aspects. For more details, * see the other overloaded version. * * @param rightHandSide Compare this against leftHandSide. * @param leftHandSide Compare this against rightHandSide. * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return True, if all comparison are true. False in any other case. */ MITKCORE_EXPORT bool Equal(const mitk::BaseGeometry &leftHandSide, const mitk::BaseGeometry &rightHandSide, ScalarType eps = mitk::eps, bool verbose = false); /** * @brief Equal A function comparing two transforms (TransformType) for being identical. * * @ingroup MITKTestingAPI * * The function compares the IndexToWorldTransform (elementwise). * * The parameter eps is a tolarence value for all methods which are internally used for comparison. * @param rightHandSide Compare this against leftHandSide. * @param leftHandSide Compare this against rightHandSide. * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return True, if all comparison are true. False in any other case. */ MITKCORE_EXPORT bool Equal(const mitk::BaseGeometry::TransformType &leftHandSide, const mitk::BaseGeometry::TransformType &rightHandSide, ScalarType eps, bool verbose); /** * @brief Equal A function comparing two bounding boxes (BoundingBoxType) for being identical. * * @ingroup MITKTestingAPI * * The function compares the bounds (elementwise). * * The parameter eps is a tolarence value for all methods which are internally used for comparison. * @param rightHandSide Compare this against leftHandSide. * @param leftHandSide Compare this against rightHandSide. * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return True, if all comparison are true. False in any other case. */ MITKCORE_EXPORT bool Equal(const mitk::BaseGeometry::BoundingBoxType &leftHandSide, const mitk::BaseGeometry::BoundingBoxType &rightHandSide, ScalarType eps, bool verbose); /** * @brief A function checks if a test geometry is a sub geometry of * a given reference geometry. * * Sub geometry means that both geometries have the same voxel grid (same spacing, same axes, * origin is on voxel grid), but the bounding box of the checked geometry is contained or equal * to the bounding box of the reference geometry.\n * By this definition equal geometries are always sub geometries of each other. * * The function checks the spacing, origin, axis vectors, extents, the matrix of the * IndexToWorldTransform (elementwise), the bounding (elementwise) and the ImageGeometry flag. * * The parameter eps is a tolerance value for all methods which are internally used for comparison. * @param testGeo Geometry that should be checked if it is a sub geometry of referenceGeo. * @param referenceGeo Geometry that should contain testedGeometry as sub geometry. * @param coordinateEps Tolerance for comparison of all spatial aspects (spacing, origin and grid alignment). * You can use mitk::eps in most cases. * @param directionEps Tolerance for comparison of all directional aspects (axis). You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return True, if all comparisons are true. False otherwise. */ MITKCORE_EXPORT bool IsSubGeometry(const mitk::BaseGeometry& testGeo, const mitk::BaseGeometry& referenceGeo, ScalarType coordinateEps, ScalarType directionEps, bool verbose = false); /** * @brief A function checks if a test geometry is a sub geometry of * a given reference geometry. * * This is a overloaded version that uses a single tolerance for spatial and directional aspects. For more details, * see the other overloaded version. * * @param testGeo Geometry that should be checked if it is a sub geometry of referenceGeo. * @param referenceGeo Geometry that should contain testedGeometry as sub geometry. * @param eps Tolarence for comparison (both spatial and directional). You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return True, if all comparison are true. False otherwise. */ MITKCORE_EXPORT bool IsSubGeometry(const mitk::BaseGeometry& testGeo, const mitk::BaseGeometry& referenceGeo, ScalarType eps = mitk::eps, bool verbose = false); } // namespace mitk #endif diff --git a/Modules/Core/include/mitkPlaneGeometry.h b/Modules/Core/include/mitkPlaneGeometry.h index 0fec6a0794..81a0c3c0e1 100644 --- a/Modules/Core/include/mitkPlaneGeometry.h +++ b/Modules/Core/include/mitkPlaneGeometry.h @@ -1,608 +1,606 @@ /*============================================================================ 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 mitkPlaneGeometry_h #define mitkPlaneGeometry_h #include #include #include #include #include namespace mitk { template class Line; typedef Line Line3D; /** * \brief Describes the geometry of a plane object * * Describes a two-dimensional manifold, i.e., to put it simply, * an object that can be described using a 2D coordinate-system. * * PlaneGeometry can map points between 3D world coordinates * (in mm) and the described 2D coordinate-system (in mm) by first projecting * the 3D point onto the 2D manifold and then calculating the 2D-coordinates * (in mm). These 2D-mm-coordinates can be further converted into * 2D-unit-coordinates (e.g., pixels), giving a parameter representation of * the object with parameter values inside a rectangle * (e.g., [0,0]..[width, height]), which is the bounding box (bounding range * in z-direction always [0]..[1]). * * A PlaneGeometry describes the 2D representation within a 3D object (derived from BaseGeometry). For example, * a single CT-image (slice) is 2D in the sense that you can access the * pixels using 2D-coordinates, but is also 3D, as the pixels are really * voxels, thus have an extension (thickness) in the 3rd dimension. * * * Optionally, a reference BaseGeometry can be specified, which usually would * be the geometry associated with the underlying dataset. This is currently * used for calculating the intersection of inclined / rotated planes * (represented as PlaneGeometry) with the bounding box of the associated * BaseGeometry. * * \warning The PlaneGeometry are not necessarily up-to-date and not even * initialized. As described in the previous paragraph, one of the * Generate-/Copy-/UpdateOutputInformation methods have to initialize it. * mitk::BaseData::GetPlaneGeometry() makes sure, that the PlaneGeometry is * up-to-date before returning it (by setting the update extent appropriately * and calling UpdateOutputInformation). * * Rule: everything is in mm (or ms for temporal information) if not * stated otherwise. * \ingroup Geometry */ class PlaneGeometry; /** \deprecatedSince{2014_10} This class is deprecated. Please use PlaneGeometry instead. */ DEPRECATED(typedef PlaneGeometry Geometry2D); /** * \brief Describes a two-dimensional, rectangular plane * * \ingroup Geometry */ class MITKCORE_EXPORT PlaneGeometry : public BaseGeometry { public: mitkClassMacro(PlaneGeometry, BaseGeometry); /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); virtual void IndexToWorld(const Point2D &pt_units, Point2D &pt_mm) const; virtual void WorldToIndex(const Point2D &pt_mm, Point2D &pt_units) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## @deprecated First parameter (Point2D) is not used. If possible, please use void IndexToWorld(const // mitk::Vector2D& vec_units, mitk::Vector2D& vec_mm) const. //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Point2D &atPt2d_untis, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## @deprecated First parameter (Point2D) is not used. If possible, please use void WorldToIndex(const // mitk::Vector2D& vec_mm, mitk::Vector2D& vec_units) const. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; /** * \brief Initialize a plane with orientation \a AnatomicalPlane * (default: axial) with respect to \a BaseGeometry (default: identity). * Spacing also taken from \a BaseGeometry. * * \warning A former version of this method created a geometry with unit * spacing. For unit spacing use * * \code * // for in-plane unit spacing: * thisgeometry->SetSizeInUnits(thisgeometry->GetExtentInMM(0), * thisgeometry->GetExtentInMM(1)); * // additionally, for unit spacing in normal direction (former version * // did not do this): * thisgeometry->SetExtentInMM(2, 1.0); * \endcode */ virtual void InitializeStandardPlane(const BaseGeometry *geometry3D, AnatomicalPlane planeorientation = AnatomicalPlane::Axial, ScalarType zPosition = 0, bool frontside = true, bool rotated = false, bool top = true); /** * \brief Initialize a plane with orientation \a AnatomicalPlane * (default: axial) with respect to \a BaseGeometry (default: identity). * Spacing also taken from \a BaseGeometry. * * \param geometry3D * \param top if \a true, create plane at top, otherwise at bottom * (for AnatomicalPlane Axial, for other plane locations respectively) * \param planeorientation * \param frontside * \param rotated */ virtual void InitializeStandardPlane(const BaseGeometry *geometry3D, bool top, AnatomicalPlane planeorientation = AnatomicalPlane::Axial, bool frontside = true, bool rotated = false); /** * \brief Initialize a plane with orientation \a AnatomicalPlane * (default: axial) with respect to \a transform (default: identity) * given width and height in units. * * \a Rotated means rotated by 180 degrees (1/2 rotation) within the plane. * Rotation by 90 degrees (1/4 rotation) is not implemented as of now. * * \a Frontside/Backside: * Viewed from below = frontside in the axial case; * (radiologist's view versus neuro-surgeon's view, see: * http://www.itk.org/Wiki/images/e/ed/DICOM-OrientationDiagram-Radiologist-vs-NeuroSurgeon.png ) * Viewed from front = frontside in the coronal case; * Viewed from left = frontside in the sagittal case. * * \a Cave/Caution: Currently only RPI, LAI, LPS and RAS in the three standard planes are covered, * i.e. 12 cases of 144: 3 standard planes * 48 coordinate orientations = 144 cases. */ virtual void InitializeStandardPlane(ScalarType width, ScalarType height, const AffineTransform3D *transform = nullptr, AnatomicalPlane planeorientation = AnatomicalPlane::Axial, ScalarType zPosition = 0, bool frontside = true, bool rotated = false, bool top = true); /** * \brief Initialize plane with orientation \a AnatomicalPlane * (default: axial) given width, height and spacing. * */ virtual void InitializeStandardPlane(ScalarType width, ScalarType height, const Vector3D &spacing, AnatomicalPlane planeorientation = AnatomicalPlane::Axial, ScalarType zPosition = 0, bool frontside = true, bool rotated = false, bool top = true); /** * \brief Initialize plane by width and height in pixels, right-/down-vector * (itk) to describe orientation in world-space (vectors will be normalized) * and spacing (default: 1.0 mm in all directions). * * The vectors are normalized and multiplied by the respective spacing before * they are set in the matrix. * * This overloaded version of InitializeStandardPlane() creates only righthanded * coordinate orientations, unless spacing contains 1 or 3 negative entries. * */ virtual void InitializeStandardPlane(ScalarType width, ScalarType height, const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing = nullptr); /** * \brief Initialize plane by width and height in pixels, * right-/down-vector (vnl) to describe orientation in world-space (vectors * will be normalized) and spacing (default: 1.0 mm in all directions). * * The vectors are normalized and multiplied by the respective spacing * before they are set in the matrix. * * This overloaded version of InitializeStandardPlane() creates only righthanded * coordinate orientations, unless spacing contains 1 or 3 negative entries. * */ virtual void InitializeStandardPlane(ScalarType width, ScalarType height, const VnlVector &rightVector, const VnlVector &downVector, const Vector3D *spacing = nullptr); /** * \brief Initialize plane by right-/down-vector (itk) and spacing * (default: 1.0 mm in all directions). * * The length of the right-/-down-vector is used as width/height in units, * respectively. Then, the vectors are normalized and multiplied by the * respective spacing before they are set in the matrix. */ virtual void InitializeStandardPlane(const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing = nullptr); /** * \brief Initialize plane by right-/down-vector (vnl) and spacing * (default: 1.0 mm in all directions). * * The length of the right-/-down-vector is used as width/height in units, * respectively. Then, the vectors are normalized and multiplied by the * respective spacing before they are set in the matrix. */ virtual void InitializeStandardPlane(const VnlVector &rightVector, const VnlVector &downVector, const Vector3D *spacing = nullptr); /** * \brief Initialize plane by origin and normal (size is 1.0 mm in * all directions, direction of right-/down-vector valid but * undefined). * \warning This function can only produce righthanded coordinate orientation, not lefthanded. */ virtual void InitializePlane(const Point3D &origin, const Vector3D &normal); /** * \brief Initialize plane by right-/down-vector. * * \warning The vectors are set into the matrix as they are, * \em without normalization! * This function creates a righthanded IndexToWorldTransform, * only a negative thickness could still make it lefthanded. */ void SetMatrixByVectors(const VnlVector &rightVector, const VnlVector &downVector, ScalarType thickness = 1.0); /** * \brief Check if matrix is a rotation matrix: * - determinant is 1? * - R*R^T is ID? * Output warning otherwise. */ static bool CheckRotationMatrix(AffineTransform3D *transform, double epsilon=1e-6); /** * \brief Normal of the plane * */ Vector3D GetNormal() const; /** * \brief Normal of the plane as VnlVector * */ VnlVector GetNormalVnl() const; virtual ScalarType SignedDistance(const Point3D &pt3d_mm) const; /** * \brief Calculates, whether a point is below or above the plane. There are two different *calculation methods, with or without consideration of the bounding box. */ virtual bool IsAbove(const Point3D &pt3d_mm, bool considerBoundingBox = false) const; /** * \brief Distance of the point from the plane * (bounding-box \em not considered) * */ ScalarType DistanceFromPlane(const Point3D &pt3d_mm) const; /** * \brief Signed distance of the point from the plane * (bounding-box \em not considered) * * > 0 : point is in the direction of the direction vector. */ inline ScalarType SignedDistanceFromPlane(const Point3D &pt3d_mm) const { ScalarType len = GetNormalVnl().two_norm(); if (len == 0) return 0; return (pt3d_mm - GetOrigin()) * GetNormal() / len; } /** * \brief Distance of the plane from another plane * (bounding-box \em not considered) * * Result is 0 if planes are not parallel. */ ScalarType DistanceFromPlane(const PlaneGeometry *plane) const { return fabs(SignedDistanceFromPlane(plane)); } /** * \brief Signed distance of the plane from another plane * (bounding-box \em not considered) * * Result is 0 if planes are not parallel. */ inline ScalarType SignedDistanceFromPlane(const PlaneGeometry *plane) const { if (IsParallel(plane)) { return SignedDistance(plane->GetOrigin()); } return 0; } /** * \brief Calculate the intersecting line of two planes * * \return \a true planes are intersecting * \return \a false planes do not intersect */ bool IntersectionLine(const PlaneGeometry *plane, Line3D &crossline) const; /** * \brief Calculate two points where another plane intersects the border of this plane * * \return number of intersection points (0..2). First interection point (if existing) * is returned in \a lineFrom, second in \a lineTo. */ unsigned int IntersectWithPlane2D(const PlaneGeometry *plane, Point2D &lineFrom, Point2D &lineTo) const; /** * \brief Calculate the angle between two planes * * \return angle in radiants */ double Angle(const PlaneGeometry *plane) const; /** * \brief Calculate the angle between the plane and a line * * \return angle in radiants */ double Angle(const Line3D &line) const; /** * \brief Calculate intersection point between the plane and a line * * \param line * \param intersectionPoint intersection point * \return \a true if \em unique intersection exists, i.e., if line * is \em not on or parallel to the plane */ bool IntersectionPoint(const Line3D &line, Point3D &intersectionPoint) const; /** * \brief Calculate line parameter of intersection point between the * plane and a line * * \param line * \param t parameter of line: intersection point is * line.GetPoint()+t*line.GetDirection() * \return \a true if \em unique intersection exists, i.e., if line * is \em not on or parallel to the plane */ bool IntersectionPointParam(const Line3D &line, double &t) const; /** * \brief Returns whether the plane is parallel to another plane * * @return true iff the normal vectors both point to the same or exactly oposit direction */ bool IsParallel(const PlaneGeometry *plane) const; /** * \brief Returns whether the point is on the plane * (bounding-box \em not considered) */ bool IsOnPlane(const Point3D &point) const; /** * \brief Returns whether the line is on the plane * (bounding-box \em not considered) */ bool IsOnPlane(const Line3D &line) const; /** * \brief Returns whether the plane is on the plane * (bounding-box \em not considered) * * @return true if the normal vector of the planes point to the same or the exactly oposit direction and * the distance of the planes is < eps * */ bool IsOnPlane(const PlaneGeometry *plane) const; /** * \brief Returns the lot from the point to the plane */ Point3D ProjectPointOntoPlane(const Point3D &pt) const; itk::LightObject::Pointer InternalClone() const override; /** Implements operation to re-orient the plane */ void ExecuteOperation(Operation *operation) override; /** * \brief Project a 3D point given in mm (\a pt3d_mm) onto the 2D * geometry. The result is a 2D point in mm (\a pt2d_mm). * * The result is a 2D point in mm (\a pt2d_mm) relative to the upper-left * corner of the geometry. To convert this point into units (e.g., pixels * in case of an image), use WorldToIndex. * \return true projection was possible * \sa Project(const mitk::Point3D &pt3d_mm, mitk::Point3D * &projectedPt3d_mm) */ virtual bool Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const; /** * \brief Converts a 2D point given in mm (\a pt2d_mm) relative to the * upper-left corner of the geometry into the corresponding * world-coordinate (a 3D point in mm, \a pt3d_mm). * * To convert a 2D point given in units (e.g., pixels in case of an * image) into a 2D point given in mm (as required by this method), use * IndexToWorld. */ virtual void Map(const mitk::Point2D &pt2d_mm, mitk::Point3D &pt3d_mm) const; /** * \brief Set the width and height of this 2D-geometry in units by calling * SetBounds. This does \a not change the extent in mm! * * For an image, this is the number of pixels in x-/y-direction. * \note In contrast to calling SetBounds directly, this does \a not change * the extent in mm! */ virtual void SetSizeInUnits(mitk::ScalarType width, mitk::ScalarType height); /** * \brief Project a 3D point given in mm (\a pt3d_mm) onto the 2D * geometry. The result is a 3D point in mm (\a projectedPt3d_mm). * * \return true projection was possible */ virtual bool Project(const mitk::Point3D &pt3d_mm, mitk::Point3D &projectedPt3d_mm) const; /** * \brief Project a 3D vector given in mm (\a vec3d_mm) onto the 2D * geometry. The result is a 2D vector in mm (\a vec2d_mm). * * The result is a 2D vector in mm (\a vec2d_mm) relative to the * upper-left * corner of the geometry. To convert this point into units (e.g., pixels * in case of an image), use WorldToIndex. * \return true projection was possible * \sa Project(const mitk::Vector3D &vec3d_mm, mitk::Vector3D * &projectedVec3d_mm) */ virtual bool Map(const mitk::Point3D &atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector2D &vec2d_mm) const; /** * \brief Converts a 2D vector given in mm (\a vec2d_mm) relative to the * upper-left corner of the geometry into the corresponding * world-coordinate (a 3D vector in mm, \a vec3d_mm). * * To convert a 2D vector given in units (e.g., pixels in case of an * image) into a 2D vector given in mm (as required by this method), use * IndexToWorld. */ virtual void Map(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec2d_mm, mitk::Vector3D &vec3d_mm) const; /** * \brief Project a 3D vector given in mm (\a vec3d_mm) onto the 2D * geometry. The result is a 3D vector in mm (\a projectedVec3d_mm). * * DEPRECATED. Use Project(vector,vector) instead * * \return true projection was possible */ virtual bool Project(const mitk::Point3D &atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const; /** * \brief Project a 3D vector given in mm (\a vec3d_mm) onto the 2D * geometry. The result is a 3D vector in mm (\a projectedVec3d_mm). * * \return true projection was possible */ virtual bool Project(const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const; /** * \brief Distance of the point from the geometry * (bounding-box \em not considered) * */ inline ScalarType Distance(const Point3D &pt3d_mm) const { return fabs(SignedDistance(pt3d_mm)); } /** * \brief Set the geometrical frame of reference in which this PlaneGeometry * is placed. * * This would usually be the BaseGeometry of the underlying dataset, but * setting it is optional. */ void SetReferenceGeometry(const mitk::BaseGeometry *geometry); /** * \brief Get the geometrical frame of reference for this PlaneGeometry. */ const BaseGeometry *GetReferenceGeometry() const; bool HasReferenceGeometry() const; - static std::vector< int > CalculateDominantAxes(mitk::AffineTransform3D::MatrixType::InternalMatrixType& rotation_matrix); - protected: PlaneGeometry(); PlaneGeometry(const PlaneGeometry &other); ~PlaneGeometry() override; void PrintSelf(std::ostream &os, itk::Indent indent) const override; const mitk::BaseGeometry *m_ReferenceGeometry; //##Documentation //## @brief PreSetSpacing //## //## These virtual function allows a different beahiour in subclasses. //## Do implement them in every subclass of BaseGeometry. If not needed, use //## {Superclass::PreSetSpacing();}; void PreSetSpacing(const mitk::Vector3D &aSpacing) override { Superclass::PreSetSpacing(aSpacing); }; //##Documentation //## @brief CheckBounds //## //## This function is called in SetBounds. Assertions can be implemented in this function (see PlaneGeometry.cpp). //## If you implement this function in a subclass, make sure, that all classes were your class inherits from //## have an implementation of CheckBounds //## (e.g. inheritance BaseGeometry <- A <- B. Implementation of CheckBounds in class B needs implementation in A as // well!) void CheckBounds(const BoundsArrayType &bounds) override; //##Documentation //## @brief CheckIndexToWorldTransform //## //## This function is called in SetIndexToWorldTransform. Assertions can be implemented in this function (see // PlaneGeometry.cpp). //## In Subclasses of BaseGeometry, implement own conditions or call Superclass::CheckBounds(bounds);. void CheckIndexToWorldTransform(mitk::AffineTransform3D *transform) override; private: /** * \brief Compares plane with another plane: \a true if IsOnPlane * (bounding-box \em not considered) */ virtual bool operator==(const PlaneGeometry *) const { return false; }; /** * \brief Compares plane with another plane: \a false if IsOnPlane * (bounding-box \em not considered) */ virtual bool operator!=(const PlaneGeometry *) const { return false; }; }; } // namespace mitk #endif diff --git a/Modules/Core/src/DataManagement/mitkBaseGeometry.cpp b/Modules/Core/src/DataManagement/mitkBaseGeometry.cpp index 55ea6e4b07..6a3a8352e7 100644 --- a/Modules/Core/src/DataManagement/mitkBaseGeometry.cpp +++ b/Modules/Core/src/DataManagement/mitkBaseGeometry.cpp @@ -1,1101 +1,1185 @@ /*============================================================================ 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 #include #include #include #include #include "mitkApplyTransformMatrixOperation.h" #include "mitkBaseGeometry.h" #include "mitkGeometryTransformHolder.h" #include "mitkInteractionConst.h" #include "mitkMatrixConvert.h" #include "mitkModifiedLock.h" #include "mitkPointOperation.h" #include "mitkRestorePlanePositionOperation.h" #include "mitkRotationOperation.h" #include "mitkScaleOperation.h" #include "mitkVector.h" #include "mitkMatrix.h" mitk::BaseGeometry::BaseGeometry() : Superclass(), mitk::OperationActor(), m_FrameOfReferenceID(0), m_IndexToWorldTransformLastModified(0), m_ImageGeometry(false), m_ModifiedLockFlag(false), m_ModifiedCalledFlag(false) { m_GeometryTransform = new GeometryTransformHolder(); Initialize(); } mitk::BaseGeometry::BaseGeometry(const BaseGeometry &other) : Superclass(), mitk::OperationActor(), m_FrameOfReferenceID(other.m_FrameOfReferenceID), m_IndexToWorldTransformLastModified(other.m_IndexToWorldTransformLastModified), m_ImageGeometry(other.m_ImageGeometry), m_ModifiedLockFlag(false), m_ModifiedCalledFlag(false) { m_GeometryTransform = new GeometryTransformHolder(*other.GetGeometryTransformHolder()); other.InitializeGeometry(this); } mitk::BaseGeometry::~BaseGeometry() { delete m_GeometryTransform; } void mitk::BaseGeometry::SetVtkMatrixDeepCopy(vtkTransform *vtktransform) { m_GeometryTransform->SetVtkMatrixDeepCopy(vtktransform); } const mitk::Point3D mitk::BaseGeometry::GetOrigin() const { return m_GeometryTransform->GetOrigin(); } void mitk::BaseGeometry::SetOrigin(const Point3D &origin) { mitk::ModifiedLock lock(this); if (origin != GetOrigin()) { m_GeometryTransform->SetOrigin(origin); Modified(); } } const mitk::Vector3D mitk::BaseGeometry::GetSpacing() const { return m_GeometryTransform->GetSpacing(); } void mitk::BaseGeometry::Initialize() { float b[6] = {0, 1, 0, 1, 0, 1}; SetFloatBounds(b); m_GeometryTransform->Initialize(); m_FrameOfReferenceID = 0; m_ImageGeometry = false; } void mitk::BaseGeometry::SetFloatBounds(const float bounds[6]) { mitk::BoundingBox::BoundsArrayType b; const float *input = bounds; int i = 0; for (mitk::BoundingBox::BoundsArrayType::Iterator it = b.Begin(); i < 6; ++i) *it++ = (mitk::ScalarType)*input++; SetBounds(b); } void mitk::BaseGeometry::SetFloatBounds(const double bounds[6]) { mitk::BoundingBox::BoundsArrayType b; const double *input = bounds; int i = 0; for (mitk::BoundingBox::BoundsArrayType::Iterator it = b.Begin(); i < 6; ++i) *it++ = (mitk::ScalarType)*input++; SetBounds(b); } /** Initialize the geometry */ void mitk::BaseGeometry::InitializeGeometry(BaseGeometry *newGeometry) const { newGeometry->SetBounds(m_BoundingBox->GetBounds()); newGeometry->SetFrameOfReferenceID(GetFrameOfReferenceID()); newGeometry->InitializeGeometryTransformHolder(this); newGeometry->m_ImageGeometry = m_ImageGeometry; } void mitk::BaseGeometry::InitializeGeometryTransformHolder(const BaseGeometry *otherGeometry) { this->m_GeometryTransform->Initialize(otherGeometry->GetGeometryTransformHolder()); } /** Set the bounds */ void mitk::BaseGeometry::SetBounds(const BoundsArrayType &bounds) { mitk::ModifiedLock lock(this); this->CheckBounds(bounds); m_BoundingBox = BoundingBoxType::New(); BoundingBoxType::PointsContainer::Pointer pointscontainer = BoundingBoxType::PointsContainer::New(); BoundingBoxType::PointType p; BoundingBoxType::PointIdentifier pointid; for (pointid = 0; pointid < 2; ++pointid) { unsigned int i; for (i = 0; i < m_NDimensions; ++i) { p[i] = bounds[2 * i + pointid]; } pointscontainer->InsertElement(pointid, p); } m_BoundingBox->SetPoints(pointscontainer); m_BoundingBox->ComputeBoundingBox(); this->Modified(); } void mitk::BaseGeometry::SetIndexToWorldTransform(mitk::AffineTransform3D *transform) { mitk::ModifiedLock lock(this); CheckIndexToWorldTransform(transform); m_GeometryTransform->SetIndexToWorldTransform(transform); Modified(); } void mitk::BaseGeometry::SetIndexToWorldTransformWithoutChangingSpacing(mitk::AffineTransform3D *transform) { // security check mitk::Vector3D originalSpacing = this->GetSpacing(); mitk::ModifiedLock lock(this); CheckIndexToWorldTransform(transform); m_GeometryTransform->SetIndexToWorldTransformWithoutChangingSpacing(transform); Modified(); // Security check. Spacig must not have changed if (!mitk::Equal(originalSpacing, this->GetSpacing())) { MITK_WARN << "Spacing has changed in a method, where the spacing must not change."; assert(false); } } const mitk::BaseGeometry::BoundsArrayType mitk::BaseGeometry::GetBounds() const { assert(m_BoundingBox.IsNotNull()); return m_BoundingBox->GetBounds(); } bool mitk::BaseGeometry::IsValid() const { return true; } void mitk::BaseGeometry::SetSpacing(const mitk::Vector3D &aSpacing, bool enforceSetSpacing) { PreSetSpacing(aSpacing); _SetSpacing(aSpacing, enforceSetSpacing); } void mitk::BaseGeometry::_SetSpacing(const mitk::Vector3D &aSpacing, bool enforceSetSpacing) { m_GeometryTransform->SetSpacing(aSpacing, enforceSetSpacing); } mitk::Vector3D mitk::BaseGeometry::GetAxisVector(unsigned int direction) const { Vector3D frontToBack; frontToBack.SetVnlVector(this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(direction).as_ref()); frontToBack *= GetExtent(direction); return frontToBack; } mitk::ScalarType mitk::BaseGeometry::GetExtent(unsigned int direction) const { assert(m_BoundingBox.IsNotNull()); if (direction >= m_NDimensions) mitkThrow() << "Direction is too big. This geometry is for 3D Data"; BoundsArrayType bounds = m_BoundingBox->GetBounds(); return bounds[direction * 2 + 1] - bounds[direction * 2]; } bool mitk::BaseGeometry::Is2DConvertable() { bool isConvertableWithoutLoss = true; do { if (this->GetSpacing()[2] != 1) { isConvertableWithoutLoss = false; break; } if (this->GetOrigin()[2] != 0) { isConvertableWithoutLoss = false; break; } mitk::Vector3D col0, col1, col2; col0.SetVnlVector(this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0).as_ref()); col1.SetVnlVector(this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1).as_ref()); col2.SetVnlVector(this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2).as_ref()); if ((col0[2] != 0) || (col1[2] != 0) || (col2[0] != 0) || (col2[1] != 0) || (col2[2] != 1)) { isConvertableWithoutLoss = false; break; } } while (false); return isConvertableWithoutLoss; } mitk::Point3D mitk::BaseGeometry::GetCenter() const { assert(m_BoundingBox.IsNotNull()); Point3D c = m_BoundingBox->GetCenter(); if (m_ImageGeometry) { // Get Center returns the middel of min and max pixel index. In corner based images, this is the right position. // In center based images (imageGeometry == true), the index needs to be shifted back. c[0] -= 0.5; c[1] -= 0.5; c[2] -= 0.5; } this->IndexToWorld(c, c); return c; } double mitk::BaseGeometry::GetDiagonalLength2() const { Vector3D diagonalvector = GetCornerPoint() - GetCornerPoint(false, false, false); return diagonalvector.GetSquaredNorm(); } double mitk::BaseGeometry::GetDiagonalLength() const { return sqrt(GetDiagonalLength2()); } mitk::Point3D mitk::BaseGeometry::GetCornerPoint(int id) const { assert(id >= 0); assert(this->IsBoundingBoxNull() == false); BoundingBox::BoundsArrayType bounds = this->GetBoundingBox()->GetBounds(); Point3D cornerpoint; switch (id) { case 0: FillVector3D(cornerpoint, bounds[0], bounds[2], bounds[4]); break; case 1: FillVector3D(cornerpoint, bounds[0], bounds[2], bounds[5]); break; case 2: FillVector3D(cornerpoint, bounds[0], bounds[3], bounds[4]); break; case 3: FillVector3D(cornerpoint, bounds[0], bounds[3], bounds[5]); break; case 4: FillVector3D(cornerpoint, bounds[1], bounds[2], bounds[4]); break; case 5: FillVector3D(cornerpoint, bounds[1], bounds[2], bounds[5]); break; case 6: FillVector3D(cornerpoint, bounds[1], bounds[3], bounds[4]); break; case 7: FillVector3D(cornerpoint, bounds[1], bounds[3], bounds[5]); break; default: { itkExceptionMacro(<< "A cube only has 8 corners. These are labeled 0-7."); } } if (m_ImageGeometry) { // Here i have to adjust the 0.5 offset manually, because the cornerpoint is the corner of the // bounding box. The bounding box itself is no image, so it is corner-based FillVector3D(cornerpoint, cornerpoint[0] - 0.5, cornerpoint[1] - 0.5, cornerpoint[2] - 0.5); } return this->GetIndexToWorldTransform()->TransformPoint(cornerpoint); } mitk::Point3D mitk::BaseGeometry::GetCornerPoint(bool xFront, bool yFront, bool zFront) const { assert(this->IsBoundingBoxNull() == false); BoundingBox::BoundsArrayType bounds = this->GetBoundingBox()->GetBounds(); Point3D cornerpoint; cornerpoint[0] = (xFront ? bounds[0] : bounds[1]); cornerpoint[1] = (yFront ? bounds[2] : bounds[3]); cornerpoint[2] = (zFront ? bounds[4] : bounds[5]); if (m_ImageGeometry) { // Here i have to adjust the 0.5 offset manually, because the cornerpoint is the corner of the // bounding box. The bounding box itself is no image, so it is corner-based FillVector3D(cornerpoint, cornerpoint[0] - 0.5, cornerpoint[1] - 0.5, cornerpoint[2] - 0.5); } return this->GetIndexToWorldTransform()->TransformPoint(cornerpoint); } mitk::ScalarType mitk::BaseGeometry::GetExtentInMM(int direction) const { return this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(direction).magnitude() * GetExtent(direction); } void mitk::BaseGeometry::SetExtentInMM(int direction, ScalarType extentInMM) { mitk::ModifiedLock lock(this); ScalarType len = GetExtentInMM(direction); if (fabs(len - extentInMM) >= mitk::eps) { AffineTransform3D::MatrixType::InternalMatrixType vnlmatrix; vnlmatrix = m_GeometryTransform->GetVnlMatrix(); if (len > extentInMM) vnlmatrix.set_column(direction, vnlmatrix.get_column(direction) / len * extentInMM); else vnlmatrix.set_column(direction, vnlmatrix.get_column(direction) * extentInMM / len); Matrix3D matrix; matrix = vnlmatrix; m_GeometryTransform->SetMatrix(matrix); Modified(); } } bool mitk::BaseGeometry::IsInside(const mitk::Point3D &p) const { mitk::Point3D index; WorldToIndex(p, index); return IsIndexInside(index); } bool mitk::BaseGeometry::IsIndexInside(const mitk::Point3D &index) const { bool inside = false; // if it is an image geometry, we need to convert the index to discrete values // this is done by applying the rounding function also used in WorldToIndex (see line 323) if (m_ImageGeometry) { mitk::Point3D discretIndex; discretIndex[0] = itk::Math::RoundHalfIntegerUp(index[0]); discretIndex[1] = itk::Math::RoundHalfIntegerUp(index[1]); discretIndex[2] = itk::Math::RoundHalfIntegerUp(index[2]); inside = this->GetBoundingBox()->IsInside(discretIndex); // we have to check if the index is at the upper border of each dimension, // because the boundingbox is not centerbased if (inside) { const BoundingBox::BoundsArrayType &bounds = this->GetBoundingBox()->GetBounds(); if ((discretIndex[0] == bounds[1]) || (discretIndex[1] == bounds[3]) || (discretIndex[2] == bounds[5])) inside = false; } } else inside = this->GetBoundingBox()->IsInside(index); return inside; } void mitk::BaseGeometry::WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const { mitk::Vector3D tempIn, tempOut; const TransformType::OffsetType &offset = this->GetIndexToWorldTransform()->GetOffset(); tempIn = pt_mm.GetVectorFromOrigin() - offset; WorldToIndex(tempIn, tempOut); pt_units = Point3D(tempOut); } void mitk::BaseGeometry::WorldToIndex(const mitk::Vector3D &vec_mm, mitk::Vector3D &vec_units) const { // Get WorldToIndex transform if (m_IndexToWorldTransformLastModified != this->GetIndexToWorldTransform()->GetMTime()) { if (!m_InvertedTransform) { m_InvertedTransform = TransformType::New(); } if (!this->GetIndexToWorldTransform()->GetInverse(m_InvertedTransform.GetPointer())) { itkExceptionMacro("Internal ITK matrix inversion error, cannot proceed."); } m_IndexToWorldTransformLastModified = this->GetIndexToWorldTransform()->GetMTime(); } // Check for valid matrix inversion const TransformType::MatrixType &inverse = m_InvertedTransform->GetMatrix(); if (inverse.GetVnlMatrix().has_nans()) { itkExceptionMacro("Internal ITK matrix inversion error, cannot proceed. Matrix was: " << std::endl << this->GetIndexToWorldTransform()->GetMatrix() << "Suggested inverted matrix is:" << std::endl << inverse); } vec_units = inverse * vec_mm; } void mitk::BaseGeometry::WorldToIndex(const mitk::Point3D & /*atPt3d_mm*/, const mitk::Vector3D &vec_mm, mitk::Vector3D &vec_units) const { MITK_WARN << "Warning! Call of the deprecated function BaseGeometry::WorldToIndex(point, vec, vec). Use " "BaseGeometry::WorldToIndex(vec, vec) instead!"; this->WorldToIndex(vec_mm, vec_units); } mitk::VnlVector mitk::BaseGeometry::GetOriginVnl() const { return GetOrigin().GetVnlVector(); } vtkLinearTransform *mitk::BaseGeometry::GetVtkTransform() const { return m_GeometryTransform->GetVtkTransform(); } void mitk::BaseGeometry::SetIdentity() { mitk::ModifiedLock lock(this); m_GeometryTransform->SetIdentity(); Modified(); } void mitk::BaseGeometry::Compose(const mitk::BaseGeometry::TransformType *other, bool pre) { mitk::ModifiedLock lock(this); m_GeometryTransform->Compose(other, pre); Modified(); } void mitk::BaseGeometry::Compose(const vtkMatrix4x4 *vtkmatrix, bool pre) { mitk::BaseGeometry::TransformType::Pointer itkTransform = mitk::BaseGeometry::TransformType::New(); TransferVtkMatrixToItkTransform(vtkmatrix, itkTransform.GetPointer()); Compose(itkTransform, pre); } void mitk::BaseGeometry::Translate(const Vector3D &vector) { if ((vector[0] != 0) || (vector[1] != 0) || (vector[2] != 0)) { this->SetOrigin(this->GetOrigin() + vector); } } void mitk::BaseGeometry::IndexToWorld(const mitk::Point3D &pt_units, mitk::Point3D &pt_mm) const { pt_mm = this->GetIndexToWorldTransform()->TransformPoint(pt_units); } void mitk::BaseGeometry::IndexToWorld(const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const { vec_mm = this->GetIndexToWorldTransform()->TransformVector(vec_units); } void mitk::BaseGeometry::ExecuteOperation(Operation *operation) { mitk::ModifiedLock lock(this); vtkTransform *vtktransform = vtkTransform::New(); vtktransform->SetMatrix(this->GetVtkMatrix()); switch (operation->GetOperationType()) { case OpNOTHING: break; case OpMOVE: { auto *pointOp = dynamic_cast(operation); if (pointOp == nullptr) { MITK_ERROR << "Point move operation is null!"; return; } mitk::Point3D newPos = pointOp->GetPoint(); ScalarType data[3]; vtktransform->GetPosition(data); vtktransform->PostMultiply(); vtktransform->Translate(newPos[0], newPos[1], newPos[2]); vtktransform->PreMultiply(); break; } case OpSCALE: { auto *scaleOp = dynamic_cast(operation); if (scaleOp == nullptr) { MITK_ERROR << "Scale operation is null!"; return; } mitk::Point3D newScale = scaleOp->GetScaleFactor(); ScalarType scalefactor[3]; scalefactor[0] = 1 + (newScale[0] / GetMatrixColumn(0).magnitude()); scalefactor[1] = 1 + (newScale[1] / GetMatrixColumn(1).magnitude()); scalefactor[2] = 1 + (newScale[2] / GetMatrixColumn(2).magnitude()); mitk::Point3D anchor = scaleOp->GetScaleAnchorPoint(); vtktransform->PostMultiply(); vtktransform->Translate(-anchor[0], -anchor[1], -anchor[2]); vtktransform->Scale(scalefactor[0], scalefactor[1], scalefactor[2]); vtktransform->Translate(anchor[0], anchor[1], anchor[2]); break; } case OpROTATE: { auto *rotateOp = dynamic_cast(operation); if (rotateOp == nullptr) { MITK_ERROR << "Rotation operation is null!"; return; } Vector3D rotationVector = rotateOp->GetVectorOfRotation(); Point3D center = rotateOp->GetCenterOfRotation(); ScalarType angle = rotateOp->GetAngleOfRotation(); vtktransform->PostMultiply(); vtktransform->Translate(-center[0], -center[1], -center[2]); vtktransform->RotateWXYZ(angle, rotationVector[0], rotationVector[1], rotationVector[2]); vtktransform->Translate(center[0], center[1], center[2]); vtktransform->PreMultiply(); break; } case OpRESTOREPLANEPOSITION: { // Copy necessary to avoid vtk warning vtkMatrix4x4 *matrix = vtkMatrix4x4::New(); TransferItkTransformToVtkMatrix( dynamic_cast(operation)->GetTransform().GetPointer(), matrix); vtktransform->SetMatrix(matrix); matrix->Delete(); break; } case OpAPPLYTRANSFORMMATRIX: { auto *applyMatrixOp = dynamic_cast(operation); vtktransform->SetMatrix(applyMatrixOp->GetMatrix()); break; } default: vtktransform->Delete(); return; } this->SetVtkMatrixDeepCopy(vtktransform); Modified(); vtktransform->Delete(); } mitk::VnlVector mitk::BaseGeometry::GetMatrixColumn(unsigned int direction) const { return this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(direction).as_ref(); } mitk::BoundingBox::Pointer mitk::BaseGeometry::CalculateBoundingBoxRelativeToTransform( const mitk::AffineTransform3D *transform) const { mitk::BoundingBox::PointsContainer::Pointer pointscontainer = mitk::BoundingBox::PointsContainer::New(); mitk::BoundingBox::PointIdentifier pointid = 0; unsigned char i; if (transform != nullptr) { mitk::AffineTransform3D::Pointer inverse = mitk::AffineTransform3D::New(); transform->GetInverse(inverse); for (i = 0; i < 8; ++i) pointscontainer->InsertElement(pointid++, inverse->TransformPoint(GetCornerPoint(i))); } else { for (i = 0; i < 8; ++i) pointscontainer->InsertElement(pointid++, GetCornerPoint(i)); } mitk::BoundingBox::Pointer result = mitk::BoundingBox::New(); result->SetPoints(pointscontainer); result->ComputeBoundingBox(); return result; } const std::string mitk::BaseGeometry::GetTransformAsString(TransformType *transformType) { std::ostringstream out; out << '['; for (int i = 0; i < 3; ++i) { out << '['; for (int j = 0; j < 3; ++j) out << transformType->GetMatrix().GetVnlMatrix().get(i, j) << ' '; out << ']'; } out << "]["; for (int i = 0; i < 3; ++i) out << transformType->GetOffset()[i] << ' '; out << "]\0"; return out.str(); } void mitk::BaseGeometry::SetIndexToWorldTransformByVtkMatrix(vtkMatrix4x4 *vtkmatrix) { m_GeometryTransform->SetIndexToWorldTransformByVtkMatrix(vtkmatrix); } void mitk::BaseGeometry::SetIndexToWorldTransformByVtkMatrixWithoutChangingSpacing(vtkMatrix4x4 *vtkmatrix) { m_GeometryTransform->SetIndexToWorldTransformByVtkMatrixWithoutChangingSpacing(vtkmatrix); } void mitk::BaseGeometry::IndexToWorld(const mitk::Point3D & /*atPt3d_units*/, const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const { MITK_WARN << "Warning! Call of the deprecated function BaseGeometry::IndexToWorld(point, vec, vec). Use " "BaseGeometry::IndexToWorld(vec, vec) instead!"; // vec_mm = m_IndexToWorldTransform->TransformVector(vec_units); this->IndexToWorld(vec_units, vec_mm); } vtkMatrix4x4 *mitk::BaseGeometry::GetVtkMatrix() { return m_GeometryTransform->GetVtkMatrix(); } bool mitk::BaseGeometry::IsBoundingBoxNull() const { return m_BoundingBox.IsNull(); } bool mitk::BaseGeometry::IsIndexToWorldTransformNull() const { return m_GeometryTransform->IsIndexToWorldTransformNull(); } void mitk::BaseGeometry::ChangeImageGeometryConsideringOriginOffset(const bool isAnImageGeometry) { // If Geometry is switched to ImageGeometry, you have to put an offset to the origin, because // imageGeometries origins are pixel-center-based // ... and remove the offset, if you switch an imageGeometry back to a normal geometry // For more information please see the Geometry documentation page if (m_ImageGeometry == isAnImageGeometry) return; const BoundingBox::BoundsArrayType &boundsarray = this->GetBoundingBox()->GetBounds(); Point3D originIndex; FillVector3D(originIndex, boundsarray[0], boundsarray[2], boundsarray[4]); if (isAnImageGeometry == true) FillVector3D(originIndex, originIndex[0] + 0.5, originIndex[1] + 0.5, originIndex[2] + 0.5); else FillVector3D(originIndex, originIndex[0] - 0.5, originIndex[1] - 0.5, originIndex[2] - 0.5); Point3D originWorld; originWorld = GetIndexToWorldTransform()->TransformPoint(originIndex); // instead could as well call IndexToWorld(originIndex,originWorld); SetOrigin(originWorld); this->SetImageGeometry(isAnImageGeometry); } void mitk::BaseGeometry::PrintSelf(std::ostream &os, itk::Indent indent) const { os << indent << " IndexToWorldTransform: "; if (this->IsIndexToWorldTransformNull()) os << "nullptr" << std::endl; else { // from itk::MatrixOffsetTransformBase unsigned int i, j; os << std::endl; os << indent << "Matrix: " << std::endl; for (i = 0; i < 3; i++) { os << indent.GetNextIndent(); for (j = 0; j < 3; j++) { os << this->GetIndexToWorldTransform()->GetMatrix()[i][j] << " "; } os << std::endl; } os << indent << "Offset: " << this->GetIndexToWorldTransform()->GetOffset() << std::endl; os << indent << "Center: " << this->GetIndexToWorldTransform()->GetCenter() << std::endl; os << indent << "Translation: " << this->GetIndexToWorldTransform()->GetTranslation() << std::endl; auto inverse = mitk::AffineTransform3D::New(); if (this->GetIndexToWorldTransform()->GetInverse(inverse)) { os << indent << "Inverse: " << std::endl; for (i = 0; i < 3; i++) { os << indent.GetNextIndent(); for (j = 0; j < 3; j++) { os << inverse->GetMatrix()[i][j] << " "; } os << std::endl; } } // from itk::ScalableAffineTransform os << indent << "Scale : "; for (i = 0; i < 3; i++) { os << this->GetIndexToWorldTransform()->GetScale()[i] << " "; } os << std::endl; } os << indent << " BoundingBox: "; if (this->IsBoundingBoxNull()) os << "nullptr" << std::endl; else { os << indent << "( "; for (unsigned int i = 0; i < 3; i++) { os << this->GetBoundingBox()->GetBounds()[2 * i] << "," << this->GetBoundingBox()->GetBounds()[2 * i + 1] << " "; } os << " )" << std::endl; } os << indent << " Origin: " << this->GetOrigin() << std::endl; os << indent << " ImageGeometry: " << this->GetImageGeometry() << std::endl; os << indent << " Spacing: " << this->GetSpacing() << std::endl; } void mitk::BaseGeometry::Modified() const { if (!m_ModifiedLockFlag) Superclass::Modified(); else m_ModifiedCalledFlag = true; } mitk::AffineTransform3D *mitk::BaseGeometry::GetIndexToWorldTransform() { return m_GeometryTransform->GetIndexToWorldTransform(); } const mitk::AffineTransform3D *mitk::BaseGeometry::GetIndexToWorldTransform() const { return m_GeometryTransform->GetIndexToWorldTransform(); } const mitk::GeometryTransformHolder *mitk::BaseGeometry::GetGeometryTransformHolder() const { return m_GeometryTransform; } +void mitk::BaseGeometry::MapAxesToOrientations(int axes[]) const +{ + auto affineTransform = this->GetIndexToWorldTransform(); + auto matrix = affineTransform->GetMatrix(); + matrix.GetVnlMatrix().normalize_columns(); + auto inverseMatrix = matrix.GetInverse(); + + bool mapped[3] = {false, false, false}; + + // We need to allow an epsilon difference to ignore rounding. + const double eps = 0.0001; + + for (int orientation = 0; orientation < 3; ++orientation) + { + auto absX = std::abs(inverseMatrix[0][orientation]); + auto absY = std::abs(inverseMatrix[1][orientation]); + auto absZ = std::abs(inverseMatrix[2][orientation]); + + // First we check if there is a single maximum value. If there is, we found the axis + // that corresponds to the given orientation. If there is no single maximum value, + // we choose one from the the two or three axes that have the maximum value, but we + // need to make sure that we do not map the same axis to different orientations. + // Equal values are valid if the volume is rotated by exactly 45 degrees around one + // axis. If the volume is rotated by 45 degrees around two axes, you will get single + // maximum values at the same axes for two different orientations. In this case, + // the axis is mapped to one of the orientations, and for the other orientation we + // choose a different axis that has not been mapped yet, even if it is not a maximum. + + if (absX > absY + eps) + { + if (absX > absZ + eps) + { + // x is the greatest + int axis = !mapped[0] ? 0 : !mapped[1] ? 1 : 2; + axes[orientation] = axis; + mapped[axis] = true; + } + else + { + // z is the greatest OR x and z are equal and greater than y + int axis = !mapped[2] ? 2 : !mapped[0] ? 0 : 1; + axes[orientation] = axis; + mapped[axis] = true; + } + } + else if (absY > absX + eps) + { + if (absY > absZ + eps) + { + // y is the greatest + int axis = !mapped[1] ? 1 : !mapped[2] ? 2 : 0; + axes[orientation] = axis; + mapped[axis] = true; + } + else + { + // z is the greatest OR y and z are equal and greater than x + int axis = !mapped[2] ? 2 : !mapped[1] ? 1 : 0; + axes[orientation] = axis; + mapped[axis] = true; + } + } + else + { + if (absZ > absX + eps) + { + // z is the greatest + int axis = !mapped[2] ? 2 : !mapped[0] ? 0 : 1; + axes[orientation] = axis; + mapped[axis] = true; + } + else + { + // x and y are equal and greater than z OR x and y and z are equal + int axis = !mapped[0] ? 0 : !mapped[1] ? 1 : 2; + axes[orientation] = axis; + mapped[axis] = true; + } + } + } + + assert(mapped[0] && mapped[1] && mapped[2]); +} + bool mitk::Equal(const mitk::BaseGeometry::BoundingBoxType &leftHandSide, const mitk::BaseGeometry::BoundingBoxType &rightHandSide, ScalarType eps, bool verbose) { bool result = true; BaseGeometry::BoundsArrayType rightBounds = rightHandSide.GetBounds(); BaseGeometry::BoundsArrayType leftBounds = leftHandSide.GetBounds(); BaseGeometry::BoundsArrayType::Iterator itLeft = leftBounds.Begin(); for (BaseGeometry::BoundsArrayType::Iterator itRight = rightBounds.Begin(); itRight != rightBounds.End(); ++itRight) { if ((!mitk::Equal(*itLeft, *itRight, eps))) { if (verbose) { MITK_INFO << "[( Geometry3D::BoundingBoxType )] bounds are not equal."; MITK_INFO << "rightHandSide is " << setprecision(12) << *itRight << " : leftHandSide is " << *itLeft << " and tolerance is " << eps; } result = false; } itLeft++; } return result; } bool mitk::Equal(const mitk::BaseGeometry &leftHandSide, const mitk::BaseGeometry &rightHandSide, ScalarType coordinateEps, ScalarType directionEps, bool verbose) { bool result = true; // Compare spacings if (!mitk::Equal(leftHandSide.GetSpacing(), rightHandSide.GetSpacing(), coordinateEps)) { if (verbose) { MITK_INFO << "[( Geometry3D )] Spacing differs."; MITK_INFO << "rightHandSide is " << setprecision(12) << rightHandSide.GetSpacing() << " : leftHandSide is " << leftHandSide.GetSpacing() << " and tolerance is " << coordinateEps; } result = false; } // Compare Origins if (!mitk::Equal(leftHandSide.GetOrigin(), rightHandSide.GetOrigin(), coordinateEps)) { if (verbose) { MITK_INFO << "[( Geometry3D )] Origin differs."; MITK_INFO << "rightHandSide is " << setprecision(12) << rightHandSide.GetOrigin() << " : leftHandSide is " << leftHandSide.GetOrigin() << " and tolerance is " << coordinateEps; } result = false; } // Compare Axis and Extents for (unsigned int i = 0; i < 3; ++i) { if (!mitk::Equal(leftHandSide.GetAxisVector(i), rightHandSide.GetAxisVector(i), directionEps)) { if (verbose) { MITK_INFO << "[( Geometry3D )] AxisVector #" << i << " differ"; MITK_INFO << "rightHandSide is " << setprecision(12) << rightHandSide.GetAxisVector(i) << " : leftHandSide is " << leftHandSide.GetAxisVector(i) << " and tolerance is " << directionEps; } result = false; } if (!mitk::Equal(leftHandSide.GetExtent(i), rightHandSide.GetExtent(i), coordinateEps)) { if (verbose) { MITK_INFO << "[( Geometry3D )] Extent #" << i << " differ"; MITK_INFO << "rightHandSide is " << setprecision(12) << rightHandSide.GetExtent(i) << " : leftHandSide is " << leftHandSide.GetExtent(i) << " and tolerance is " << coordinateEps; } result = false; } } // Compare ImageGeometry Flag if (rightHandSide.GetImageGeometry() != leftHandSide.GetImageGeometry()) { if (verbose) { MITK_INFO << "[( Geometry3D )] GetImageGeometry is different."; MITK_INFO << "rightHandSide is " << rightHandSide.GetImageGeometry() << " : leftHandSide is " << leftHandSide.GetImageGeometry(); } result = false; } // Compare FrameOfReference ID if (rightHandSide.GetFrameOfReferenceID() != leftHandSide.GetFrameOfReferenceID()) { if (verbose) { MITK_INFO << "[( Geometry3D )] GetFrameOfReferenceID is different."; MITK_INFO << "rightHandSide is " << rightHandSide.GetFrameOfReferenceID() << " : leftHandSide is " << leftHandSide.GetFrameOfReferenceID(); } result = false; } // Compare BoundingBoxes if (!mitk::Equal(*leftHandSide.GetBoundingBox(), *rightHandSide.GetBoundingBox(), coordinateEps, verbose)) { result = false; } // Compare IndexToWorldTransform Matrix if (!mitk::Equal(*leftHandSide.GetIndexToWorldTransform(), *rightHandSide.GetIndexToWorldTransform(), directionEps, verbose)) { result = false; } return result; } bool mitk::Equal(const mitk::BaseGeometry& leftHandSide, const mitk::BaseGeometry& rightHandSide, ScalarType eps, bool verbose) { return Equal(leftHandSide, rightHandSide, eps, eps, verbose); } bool mitk::Equal(const mitk::BaseGeometry::TransformType &leftHandSide, const mitk::BaseGeometry::TransformType &rightHandSide, ScalarType eps, bool verbose) { // Compare IndexToWorldTransform Matrix if (!mitk::MatrixEqualElementWise(leftHandSide.GetMatrix(), rightHandSide.GetMatrix(), eps)) { if (verbose) { MITK_INFO << "[( Geometry3D::TransformType )] Index to World Transformation matrix differs."; MITK_INFO << "rightHandSide is " << setprecision(12) << rightHandSide.GetMatrix() << " : leftHandSide is " << leftHandSide.GetMatrix() << " and tolerance is " << eps; } return false; } return true; } bool mitk::IsSubGeometry(const mitk::BaseGeometry& testGeo, const mitk::BaseGeometry& referenceGeo, ScalarType coordinateEps, ScalarType directionEps, bool verbose) { bool result = true; // Compare spacings (must be equal) const auto testedSpacing = testGeo.GetSpacing(); if (!mitk::Equal(testedSpacing, referenceGeo.GetSpacing(), coordinateEps)) { if (verbose) { MITK_INFO << "[( Geometry3D )] Spacing differs."; MITK_INFO << "testedGeometry is " << setprecision(12) << testedSpacing << " : referenceGeometry is " << referenceGeo.GetSpacing() << " and tolerance is " << coordinateEps; } result = false; } // Compare ImageGeometry Flag (must be equal) if (referenceGeo.GetImageGeometry() != testGeo.GetImageGeometry()) { if (verbose) { MITK_INFO << "[( Geometry3D )] GetImageGeometry is different."; MITK_INFO << "referenceGeo is " << referenceGeo.GetImageGeometry() << " : testGeo is " << testGeo.GetImageGeometry(); } result = false; } // Compare IndexToWorldTransform Matrix (must be equal -> same axis directions) if (!Equal(*(testGeo.GetIndexToWorldTransform()), *(referenceGeo.GetIndexToWorldTransform()), directionEps, verbose)) { result = false; } //check if the geometry is within or equal to the bounds of reference geomentry. for (int i = 0; i<8; ++i) { auto testCorner = testGeo.GetCornerPoint(i); bool isInside = false; mitk::Point3D testCornerIndex; referenceGeo.WorldToIndex(testCorner, testCornerIndex); std::bitset bs(i); //To regard the coordinateEps, we subtract or add it to the index elements //depending on whether it was constructed by a lower or an upper bound value //(see implementation of BaseGeometry::GetCorner()). if (bs.test(0)) { testCornerIndex[2] -= coordinateEps; } else { testCornerIndex[2] += coordinateEps; } if (bs.test(1)) { testCornerIndex[1] -= coordinateEps; } else { testCornerIndex[1] += coordinateEps; } if (bs.test(2)) { testCornerIndex[0] -= coordinateEps; } else { testCornerIndex[0] += coordinateEps; } isInside = referenceGeo.IsIndexInside(testCornerIndex); if (!isInside) { if (verbose) { MITK_INFO << "[( Geometry3D )] corner point is not inside. "; MITK_INFO << "referenceGeo is " << setprecision(12) << referenceGeo << " : tested corner is " << testGeo.GetCornerPoint(i); } result = false; } } // check grid of test geometry is on the grid of the reference geometry. This is important as the // boundingbox is only checked for containing the tested geometry, but if a corner (one is enough // as we know that axis and spacing are equal, due to equal transfor (see above)) of the tested geometry // is on the grid it is really a sub geometry (as they have the same spacing and axis). auto cornerOffset = testGeo.GetCornerPoint(0) - referenceGeo.GetCornerPoint(0); mitk::Vector3D cornerIndexOffset; referenceGeo.WorldToIndex(cornerOffset, cornerIndexOffset); for (unsigned int i = 0; i < 3; ++i) { auto pixelCountContinous = cornerIndexOffset[i]; auto pixelCount = std::round(pixelCountContinous); if (std::abs(pixelCount - pixelCountContinous) > coordinateEps) { if (verbose) { MITK_INFO << "[( Geometry3D )] Tested geometry is not on the grid of the reference geometry. "; MITK_INFO << "referenceGeo is " << setprecision(15) << referenceGeo << " : tested corner offset in pixels is " << pixelCountContinous << " for axis "< #include #include namespace mitk { PlaneGeometry::PlaneGeometry() : Superclass(), m_ReferenceGeometry(nullptr) { Initialize(); } PlaneGeometry::~PlaneGeometry() {} PlaneGeometry::PlaneGeometry(const PlaneGeometry &other) : Superclass(other), m_ReferenceGeometry(other.m_ReferenceGeometry) { } bool PlaneGeometry::CheckRotationMatrix(mitk::AffineTransform3D *transform, double epsilon) { bool rotation = true; auto matrix = transform->GetMatrix().GetVnlMatrix(); matrix.normalize_columns(); auto det = vnl_determinant(matrix); if (fabs(det-1.0) > epsilon) { MITK_WARN << "Invalid rotation matrix! Determinant != 1 (" << det << ")"; rotation = false; } vnl_matrix_fixed id; id.set_identity(); auto should_be_id = matrix*matrix.transpose(); should_be_id -= id; auto max = should_be_id.absolute_value_max(); if (max > epsilon) { MITK_WARN << "Invalid rotation matrix! R*R^T != ID. Max value: " << max << " (should be 0)"; rotation = false; } return rotation; } void PlaneGeometry::CheckIndexToWorldTransform(mitk::AffineTransform3D *transform) { this->CheckRotationMatrix(transform); } void PlaneGeometry::CheckBounds(const BoundingBox::BoundsArrayType &bounds) { // error: unused parameter 'bounds' // this happens in release mode, where the assert macro is defined empty // hence we "use" the parameter: (void)bounds; // currently the unit rectangle must be starting at the origin [0,0] assert(bounds[0] == 0); assert(bounds[2] == 0); // the unit rectangle must be two-dimensional assert(bounds[1] > 0); assert(bounds[3] > 0); } void PlaneGeometry::IndexToWorld(const Point2D &pt_units, Point2D &pt_mm) const { pt_mm[0] = GetExtentInMM(0) / GetExtent(0) * pt_units[0]; pt_mm[1] = GetExtentInMM(1) / GetExtent(1) * pt_units[1]; } void PlaneGeometry::WorldToIndex(const Point2D &pt_mm, Point2D &pt_units) const { pt_units[0] = pt_mm[0] * (1.0 / (GetExtentInMM(0) / GetExtent(0))); pt_units[1] = pt_mm[1] * (1.0 / (GetExtentInMM(1) / GetExtent(1))); } void PlaneGeometry::IndexToWorld(const Point2D & /*atPt2d_units*/, const Vector2D &vec_units, Vector2D &vec_mm) const { MITK_WARN << "Warning! Call of the deprecated function PlaneGeometry::IndexToWorld(point, vec, vec). Use " "PlaneGeometry::IndexToWorld(vec, vec) instead!"; this->IndexToWorld(vec_units, vec_mm); } void PlaneGeometry::IndexToWorld(const Vector2D &vec_units, Vector2D &vec_mm) const { vec_mm[0] = (GetExtentInMM(0) / GetExtent(0)) * vec_units[0]; vec_mm[1] = (GetExtentInMM(1) / GetExtent(1)) * vec_units[1]; } void PlaneGeometry::WorldToIndex(const Point2D & /*atPt2d_mm*/, const Vector2D &vec_mm, Vector2D &vec_units) const { MITK_WARN << "Warning! Call of the deprecated function PlaneGeometry::WorldToIndex(point, vec, vec). Use " "PlaneGeometry::WorldToIndex(vec, vec) instead!"; this->WorldToIndex(vec_mm, vec_units); } void PlaneGeometry::WorldToIndex(const Vector2D &vec_mm, Vector2D &vec_units) const { vec_units[0] = vec_mm[0] * (1.0 / (GetExtentInMM(0) / GetExtent(0))); vec_units[1] = vec_mm[1] * (1.0 / (GetExtentInMM(1) / GetExtent(1))); } void PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, ScalarType height, const Vector3D &spacing, AnatomicalPlane planeorientation, ScalarType zPosition, bool frontside, bool rotated, bool top) { AffineTransform3D::Pointer transform; transform = AffineTransform3D::New(); AffineTransform3D::MatrixType matrix; AffineTransform3D::MatrixType::InternalMatrixType &vnlmatrix = matrix.GetVnlMatrix(); vnlmatrix.set_identity(); vnlmatrix(0, 0) = spacing[0]; vnlmatrix(1, 1) = spacing[1]; vnlmatrix(2, 2) = spacing[2]; transform->SetIdentity(); transform->SetMatrix(matrix); InitializeStandardPlane(width, height, transform.GetPointer(), planeorientation, zPosition, frontside, rotated, top); } void PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const AffineTransform3D *transform /* = nullptr */, AnatomicalPlane planeorientation /* = Axial */, mitk::ScalarType zPosition /* = 0 */, bool frontside /* = true */, bool rotated /* = false */, bool top /* = true */) { Superclass::Initialize(); /// construct standard view. // We define at the moment "frontside" as: axial from above, // coronal from front (nose), sagittal from right. // TODO: Double check with medicals doctors or radiologists [ ]. // We define the orientation in patient's view, e.g. LAI is in a axial cut // (parallel to the triangle ear-ear-nose): // first axis: To the left ear of the patient // seecond axis: To the nose of the patient // third axis: To the legs of the patient. // Options are: L/R left/right; A/P anterior/posterior; I/S inferior/superior // (AKA caudal/cranial). // We note on all cases in the following switch block r.h. for right handed // or l.h. for left handed to describe the different cases. // However, which system is chosen is defined at the end of the switch block. // CAVE / be careful: the vectors right and bottom are relative to the plane // and do NOT describe e.g. the right side of the patient. Point3D origin; /** Bottom means downwards, DV means Direction Vector. Both relative to the image! */ VnlVector rightDV(3), bottomDV(3); /** Origin of this plane is by default a zero vector and implicitly in the top-left corner: */ origin.Fill(0); /** This is different to all definitions in MITK, except the QT mouse clicks. * But it is like this here and we don't want to change a running system. * Just be aware, that IN THIS FUNCTION we define the origin at the top left (e.g. your screen). */ /** NormalDirection defines which axis (i.e. column index in the transform matrix) * is perpendicular to the plane: */ int normalDirection; switch (planeorientation) // Switch through our limited choice of standard planes: { case AnatomicalPlane::Original: /** Orientation 'Original' shall be done like the axial plane, * for whatever reasons. */ case AnatomicalPlane::Axial: if (frontside) // Radiologist's view from below. A cut along the triangle ear-ear-nose. { if (rotated == false) /** Origin in the top-left corner, x=[1; 0; 0], y=[0; 1; 0], z=[0; 0; 1], * origin=[0,0,zpos]: LAI (r.h.) * * 0---rightDV----> | * | | * | Picture of a finite, rectangular plane | * | ( insert LOLCAT-scan here ^_^ ) | * | | * v _________________________________________| * */ { FillVector3D(origin, 0, 0, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else // Origin rotated to the bottom-right corner, x=[-1; 0; 0], y=[0; -1; 0], z=[0; 0; 1], // origin=[w,h,zpos]: RPI (r.h.) { // Caveat emptor: Still using top-left as origin of index coordinate system! FillVector3D(origin, width, height, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } else // 'Backside, not frontside.' Neuro-Surgeons's view from above patient. { if (rotated == false) // x=[-1; 0; 0], y=[0; 1; 0], z=[0; 0; 1], origin=[w,0,zpos]: RAS (r.h.) { FillVector3D(origin, width, 0, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else // Origin in the bottom-left corner, x=[1; 0; 0], y=[0; -1; 0], z=[0; 0; 1], // origin=[0,h,zpos]: LPS (r.h.) { FillVector3D(origin, 0, height, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } normalDirection = 2; // That is S=Superior=z=third_axis=middlefinger in righthanded LPS-system. break; case AnatomicalPlane::Coronal: // Coronal=Frontal plane; cuts through patient's ear-ear-heel-heel: if (frontside) { if (rotated == false) // x=[1; 0; 0], y=[0; 0; 1], z=[0; 1; 0], origin=[0,zpos,0]: LAI (r.h.) { FillVector3D(origin, 0, zPosition, 0); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else // x=[-1;0;0], y=[0;0;-1], z=[0;1;0], origin=[w,zpos,h]: RAS (r.h.) { FillVector3D(origin, width, zPosition, height); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if (rotated == false) // x=[-1;0;0], y=[0;0;1], z=[0;1;0], origin=[w,zpos,0]: RPI (r.h.) { FillVector3D(origin, width, zPosition, 0); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else // x=[1;0;0], y=[0;1;0], z=[0;0;-1], origin=[0,zpos,h]: LPS (r.h.) { FillVector3D(origin, 0, zPosition, height); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 1; // Normal vector = posterior direction. break; case AnatomicalPlane::Sagittal: // Sagittal=Medial plane, the symmetry-plane mirroring your face. if (frontside) { if (rotated == false) // x=[0;1;0], y=[0;0;1], z=[1;0;0], origin=[zpos,0,0]: LAI (r.h.) { FillVector3D(origin, zPosition, 0, 0); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, 1); } else // x=[0;-1;0], y=[0;0;-1], z=[1;0;0], origin=[zpos,w,h]: LPS (r.h.) { FillVector3D(origin, zPosition, width, height); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if (rotated == false) // x=[0;-1;0], y=[0;0;1], z=[1;0;0], origin=[zpos,w,0]: RPI (r.h.) { FillVector3D(origin, zPosition, width, 0); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, 1); } else // x=[0;1;0], y=[0;0;-1], z=[1;0;0], origin=[zpos,0,h]: RAS (r.h.) { FillVector3D(origin, zPosition, 0, height); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 0; // Normal vector = Lateral direction: Left in a LPS-system. break; default: itkExceptionMacro("unknown AnatomicalPlane"); } VnlVector normal(3); FillVector3D(normal, 0, 0, 0); normal[normalDirection] = top ? 1 : -1; if ( transform != nullptr ) { origin = transform->TransformPoint( origin ); rightDV = transform->TransformVector( rightDV ).as_ref(); bottomDV = transform->TransformVector( bottomDV ).as_ref(); normal = transform->TransformVector( normal ).as_ref(); } ScalarType bounds[6] = {0, width, 0, height, 0, 1}; this->SetBounds(bounds); AffineTransform3D::Pointer planeTransform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightDV.as_ref()); matrix.GetVnlMatrix().set_column(1, bottomDV.as_ref()); matrix.GetVnlMatrix().set_column(2, normal.as_ref()); planeTransform->SetMatrix(matrix); planeTransform->SetOffset(this->GetIndexToWorldTransform()->GetOffset()); this->SetIndexToWorldTransform(planeTransform); this->SetOrigin(origin); } - - std::vector< int > PlaneGeometry::CalculateDominantAxes(mitk::AffineTransform3D::MatrixType::InternalMatrixType& rotation_matrix) - { - std::vector< int > axes; - - bool dominant_axis_error = false; - for (int i = 0; i < 3; ++i) - { - int dominantAxis = itk::Function::Max3( - rotation_matrix[0][i], - rotation_matrix[1][i], - rotation_matrix[2][i] - ); - - for (int j=0; jSetReferenceGeometry(geometry3D); ScalarType width, height; - // Inspired by: - // http://www.na-mic.org/Wiki/index.php/Coordinate_System_Conversion_Between_ITK_and_Slicer3 - - mitk::AffineTransform3D::MatrixType matrix = geometry3D->GetIndexToWorldTransform()->GetMatrix(); - + auto matrix = geometry3D->GetIndexToWorldTransform()->GetMatrix(); matrix.GetVnlMatrix().normalize_columns(); - mitk::AffineTransform3D::MatrixType::InternalMatrixType inverseMatrix = matrix.GetTranspose(); + auto inverseMatrix = matrix.GetInverse(); + + // The index of the sagittal, coronal and axial axes in the reference geometry. + int axes[3]; + geometry3D->MapAxesToOrientations(axes); - /// The index of the sagittal, coronal and axial axes in the reference geometry. - auto axes = CalculateDominantAxes(inverseMatrix); - /// The direction of the sagittal, coronal and axial axes in the reference geometry. - /// +1 means that the direction is straight, i.e. greater index translates to greater - /// world coordinate. -1 means that the direction is inverted. + // The direction of the sagittal, coronal and axial axes in the reference geometry. + // +1 means that the direction is straight, i.e. greater index translates to greater + // world coordinate. -1 means that the direction is inverted. int directions[3]; ScalarType extents[3]; ScalarType spacings[3]; for (int i=0; i<3; ++i) { - int dominantAxis = axes.at(i); - directions[i] = itk::Function::Sign(inverseMatrix[dominantAxis][i]); - extents[i] = geometry3D->GetExtent(dominantAxis); - spacings[i] = geometry3D->GetSpacing()[dominantAxis]; + int axis = axes[i]; + directions[i] = itk::Function::Sign(inverseMatrix[axis][i]); + extents[i] = geometry3D->GetExtent(axis); + spacings[i] = geometry3D->GetSpacing()[axis]; } // matrix(column) = inverseTransformMatrix(row) * flippedAxes * spacing matrix[0][0] = inverseMatrix[axes[0]][0] * directions[0] * spacings[0]; matrix[1][0] = inverseMatrix[axes[0]][1] * directions[0] * spacings[0]; matrix[2][0] = inverseMatrix[axes[0]][2] * directions[0] * spacings[0]; matrix[0][1] = inverseMatrix[axes[1]][0] * directions[1] * spacings[1]; matrix[1][1] = inverseMatrix[axes[1]][1] * directions[1] * spacings[1]; matrix[2][1] = inverseMatrix[axes[1]][2] * directions[1] * spacings[1]; matrix[0][2] = inverseMatrix[axes[2]][0] * directions[2] * spacings[2]; matrix[1][2] = inverseMatrix[axes[2]][1] * directions[2] * spacings[2]; matrix[2][2] = inverseMatrix[axes[2]][2] * directions[2] * spacings[2]; /// The "world origin" is the corner with the lowest physical coordinates. /// We use it as a reference point so that we get the correct anatomical /// orientations. Point3D worldOrigin = geometry3D->GetOrigin(); for (int i = 0; i < 3; ++i) { /// The distance of the plane origin from the world origin in voxels. double offset = directions[i] > 0 ? 0.0 : extents[i]; if (geometry3D->GetImageGeometry()) { offset += directions[i] * 0.5; } for (int j = 0; j < 3; ++j) { worldOrigin[j] -= offset * matrix[j][i]; } } switch(planeorientation) { case AnatomicalPlane::Original: /** Orientation 'Original' shall be done like the axial plane orientation, * for whatever reasons. */ case AnatomicalPlane::Axial: width = extents[0]; height = extents[1]; break; case AnatomicalPlane::Coronal: width = extents[0]; height = extents[2]; break; case AnatomicalPlane::Sagittal: width = extents[1]; height = extents[2]; break; default: itkExceptionMacro("unknown AnatomicalPlane"); } ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); AffineTransform3D::Pointer transform = AffineTransform3D::New(); transform->SetMatrix(matrix); transform->SetOffset(worldOrigin.GetVectorFromOrigin()); InitializeStandardPlane( width, height, transform, planeorientation, zPosition, frontside, rotated, top); } void PlaneGeometry::InitializeStandardPlane(const BaseGeometry *geometry3D, bool top, AnatomicalPlane planeorientation, bool frontside, bool rotated) { /// The index of the sagittal, coronal and axial axes in world coordinate system. int worldAxis; switch(planeorientation) { case AnatomicalPlane::Original: /** Orientation 'Original' shall be done like the axial plane orientation, * for whatever reasons. */ case AnatomicalPlane::Axial: worldAxis = 2; break; case AnatomicalPlane::Coronal: worldAxis = 1; break; case AnatomicalPlane::Sagittal: worldAxis = 0; break; default: itkExceptionMacro("unknown AnatomicalPlane"); } - // Inspired by: - // http://www.na-mic.org/Wiki/index.php/Coordinate_System_Conversion_Between_ITK_and_Slicer3 - - mitk::AffineTransform3D::ConstPointer affineTransform = geometry3D->GetIndexToWorldTransform(); - mitk::AffineTransform3D::MatrixType matrix = affineTransform->GetMatrix(); - matrix.GetVnlMatrix().normalize_columns(); - mitk::AffineTransform3D::MatrixType::InternalMatrixType inverseMatrix = matrix.GetInverse(); - - /// The index of the sagittal, coronal and axial axes in the reference geometry. - int dominantAxis = CalculateDominantAxes(inverseMatrix).at(worldAxis); + int axes[3]; + geometry3D->MapAxesToOrientations(axes); + int axis = axes[worldAxis]; - ScalarType zPosition = top ? 0.5 : geometry3D->GetExtent(dominantAxis) - 0.5; + ScalarType zPosition = top ? 0.5 : geometry3D->GetExtent(axis) - 0.5; InitializeStandardPlane(geometry3D, planeorientation, zPosition, frontside, rotated, top); } void PlaneGeometry::InitializeStandardPlane(const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing) { InitializeStandardPlane(rightVector.GetVnlVector(), downVector.GetVnlVector(), spacing); } void PlaneGeometry::InitializeStandardPlane(const VnlVector &rightVector, const VnlVector &downVector, const Vector3D *spacing) { ScalarType width = rightVector.two_norm(); ScalarType height = downVector.two_norm(); InitializeStandardPlane(width, height, rightVector, downVector, spacing); } void PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, ScalarType height, const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing) { InitializeStandardPlane(width, height, rightVector.GetVnlVector(), downVector.GetVnlVector(), spacing); } void PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, ScalarType height, const VnlVector &rightVector, const VnlVector &downVector, const Vector3D *spacing) { assert(width > 0); assert(height > 0); VnlVector rightDV = rightVector; rightDV.normalize(); VnlVector downDV = downVector; downDV.normalize(); VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); // Crossproduct vnl_cross_3d is always righthanded, but that is okay here // because in this method we create a new IndexToWorldTransform and // spacing with 1 or 3 negative components could still make it lefthanded. if (spacing != nullptr) { rightDV *= (*spacing)[0]; downDV *= (*spacing)[1]; normal *= (*spacing)[2]; } AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightDV); matrix.GetVnlMatrix().set_column(1, downDV); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(this->GetIndexToWorldTransform()->GetOffset()); ScalarType bounds[6] = {0, width, 0, height, 0, 1}; this->SetBounds(bounds); this->SetIndexToWorldTransform(transform); } void PlaneGeometry::InitializePlane(const Point3D &origin, const Vector3D &normal) { VnlVector rightVectorVnl(3), downVectorVnl; if (Equal(normal[1], 0.0f) == false) { FillVector3D(rightVectorVnl, 1.0f, -normal[0] / normal[1], 0.0f); rightVectorVnl.normalize(); } else { FillVector3D(rightVectorVnl, 0.0f, 1.0f, 0.0f); } downVectorVnl = vnl_cross_3d(normal.GetVnlVector(), rightVectorVnl); downVectorVnl.normalize(); // Crossproduct vnl_cross_3d is always righthanded. InitializeStandardPlane(rightVectorVnl, downVectorVnl); SetOrigin(origin); } void PlaneGeometry::SetMatrixByVectors(const VnlVector &rightVector, const VnlVector &downVector, ScalarType thickness /* = 1.0 */) { VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); normal *= thickness; // Crossproduct vnl_cross_3d is always righthanded, but that is okay here // because in this method we create a new IndexToWorldTransform and // a negative thickness could still make it lefthanded. AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightVector); matrix.GetVnlMatrix().set_column(1, downVector); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(this->GetIndexToWorldTransform()->GetOffset()); SetIndexToWorldTransform(transform); } Vector3D PlaneGeometry::GetNormal() const { Vector3D frontToBack; frontToBack.SetVnlVector(this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2).as_ref()); return frontToBack; } VnlVector PlaneGeometry::GetNormalVnl() const { return this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2).as_ref(); } ScalarType PlaneGeometry::DistanceFromPlane(const Point3D &pt3d_mm) const { return fabs(SignedDistance(pt3d_mm)); } ScalarType PlaneGeometry::SignedDistance(const Point3D &pt3d_mm) const { return SignedDistanceFromPlane(pt3d_mm); } bool PlaneGeometry::IsAbove(const Point3D &pt3d_mm, bool considerBoundingBox) const { if (considerBoundingBox) { Point3D pt3d_units; BaseGeometry::WorldToIndex(pt3d_mm, pt3d_units); return (pt3d_units[2] > this->GetBoundingBox()->GetBounds()[4]); } else return SignedDistanceFromPlane(pt3d_mm) > 0; } bool PlaneGeometry::IntersectionLine(const PlaneGeometry* plane, Line3D& crossline) const { Vector3D normal = this->GetNormal(); normal.Normalize(); Vector3D planeNormal = plane->GetNormal(); planeNormal.Normalize(); Vector3D direction = itk::CrossProduct(normal, planeNormal); if (direction.GetSquaredNorm() < eps) return false; crossline.SetDirection(direction); double N1dN2 = normal * planeNormal; double determinant = 1.0 - N1dN2 * N1dN2; Vector3D origin = this->GetOrigin().GetVectorFromOrigin(); Vector3D planeOrigin = plane->GetOrigin().GetVectorFromOrigin(); double d1 = normal * origin; double d2 = planeNormal * planeOrigin; double c1 = (d1 - d2 * N1dN2) / determinant; double c2 = (d2 - d1 * N1dN2) / determinant; Vector3D p = normal * c1 + planeNormal * c2; crossline.GetPoint()[0] = p.GetVnlVector()[0]; crossline.GetPoint()[1] = p.GetVnlVector()[1]; crossline.GetPoint()[2] = p.GetVnlVector()[2]; return true; } unsigned int PlaneGeometry::IntersectWithPlane2D(const PlaneGeometry *plane, Point2D &lineFrom, Point2D &lineTo) const { Line3D crossline; if (this->IntersectionLine(plane, crossline) == false) return 0; Point2D point2; Vector2D direction2; this->Map(crossline.GetPoint(), point2); this->Map(crossline.GetPoint(), crossline.GetDirection(), direction2); return Line3D::RectangleLineIntersection( 0, 0, GetExtentInMM(0), GetExtentInMM(1), point2, direction2, lineFrom, lineTo); } double PlaneGeometry::Angle(const PlaneGeometry *plane) const { return angle(plane->GetMatrixColumn(2), GetMatrixColumn(2)); } double PlaneGeometry::Angle(const Line3D &line) const { return vnl_math::pi_over_2 - angle(line.GetDirection().GetVnlVector(), GetMatrixColumn(2)); } bool PlaneGeometry::IntersectionPoint(const Line3D &line, Point3D &intersectionPoint) const { Vector3D planeNormal = this->GetNormal(); planeNormal.Normalize(); Vector3D lineDirection = line.GetDirection(); lineDirection.Normalize(); double t = planeNormal * lineDirection; if (fabs(t) < eps) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = (planeNormal * diff) / t; intersectionPoint = line.GetPoint() + lineDirection * t; return true; } bool PlaneGeometry::IntersectionPointParam(const Line3D &line, double &t) const { Vector3D planeNormal = this->GetNormal(); Vector3D lineDirection = line.GetDirection(); t = planeNormal * lineDirection; if (fabs(t) < eps) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = (planeNormal * diff) / t; return true; } bool PlaneGeometry::IsParallel(const PlaneGeometry *plane) const { return ((Angle(plane) < 10.0 * mitk::sqrteps) || (Angle(plane) > (vnl_math::pi - 10.0 * sqrteps))); } bool PlaneGeometry::IsOnPlane(const Point3D &point) const { return Distance(point) < eps; } bool PlaneGeometry::IsOnPlane(const Line3D &line) const { return ((Distance(line.GetPoint()) < eps) && (Distance(line.GetPoint2()) < eps)); } bool PlaneGeometry::IsOnPlane(const PlaneGeometry *plane) const { return (IsParallel(plane) && (Distance(plane->GetOrigin()) < eps)); } Point3D PlaneGeometry::ProjectPointOntoPlane(const Point3D &pt) const { ScalarType len = this->GetNormalVnl().two_norm(); return pt - this->GetNormal() * this->SignedDistanceFromPlane(pt) / len; } itk::LightObject::Pointer PlaneGeometry::InternalClone() const { Self::Pointer newGeometry = new PlaneGeometry(*this); newGeometry->UnRegister(); return newGeometry.GetPointer(); } void PlaneGeometry::ExecuteOperation(Operation *operation) { vtkTransform *transform = vtkTransform::New(); transform->SetMatrix(this->GetVtkMatrix()); switch (operation->GetOperationType()) { case OpORIENT: { auto *planeOp = dynamic_cast(operation); if (planeOp == nullptr) { return; } Point3D center = planeOp->GetPoint(); Vector3D orientationVector = planeOp->GetNormal(); Vector3D defaultVector; FillVector3D(defaultVector, 0.0, 0.0, 1.0); Vector3D rotationAxis = itk::CrossProduct(orientationVector, defaultVector); // double rotationAngle = acos( orientationVector[2] / orientationVector.GetNorm() ); double rotationAngle = atan2((double)rotationAxis.GetNorm(), (double)(orientationVector * defaultVector)); rotationAngle *= 180.0 / vnl_math::pi; transform->PostMultiply(); transform->Identity(); transform->Translate(center[0], center[1], center[2]); transform->RotateWXYZ(rotationAngle, rotationAxis[0], rotationAxis[1], rotationAxis[2]); transform->Translate(-center[0], -center[1], -center[2]); break; } case OpRESTOREPLANEPOSITION: { auto *op = dynamic_cast(operation); if (op == nullptr) { return; } AffineTransform3D::Pointer transform2 = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(0)); matrix.GetVnlMatrix().set_column(1, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(1)); matrix.GetVnlMatrix().set_column(2, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(2)); transform2->SetMatrix(matrix); Vector3D offset = op->GetTransform()->GetOffset(); transform2->SetOffset(offset); this->SetIndexToWorldTransform(transform2); ScalarType bounds[6] = {0, op->GetWidth(), 0, op->GetHeight(), 0, 1}; this->SetBounds(bounds); this->Modified(); transform->Delete(); return; } default: Superclass::ExecuteOperation(operation); transform->Delete(); return; } this->SetVtkMatrixDeepCopy(transform); this->Modified(); transform->Delete(); } void PlaneGeometry::PrintSelf(std::ostream &os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << " ScaleFactorMMPerUnitX: " << GetExtentInMM(0) / GetExtent(0) << std::endl; os << indent << " ScaleFactorMMPerUnitY: " << GetExtentInMM(1) / GetExtent(1) << std::endl; os << indent << " Normal: " << GetNormal() << std::endl; } bool PlaneGeometry::Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const { assert(this->IsBoundingBoxNull() == false); Point3D pt3d_units; Superclass::WorldToIndex(pt3d_mm, pt3d_units); pt2d_mm[0] = pt3d_units[0] * GetExtentInMM(0) / GetExtent(0); pt2d_mm[1] = pt3d_units[1] * GetExtentInMM(1) / GetExtent(1); pt3d_units[2] = 0; return this->GetBoundingBox()->IsInside(pt3d_units); } void PlaneGeometry::Map(const mitk::Point2D &pt2d_mm, mitk::Point3D &pt3d_mm) const { // pt2d_mm is measured from the origin of the world geometry (at least it called form BaseRendere::Mouse...Event) Point3D pt3d_units; pt3d_units[0] = pt2d_mm[0] / (GetExtentInMM(0) / GetExtent(0)); pt3d_units[1] = pt2d_mm[1] / (GetExtentInMM(1) / GetExtent(1)); pt3d_units[2] = 0; // pt3d_units is a continuous index. We divided it with the Scale Factor (= spacing in x and y) to convert it from mm // to index units. // pt3d_mm = GetIndexToWorldTransform()->TransformPoint(pt3d_units); // now we convert the 3d index to a 3D world point in mm. We could have used IndexToWorld as well as // GetITW->Transform... } void PlaneGeometry::SetSizeInUnits(mitk::ScalarType width, mitk::ScalarType height) { ScalarType bounds[6] = {0, width, 0, height, 0, 1}; ScalarType extent, newextentInMM; if (GetExtent(0) > 0) { extent = GetExtent(0); if (width > extent) newextentInMM = GetExtentInMM(0) / width * extent; else newextentInMM = GetExtentInMM(0) * extent / width; SetExtentInMM(0, newextentInMM); } if (GetExtent(1) > 0) { extent = GetExtent(1); if (width > extent) newextentInMM = GetExtentInMM(1) / height * extent; else newextentInMM = GetExtentInMM(1) * extent / height; SetExtentInMM(1, newextentInMM); } SetBounds(bounds); } bool PlaneGeometry::Project(const mitk::Point3D &pt3d_mm, mitk::Point3D &projectedPt3d_mm) const { assert(this->IsBoundingBoxNull() == false); Point3D pt3d_units; Superclass::WorldToIndex(pt3d_mm, pt3d_units); pt3d_units[2] = 0; projectedPt3d_mm = GetIndexToWorldTransform()->TransformPoint(pt3d_units); return this->GetBoundingBox()->IsInside(pt3d_units); } bool PlaneGeometry::Project(const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const { assert(this->IsBoundingBoxNull() == false); Vector3D vec3d_units; Superclass::WorldToIndex(vec3d_mm, vec3d_units); vec3d_units[2] = 0; projectedVec3d_mm = GetIndexToWorldTransform()->TransformVector(vec3d_units); return true; } bool PlaneGeometry::Project(const mitk::Point3D &atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const { MITK_WARN << "Deprecated function! Call Project(vec3D,vec3D) instead."; assert(this->IsBoundingBoxNull() == false); Vector3D vec3d_units; Superclass::WorldToIndex(atPt3d_mm, vec3d_mm, vec3d_units); vec3d_units[2] = 0; projectedVec3d_mm = GetIndexToWorldTransform()->TransformVector(vec3d_units); Point3D pt3d_units; Superclass::WorldToIndex(atPt3d_mm, pt3d_units); return this->GetBoundingBox()->IsInside(pt3d_units); } bool PlaneGeometry::Map(const mitk::Point3D &atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector2D &vec2d_mm) const { Point2D pt2d_mm_start, pt2d_mm_end; Point3D pt3d_mm_end; bool inside = Map(atPt3d_mm, pt2d_mm_start); pt3d_mm_end = atPt3d_mm + vec3d_mm; inside &= Map(pt3d_mm_end, pt2d_mm_end); vec2d_mm = pt2d_mm_end - pt2d_mm_start; return inside; } void PlaneGeometry::Map(const mitk::Point2D & /*atPt2d_mm*/, const mitk::Vector2D & /*vec2d_mm*/, mitk::Vector3D & /*vec3d_mm*/) const { //@todo implement parallel to the other Map method! assert(false); } void PlaneGeometry::SetReferenceGeometry(const mitk::BaseGeometry *geometry) { m_ReferenceGeometry = geometry; } const mitk::BaseGeometry *PlaneGeometry::GetReferenceGeometry() const { return m_ReferenceGeometry; } bool PlaneGeometry::HasReferenceGeometry() const { return (m_ReferenceGeometry != nullptr); } } // namespace diff --git a/Modules/Core/src/DataManagement/mitkSlicedGeometry3D.cpp b/Modules/Core/src/DataManagement/mitkSlicedGeometry3D.cpp index 6e23ef32d9..d03779a6a1 100644 --- a/Modules/Core/src/DataManagement/mitkSlicedGeometry3D.cpp +++ b/Modules/Core/src/DataManagement/mitkSlicedGeometry3D.cpp @@ -1,962 +1,960 @@ /*============================================================================ 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 #include "mitkSlicedGeometry3D.h" #include "mitkAbstractTransformGeometry.h" #include "mitkApplyTransformMatrixOperation.h" #include "mitkInteractionConst.h" #include "mitkPlaneGeometry.h" #include "mitkPlaneOperation.h" #include "mitkRestorePlanePositionOperation.h" #include "mitkRotationOperation.h" #include "mitkSliceNavigationController.h" const mitk::ScalarType PI = 3.14159265359; mitk::SlicedGeometry3D::SlicedGeometry3D() : m_EvenlySpaced(true), m_Slices(0), m_ReferenceGeometry(nullptr), m_SliceNavigationController(nullptr) { m_DirectionVector.Fill(0); this->InitializeSlicedGeometry(m_Slices); } mitk::SlicedGeometry3D::SlicedGeometry3D(const SlicedGeometry3D &other) : Superclass(other), m_EvenlySpaced(other.m_EvenlySpaced), m_Slices(other.m_Slices), m_ReferenceGeometry(other.m_ReferenceGeometry), m_SliceNavigationController(other.m_SliceNavigationController) { m_DirectionVector.Fill(0); SetSpacing(other.GetSpacing()); SetDirectionVector(other.GetDirectionVector()); if (m_EvenlySpaced) { assert(!other.m_PlaneGeometries.empty() && "This may happen when you use one of the old Initialize methods, which had a bool parameter that is implicitly casted to the number of slices now."); PlaneGeometry::Pointer geometry = other.m_PlaneGeometries[0]->Clone(); assert(geometry.IsNotNull()); SetPlaneGeometry(geometry, 0); } else { unsigned int s; for (s = 0; s < other.m_Slices; ++s) { if (other.m_PlaneGeometries[s].IsNull()) { assert(other.m_EvenlySpaced); m_PlaneGeometries[s] = nullptr; } else { PlaneGeometry *geometry2D = other.m_PlaneGeometries[s]->Clone(); assert(geometry2D != nullptr); SetPlaneGeometry(geometry2D, s); } } } } mitk::SlicedGeometry3D::~SlicedGeometry3D() { } mitk::PlaneGeometry *mitk::SlicedGeometry3D::GetPlaneGeometry(int s) const { mitk::PlaneGeometry::Pointer geometry2D = nullptr; if (this->IsValidSlice(s)) { geometry2D = m_PlaneGeometries[s]; // If (a) m_EvenlySpaced==true, (b) we don't have a PlaneGeometry stored // for the requested slice, and (c) the first slice (s=0) // is a PlaneGeometry instance, then we calculate the geometry of the // requested as the plane of the first slice shifted by m_Spacing[2]*s // in the direction of m_DirectionVector. if ((m_EvenlySpaced) && (geometry2D.IsNull())) { PlaneGeometry *firstSlice = m_PlaneGeometries[0]; if (firstSlice != nullptr && dynamic_cast(m_PlaneGeometries[0].GetPointer()) == nullptr) { if ((m_DirectionVector[0] == 0.0) && (m_DirectionVector[1] == 0.0) && (m_DirectionVector[2] == 0.0)) { m_DirectionVector = firstSlice->GetNormal(); m_DirectionVector.Normalize(); } Vector3D direction; direction = m_DirectionVector * this->GetSpacing()[2]; mitk::PlaneGeometry::Pointer requestedslice; requestedslice = static_cast(firstSlice->Clone().GetPointer()); requestedslice->SetOrigin(requestedslice->GetOrigin() + direction * s); geometry2D = requestedslice; m_PlaneGeometries[s] = geometry2D; } } return geometry2D; } else { return nullptr; } } const mitk::BoundingBox *mitk::SlicedGeometry3D::GetBoundingBox() const { assert(this->IsBoundingBoxNull() == false); return Superclass::GetBoundingBox(); } bool mitk::SlicedGeometry3D::SetPlaneGeometry(mitk::PlaneGeometry *geometry2D, int s) { if (this->IsValidSlice(s)) { m_PlaneGeometries[s] = geometry2D; m_PlaneGeometries[s]->SetReferenceGeometry(m_ReferenceGeometry); return true; } return false; } void mitk::SlicedGeometry3D::InitializeSlicedGeometry(unsigned int slices) { Superclass::Initialize(); m_Slices = slices; PlaneGeometry::Pointer gnull = nullptr; m_PlaneGeometries.assign(m_Slices, gnull); Vector3D spacing; spacing.Fill(1.0); this->SetSpacing(spacing); m_DirectionVector.Fill(0); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced(mitk::PlaneGeometry *geometry2D, unsigned int slices) { assert(geometry2D != nullptr); this->InitializeEvenlySpaced(geometry2D, geometry2D->GetExtentInMM(2) / geometry2D->GetExtent(2), slices); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced(mitk::PlaneGeometry *geometry2D, mitk::ScalarType zSpacing, unsigned int slices) { assert(geometry2D != nullptr); assert(geometry2D->GetExtent(0) > 0); assert(geometry2D->GetExtent(1) > 0); geometry2D->Register(); Superclass::Initialize(); m_Slices = slices; BoundingBox::BoundsArrayType bounds = geometry2D->GetBounds(); bounds[4] = 0; bounds[5] = slices; // clear and reserve PlaneGeometry::Pointer gnull = nullptr; m_PlaneGeometries.assign(m_Slices, gnull); Vector3D directionVector = geometry2D->GetAxisVector(2); directionVector.Normalize(); directionVector *= zSpacing; // Normally we should use the following four lines to create a copy of // the transform contained in geometry2D, because it may not be changed // by us. But we know that SetSpacing creates a new transform without // changing the old (coming from geometry2D), so we can use the fifth // line instead. We check this at (**). // // AffineTransform3D::Pointer transform = AffineTransform3D::New(); // transform->SetMatrix(geometry2D->GetIndexToWorldTransform()->GetMatrix()); // transform->SetOffset(geometry2D->GetIndexToWorldTransform()->GetOffset()); // SetIndexToWorldTransform(transform); this->SetIndexToWorldTransform(geometry2D->GetIndexToWorldTransform()); mitk::Vector3D spacing; FillVector3D(spacing, geometry2D->GetExtentInMM(0) / bounds[1], geometry2D->GetExtentInMM(1) / bounds[3], zSpacing); this->SetDirectionVector(directionVector); this->SetBounds(bounds); this->SetPlaneGeometry(geometry2D, 0); this->SetSpacing(spacing, true); this->SetEvenlySpaced(); // this->SetTimeBounds( geometry2D->GetTimeBounds() ); assert(this->GetIndexToWorldTransform() != geometry2D->GetIndexToWorldTransform()); // (**) see above. this->SetFrameOfReferenceID(geometry2D->GetFrameOfReferenceID()); this->SetImageGeometry(geometry2D->GetImageGeometry()); geometry2D->UnRegister(); } void mitk::SlicedGeometry3D::InitializePlanes(const mitk::BaseGeometry *geometry3D, mitk::AnatomicalPlane orientation, bool top, bool frontside, bool rotated) { m_ReferenceGeometry = geometry3D; PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane(geometry3D, top, orientation, frontside, rotated); int worldAxis = orientation == AnatomicalPlane::Sagittal ? 0 : orientation == AnatomicalPlane::Coronal ? 1 : 2; - // Inspired by: - // http://www.na-mic.org/Wiki/index.php/Coordinate_System_Conversion_Between_ITK_and_Slicer3 + int axes[3]; + geometry3D->MapAxesToOrientations(axes); + int axis = axes[worldAxis]; - mitk::AffineTransform3D::MatrixType matrix = geometry3D->GetIndexToWorldTransform()->GetMatrix(); - matrix.GetVnlMatrix().normalize_columns(); - mitk::AffineTransform3D::MatrixType::InternalMatrixType inverseMatrix = matrix.GetTranspose(); - - int dominantAxis = planeGeometry->CalculateDominantAxes(inverseMatrix).at(worldAxis); - ScalarType viewSpacing = geometry3D->GetSpacing()[dominantAxis]; - - /// Although the double value returned by GetExtent() holds a round number, - /// you need to add 0.5 to safely convert it to unsigned it. I have seen a - /// case when the result was less by one without this. - auto slices = static_cast(geometry3D->GetExtent(dominantAxis) + 0.5); - if ( slices == 0 && geometry3D->GetExtent(dominantAxis) > 0) { - // require at least one slice if there is _some_ extent - slices = 1; + ScalarType viewSpacing = geometry3D->GetSpacing()[axis]; + unsigned int slices = static_cast(geometry3D->GetExtent(axis) + 0.5); + + if (slices == 0 && geometry3D->GetExtent(axis) > 0) + { + // require at least one slice if there is _some_ extent + slices = 1; } #ifndef NDEBUG - int upDirection = itk::Function::Sign(inverseMatrix[dominantAxis][worldAxis]); + auto matrix = geometry3D->GetIndexToWorldTransform()->GetMatrix(); + matrix.GetVnlMatrix().normalize_columns(); + auto inverseMatrix = matrix.GetInverse(); + + int upDirection = itk::Function::Sign(inverseMatrix[axis][worldAxis]); /// The normal vector of an imaginary plane that points from the world origin (bottom left back /// corner or the world, with the lowest physical coordinates) towards the inside of the volume, /// along the renderer axis. Length is the slice thickness. - Vector3D worldPlaneNormal = inverseMatrix.get_row(dominantAxis) * (upDirection * viewSpacing); + Vector3D worldPlaneNormal = inverseMatrix.get_row(axis) * (upDirection * viewSpacing); /// The normal of the standard plane geometry just created. Vector3D standardPlaneNormal = planeGeometry->GetNormal(); /// The standard plane must be parallel to the 'world plane'. The normal of the standard plane /// must point against the world plane if and only if 'top' is 'false'. The length of the /// standard plane normal must be equal to the slice thickness. assert((standardPlaneNormal - (top ? 1.0 : -1.0) * worldPlaneNormal).GetSquaredNorm() < 0.000001); #endif this->InitializeEvenlySpaced(planeGeometry, viewSpacing, slices); #ifndef NDEBUG /// The standard plane normal and the z axis vector of the sliced geometry must point in /// the same direction. Vector3D zAxisVector = this->GetAxisVector(2); Vector3D upscaledStandardPlaneNormal = standardPlaneNormal; upscaledStandardPlaneNormal *= slices; assert((zAxisVector - upscaledStandardPlaneNormal).GetSquaredNorm() < 0.000001); /// You can use this test is to check the handedness of the coordinate system of the current /// geometry. In principle, you can use either left- or right-handed coordinate systems, but /// you normally want it to be consistent, that is the handedness should be the same across /// the renderers of the same viewer. // ScalarType det = vnl_det(this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix()); // MITK_DEBUG << "world axis: " << worldAxis << (det > 0 ? " ; right-handed" : " ; left-handed"); #endif } void mitk::SlicedGeometry3D::ReinitializePlanes(const Point3D ¢er, const Point3D &referencePoint) { // Need a reference frame to align the rotated planes if (!m_ReferenceGeometry) { return; } // Get first plane of plane stack PlaneGeometry *firstPlane = m_PlaneGeometries[0]; // If plane stack is empty, exit if (!firstPlane || dynamic_cast(firstPlane)) { return; } // Calculate the "directed" spacing when taking the plane (defined by its axes // vectors and normal) as the reference coordinate frame. // // This is done by calculating the radius of the ellipsoid defined by the // original volume spacing axes, in the direction of the respective axis of the // reference frame. mitk::Vector3D axis0 = firstPlane->GetAxisVector(0); mitk::Vector3D axis1 = firstPlane->GetAxisVector(1); mitk::Vector3D normal = firstPlane->GetNormal(); normal.Normalize(); Vector3D spacing; spacing[0] = this->CalculateSpacing(axis0); spacing[1] = this->CalculateSpacing(axis1); spacing[2] = this->CalculateSpacing(normal); Superclass::SetSpacing(spacing); // Now we need to calculate the number of slices in the plane's normal // direction, so that the entire volume is covered. This is done by first // calculating the dot product between the volume diagonal (the maximum // distance inside the volume) and the normal, and dividing this value by // the directed spacing calculated above. ScalarType directedExtent = std::abs(m_ReferenceGeometry->GetExtentInMM(0) * normal[0]) + std::abs(m_ReferenceGeometry->GetExtentInMM(1) * normal[1]) + std::abs(m_ReferenceGeometry->GetExtentInMM(2) * normal[2]); if (directedExtent >= spacing[2]) { m_Slices = static_cast(directedExtent / spacing[2] + 0.5); } else { m_Slices = 1; } // The origin of our "first plane" needs to be adapted to this new extent. // To achieve this, we first calculate the current distance to the volume's // center, and then shift the origin in the direction of the normal by the // difference between this distance and half of the new extent. double centerOfRotationDistance = firstPlane->SignedDistanceFromPlane(center); if (centerOfRotationDistance > 0) { firstPlane->SetOrigin(firstPlane->GetOrigin() + normal * (centerOfRotationDistance - directedExtent / 2.0)); m_DirectionVector = normal; } else { firstPlane->SetOrigin(firstPlane->GetOrigin() + normal * (directedExtent / 2.0 + centerOfRotationDistance)); m_DirectionVector = -normal; } // Now we adjust this distance according with respect to the given reference // point: we need to make sure that the point is touched by one slice of the // new slice stack. double referencePointDistance = firstPlane->SignedDistanceFromPlane(referencePoint); auto referencePointSlice = static_cast(referencePointDistance / spacing[2]); double alignmentValue = referencePointDistance / spacing[2] - referencePointSlice; firstPlane->SetOrigin(firstPlane->GetOrigin() + normal * alignmentValue * spacing[2]); // Finally, we can clear the previous geometry stack and initialize it with // our re-initialized "first plane". m_PlaneGeometries.assign(m_Slices, PlaneGeometry::Pointer(nullptr)); if (m_Slices > 0) { m_PlaneGeometries[0] = firstPlane; } // Reinitialize SNC with new number of slices m_SliceNavigationController->GetStepper()->SetSteps(m_Slices); this->Modified(); } double mitk::SlicedGeometry3D::CalculateSpacing(const mitk::Vector3D &d) const { // Need the spacing of the underlying dataset / geometry if (!m_ReferenceGeometry) { return 1.0; } const mitk::Vector3D &spacing = m_ReferenceGeometry->GetSpacing(); return SlicedGeometry3D::CalculateSpacing(spacing, d); } double mitk::SlicedGeometry3D::CalculateSpacing(const mitk::Vector3D &spacing, const mitk::Vector3D &d) { // The following can be derived from the ellipsoid equation // // 1 = x^2/a^2 + y^2/b^2 + z^2/c^2 // // where (a,b,c) = spacing of original volume (ellipsoid radii) // and (x,y,z) = scaled coordinates of vector d (according to ellipsoid) // double scaling = d[0] * d[0] / (spacing[0] * spacing[0]) + d[1] * d[1] / (spacing[1] * spacing[1]) + d[2] * d[2] / (spacing[2] * spacing[2]); scaling = sqrt(scaling); return (sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]) / scaling); } mitk::Vector3D mitk::SlicedGeometry3D::AdjustNormal(const mitk::Vector3D &normal) const { TransformType::Pointer inverse = TransformType::New(); m_ReferenceGeometry->GetIndexToWorldTransform()->GetInverse(inverse); Vector3D transformedNormal = inverse->TransformVector(normal); transformedNormal.Normalize(); return transformedNormal; } void mitk::SlicedGeometry3D::SetImageGeometry(const bool isAnImageGeometry) { Superclass::SetImageGeometry(isAnImageGeometry); unsigned int s; for (s = 0; s < m_Slices; ++s) { mitk::BaseGeometry *geometry = m_PlaneGeometries[s]; if (geometry != nullptr) { geometry->SetImageGeometry(isAnImageGeometry); } } } void mitk::SlicedGeometry3D::ChangeImageGeometryConsideringOriginOffset(const bool isAnImageGeometry) { unsigned int s; for (s = 0; s < m_Slices; ++s) { mitk::BaseGeometry *geometry = m_PlaneGeometries[s]; if (geometry != nullptr) { geometry->ChangeImageGeometryConsideringOriginOffset(isAnImageGeometry); } } Superclass::ChangeImageGeometryConsideringOriginOffset(isAnImageGeometry); } bool mitk::SlicedGeometry3D::IsValidSlice(int s) const { return ((s >= 0) && (s < (int)m_Slices)); } const mitk::BaseGeometry *mitk::SlicedGeometry3D::GetReferenceGeometry() const { return m_ReferenceGeometry; } void mitk::SlicedGeometry3D::SetReferenceGeometry(const BaseGeometry *referenceGeometry) { m_ReferenceGeometry = referenceGeometry; std::vector::iterator it; for (it = m_PlaneGeometries.begin(); it != m_PlaneGeometries.end(); ++it) { (*it)->SetReferenceGeometry(referenceGeometry); } } bool mitk::SlicedGeometry3D::HasReferenceGeometry() const { return ( m_ReferenceGeometry != nullptr ); } void mitk::SlicedGeometry3D::PreSetSpacing(const mitk::Vector3D &aSpacing) { bool hasEvenlySpacedPlaneGeometry = false; mitk::Point3D origin; mitk::Vector3D rightDV, bottomDV; BoundingBox::BoundsArrayType bounds; // Check for valid spacing if (!(aSpacing[0] > 0 && aSpacing[1] > 0 && aSpacing[2] > 0)) { mitkThrow() << "You try to set a spacing with at least one element equal or " "smaller to \"0\". This might lead to a crash during rendering. Please double" " check your data!"; } // In case of evenly-spaced data: re-initialize instances of PlaneGeometry, // since the spacing influences them if ((m_EvenlySpaced) && (m_PlaneGeometries.size() > 0)) { const PlaneGeometry *planeGeometry = m_PlaneGeometries[0]; if (planeGeometry && !dynamic_cast(planeGeometry)) { this->WorldToIndex(planeGeometry->GetOrigin(), origin); this->WorldToIndex(planeGeometry->GetAxisVector(0), rightDV); this->WorldToIndex(planeGeometry->GetAxisVector(1), bottomDV); bounds = planeGeometry->GetBounds(); hasEvenlySpacedPlaneGeometry = true; } } BaseGeometry::_SetSpacing(aSpacing); mitk::PlaneGeometry::Pointer firstGeometry; // In case of evenly-spaced data: re-initialize instances of PlaneGeometry, // since the spacing influences them if (hasEvenlySpacedPlaneGeometry) { // create planeGeometry according to new spacing this->IndexToWorld(origin, origin); this->IndexToWorld(rightDV, rightDV); this->IndexToWorld(bottomDV, bottomDV); mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->SetImageGeometry(this->GetImageGeometry()); planeGeometry->SetReferenceGeometry(m_ReferenceGeometry); // Store spacing, as Initialize... needs a pointer mitk::Vector3D lokalSpacing = this->GetSpacing(); planeGeometry->InitializeStandardPlane(rightDV.GetVnlVector(), bottomDV.GetVnlVector(), &lokalSpacing); planeGeometry->SetOrigin(origin); planeGeometry->SetBounds(bounds); firstGeometry = planeGeometry; } else if ((m_EvenlySpaced) && (m_PlaneGeometries.size() > 0)) { firstGeometry = m_PlaneGeometries[0].GetPointer(); } // clear and reserve PlaneGeometry::Pointer gnull = nullptr; m_PlaneGeometries.assign(m_Slices, gnull); if (m_Slices > 0) { m_PlaneGeometries[0] = firstGeometry; } this->Modified(); } void mitk::SlicedGeometry3D::SetSliceNavigationController(SliceNavigationController *snc) { m_SliceNavigationController = snc; } mitk::SliceNavigationController *mitk::SlicedGeometry3D::GetSliceNavigationController() { return m_SliceNavigationController; } void mitk::SlicedGeometry3D::SetEvenlySpaced(bool on) { if (m_EvenlySpaced != on) { m_EvenlySpaced = on; this->Modified(); } } void mitk::SlicedGeometry3D::SetDirectionVector(const mitk::Vector3D &directionVector) { Vector3D newDir = directionVector; newDir.Normalize(); if (newDir != m_DirectionVector) { m_DirectionVector = newDir; this->Modified(); } } // void // mitk::SlicedGeometry3D::SetTimeBounds( const mitk::TimeBounds& timebounds ) //{ // Superclass::SetTimeBounds( timebounds ); // // unsigned int s; // for ( s = 0; s < m_Slices; ++s ) // { // if(m_Geometry2Ds[s].IsNotNull()) // { // m_Geometry2Ds[s]->SetTimeBounds( timebounds ); // } // } // m_TimeBounds = timebounds; //} itk::LightObject::Pointer mitk::SlicedGeometry3D::InternalClone() const { Self::Pointer newGeometry = new SlicedGeometry3D(*this); newGeometry->UnRegister(); return newGeometry.GetPointer(); } void mitk::SlicedGeometry3D::PrintSelf(std::ostream &os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << " EvenlySpaced: " << m_EvenlySpaced << std::endl; if (m_EvenlySpaced) { os << indent << " DirectionVector: " << m_DirectionVector << std::endl; } os << indent << " Slices: " << m_Slices << std::endl; os << std::endl; os << indent << " GetPlaneGeometry(0): "; if (this->GetPlaneGeometry(0) == nullptr) { os << "nullptr" << std::endl; } else { this->GetPlaneGeometry(0)->Print(os, indent); } } void mitk::SlicedGeometry3D::ExecuteOperation(Operation *operation) { PlaneGeometry::Pointer geometry2D; ApplyTransformMatrixOperation *applyMatrixOp; Point3D center; switch (operation->GetOperationType()) { case OpNOTHING: break; case OpROTATE: if (m_EvenlySpaced) { // Need a reference frame to align the rotation if (m_ReferenceGeometry) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Save first slice PlaneGeometry::Pointer geometry2D = m_PlaneGeometries[0]; auto *rotOp = dynamic_cast(operation); // Generate a RotationOperation using the dataset center instead of // the supplied rotation center. This is necessary so that the rotated // zero-plane does not shift away. The supplied center is instead used // to adjust the slice stack afterwards. Point3D center = m_ReferenceGeometry->GetCenter(); RotationOperation centeredRotation( rotOp->GetOperationType(), center, rotOp->GetVectorOfRotation(), rotOp->GetAngleOfRotation()); // Rotate first slice geometry2D->ExecuteOperation(¢eredRotation); // Clear the slice stack and adjust it according to the center of // the dataset and the supplied rotation center (see documentation of // ReinitializePlanes) this->ReinitializePlanes(center, rotOp->GetCenterOfRotation()); geometry2D->SetSpacing(this->GetSpacing()); if (m_SliceNavigationController) { m_SliceNavigationController->SelectSliceByPoint(rotOp->GetCenterOfRotation()); m_SliceNavigationController->AdjustSliceStepperRange(); } BaseGeometry::ExecuteOperation(¢eredRotation); } else { // we also have to consider the case, that there is no reference geometry available. if (m_PlaneGeometries.size() > 0) { // Reach through to all slices in my container for (auto iter = m_PlaneGeometries.begin(); iter != m_PlaneGeometries.end(); ++iter) { // Test for empty slices, which can happen if evenly spaced geometry if ((*iter).IsNotNull()) { (*iter)->ExecuteOperation(operation); } } // rotate overall geometry auto *rotOp = dynamic_cast(operation); BaseGeometry::ExecuteOperation(rotOp); } } } else { // Reach through to all slices for (auto iter = m_PlaneGeometries.begin(); iter != m_PlaneGeometries.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpORIENT: if (m_EvenlySpaced) { // get operation data auto *planeOp = dynamic_cast(operation); // Get first slice PlaneGeometry::Pointer planeGeometry = m_PlaneGeometries[0]; // Need a PlaneGeometry, a PlaneOperation and a reference frame to // carry out the re-orientation. If not all available, stop here if (!m_ReferenceGeometry || (!planeGeometry || dynamic_cast(planeGeometry.GetPointer())) || !planeOp) { break; } // General Behavior: // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // // 1st Step: Reorient Normal Vector of first plane // Point3D center = planeOp->GetPoint(); // m_ReferenceGeometry->GetCenter(); mitk::Vector3D currentNormal = planeGeometry->GetNormal(); mitk::Vector3D newNormal; if (planeOp->AreAxisDefined()) { // If planeOp was defined by one centerpoint and two axis vectors newNormal = CrossProduct(planeOp->GetAxisVec0(), planeOp->GetAxisVec1()); } else { // If planeOp was defined by one centerpoint and one normal vector newNormal = planeOp->GetNormal(); } // Get Rotation axis und angle currentNormal.Normalize(); newNormal.Normalize(); ScalarType rotationAngle = angle(currentNormal.GetVnlVector(), newNormal.GetVnlVector()); rotationAngle *= 180.0 / vnl_math::pi; // from rad to deg Vector3D rotationAxis = itk::CrossProduct(currentNormal, newNormal); if (std::abs(rotationAngle - 180) < mitk::eps) { // current Normal and desired normal are not linear independent!!(e.g 1,0,0 and -1,0,0). // Rotation Axis should be ANY vector that is 90� to current Normal mitk::Vector3D helpNormal; helpNormal = currentNormal; helpNormal[0] += 1; helpNormal[1] -= 1; helpNormal[2] += 1; helpNormal.Normalize(); rotationAxis = itk::CrossProduct(helpNormal, currentNormal); } RotationOperation centeredRotation(mitk::OpROTATE, center, rotationAxis, rotationAngle); // Rotate first slice planeGeometry->ExecuteOperation(¢eredRotation); // Reinitialize planes and select slice, if my rotations are all done. if (!planeOp->AreAxisDefined()) { // Clear the slice stack and adjust it according to the center of // rotation and plane position (see documentation of ReinitializePlanes) this->ReinitializePlanes(center, planeOp->GetPoint()); planeGeometry->SetSpacing(this->GetSpacing()); if (m_SliceNavigationController) { m_SliceNavigationController->SelectSliceByPoint(planeOp->GetPoint()); m_SliceNavigationController->AdjustSliceStepperRange(); } } // Also apply rotation on the slicedGeometry - Geometry3D (Bounding geometry) BaseGeometry::ExecuteOperation(¢eredRotation); // // 2nd step. If axis vectors were defined, rotate the plane around its normal to fit these // if (planeOp->AreAxisDefined()) { mitk::Vector3D vecAxixNew = planeOp->GetAxisVec0(); vecAxixNew.Normalize(); mitk::Vector3D VecAxisCurr = planeGeometry->GetAxisVector(0); VecAxisCurr.Normalize(); ScalarType rotationAngle = angle(VecAxisCurr.GetVnlVector(), vecAxixNew.GetVnlVector()); rotationAngle = rotationAngle * 180 / PI; // Rad to Deg // we rotate around the normal of the plane, but we do not know, if we need to rotate clockwise // or anti-clockwise. So we rotate around the crossproduct of old and new Axisvector. // Since both axis vectors lie in the plane, the crossproduct is the planes normal or the negative planes // normal rotationAxis = itk::CrossProduct(VecAxisCurr, vecAxixNew); if (std::abs(rotationAngle - 180) < mitk::eps) { // current axisVec and desired axisVec are not linear independent!!(e.g 1,0,0 and -1,0,0). // Rotation Axis can be just plane Normal. (have to rotate by 180�) rotationAxis = newNormal; } // Perform Rotation mitk::RotationOperation op(mitk::OpROTATE, center, rotationAxis, rotationAngle); planeGeometry->ExecuteOperation(&op); // Apply changes on first slice to whole slice stack this->ReinitializePlanes(center, planeOp->GetPoint()); planeGeometry->SetSpacing(this->GetSpacing()); if (m_SliceNavigationController) { m_SliceNavigationController->SelectSliceByPoint(planeOp->GetPoint()); m_SliceNavigationController->AdjustSliceStepperRange(); } // Also apply rotation on the slicedGeometry - Geometry3D (Bounding geometry) BaseGeometry::ExecuteOperation(&op); } } else { // Reach through to all slices for (auto iter = m_PlaneGeometries.begin(); iter != m_PlaneGeometries.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpRESTOREPLANEPOSITION: if (m_EvenlySpaced) { // Save first slice PlaneGeometry::Pointer planeGeometry = m_PlaneGeometries[0]; auto *restorePlaneOp = dynamic_cast(operation); // Need a PlaneGeometry, a PlaneOperation and a reference frame to // carry out the re-orientation if (m_ReferenceGeometry && (planeGeometry && dynamic_cast(planeGeometry.GetPointer()) == nullptr) && restorePlaneOp) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Rotate first slice planeGeometry->ExecuteOperation(restorePlaneOp); m_DirectionVector = restorePlaneOp->GetDirectionVector(); double centerOfRotationDistance = planeGeometry->SignedDistanceFromPlane(m_ReferenceGeometry->GetCenter()); if (centerOfRotationDistance <= 0) { m_DirectionVector = -m_DirectionVector; } Vector3D spacing = restorePlaneOp->GetSpacing(); Superclass::SetSpacing(spacing); // /*Now we need to calculate the number of slices in the plane's normal // direction, so that the entire volume is covered. This is done by first // calculating the dot product between the volume diagonal (the maximum // distance inside the volume) and the normal, and dividing this value by // the directed spacing calculated above.*/ ScalarType directedExtent = std::abs(m_ReferenceGeometry->GetExtentInMM(0) * m_DirectionVector[0]) + std::abs(m_ReferenceGeometry->GetExtentInMM(1) * m_DirectionVector[1]) + std::abs(m_ReferenceGeometry->GetExtentInMM(2) * m_DirectionVector[2]); if (directedExtent >= spacing[2]) { m_Slices = static_cast(directedExtent / spacing[2] + 0.5); } else { m_Slices = 1; } m_PlaneGeometries.assign(m_Slices, PlaneGeometry::Pointer(nullptr)); if (m_Slices > 0) { m_PlaneGeometries[0] = planeGeometry; } m_SliceNavigationController->GetStepper()->SetSteps(m_Slices); this->Modified(); // End Reinitialization if (m_SliceNavigationController) { m_SliceNavigationController->GetStepper()->SetPos(restorePlaneOp->GetPos()); m_SliceNavigationController->AdjustSliceStepperRange(); } BaseGeometry::ExecuteOperation(restorePlaneOp); } } else { // Reach through to all slices for (auto iter = m_PlaneGeometries.begin(); iter != m_PlaneGeometries.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpAPPLYTRANSFORMMATRIX: // Clear all generated geometries and then transform only the first slice. // The other slices will be re-generated on demand // Save first slice geometry2D = m_PlaneGeometries[0]; applyMatrixOp = dynamic_cast(operation); // Apply transformation to first plane geometry2D->ExecuteOperation(applyMatrixOp); // Generate a ApplyTransformMatrixOperation using the dataset center instead of // the supplied rotation center. The supplied center is instead used to adjust the // slice stack afterwards (see OpROTATE). center = m_ReferenceGeometry->GetCenter(); // Clear the slice stack and adjust it according to the center of // the dataset and the supplied rotation center (see documentation of // ReinitializePlanes) this->ReinitializePlanes(center, applyMatrixOp->GetReferencePoint()); BaseGeometry::ExecuteOperation(applyMatrixOp); break; default: // let handle by base class if we don't do anything BaseGeometry::ExecuteOperation(operation); } this->Modified(); } diff --git a/Modules/Core/test/mitkPlaneGeometryTest.cpp b/Modules/Core/test/mitkPlaneGeometryTest.cpp index e64ebc6e26..737222fc05 100644 --- a/Modules/Core/test/mitkPlaneGeometryTest.cpp +++ b/Modules/Core/test/mitkPlaneGeometryTest.cpp @@ -1,1093 +1,1084 @@ /*============================================================================ 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 "mitkAffineTransform3D.h" #include "mitkBaseGeometry.h" #include "mitkGeometry3D.h" #include "mitkInteractionConst.h" #include "mitkLine.h" #include "mitkPlaneGeometry.h" #include "mitkRotationOperation.h" #include "mitkSlicedGeometry3D.h" #include "mitkThinPlateSplineCurvedGeometry.h" #include #include #include #include #include #include #include #include static const mitk::ScalarType testEps = 1E-9; // the epsilon used in this test == at least float precision. class mitkPlaneGeometryTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPlaneGeometryTestSuite); MITK_TEST(TestInitializeStandardPlane); MITK_TEST(TestProjectPointOntoPlane); MITK_TEST(TestPlaneGeometryCloning); MITK_TEST(TestInheritance); MITK_TEST(TestSetExtendInMM); MITK_TEST(TestRotate); MITK_TEST(TestClone); MITK_TEST(TestPlaneComparison); MITK_TEST(TestAxialInitialization); MITK_TEST(TestCoronalInitialization); MITK_TEST(TestSagittalInitialization); MITK_TEST(TestLefthandedCoordinateSystem); - MITK_TEST(TestDominantAxesError); MITK_TEST(TestCheckRotationMatrix); // Currently commented out, see See bug 15990 // MITK_TEST(testPlaneGeometryInitializeOrder); MITK_TEST(TestIntersectionPoint); MITK_TEST(TestCase1210); CPPUNIT_TEST_SUITE_END(); private: // private test members that are initialized by setUp() mitk::PlaneGeometry::Pointer planegeometry; mitk::Point3D origin; mitk::Vector3D right, bottom, normal, spacing; mitk::ScalarType width, height; mitk::ScalarType widthInMM, heightInMM, thicknessInMM; public: void setUp() override { planegeometry = mitk::PlaneGeometry::New(); width = 100; widthInMM = width; height = 200; heightInMM = height; thicknessInMM = 1.0; mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); mitk::FillVector3D(normal, 0, 0, thicknessInMM); mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM); planegeometry->InitializeStandardPlane(right, bottom); planegeometry->SetOrigin(origin); planegeometry->SetSpacing(spacing); } void tearDown() override {} // This test verifies inheritance behaviour, this test will fail if the behaviour changes in the future void TestInheritance() { mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); mitk::Geometry3D::Pointer g3d = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Planegeometry should not be castable to Geometry 3D", g3d.IsNull()); mitk::BaseGeometry::Pointer base = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Planegeometry should be castable to BaseGeometry", base.IsNotNull()); g3d = mitk::Geometry3D::New(); base = dynamic_cast(g3d.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Geometry3D should be castable to BaseGeometry", base.IsNotNull()); mitk::SlicedGeometry3D::Pointer sliced = mitk::SlicedGeometry3D::New(); g3d = dynamic_cast(sliced.GetPointer()); CPPUNIT_ASSERT_MESSAGE("SlicedGeometry3D should not be castable to Geometry3D", g3d.IsNull()); mitk::ThinPlateSplineCurvedGeometry::Pointer thin = mitk::ThinPlateSplineCurvedGeometry::New(); plane = dynamic_cast(thin.GetPointer()); CPPUNIT_ASSERT_MESSAGE("AbstractTransformGeometry should be castable to PlaneGeometry", plane.IsNotNull()); plane = mitk::PlaneGeometry::New(); mitk::AbstractTransformGeometry::Pointer atg = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("PlaneGeometry should not be castable to AbstractTransofrmGeometry", atg.IsNull()); } - void TestDominantAxesError() - { - auto image = mitk::IOUtil::Load(GetTestDataFilePath("NotQuiteARotationMatrix.nrrd")); - auto matrix = image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().transpose(); - std::vector< int > axes = mitk::PlaneGeometry::CalculateDominantAxes(matrix); - CPPUNIT_ASSERT_MESSAGE("Domiant axes cannot be determined in this dataset. Output should be default ordering.", axes.at(0)==0 && axes.at(1)==1 && axes.at(2)==2); - } - void TestCheckRotationMatrix() { auto image = mitk::IOUtil::Load(GetTestDataFilePath("NotQuiteARotationMatrix.nrrd")); bool is_rotation = mitk::PlaneGeometry::CheckRotationMatrix(image->GetGeometry()->GetIndexToWorldTransform(), 1e-8); CPPUNIT_ASSERT_MESSAGE("Since the test data matrix is not quite a rotation matrix, this should be detected.", !is_rotation); } void TestLefthandedCoordinateSystem() { /** * @brief This method tests InitializeStandardPlane() and IndexToWorld() * with a left-handed coordinate orientation or indexToWorldMatrix. * * Of course this test does not use standard Parameters, which are right-handed. * See also discussion of bug #11477: https://phabricator.mitk.org/T11477 */ planegeometry = mitk::PlaneGeometry::New(); width = 100; widthInMM = 5; height = 200; heightInMM = 3; thicknessInMM = 1.0; mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); // This one negative sign results in lefthanded coordinate orientation and det(matrix) < 0. mitk::FillVector3D(normal, 0, 0, -thicknessInMM); mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); mitk::AffineTransform3D::MatrixType matrix; mitk::AffineTransform3D::MatrixType::InternalMatrixType &vnl_matrix = matrix.GetVnlMatrix(); vnl_matrix.set_column(0, right); vnl_matrix.set_column(1, bottom); vnl_matrix.set_column(2, normal); // making sure that we didn't screw up this special test case or else fail deadly: assert(vnl_determinant(vnl_matrix) < 0.0); transform->SetIdentity(); transform->SetMatrix(matrix); planegeometry->InitializeStandardPlane(width, height, transform); // Crux of the matter. CPPUNIT_ASSERT_MESSAGE( "Testing if IndexToWorldMatrix is correct after InitializeStandardPlane( width, height, transform ) ", mitk::MatrixEqualElementWise(planegeometry->GetIndexToWorldTransform()->GetMatrix(), matrix)); mitk::Point3D p_index; p_index[0] = 10.; p_index[1] = 10.; p_index[2] = 0.; mitk::Point3D p_world; mitk::Point3D p_expectedResult; p_expectedResult[0] = 50.; p_expectedResult[1] = 30.; p_expectedResult[2] = 0.; ((mitk::BaseGeometry::Pointer)planegeometry)->IndexToWorld(p_index, p_world); // Crux of the matter. CPPUNIT_ASSERT_MESSAGE("Testing if IndexToWorld(a,b) function works correctly with lefthanded matrix ", mitk::Equal(p_world, p_expectedResult, testEps)); } // See bug 1210 // Test does not use standard Parameters void TestCase1210() { mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; mitk::Vector3D right, down, spacing; mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, 1.015625, 1.015625, 1.1999969482421875); mitk::FillVector3D(down, 1.4012984643248170709237295832899161312802619418765e-45, 0, 0); mitk::FillVector3D(spacing, 0, 1.4713633875410579244699160624544119378442750389703e-43, 9.2806360452222355258639080851310540729807238879469e-32); std::cout << "Testing InitializeStandardPlane(rightVector, downVector, spacing = nullptr): " << std::endl; CPPUNIT_ASSERT_NO_THROW(planegeometry->InitializeStandardPlane(right, down, &spacing)); /* std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(planegeometry->GetExtent(0),width)==false) || (mitk::Equal(planegeometry->GetExtent(1),height)==false) || (mitk::Equal(planegeometry->GetExtent(2),1)==false) ) { std::cout<<"[FAILED]"<GetExtentInMM(0),widthInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(1),heightInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(2),thicknessInMM)==false) ) { std::cout<<"[FAILED]"< 0. * */ // Test does not use standard Parameters void TestIntersectionPoint() { // init plane with its parameter mitk::PlaneGeometry::Pointer myPlaneGeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; origin[0] = 0.0; origin[1] = 2.0; origin[2] = 0.0; mitk::Vector3D normal; normal[0] = 0.0; normal[1] = 1.0; normal[2] = 0.0; myPlaneGeometry->InitializePlane(origin, normal); // generate points and line for intersection testing // point distance of given line > 1 mitk::Point3D pointP1; pointP1[0] = 2.0; pointP1[1] = 1.0; pointP1[2] = 0.0; mitk::Point3D pointP2; pointP2[0] = 2.0; pointP2[1] = 4.0; pointP2[2] = 0.0; mitk::Vector3D lineDirection; lineDirection[0] = pointP2[0] - pointP1[0]; lineDirection[1] = pointP2[1] - pointP1[1]; lineDirection[2] = pointP2[2] - pointP1[2]; mitk::Line3D xingline(pointP1, lineDirection); mitk::Point3D calcXingPoint; myPlaneGeometry->IntersectionPoint(xingline, calcXingPoint); // point distance of given line < 1 mitk::Point3D pointP3; pointP3[0] = 2.0; pointP3[1] = 2.2; pointP3[2] = 0.0; mitk::Point3D pointP4; pointP4[0] = 2.0; pointP4[1] = 1.7; pointP4[2] = 0.0; mitk::Vector3D lineDirection2; lineDirection2[0] = pointP4[0] - pointP3[0]; lineDirection2[1] = pointP4[1] - pointP3[1]; lineDirection2[2] = pointP4[2] - pointP3[2]; mitk::Line3D xingline2(pointP3, lineDirection2); mitk::Point3D calcXingPoint2; myPlaneGeometry->IntersectionPoint(xingline2, calcXingPoint2); // intersection points must be the same CPPUNIT_ASSERT_MESSAGE("Failed to calculate Intersection Point", calcXingPoint == calcXingPoint2); } /** * @brief This method tests method ProjectPointOntoPlane. * * See also bug #3409. */ // Test does not use standard Parameters void TestProjectPointOntoPlane() { mitk::PlaneGeometry::Pointer myPlaneGeometry = mitk::PlaneGeometry::New(); // create normal mitk::Vector3D normal; normal[0] = 0.0; normal[1] = 0.0; normal[2] = 1.0; // create origin mitk::Point3D origin; origin[0] = -27.582859; origin[1] = 50; origin[2] = 200.27742; // initialize plane geometry myPlaneGeometry->InitializePlane(origin, normal); // output to describe the test std::cout << "Testing PlaneGeometry according to bug #3409" << std::endl; std::cout << "Our normal is: " << normal << std::endl; std::cout << "So ALL projected points should have exactly the same z-value!" << std::endl; // create a number of points mitk::Point3D myPoints[5]; myPoints[0][0] = -27.582859; myPoints[0][1] = 50.00; myPoints[0][2] = 200.27742; myPoints[1][0] = -26.58662; myPoints[1][1] = 50.00; myPoints[1][2] = 200.19026; myPoints[2][0] = -26.58662; myPoints[2][1] = 50.00; myPoints[2][2] = 200.33124; myPoints[3][0] = 104.58662; myPoints[3][1] = 452.12313; myPoints[3][2] = 866.41236; myPoints[4][0] = -207.58662; myPoints[4][1] = 312.00; myPoints[4][2] = -300.12346; // project points onto plane mitk::Point3D myProjectedPoints[5]; for (unsigned int i = 0; i < 5; ++i) { myProjectedPoints[i] = myPlaneGeometry->ProjectPointOntoPlane(myPoints[i]); } // compare z-values with z-value of plane (should be equal) bool allPointsOnPlane = true; for (auto &myProjectedPoint : myProjectedPoints) { if (fabs(myProjectedPoint[2] - origin[2]) > mitk::sqrteps) { allPointsOnPlane = false; } } CPPUNIT_ASSERT_MESSAGE("All points lie not on the same plane", allPointsOnPlane); } void TestPlaneGeometryCloning() { mitk::PlaneGeometry::Pointer geometry2D = createPlaneGeometry(); try { mitk::PlaneGeometry::Pointer clone = geometry2D->Clone(); itk::Matrix matrix = clone->GetIndexToWorldTransform()->GetMatrix(); CPPUNIT_ASSERT_MESSAGE("Test if matrix element exists...", matrix[0][0] == 31); double origin = geometry2D->GetOrigin()[0]; CPPUNIT_ASSERT_MESSAGE("First Point of origin as expected...", mitk::Equal(origin, 8)); double spacing = geometry2D->GetSpacing()[0]; CPPUNIT_ASSERT_MESSAGE("First Point of spacing as expected...", mitk::Equal(spacing, 31)); } catch (...) { CPPUNIT_FAIL("Error during access on a member of cloned geometry"); } // direction [row] [column] MITK_TEST_OUTPUT(<< "Casting a rotated 2D ITK Image to a MITK Image and check if Geometry is still same"); } void TestPlaneGeometryInitializeOrder() { mitk::Vector3D mySpacing; mySpacing[0] = 31; mySpacing[1] = 0.1; mySpacing[2] = 5.4; mitk::Point3D myOrigin; myOrigin[0] = 8; myOrigin[1] = 9; myOrigin[2] = 10; mitk::AffineTransform3D::Pointer myTransform = mitk::AffineTransform3D::New(); itk::Matrix transMatrix; transMatrix.Fill(0); transMatrix[0][0] = 1; transMatrix[1][1] = 2; transMatrix[2][2] = 4; myTransform->SetMatrix(transMatrix); mitk::PlaneGeometry::Pointer geometry2D1 = mitk::PlaneGeometry::New(); geometry2D1->SetIndexToWorldTransform(myTransform); geometry2D1->SetSpacing(mySpacing); geometry2D1->SetOrigin(myOrigin); mitk::PlaneGeometry::Pointer geometry2D2 = mitk::PlaneGeometry::New(); geometry2D2->SetSpacing(mySpacing); geometry2D2->SetOrigin(myOrigin); geometry2D2->SetIndexToWorldTransform(myTransform); mitk::PlaneGeometry::Pointer geometry2D3 = mitk::PlaneGeometry::New(); geometry2D3->SetIndexToWorldTransform(myTransform); geometry2D3->SetSpacing(mySpacing); geometry2D3->SetOrigin(myOrigin); geometry2D3->SetIndexToWorldTransform(myTransform); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 1 matches that of Geometry 2.", mitk::Equal(geometry2D1->GetOrigin(), geometry2D2->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 1 match those of Geometry 3.", mitk::Equal(geometry2D1->GetOrigin(), geometry2D3->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 2 match those of Geometry 3.", mitk::Equal(geometry2D2->GetOrigin(), geometry2D3->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 1 match those of Geometry 2.", mitk::Equal(geometry2D1->GetSpacing(), geometry2D2->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 1 match those of Geometry 3.", mitk::Equal(geometry2D1->GetSpacing(), geometry2D3->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 2 match those of Geometry 3.", mitk::Equal(geometry2D2->GetSpacing(), geometry2D3->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 1 match those of Geometry 2.", compareMatrix(geometry2D1->GetIndexToWorldTransform()->GetMatrix(), geometry2D2->GetIndexToWorldTransform()->GetMatrix())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 1 match those of Geometry 3.", compareMatrix(geometry2D1->GetIndexToWorldTransform()->GetMatrix(), geometry2D3->GetIndexToWorldTransform()->GetMatrix())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 2 match those of Geometry 3.", compareMatrix(geometry2D2->GetIndexToWorldTransform()->GetMatrix(), geometry2D3->GetIndexToWorldTransform()->GetMatrix())); } void TestInitializeStandardPlane() { CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: width", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: height", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: depth", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: width in mm", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: heght in mm", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: depth in mm", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorRight", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorBottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorNormal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mitk::Vector3D spacing; thicknessInMM = 1.5; normal.Normalize(); normal *= thicknessInMM; mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM); planegeometry->InitializeStandardPlane(right.GetVnlVector(), bottom.GetVnlVector(), &spacing); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: width", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: height", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: depth", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: width in mm", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: height in mm", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: depth in mm", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorRight", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorBottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorNormal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); ; } void TestSetExtendInMM() { normal.Normalize(); normal *= thicknessInMM; planegeometry->SetExtentInMM(2, thicknessInMM); CPPUNIT_ASSERT_MESSAGE("Testing SetExtentInMM(2, ...), querying by GetExtentInMM(2): ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetExtentInMM(2, ...), querying by GetAxisVector(2) and comparing to normal: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); planegeometry->SetOrigin(origin); CPPUNIT_ASSERT_MESSAGE("Testing SetOrigin", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Right", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestRotate() { // Changing the IndexToWorldTransform to a rotated version by SetIndexToWorldTransform() (keep origin): mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); mitk::AffineTransform3D::MatrixType::InternalMatrixType vnlmatrix; vnlmatrix = planegeometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); mitk::VnlVector axis(3); mitk::FillVector3D(axis, 1.0, 1.0, 1.0); axis.normalize(); vnl_quaternion rotation(axis, 0.223); vnlmatrix = rotation.rotation_matrix_transpose() * vnlmatrix; mitk::Matrix3D matrix; matrix = vnlmatrix; transform->SetMatrix(matrix); transform->SetOffset(planegeometry->GetIndexToWorldTransform()->GetOffset()); right.SetVnlVector(rotation.rotation_matrix_transpose() * right.GetVnlVector()); bottom.SetVnlVector(rotation.rotation_matrix_transpose() * bottom.GetVnlVector()); normal.SetVnlVector(rotation.rotation_matrix_transpose() * normal.GetVnlVector()); planegeometry->SetIndexToWorldTransform(transform); // The origin changed,because m_Origin=m_IndexToWorldTransform->GetOffset()+GetAxisVector(2)*0.5 // and the AxisVector changes due to the rotation. In other words: the rotation was done around // the corner of the box, not around the planes origin. Now change it to a rotation around // the origin, simply by re-setting the origin to the original one: planegeometry->SetOrigin(origin); CPPUNIT_ASSERT_MESSAGE("Testing whether SetIndexToWorldTransform kept origin: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); mitk::Point2D point; point[0] = 4; point[1] = 3; mitk::Point2D dummy; planegeometry->WorldToIndex(point, dummy); planegeometry->IndexToWorld(dummy, dummy); CPPUNIT_ASSERT_MESSAGE("Testing consistency of index and world coordinates.", dummy == point); CPPUNIT_ASSERT_MESSAGE("Testing width of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: right ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(0).GetNorm(), planegeometry->GetExtentInMM(0), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(1).GetNorm(), planegeometry->GetExtentInMM(1), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(2).GetNorm(), planegeometry->GetExtentInMM(2), testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); width *= 2; height *= 3; planegeometry->SetSizeInUnits(width, height); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: right ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(0).GetNorm(), planegeometry->GetExtentInMM(0), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(1).GetNorm(), planegeometry->GetExtentInMM(1), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(2).GetNorm(), planegeometry->GetExtentInMM(2), testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestClone() { mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); // Cave: Statement below is negated! CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry.IsNull()) || (clonedplanegeometry->GetReferenceCount() != 1))); CPPUNIT_ASSERT_MESSAGE("Testing origin of cloned version: ", mitk::Equal(clonedplanegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing extent (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: right", mitk::Equal(clonedplanegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: bottom", mitk::Equal(clonedplanegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: normal", mitk::Equal(clonedplanegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(clonedplanegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestSagittalInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); mitk::PlaneGeometry::Pointer clonedplanegeometry = planegeometry->Clone(); // Testing InitializeStandardPlane(clonedplanegeometry, anatomicalplane = Sagittal, zPosition = 0, frontside=true): planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::AnatomicalPlane::Sagittal); mitk::Vector3D newright, newbottom, newnormal; mitk::ScalarType newthicknessInMM; newright = bottom; newthicknessInMM = widthInMM / width * 1.0; // extent in normal direction is 1; newnormal = right; newnormal.Normalize(); newnormal *= newthicknessInMM; newbottom = normal; newbottom.Normalize(); newbottom *= thicknessInMM; CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of sagittally initialized version:", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0, testEps)); // ok, corner was fine, so we can dare to believe the origin is ok. origin = planegeometry->GetOrigin(); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), newnormal, testEps)); mappingTests2D(planegeometry, height, 1, heightInMM, thicknessInMM, origin, newright, newbottom); // set origin back to the one of the axial slice: origin = clonedplanegeometry->GetOrigin(); // Testing backside initialization: InitializeStandardPlane(clonedplanegeometry, anatomicalplane = Axial, zPosition // = 0, frontside=false, rotated=true): planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::AnatomicalPlane::Axial, 0, false, true); mitk::Point3D backsideorigin; backsideorigin = origin + clonedplanegeometry->GetAxisVector(1); //+clonedplanegeometry->GetAxisVector(2); CPPUNIT_ASSERT_MESSAGE("Testing origin of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetOrigin(), backsideorigin, testEps)); mitk::Point3D backsidecornerpoint0; backsidecornerpoint0 = cornerpoint0 + clonedplanegeometry->GetAxisVector(1); //+clonedplanegeometry->GetAxisVector(2); CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of sagittally initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), backsidecornerpoint0, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), -bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, backsideorigin, right, -bottom); } void TestCoronalInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); //-------- mitk::Vector3D newright, newbottom, newnormal; mitk::ScalarType newthicknessInMM; // Testing InitializeStandardPlane(clonedplanegeometry, anatomicalplane = Coronal, zPosition = 0, frontside=true) planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::AnatomicalPlane::Coronal); newright = right; newbottom = normal; newbottom.Normalize(); newbottom *= thicknessInMM; newthicknessInMM = heightInMM / height * 1.0 /*extent in normal direction is 1*/; newnormal = -bottom; newnormal.Normalize(); newnormal *= newthicknessInMM; CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of coronally initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0, testEps)); // ok, corner was fine, so we can dare to believe the origin is ok. origin = planegeometry->GetOrigin(); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, width, 1, widthInMM, thicknessInMM, origin, newright, newbottom); // Changing plane to in-plane unit spacing using SetSizeInUnits: planegeometry->SetSizeInUnits(planegeometry->GetExtentInMM(0), planegeometry->GetExtentInMM(1)); CPPUNIT_ASSERT_MESSAGE("Testing origin of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, widthInMM, thicknessInMM, widthInMM, thicknessInMM, origin, newright, newbottom); // Changing plane to unit spacing also in normal direction using SetExtentInMM(2, 1.0): planegeometry->SetExtentInMM(2, 1.0); newnormal.Normalize(); CPPUNIT_ASSERT_MESSAGE("Testing origin of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), 1.0, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, widthInMM, thicknessInMM, widthInMM, thicknessInMM, origin, newright, newbottom); } void TestAxialInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); // Clone, move, rotate and test for 'IsParallel' and 'IsOnPlane' mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry.IsNull()) || (clonedplanegeometry->GetReferenceCount() != 1))); std::cout << "Testing InitializeStandardPlane(clonedplanegeometry, anatomicalplane = Axial, zPosition = 0, " "frontside=true): " << std::endl; planegeometry->InitializeStandardPlane(clonedplanegeometry); CPPUNIT_ASSERT_MESSAGE("Testing origin of axially initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin)); CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of axially initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0)); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of axially initialized version (should be same as in mm due to " "unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of axially initialized version (should be same as in mm due to " "unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in units) of axially initialized version (should be same as in mm due " "to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestPlaneComparison() { // Clone, move, rotate and test for 'IsParallel' and 'IsOnPlane' mitk::PlaneGeometry::Pointer clonedplanegeometry2 = dynamic_cast(planegeometry->Clone().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry2.IsNull()) || (clonedplanegeometry2->GetReferenceCount() != 1))); CPPUNIT_ASSERT_MESSAGE("Testing whether original and clone are at the same position", clonedplanegeometry2->IsOnPlane(planegeometry.GetPointer())); CPPUNIT_ASSERT_MESSAGE(" Asserting that origin is on the plane cloned plane:", clonedplanegeometry2->IsOnPlane(origin)); mitk::VnlVector newaxis(3); mitk::FillVector3D(newaxis, 1.0, 1.0, 1.0); newaxis.normalize(); vnl_quaternion rotation2(newaxis, 0.0); mitk::Vector3D clonednormal = clonedplanegeometry2->GetNormal(); mitk::Point3D clonedorigin = clonedplanegeometry2->GetOrigin(); auto planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 180.0); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE(" Asserting that a flipped plane is still on the original plane: ", clonedplanegeometry2->IsOnPlane(planegeometry.GetPointer())); clonedorigin += clonednormal; clonedplanegeometry2->SetOrigin(clonedorigin); CPPUNIT_ASSERT_MESSAGE("Testing if the translated (cloned, flipped) plane is parallel to its origin plane: ", clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 0.5); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-parallel plane gets recognized as not parallel [rotation +0.5 degree] : ", !clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), -1.0); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-parallel plane gets recognized as not parallel [rotation -0.5 degree] : ", !clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 360.5); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-parallel plane gets recognized as parallel [rotation 360 degree] : ", clonedplanegeometry2->IsParallel(planegeometry)); } private: // helper Methods for the Tests mitk::PlaneGeometry::Pointer createPlaneGeometry() { mitk::Vector3D mySpacing; mySpacing[0] = 31; mySpacing[1] = 0.1; mySpacing[2] = 5.4; mitk::Point3D myOrigin; myOrigin[0] = 8; myOrigin[1] = 9; myOrigin[2] = 10; mitk::AffineTransform3D::Pointer myTransform = mitk::AffineTransform3D::New(); itk::Matrix transMatrix; transMatrix.Fill(0); transMatrix[0][0] = 1; transMatrix[1][1] = 2; transMatrix[2][2] = 4; myTransform->SetMatrix(transMatrix); mitk::PlaneGeometry::Pointer geometry2D = mitk::PlaneGeometry::New(); geometry2D->SetIndexToWorldTransform(myTransform); geometry2D->SetSpacing(mySpacing); geometry2D->SetOrigin(myOrigin); return geometry2D; } bool compareMatrix(itk::Matrix left, itk::Matrix right) { bool equal = true; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) equal &= mitk::Equal(left[i][j], right[i][j]); return equal; } /** * This function tests for correct mapping and is called several times from other tests **/ void mappingTests2D(const mitk::PlaneGeometry *planegeometry, const mitk::ScalarType &width, const mitk::ScalarType &height, const mitk::ScalarType &widthInMM, const mitk::ScalarType &heightInMM, const mitk::Point3D &origin, const mitk::Vector3D &right, const mitk::Vector3D &bottom) { std::cout << "Testing mapping Map(pt2d_mm(x=widthInMM/2.3,y=heightInMM/2.5), pt3d_mm) and compare with expected: "; mitk::Point2D pt2d_mm; mitk::Point3D pt3d_mm, expected_pt3d_mm; pt2d_mm[0] = widthInMM / 2.3; pt2d_mm[1] = heightInMM / 2.5; expected_pt3d_mm = origin + right * (pt2d_mm[0] / right.GetNorm()) + bottom * (pt2d_mm[1] / bottom.GetNorm()); planegeometry->Map(pt2d_mm, pt3d_mm); CPPUNIT_ASSERT_MESSAGE( "Testing mapping Map(pt2d_mm(x=widthInMM/2.3,y=heightInMM/2.5), pt3d_mm) and compare with expected", mitk::Equal(pt3d_mm, expected_pt3d_mm, testEps)); std::cout << "Testing mapping Map(pt3d_mm, pt2d_mm) and compare with expected: "; mitk::Point2D testpt2d_mm; planegeometry->Map(pt3d_mm, testpt2d_mm); std::cout << std::setprecision(12) << "Expected pt2d_mm " << pt2d_mm << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_mm " << testpt2d_mm << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing mapping Map(pt3d_mm, pt2d_mm) and compare with expected", mitk::Equal(pt2d_mm, testpt2d_mm, 10 * mitk::eps)); std::cout << "Testing IndexToWorld(pt2d_units, pt2d_mm) and compare with expected: "; mitk::Point2D pt2d_units; pt2d_units[0] = width / 2.0; pt2d_units[1] = height / 2.0; pt2d_mm[0] = widthInMM / 2.0; pt2d_mm[1] = heightInMM / 2.0; planegeometry->IndexToWorld(pt2d_units, testpt2d_mm); std::cout << std::setprecision(12) << "Expected pt2d_mm " << pt2d_mm << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_mm " << testpt2d_mm << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing IndexToWorld(pt2d_units, pt2d_mm) and compare with expected: ", mitk::Equal(pt2d_mm, testpt2d_mm, 10 * mitk::eps)); std::cout << "Testing WorldToIndex(pt2d_mm, pt2d_units) and compare with expected: "; mitk::Point2D testpt2d_units; planegeometry->WorldToIndex(pt2d_mm, testpt2d_units); std::cout << std::setprecision(12) << "Expected pt2d_units " << pt2d_units << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_units " << testpt2d_units << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing WorldToIndex(pt2d_mm, pt2d_units) and compare with expected:", mitk::Equal(pt2d_units, testpt2d_units, 10 * mitk::eps)); } }; MITK_TEST_SUITE_REGISTRATION(mitkPlaneGeometry) diff --git a/Modules/CppMicroServices/CMakeLists.txt b/Modules/CppMicroServices/CMakeLists.txt index 4a7d9ca897..4a026cf4e3 100644 --- a/Modules/CppMicroServices/CMakeLists.txt +++ b/Modules/CppMicroServices/CMakeLists.txt @@ -1,440 +1,438 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 2) set(${PROJECT_NAME}_MINOR_VERSION 99) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) -cmake_minimum_required(VERSION 2.8.12) -cmake_policy(VERSION 2.8.12) -cmake_policy(SET CMP0017 NEW) +cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(US_CMAKE_DIR ${PROJECT_SOURCE_DIR}/cmake) set(CMAKE_MODULE_PATH ${US_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CMakeParseArguments) include(CMakePackageConfigHelpers) include(CheckCXXSourceCompiles) include(usFunctionAddResources) include(usFunctionEmbedResources) include(usFunctionGetResourceSource) include(usFunctionCheckResourceLinking) include(usFunctionCheckCompilerFlags) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) include(usMacroCreateModule) if(US_BUILD_TESTING) include(usFunctionCompileSnippets) endif() #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # CMake options #----------------------------------------------------------------------------- function(us_cache_var _var_name _var_default _var_type _var_help) set(_advanced 0) set(_force) foreach(_argn ${ARGN}) if(_argn STREQUAL ADVANCED) set(_advanced 1) elseif(_argn STREQUAL FORCE) set(_force FORCE) endif() endforeach() if(US_IS_EMBEDDED) if(NOT DEFINED ${_var_name} OR _force) set(${_var_name} ${_var_default} PARENT_SCOPE) endif() else() set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) if(_advanced) mark_as_advanced(${_var_name}) endif() endif() endfunction() # Determine if we are being build inside a larger project if(NOT DEFINED US_IS_EMBEDDED) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(US_IS_EMBEDDED 0) else() set(US_IS_EMBEDDED 1) endif() endif() # Determine the name of the install component for "SDK" artifacts. # The default is "sdk" if(NOT DEFINED US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT sdk) elseif(US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT ${US_SDK_INSTALL_COMPONENT}) endif() us_cache_var(US_ENABLE_AUTOLOADING_SUPPORT OFF BOOL "Enable module auto-loading support") us_cache_var(US_ENABLE_THREADING_SUPPORT OFF BOOL "Enable threading support") us_cache_var(US_ENABLE_DEBUG_OUTPUT OFF BOOL "Enable debug messages" ADVANCED) us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") us_cache_var(US_BUILD_EXAMPLES OFF BOOL "Build example projects") if(US_BUILD_TESTING) enable_testing() endif() if(WIN32 AND NOT CYGWIN) set(default_runtime_install_dir bin/) set(default_library_install_dir bin/) set(default_archive_install_dir lib/) set(default_header_install_dir include/) set(default_auxiliary_install_dir share/) else() set(default_runtime_install_dir bin/) set(default_library_install_dir lib/${PROJECT_NAME}) set(default_archive_install_dir lib/${PROJECT_NAME}) set(default_header_install_dir include/${PROJECT_NAME}) set(default_auxiliary_install_dir share/${PROJECT_NAME}) endif() us_cache_var(RUNTIME_INSTALL_DIR ${default_runtime_install_dir} STRING "Relative install location for binaries" ADVANCED) us_cache_var(LIBRARY_INSTALL_DIR ${default_library_install_dir} STRING "Relative install location for libraries" ADVANCED) us_cache_var(ARCHIVE_INSTALL_DIR ${default_archive_install_dir} STRING "Relative install location for archives" ADVANCED) us_cache_var(HEADER_INSTALL_DIR ${default_header_install_dir} STRING "Relative install location for headers" ADVANCED) us_cache_var(AUXILIARY_INSTALL_DIR ${default_auxiliary_install_dir} STRING "Relative install location for auxiliary files" ADVANCED) set(AUXILIARY_CMAKE_INSTALL_DIR ${AUXILIARY_INSTALL_DIR}/cmake) us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ Micro Services symbols") set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) set(US_MODULE_INIT_TEMPLATE "${US_CMAKE_DIR}/usModuleInit.cpp" CACHE INTERNAL "The module initialization template code") set(US_RESOURCE_RC_TEMPLATE "${US_CMAKE_DIR}/us_resources.rc.in" CACHE INTERNAL "The Windows RC resource template") set(US_CMAKE_RESOURCE_DEPENDENCIES_CPP "${US_CMAKE_DIR}/usCMakeResourceDependencies.cpp" CACHE INTERNAL "The dummy resource dependencies code") #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- if(US_IS_EMBEDDED) set(CMAKE_C_FLAGS) set(CMAKE_C_FLAGS_RELEASE) set(CMAKE_C_FLAGS_DEBUG) set(CMAKE_CXX_FLAGS) set(CMAKE_CXX_FLAGS_RELEASE) set(CMAKE_CXX_FLAGS_DEBUG) set(CMAKE_LINK_FLAGS) set(CMAKE_LINK_FLAGS_RELEASE) set(CMAKE_LINK_FLAGS_DEBUG) endif() # Set C++ compiler flags if(NOT MSVC) foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option -Wno-error=deprecated-copy -Wno-error=implicit-int-float-conversion) usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) endforeach() endif() set(US_HAVE_VISIBILITY_ATTRIBUTE 0) usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" _have_visibility) if(_have_visibility) set(US_HAVE_VISIBILITY_ATTRIBUTE 1) endif() if(CMAKE_COMPILER_IS_GNUCXX) usFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) if(${GCC_VERSION} VERSION_LESS "4.0.0") message(FATAL_ERROR "gcc version ${GCC_VERSION} not supported. Please use gcc >= 4.") endif() # With older versions of gcc the flag -fstack-protector-all requires an extra dependency to libssp.so. # If the gcc version is lower than 4.4.0 and the build type is Release let's not include the flag. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) usFunctionCheckCompilerFlags("-fstack-protector-all" US_CXX_FLAGS) endif() # Enable visibility support (only for gcc >= 4.5) # We only support hidden visibility with gcc for now. # # Clang has troubles with correctly marking template declarations and explicit template # instantiations as exported across shared library boundaries. Specifically, comparing # type_info objects from STL types does not work (used in us::Any::Type() == typeid(std::string)) # which could be related to the default visibility of STL types declared in libstdc++ and/or libc++ # but also to using RTLD_LOCAL or RTLD_GLOBAL when loading shared libraries via dlopen(). # if(_have_visibility AND NOT ${GCC_VERSION} VERSION_LESS "4.5") set(US_CXX_FLAGS "${US_CXX_FLAGS} ${_have_visibility}") else() set(US_GCC_RTTI_WORKAROUND_NEEDED 1) endif() usFunctionCheckCompilerFlags("-O1 -D_FORTIFY_SOURCE=2" _fortify_source_flag) if(_fortify_source_flag) set(US_CXX_FLAGS_RELEASE "${US_CXX_FLAGS_RELEASE} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") endif() endif() if(MSVC) set(US_CXX_FLAGS "/MP /WX /wd4180 /wd4996 /wd4251 /wd4503 ${US_CXX_FLAGS}") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${US_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") set(CMAKE_C_FLAGS_REALEASE "${CMAKE_C_FLAGS_RELEASE} ${US_C_FLAGS_RELEASE}") #----------------------------------------------------------------------------- # US Link Flags #----------------------------------------------------------------------------- set(US_LINK_FLAGS ) if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) foreach(_linkflag -Wl,--no-undefined) set(_add_flag) usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) if(_add_flag) set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") endif() endforeach() endif() usFunctionCheckResourceLinking() #----------------------------------------------------------------------------- # US Header Checks #----------------------------------------------------------------------------- include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) CHECK_INCLUDE_FILE_CXX(cxxabi.h US_HAVE_CXXABI_H) CHECK_INCLUDE_FILE_CXX(stdint.h US_HAVE_STDINT_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_map US_HAVE_TR1_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_set US_HAVE_TR1_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(tr1/functional US_HAVE_TR1_FUNCTIONAL_H) CHECK_INCLUDE_FILE_CXX(unordered_map US_HAVE_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(unordered_set US_HAVE_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(functional US_HAVE_FUNCTIONAL_H) if(US_HAVE_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() elseif(US_HAVE_TR1_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() else() message(SEND_ERROR "The header file \"unordered_map\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_MAP OR US_HAVE_STD_UNORDERED_MAP)) message(SEND_ERROR "The \"unordered_map\" type is not available.") endif() if(US_HAVE_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) elseif(US_HAVE_TR1_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) else() message(SEND_ERROR "The header file \"unordered_set\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_SET OR US_HAVE_STD_UNORDERED_SET)) message(SEND_ERROR "The \"unordered_set\" type is not available.") endif() if(NOT (US_HAVE_FUNCTIONAL_H OR US_HAVE_TR1_FUNCTIONAL_H)) message(SEND_ERROR "The header file \"functional\" is not available.") endif() if(US_HAVE_FUNCTIONAL_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if((NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) AND US_HAVE_TR1_FUNCTIONAL_H) unset(US_HAVE_TR1_FUNCTION CACHE) unset(US_HAVE_STD_FUNCTION CACHE) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if(NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) message(SEND_ERROR "The \"function\" type is not available.") endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- set(US_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/third_party ${PROJECT_BINARY_DIR}/include) # Configure CppMicroServicesConfig.cmake for the build tree. # The file is used in sub-directories. set(PACKAGE_CONFIG_INCLUDE_DIR ${US_INCLUDE_DIRS}) set(PACKAGE_CONFIG_RUNTIME_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(PACKAGE_CONFIG_CMAKE_DIR ${US_CMAKE_DIR}) set(US_RCC_EXECUTABLE_NAME usResourceCompiler CACHE INTERNAL "The target name of the usResourceCompiler executable.") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) set(us_global_config_h_file "${PROJECT_BINARY_DIR}/include/usGlobalConfig.h") configure_file(${US_CMAKE_DIR}/usGlobalConfig.h.in ${us_global_config_h_file}) include_directories(${US_INCLUDE_DIRS}) add_subdirectory(tools) add_subdirectory(core) #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(doc) #----------------------------------------------------------------------------- # Last configuration and install steps #----------------------------------------------------------------------------- # Version information configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) export(TARGETS ${US_RCC_EXECUTABLE_NAME} FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake) if(NOT US_NO_INSTALL) install(EXPORT ${PROJECT_NAME}Targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) set(_install_cmake_scripts ${US_MODULE_INIT_TEMPLATE} ${US_CMAKE_RESOURCE_DEPENDENCIES_CPP} ${US_CMAKE_DIR}/usFunctionGenerateModuleInit.cmake ${US_CMAKE_DIR}/usFunctionAddResources.cmake ${US_CMAKE_DIR}/usFunctionEmbedResources.cmake ${US_CMAKE_DIR}/usFunctionGetResourceSource.cmake ${US_CMAKE_DIR}/usFunctionCheckResourceLinking.cmake ${US_CMAKE_DIR}/usFunctionCheckCompilerFlags.cmake ) install(FILES ${_install_cmake_scripts} DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) install(FILES ${us_global_config_h_file} DESTINATION ${HEADER_INSTALL_DIR}) # Configure CppMicroServicesConfig.cmake for the install tree set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) set(CONFIG_RUNTIME_DIR ${RUNTIME_INSTALL_DIR}) set(CONFIG_CMAKE_DIR ${AUXILIARY_CMAKE_INSTALL_DIR}) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_DIR CONFIG_CMAKE_DIR NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} ) endif() diff --git a/Modules/ModelFit/autoload/Models/mitkModelFitModelsActivator.cpp b/Modules/ModelFit/autoload/Models/mitkModelFitModelsActivator.cpp index 6c62aaf983..c9688f320c 100644 --- a/Modules/ModelFit/autoload/Models/mitkModelFitModelsActivator.cpp +++ b/Modules/ModelFit/autoload/Models/mitkModelFitModelsActivator.cpp @@ -1,64 +1,68 @@ /*============================================================================ 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 #include #include //general models #include "mitkGenericParamModelFactory.h" #include "mitkLinearModelFactory.h" -#include "mitkT2DecayModelFactory.h" +#include "mitkExponentialDecayModelFactory.h" #include "mitkExpDecayOffsetModelFactory.h" #include "mitkExponentialSaturationModelFactory.h" +#include "mitkTwoStepLinearModelFactory.h" +#include "mitkThreeStepLinearModelFactory.h" namespace mitk { /* * This is the module activator for the IO aspects of the "ModelFit" module. */ class ModelFitModelsActivator : public us::ModuleActivator { public: template void RegisterProvider(us::ModuleContext* context) { auto provider = new TProvider(); provider->RegisterService(context); m_RegisteredProviders.push_back(std::unique_ptr(provider)); } void Load(us::ModuleContext* context) override { m_RegisteredProviders.clear(); RegisterProvider >(context); RegisterProvider >(context); - RegisterProvider >(context); + RegisterProvider >(context); RegisterProvider >(context); RegisterProvider >(context); + RegisterProvider >(context); + RegisterProvider >(context); } void Unload(us::ModuleContext* ) override { } private: std::vector > m_RegisteredProviders; }; } US_EXPORT_MODULE_ACTIVATOR(mitk::ModelFitModelsActivator) diff --git a/Modules/ModelFit/files.cmake b/Modules/ModelFit/files.cmake index 97c70eaeb0..2749ab3b99 100644 --- a/Modules/ModelFit/files.cmake +++ b/Modules/ModelFit/files.cmake @@ -1,82 +1,88 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES Common/mitkExtractTimeGrid.cpp Common/mitkTimeGridHelper.cpp Common/mitkMaskedDynamicImageStatisticsGenerator.cpp Common/mitkModelFitConstants.cpp Common/mitkModelFitParameter.cpp Common/mitkModelFitCmdAppsHelper.cpp Common/mitkParameterFitImageGeneratorBase.cpp Common/mitkPixelBasedParameterFitImageGenerator.cpp Common/mitkROIBasedParameterFitImageGenerator.cpp Common/mitkModelFitInfo.cpp Common/mitkModelFitStaticParameterMap.cpp Common/mitkModelGenerator.cpp Common/mitkModelFitResultHelper.cpp Common/mitkScalarListLookupTable.cpp Common/mitkScalarListLookupTableProperty.cpp Common/mitkScalarListLookupTablePropertySerializer.cpp Common/mitkIModelFitProvider.cpp Common/mitkModelFitParameterValueExtraction.cpp Common/mitkBinaryImageToLabelSetImageFilter.cpp Common/mitkFormulaParser.cpp Common/mitkFresnel.cpp Common/mitkModelFitPlotDataHelper.cpp Common/mitkModelSignalImageGenerator.cpp Common/mitkModelFitResultRelationRule.cpp Functors/mitkSimpleFunctorBase.cpp Functors/mitkSimpleFunctorPolicy.cpp Functors/mitkChiSquareFitCostFunction.cpp Functors/mitkReducedChiSquareFitCostFunction.cpp Functors/mitkConstraintCheckerBase.cpp Functors/mitkSimpleBarrierConstraintChecker.cpp Functors/mitkSquaredDifferencesFitCostFunction.cpp Functors/mitkSumOfSquaredDifferencesFitCostFunction.cpp Functors/mitkMVConstrainedCostFunctionDecorator.cpp Functors/mitkMVModelFitCostFunction.cpp Functors/mitkNormalizedSumOfSquaredDifferencesFitCostFunction.cpp Functors/mitkSVModelFitCostFunction.cpp Functors/mitkModelFitFunctorBase.cpp Functors/mitkLevenbergMarquardtModelFitFunctor.cpp Functors/mitkDummyModelFitFunctor.cpp Functors/mitkModelFitInfoSignalGenerationFunctor.cpp Functors/mitkIndexedValueFunctorPolicy.cpp Functors/mitkModelDataGenerationFunctor.cpp Models/mitkModelBase.cpp Models/mitkModelFactoryBase.cpp Models/mitkModelParameterizerBase.cpp Models/mitkLinearModel.cpp Models/mitkLinearModelFactory.cpp Models/mitkInitialParameterizationDelegateBase.cpp Models/mitkImageBasedParameterizationDelegate.cpp Models/mitkGenericParamModel.cpp Models/mitkGenericParamModelFactory.cpp Models/mitkGenericParamModelParameterizer.cpp Models/mitkValueBasedParameterizationDelegate.cpp - Models/mitkT2DecayModel.cpp - Models/mitkT2DecayModelFactory.cpp - Models/mitkT2DecayModelParameterizer.cpp + Models/mitkExponentialDecayModel.cpp + Models/mitkExponentialDecayModelFactory.cpp + Models/mitkExponentialDecayModelParameterizer.cpp Models/mitkExponentialSaturationModel.cpp Models/mitkExponentialSaturationModelFactory.cpp Models/mitkExponentialSaturationModelParameterizer.cpp Models/mitkExpDecayOffsetModel.cpp Models/mitkExpDecayOffsetModelFactory.cpp Models/mitkExpDecayOffsetModelParameterizer.cpp + Models/mitkTwoStepLinearModel.cpp + Models/mitkTwoStepLinearModelFactory.cpp + Models/mitkTwoStepLinearModelParameterizer.cpp + Models/mitkThreeStepLinearModel.cpp + Models/mitkThreeStepLinearModelFactory.cpp + Models/mitkThreeStepLinearModelParameterizer.cpp TestingHelper/mitkTestModel.cpp TestingHelper/mitkTestModelFactory.cpp ) set(TPP_FILES include/itkMultiOutputNaryFunctorImageFilter.tpp include/itkMaskedStatisticsImageFilter.hxx include/itkMaskedNaryStatisticsImageFilter.hxx include/mitkModelFitProviderBase.tpp ) set(HXX_FILES ) set(MOC_H_FILES ) diff --git a/Modules/ModelFit/include/mitkExpDecayOffsetModel.h b/Modules/ModelFit/include/mitkExpDecayOffsetModel.h index 33d286984b..e9b779f3bf 100644 --- a/Modules/ModelFit/include/mitkExpDecayOffsetModel.h +++ b/Modules/ModelFit/include/mitkExpDecayOffsetModel.h @@ -1,87 +1,129 @@ /*============================================================================ 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 mitkExpDecayOffsetModel_h #define mitkExpDecayOffsetModel_h #include "mitkModelBase.h" #include "MitkModelFitExports.h" namespace mitk { /** @class ExpDecayOffsetModel * @brief Implementation of a general exponential decay model with offset, - * following the function: f(x) = a * exp(-1.0 * x * b) + c. + * following the function: y(x) = y-intercept * exp(-rate*x) + baseline. */ class MITKMODELFIT_EXPORT ExpDecayOffsetModel : public mitk::ModelBase { public: typedef ExpDecayOffsetModel Self; typedef mitk::ModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; typedef Superclass::ParameterNameType ParameterNameType; typedef Superclass::ParametersSizeType ParametersSizeType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(ExpDecayOffsetModel, ModelBase); - std::string GetModelDisplayName() const override; + static const std::string NAME_PARAMETER_y0; + static const std::string NAME_PARAMETER_k; + static const std::string NAME_PARAMETER_y_bl; - std::string GetModelType() const override; + static const unsigned int NUMBER_OF_PARAMETERS; - FunctionStringType GetFunctionString() const override; + static const std::string UNIT_PARAMETER_y0; + static const std::string UNIT_PARAMETER_k; + static const std::string UNIT_PARAMETER_y_bl; - std::string GetXName() const override; + static const unsigned int POSITION_PARAMETER_y0; + static const unsigned int POSITION_PARAMETER_k; + static const unsigned int POSITION_PARAMETER_y_bl; + + static const unsigned int NUMBER_OF_STATIC_PARAMETERS; + + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + + static const std::string FUNCTION_STRING; + + static const std::string X_NAME; + + static const std::string X_AXIS_NAME; + + static const std::string X_AXIS_UNIT; + + static const std::string Y_AXIS_NAME; + + static const std::string Y_AXIS_UNIT; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; + ParamterUnitMapType GetParameterUnits() const override; + ParameterNamesType GetStaticParameterNames() const override; ParametersSizeType GetNumberOfStaticParameters() const override; + std::string GetModelDisplayName() const override; + + std::string GetModelType() const override; + + FunctionStringType GetFunctionString() const override; + + std::string GetXName() const override; + + std::string GetXAxisName() const override; + + std::string GetXAxisUnit() const override; + + std::string GetYAxisName() const override; + + std::string GetYAxisUnit() const override; + protected: ExpDecayOffsetModel() {}; ~ExpDecayOffsetModel() override {}; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) override; StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const override; private: //No copy constructor allowed ExpDecayOffsetModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/ModelFit/include/mitkT2DecayModel.h b/Modules/ModelFit/include/mitkExponentialDecayModel.h similarity index 54% rename from Modules/ModelFit/include/mitkT2DecayModel.h rename to Modules/ModelFit/include/mitkExponentialDecayModel.h index 7bb5f48409..60797f420b 100644 --- a/Modules/ModelFit/include/mitkT2DecayModel.h +++ b/Modules/ModelFit/include/mitkExponentialDecayModel.h @@ -1,95 +1,142 @@ /*============================================================================ 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 mitkT2DecayModel_h -#define mitkT2DecayModel_h +#ifndef mitkExponentialDecayModel_h +#define mitkExponentialDecayModel_h #include "mitkModelBase.h" #include "MitkModelFitExports.h" namespace mitk { - /** @class T2DecayModel - * @brief Simple model of the MR T2 signal decay. This corresponds to an exponential decay in the form of: - * f(t) = M0 * exp(-t/T2) with T2 being the transverse / spin-spin relaxation time. The derived parameter R2 - * is calculated from T2 by inversion. + /** @class ExponentialDecayModel + * @brief Simple model of exponential decay in the form of: + * y(x) = y-intercept * exp(-x/lambda) with lambda being the decay constant. */ - class MITKMODELFIT_EXPORT T2DecayModel : public mitk::ModelBase + class MITKMODELFIT_EXPORT ExponentialDecayModel : public mitk::ModelBase { public: - typedef T2DecayModel Self; + typedef ExponentialDecayModel Self; typedef mitk::ModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; typedef Superclass::ParameterNameType ParameterNameType; typedef Superclass::ParametersSizeType ParametersSizeType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ - itkTypeMacro(T2DecayModel, ModelBase); + itkTypeMacro(ExponentialDecayModel, ModelBase); - std::string GetModelDisplayName() const override; - std::string GetModelType() const override; + static const std::string NAME_PARAMETER_y0; + static const std::string NAME_PARAMETER_lambda; - FunctionStringType GetFunctionString() const override; + static const unsigned int NUMBER_OF_PARAMETERS; - std::string GetXName() const override; + static const std::string UNIT_PARAMETER_y0; + static const std::string UNIT_PARAMETER_lambda; + + static const unsigned int POSITION_PARAMETER_y0; + static const unsigned int POSITION_PARAMETER_lambda; + + static const std::string NAME_DERIVED_PARAMETER_k; + + static const unsigned int NUMBER_OF_DERIVED_PARAMETERS; + + static const std::string UNIT_DERIVED_PARAMETER_k; + + static const unsigned int NUMBER_OF_STATIC_PARAMETERS; + + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + + static const std::string FUNCTION_STRING; + + static const std::string X_NAME; + + static const std::string X_AXIS_NAME; + + static const std::string X_AXIS_UNIT; + + static const std::string Y_AXIS_NAME; + + static const std::string Y_AXIS_UNIT; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; + ParamterUnitMapType GetParameterUnits() const override; + + ParameterNamesType GetDerivedParameterNames() const override; + + ParametersSizeType GetNumberOfDerivedParameters() const override; + + ParamterUnitMapType GetDerivedParameterUnits() const override; + ParameterNamesType GetStaticParameterNames() const override; ParametersSizeType GetNumberOfStaticParameters() const override; - DerivedParametersSizeType GetNumberOfDerivedParameters() const override; + std::string GetModelDisplayName() const override; + + std::string GetModelType() const override; + + FunctionStringType GetFunctionString() const override; + + std::string GetXName() const override; + + std::string GetXAxisName() const override; + + std::string GetXAxisUnit() const override; + + std::string GetYAxisName() const override; - DerivedParameterNamesType GetDerivedParameterNames() const override; + std::string GetYAxisUnit() const override; mitk::ModelBase::DerivedParameterMapType ComputeDerivedParameters( const mitk::ModelBase::ParametersType ¶meters) const; protected: - T2DecayModel() {}; - ~T2DecayModel() override {}; + ExponentialDecayModel() {}; + ~ExponentialDecayModel() override {}; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) override; StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const override; private: //No copy constructor allowed - T2DecayModel(const Self& source); + ExponentialDecayModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/ModelFit/include/mitkT2DecayModelFactory.h b/Modules/ModelFit/include/mitkExponentialDecayModelFactory.h similarity index 66% rename from Modules/ModelFit/include/mitkT2DecayModelFactory.h rename to Modules/ModelFit/include/mitkExponentialDecayModelFactory.h index c3553fe9c1..2a7c1ded12 100644 --- a/Modules/ModelFit/include/mitkT2DecayModelFactory.h +++ b/Modules/ModelFit/include/mitkExponentialDecayModelFactory.h @@ -1,53 +1,53 @@ /*============================================================================ 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 mitkT2DecayModelFactory_h -#define mitkT2DecayModelFactory_h +#ifndef mitkExponentialDecayModelFactory_h +#define mitkExponentialDecayModelFactory_h #include #include "mitkConcreteModelFactoryBase.h" -#include "mitkT2DecayModel.h" +#include "mitkExponentialDecayModel.h" #include "MitkModelFitExports.h" namespace mitk { - class MITKMODELFIT_EXPORT T2DecayModelFactory : public ConcreteModelFactoryBase + class MITKMODELFIT_EXPORT ExponentialDecayModelFactory : public ConcreteModelFactoryBase { public: - mitkClassMacroItkParent(T2DecayModelFactory, ConcreteModelFactoryBase); + mitkClassMacroItkParent(ExponentialDecayModelFactory, ConcreteModelFactoryBase); itkFactorylessNewMacro(Self); ParametersType GetDefaultInitialParameterization() const override; ConstraintCheckerBase::Pointer CreateDefaultConstraints() const override; protected: ModelParameterizerBase::Pointer DoCreateParameterizer(const modelFit::ModelFitInfo* fit) const override; - T2DecayModelFactory(); + ExponentialDecayModelFactory(); - ~T2DecayModelFactory() override; + ~ExponentialDecayModelFactory() override; private: //No copy constructor allowed - T2DecayModelFactory(const Self& source); + ExponentialDecayModelFactory(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/ModelFit/include/mitkT2DecayModelParameterizer.h b/Modules/ModelFit/include/mitkExponentialDecayModelParameterizer.h similarity index 66% rename from Modules/ModelFit/include/mitkT2DecayModelParameterizer.h rename to Modules/ModelFit/include/mitkExponentialDecayModelParameterizer.h index 3f4fe5e092..2606384594 100644 --- a/Modules/ModelFit/include/mitkT2DecayModelParameterizer.h +++ b/Modules/ModelFit/include/mitkExponentialDecayModelParameterizer.h @@ -1,63 +1,63 @@ /*============================================================================ 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 mitkT2DecayModelParameterizer_h -#define mitkT2DecayModelParameterizer_h +#ifndef mitkExponentialDecayModelParameterizer_h +#define mitkExponentialDecayModelParameterizer_h #include "mitkConcreteModelParameterizerBase.h" -#include "mitkT2DecayModel.h" +#include "mitkExponentialDecayModel.h" #include "MitkModelFitExports.h" namespace mitk { - class MITKMODELFIT_EXPORT T2DecayModelParameterizer : public - mitk::ConcreteModelParameterizerBase + class MITKMODELFIT_EXPORT ExponentialDecayModelParameterizer : public + mitk::ConcreteModelParameterizerBase { public: - typedef T2DecayModelParameterizer Self; - typedef mitk::ConcreteModelParameterizerBase Superclass; + typedef ExponentialDecayModelParameterizer Self; + typedef mitk::ConcreteModelParameterizerBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; - itkTypeMacro(T2DecayModelParameterizer, - mitk::ConcreteModelParameterizerBase); + itkTypeMacro(ExponentialDecayModelParameterizer, + mitk::ConcreteModelParameterizerBase); itkFactorylessNewMacro(Self); typedef Superclass::ModelBaseType ModelBaseType; typedef Superclass::ModelBasePointer ModelBasePointer; typedef Superclass::ModelType ModelType; typedef ModelType::Pointer ModelPointer; typedef Superclass::StaticParameterValueType StaticParameterValueType; typedef Superclass::StaticParameterValuesType StaticParameterValuesType; typedef Superclass::StaticParameterMapType StaticParameterMapType; typedef Superclass::IndexType IndexType; ParametersType GetDefaultInitialParameterization() const override; protected: - T2DecayModelParameterizer(); + ExponentialDecayModelParameterizer(); - ~T2DecayModelParameterizer() override; + ~ExponentialDecayModelParameterizer() override; private: //No copy constructor allowed - T2DecayModelParameterizer(const Self& source); + ExponentialDecayModelParameterizer(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/ModelFit/include/mitkExponentialSaturationModel.h b/Modules/ModelFit/include/mitkExponentialSaturationModel.h index 7072660796..daba982745 100644 --- a/Modules/ModelFit/include/mitkExponentialSaturationModel.h +++ b/Modules/ModelFit/include/mitkExponentialSaturationModel.h @@ -1,86 +1,132 @@ /*============================================================================ 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 __MITK_EXPONENTIAL_SATURATION_MODEL_H_ #define __MITK_EXPONENTIAL_SATURATION_MODEL_H_ #include "mitkModelBase.h" #include "MitkModelFitExports.h" namespace mitk { /** @class ExponentialSaturationModel - * @brief This genric model has the form: if x Pointer; typedef itk::SmartPointer< const Self > ConstPointer; typedef Superclass::ParameterNameType ParameterNameType; typedef Superclass::ParametersSizeType ParametersSizeType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(ExponentialSaturationModel, ModelBase); - std::string GetModelDisplayName() const override; + static const std::string NAME_PARAMETER_BAT; + static const std::string NAME_PARAMETER_y_bl; + static const std::string NAME_PARAMETER_y_fin; + static const std::string NAME_PARAMETER_k; - std::string GetModelType() const override; + static const unsigned int NUMBER_OF_PARAMETERS; - FunctionStringType GetFunctionString() const override; + static const std::string UNIT_PARAMETER_BAT; + static const std::string UNIT_PARAMETER_y_bl; + static const std::string UNIT_PARAMETER_y_fin; + static const std::string UNIT_PARAMETER_k; - std::string GetXName() const override; + static const unsigned int POSITION_PARAMETER_BAT; + static const unsigned int POSITION_PARAMETER_y_bl; + static const unsigned int POSITION_PARAMETER_y_fin; + static const unsigned int POSITION_PARAMETER_k; + + static const unsigned int NUMBER_OF_STATIC_PARAMETERS; + + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + + static const std::string FUNCTION_STRING; + + static const std::string X_NAME; + + static const std::string X_AXIS_NAME; + + static const std::string X_AXIS_UNIT; + + static const std::string Y_AXIS_NAME; + + static const std::string Y_AXIS_UNIT; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; + ParamterUnitMapType GetParameterUnits() const override; + ParameterNamesType GetStaticParameterNames() const override; ParametersSizeType GetNumberOfStaticParameters() const override; + std::string GetModelDisplayName() const override; + + std::string GetModelType() const override; + + FunctionStringType GetFunctionString() const override; + + std::string GetXName() const override; + + std::string GetXAxisName() const override; + + std::string GetXAxisUnit() const override; + + std::string GetYAxisName() const override; + + std::string GetYAxisUnit() const override; + + protected: ExponentialSaturationModel() {}; ~ExponentialSaturationModel() override {}; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) override; StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const override; private: //No copy constructor allowed ExponentialSaturationModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/ModelFit/include/mitkLinearModel.h b/Modules/ModelFit/include/mitkLinearModel.h index fe12b0d16b..e10578f78d 100644 --- a/Modules/ModelFit/include/mitkLinearModel.h +++ b/Modules/ModelFit/include/mitkLinearModel.h @@ -1,89 +1,138 @@ /*============================================================================ 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 mitkLinearModel_h #define mitkLinearModel_h #include "mitkModelBase.h" #include "MitkModelFitExports.h" namespace mitk { class MITKMODELFIT_EXPORT LinearModel : public mitk::ModelBase { public: typedef LinearModel Self; typedef mitk::ModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; typedef Superclass::ParameterNameType ParameterNameType; typedef Superclass::ParametersSizeType ParametersSizeType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(LinearModel, ModelBase); - std::string GetModelDisplayName() const override; + static const std::string NAME_PARAMETER_y0; + static const std::string NAME_PARAMETER_b; - std::string GetModelType() const override; + static const unsigned int NUMBER_OF_PARAMETERS; - FunctionStringType GetFunctionString() const override; + static const std::string UNIT_PARAMETER_y0; + static const std::string UNIT_PARAMETER_b; + + static const unsigned int POSITION_PARAMETER_y0; + static const unsigned int POSITION_PARAMETER_b; + + static const std::string NAME_DERIVED_PARAMETER_x_intercept; + + static const unsigned int NUMBER_OF_DERIVED_PARAMETERS; + + static const std::string UNIT_DERIVED_PARAMETER_x_intercept; + + static const unsigned int NUMBER_OF_STATIC_PARAMETERS; + + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + + static const std::string FUNCTION_STRING; + + static const std::string X_NAME; + + static const std::string X_AXIS_NAME; + + static const std::string X_AXIS_UNIT; + + static const std::string Y_AXIS_NAME; + + static const std::string Y_AXIS_UNIT; - std::string GetXName() const override; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; + ParamterUnitMapType GetParameterUnits() const override; + + ParameterNamesType GetDerivedParameterNames() const override; + + ParametersSizeType GetNumberOfDerivedParameters() const override; + + ParamterUnitMapType GetDerivedParameterUnits() const override; + ParameterNamesType GetStaticParameterNames() const override; ParametersSizeType GetNumberOfStaticParameters() const override; - ParameterNamesType GetDerivedParameterNames() const override; + std::string GetModelDisplayName() const override; + + std::string GetModelType() const override; + + FunctionStringType GetFunctionString() const override; + + std::string GetXName() const override; + + std::string GetXAxisName() const override; + + std::string GetXAxisUnit() const override; + + std::string GetYAxisName() const override; + + std::string GetYAxisUnit() const override; - ParametersSizeType GetNumberOfDerivedParameters() const override; protected: LinearModel() {}; ~LinearModel() override {}; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; DerivedParameterMapType ComputeDerivedParameters(const mitk::ModelBase::ParametersType& parameters) const override; void SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) override; StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const override; private: //No copy constructor allowed LinearModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkThreeStepLinearModel.h b/Modules/ModelFit/include/mitkThreeStepLinearModel.h similarity index 61% rename from Modules/Pharmacokinetics/include/mitkThreeStepLinearModel.h rename to Modules/ModelFit/include/mitkThreeStepLinearModel.h index bdfc6a7cff..144c14f081 100644 --- a/Modules/Pharmacokinetics/include/mitkThreeStepLinearModel.h +++ b/Modules/ModelFit/include/mitkThreeStepLinearModel.h @@ -1,125 +1,160 @@ /*============================================================================ 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 mitkThreeStepLinearModel_h #define mitkThreeStepLinearModel_h #include "mitkModelBase.h" -#include "MitkPharmacokineticsExports.h" +#include "MitkModelFitExports.h" namespace mitk { - class MITKPHARMACOKINETICS_EXPORT ThreeStepLinearModel : public mitk::ModelBase + class MITKMODELFIT_EXPORT ThreeStepLinearModel : public mitk::ModelBase { public: typedef ThreeStepLinearModel Self; typedef mitk::ModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; typedef Superclass::ParameterNameType ParameterNameType; typedef Superclass::ParametersSizeType ParametersSizeType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(ThreeStepLinearModel, ModelBase); - static const std::string MODEL_DISPLAY_NAME; - static const std::string NAME_PARAMETER_s0; - static const std::string NAME_PARAMETER_t1; - static const std::string NAME_PARAMETER_t2; - static const std::string NAME_PARAMETER_a1; - static const std::string NAME_PARAMETER_a2; + static const std::string NAME_PARAMETER_y_bl; + static const std::string NAME_PARAMETER_x0; + static const std::string NAME_PARAMETER_x1; + static const std::string NAME_PARAMETER_b0; static const std::string NAME_PARAMETER_b1; - static const std::string NAME_PARAMETER_b2; - static const std::string UNIT_PARAMETER_s0; - static const std::string UNIT_PARAMETER_t1; - static const std::string UNIT_PARAMETER_t2; - static const std::string UNIT_PARAMETER_a1; - static const std::string UNIT_PARAMETER_a2; + static const unsigned int NUMBER_OF_PARAMETERS; + + static const std::string UNIT_PARAMETER_y_bl; + static const std::string UNIT_PARAMETER_x0; + static const std::string UNIT_PARAMETER_x1; + static const std::string UNIT_PARAMETER_b0; static const std::string UNIT_PARAMETER_b1; - static const std::string UNIT_PARAMETER_b2; - static const unsigned int POSITION_PARAMETER_s0; - static const unsigned int POSITION_PARAMETER_t1; - static const unsigned int POSITION_PARAMETER_t2; - static const unsigned int POSITION_PARAMETER_a1; - static const unsigned int POSITION_PARAMETER_a2; + static const unsigned int POSITION_PARAMETER_y_bl; + static const unsigned int POSITION_PARAMETER_x0; + static const unsigned int POSITION_PARAMETER_x1; + static const unsigned int POSITION_PARAMETER_b0; static const unsigned int POSITION_PARAMETER_b1; - static const unsigned int POSITION_PARAMETER_b2; - static const unsigned int NUMBER_OF_PARAMETERS; + static const std::string NAME_DERIVED_PARAMETER_auc; + static const std::string NAME_DERIVED_PARAMETER_x_fin; + static const std::string NAME_DERIVED_PARAMETER_y_fin; + static const std::string NAME_DERIVED_PARAMETER_y_max; + static const std::string NAME_DERIVED_PARAMETER_y1; + static const std::string NAME_DERIVED_PARAMETER_y2; - std::string GetModelDisplayName() const override; + static const unsigned int NUMBER_OF_DERIVED_PARAMETERS; - std::string GetModelType() const override; + static const std::string UNIT_DERIVED_PARAMETER_auc; + static const std::string UNIT_DERIVED_PARAMETER_x_fin; + static const std::string UNIT_DERIVED_PARAMETER_y_fin; + static const std::string UNIT_DERIVED_PARAMETER_y_max; + static const std::string UNIT_DERIVED_PARAMETER_y1; + static const std::string UNIT_DERIVED_PARAMETER_y2; - FunctionStringType GetFunctionString() const override; + static const unsigned int NUMBER_OF_STATIC_PARAMETERS; - std::string GetXName() const override; + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + + static const std::string FUNCTION_STRING; + + static const std::string X_NAME; + + static const std::string X_AXIS_NAME; + + static const std::string X_AXIS_UNIT; + + static const std::string Y_AXIS_NAME; + + static const std::string Y_AXIS_UNIT; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; + ParameterNamesType GetDerivedParameterNames() const override; + + ParametersSizeType GetNumberOfDerivedParameters() const override; + + ParamterUnitMapType GetDerivedParameterUnits() const override; + ParameterNamesType GetStaticParameterNames() const override; ParametersSizeType GetNumberOfStaticParameters() const override; - ParameterNamesType GetDerivedParameterNames() const override; + std::string GetModelDisplayName() const override; - ParametersSizeType GetNumberOfDerivedParameters() const override; + std::string GetModelType() const override; - ParamterUnitMapType GetDerivedParameterUnits() const override; + FunctionStringType GetFunctionString() const override; + + std::string GetXName() const override; + + std::string GetXAxisName() const override; + + std::string GetXAxisUnit() const override; + + std::string GetYAxisName() const override; + + std::string GetYAxisUnit() const override; protected: ThreeStepLinearModel() {}; ~ThreeStepLinearModel() override{}; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; DerivedParameterMapType ComputeDerivedParameters(const mitk::ModelBase::ParametersType& parameters) const override; void SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) override; StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const override; static double ComputeSignalFromParameters(double x, double s0, double t1, double t2, double a1, double a2, double b1, double b2); private: //No copy constructor allowed ThreeStepLinearModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkThreeStepLinearModelFactory.h b/Modules/ModelFit/include/mitkThreeStepLinearModelFactory.h similarity index 89% rename from Modules/Pharmacokinetics/include/mitkThreeStepLinearModelFactory.h rename to Modules/ModelFit/include/mitkThreeStepLinearModelFactory.h index 9ea1d756a4..8d844f5abe 100644 --- a/Modules/Pharmacokinetics/include/mitkThreeStepLinearModelFactory.h +++ b/Modules/ModelFit/include/mitkThreeStepLinearModelFactory.h @@ -1,55 +1,55 @@ /*============================================================================ 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 mitkThreeStepLinearModelFactory_h #define mitkThreeStepLinearModelFactory_h #include #include "mitkConcreteModelFactoryBase.h" #include "mitkThreeStepLinearModel.h" #include "mitkThreeStepLinearModelParameterizer.h" -#include "MitkPharmacokineticsExports.h" +#include "MitkModelFitExports.h" namespace mitk { - class MITKPHARMACOKINETICS_EXPORT ThreeStepLinearModelFactory : public ConcreteModelFactoryBase + class MITKMODELFIT_EXPORT ThreeStepLinearModelFactory : public ConcreteModelFactoryBase { public: mitkClassMacroItkParent(ThreeStepLinearModelFactory, ConcreteModelFactoryBase); itkFactorylessNewMacro(Self); /** This function returns the default parameterization (e.g. initial parametrization for fitting) defined by the model developer for for the given model.*/ ParametersType GetDefaultInitialParameterization() const override; protected: ModelParameterizerBase::Pointer DoCreateParameterizer(const modelFit::ModelFitInfo* fit) const override; ThreeStepLinearModelFactory(); ~ThreeStepLinearModelFactory() override; private: //No copy constructor allowed ThreeStepLinearModelFactory(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkThreeStepLinearModelParameterizer.h b/Modules/ModelFit/include/mitkThreeStepLinearModelParameterizer.h similarity index 96% rename from Modules/Pharmacokinetics/include/mitkThreeStepLinearModelParameterizer.h rename to Modules/ModelFit/include/mitkThreeStepLinearModelParameterizer.h index d5dfcd1571..e03e3d8751 100644 --- a/Modules/Pharmacokinetics/include/mitkThreeStepLinearModelParameterizer.h +++ b/Modules/ModelFit/include/mitkThreeStepLinearModelParameterizer.h @@ -1,62 +1,62 @@ /*============================================================================ 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 mitkThreeStepLinearModelParameterizer_h #define mitkThreeStepLinearModelParameterizer_h #include "mitkConcreteModelParameterizerBase.h" #include "mitkThreeStepLinearModel.h" namespace mitk { -class MITKPHARMACOKINETICS_EXPORT ThreeStepLinearModelParameterizer : public +class MITKMODELFIT_EXPORT ThreeStepLinearModelParameterizer : public mitk::ConcreteModelParameterizerBase { public: typedef ThreeStepLinearModelParameterizer Self; typedef mitk::ConcreteModelParameterizerBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; itkTypeMacro(ThreeStepLinearModelParameterizer, ConcreteModelParameterizerBase); itkFactorylessNewMacro(Self); typedef Superclass::ModelBaseType ModelBaseType; typedef Superclass::ModelBasePointer ModelBasePointer; typedef Superclass::ModelType ModelType; typedef Superclass::ModelPointer ModelPointer; typedef Superclass::StaticParameterValueType StaticParameterValueType; typedef Superclass::StaticParameterValuesType StaticParameterValuesType; typedef Superclass::StaticParameterMapType StaticParameterMapType; typedef Superclass::IndexType IndexType; /** This function returns the default parameterization (e.g. initial parametrization for fitting) defined by the model developer for for the given model.*/ ParametersType GetDefaultInitialParameterization() const override; protected: ThreeStepLinearModelParameterizer(){}; ~ThreeStepLinearModelParameterizer() override{}; private: //No copy constructor allowed ThreeStepLinearModelParameterizer(const Self& source); void operator=(const Self&); //purposely not implemented };} #endif diff --git a/Modules/ModelFit/include/mitkTwoStepLinearModel.h b/Modules/ModelFit/include/mitkTwoStepLinearModel.h new file mode 100644 index 0000000000..8e93819089 --- /dev/null +++ b/Modules/ModelFit/include/mitkTwoStepLinearModel.h @@ -0,0 +1,153 @@ +/*============================================================================ + +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 mitkTwoStepLinearModel_h +#define mitkTwoStepLinearModel_h + +#include "mitkModelBase.h" + +#include "MitkModelFitExports.h" + +namespace mitk +{ + + class MITKMODELFIT_EXPORT TwoStepLinearModel : public mitk::ModelBase + { + + public: + typedef TwoStepLinearModel Self; + typedef mitk::ModelBase Superclass; + typedef itk::SmartPointer< Self > Pointer; + typedef itk::SmartPointer< const Self > ConstPointer; + + typedef Superclass::ParameterNameType ParameterNameType; + typedef Superclass::ParametersSizeType ParametersSizeType; + + /** Method for creation through the object factory. */ + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(TwoStepLinearModel, ModelBase) + + static const std::string NAME_PARAMETER_y0; + static const std::string NAME_PARAMETER_x0; + static const std::string NAME_PARAMETER_b0; + static const std::string NAME_PARAMETER_b1; + + static const unsigned int NUMBER_OF_PARAMETERS; + + static const std::string UNIT_PARAMETER_y0; + static const std::string UNIT_PARAMETER_x0; + static const std::string UNIT_PARAMETER_b0; + static const std::string UNIT_PARAMETER_b1; + + static const unsigned int POSITION_PARAMETER_y0; + static const unsigned int POSITION_PARAMETER_x0; + static const unsigned int POSITION_PARAMETER_b0; + static const unsigned int POSITION_PARAMETER_b1; + + static const std::string NAME_DERIVED_PARAMETER_auc; + static const std::string NAME_DERIVED_PARAMETER_y_fin; + static const std::string NAME_DERIVED_PARAMETER_y_max; + static const std::string NAME_DERIVED_PARAMETER_y1; + + static const unsigned int NUMBER_OF_DERIVED_PARAMETERS; + + static const std::string UNIT_DERIVED_PARAMETER_auc; + static const std::string UNIT_DERIVED_PARAMETER_y_fin; + static const std::string UNIT_DERIVED_PARAMETER_y_max; + static const std::string UNIT_DERIVED_PARAMETER_y1; + + static const unsigned int NUMBER_OF_STATIC_PARAMETERS; + + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + + static const std::string FUNCTION_STRING; + + static const std::string X_NAME; + + static const std::string X_AXIS_NAME; + + static const std::string X_AXIS_UNIT; + + static const std::string Y_AXIS_NAME; + + static const std::string Y_AXIS_UNIT; + + + ParameterNamesType GetParameterNames() const override; + + ParametersSizeType GetNumberOfParameters() const override; + + ParamterUnitMapType GetParameterUnits() const override; + + ParameterNamesType GetDerivedParameterNames() const override; + + ParametersSizeType GetNumberOfDerivedParameters() const override; + + ParamterUnitMapType GetDerivedParameterUnits() const override; + + ParameterNamesType GetStaticParameterNames() const override; + + ParametersSizeType GetNumberOfStaticParameters() const override; + + std::string GetModelDisplayName() const override; + + std::string GetModelType() const override; + + FunctionStringType GetFunctionString() const override; + + std::string GetXName() const override; + + std::string GetXAxisName() const override; + + std::string GetXAxisUnit() const override; + + std::string GetYAxisName() const override; + + std::string GetYAxisUnit() const override; + + + protected: + TwoStepLinearModel() {}; + virtual ~TwoStepLinearModel(){}; + + + /** + * Actual implementation of the clone method. This method should be reimplemeted + * in subclasses to clone the extra required parameters. + */ + virtual itk::LightObject::Pointer InternalClone() const; + + virtual ModelResultType ComputeModelfunction(const ParametersType& parameters) const; + virtual DerivedParameterMapType ComputeDerivedParameters(const mitk::ModelBase::ParametersType& + parameters) const; + + virtual void SetStaticParameter(const ParameterNameType& name, + const StaticParameterValuesType& values); + virtual StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const; + + static double ComputeSignalFromParameters(double x, double t, double a1, double a2, double b1, double b2); + + private: + + //No copy constructor allowed + TwoStepLinearModel(const Self& source); + void operator=(const Self&); //purposely not implemented + }; +} + + +#endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoStepLinearModelFactory.h b/Modules/ModelFit/include/mitkTwoStepLinearModelFactory.h similarity index 89% rename from Modules/Pharmacokinetics/include/mitkTwoStepLinearModelFactory.h rename to Modules/ModelFit/include/mitkTwoStepLinearModelFactory.h index fd13df6575..a4166b4278 100644 --- a/Modules/Pharmacokinetics/include/mitkTwoStepLinearModelFactory.h +++ b/Modules/ModelFit/include/mitkTwoStepLinearModelFactory.h @@ -1,55 +1,55 @@ /*============================================================================ 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 mitkTwoStepLinearModelFactory_h #define mitkTwoStepLinearModelFactory_h #include #include "mitkConcreteModelFactoryBase.h" #include "mitkTwoStepLinearModel.h" #include "mitkTwoStepLinearModelParameterizer.h" -#include "MitkPharmacokineticsExports.h" +#include "MitkModelFitExports.h" namespace mitk { - class MITKPHARMACOKINETICS_EXPORT TwoStepLinearModelFactory : public ConcreteModelFactoryBase + class MITKMODELFIT_EXPORT TwoStepLinearModelFactory : public ConcreteModelFactoryBase { public: mitkClassMacroItkParent(TwoStepLinearModelFactory, ConcreteModelFactoryBase); itkFactorylessNewMacro(Self); /** This function returns the default parameterization (e.g. initial parametrization for fitting) defined by the model developer for for the given model.*/ virtual ParametersType GetDefaultInitialParameterization() const; protected: virtual ModelParameterizerBase::Pointer DoCreateParameterizer(const modelFit::ModelFitInfo* fit) const; TwoStepLinearModelFactory(); virtual ~TwoStepLinearModelFactory(); private: //No copy constructor allowed TwoStepLinearModelFactory(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoStepLinearModelParameterizer.h b/Modules/ModelFit/include/mitkTwoStepLinearModelParameterizer.h similarity index 96% rename from Modules/Pharmacokinetics/include/mitkTwoStepLinearModelParameterizer.h rename to Modules/ModelFit/include/mitkTwoStepLinearModelParameterizer.h index 588fe4b08b..9beda06309 100644 --- a/Modules/Pharmacokinetics/include/mitkTwoStepLinearModelParameterizer.h +++ b/Modules/ModelFit/include/mitkTwoStepLinearModelParameterizer.h @@ -1,63 +1,63 @@ /*============================================================================ 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 mitkTwoStepLinearModelParameterizer_h #define mitkTwoStepLinearModelParameterizer_h #include "mitkConcreteModelParameterizerBase.h" #include "mitkTwoStepLinearModel.h" namespace mitk { -class MITKPHARMACOKINETICS_EXPORT TwoStepLinearModelParameterizer : public +class MITKMODELFIT_EXPORT TwoStepLinearModelParameterizer : public mitk::ConcreteModelParameterizerBase { public: typedef TwoStepLinearModelParameterizer Self; typedef mitk::ConcreteModelParameterizerBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; itkTypeMacro(TwoStepLinearModelParameterizer, ConcreteModelParameterizerBase); itkFactorylessNewMacro(Self); typedef typename Superclass::ModelBaseType ModelBaseType; typedef typename Superclass::ModelBasePointer ModelBasePointer; typedef typename Superclass::ModelType ModelType; typedef typename Superclass::ModelPointer ModelPointer; typedef typename Superclass::StaticParameterValueType StaticParameterValueType; typedef typename Superclass::StaticParameterValuesType StaticParameterValuesType; typedef typename Superclass::StaticParameterMapType StaticParameterMapType; typedef typename Superclass::IndexType IndexType; /** This function returns the default parameterization (e.g. initial parametrization for fitting) defined by the model developer for for the given model.*/ virtual ParametersType GetDefaultInitialParameterization() const; protected: TwoStepLinearModelParameterizer(){}; virtual ~TwoStepLinearModelParameterizer(){}; private: //No copy constructor allowed TwoStepLinearModelParameterizer(const Self& source); void operator=(const Self&); //purposely not implemented };} #endif diff --git a/Modules/ModelFit/src/Common/mitkPixelBasedParameterFitImageGenerator.cpp b/Modules/ModelFit/src/Common/mitkPixelBasedParameterFitImageGenerator.cpp index 306bc796ad..ee293b11e4 100644 --- a/Modules/ModelFit/src/Common/mitkPixelBasedParameterFitImageGenerator.cpp +++ b/Modules/ModelFit/src/Common/mitkPixelBasedParameterFitImageGenerator.cpp @@ -1,275 +1,275 @@ /*============================================================================ 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 "itkCommand.h" #include "itkMultiOutputNaryFunctorImageFilter.h" #include "mitkPixelBasedParameterFitImageGenerator.h" #include "mitkImageTimeSelector.h" #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" #include "mitkModelFitFunctorPolicy.h" #include "mitkExtractTimeGrid.h" void mitk::PixelBasedParameterFitImageGenerator:: onFitProgressEvent(::itk::Object* caller, const ::itk::EventObject& /*eventObject*/) { - this->InvokeEvent(::itk::ProgressEvent()); auto* process = dynamic_cast(caller); if (process) { this->m_Progress = process->GetProgress(); } + this->InvokeEvent(::itk::ProgressEvent()); }; template void mitk::PixelBasedParameterFitImageGenerator::DoPrepareMask(itk::Image* image) { m_InternalMask = dynamic_cast(image); if (m_InternalMask.IsNull()) { MITK_INFO << "Parameter Fit Generator. Need to cast mask for parameter fit."; using InputImageType = itk::Image; using CastFilterType = itk::CastImageFilter< InputImageType, InternalMaskType >; typename CastFilterType::Pointer spImageCaster = CastFilterType::New(); spImageCaster->SetInput(image); m_InternalMask = spImageCaster->GetOutput(); spImageCaster->Update(); } } template mitk::PixelBasedParameterFitImageGenerator::ParameterImageMapType StoreResultImages( mitk::ModelFitFunctorBase::ParameterNamesType ¶mNames, itk::ImageSource* source, mitk::ModelFitFunctorBase::ParameterNamesType::size_type startPos, mitk::ModelFitFunctorBase::ParameterNamesType::size_type& endPos ) { mitk::PixelBasedParameterFitImageGenerator::ParameterImageMapType result; for (mitk::ModelFitFunctorBase::ParameterNamesType::size_type j = 0; j < paramNames.size(); ++j) { if (source->GetNumberOfOutputs() < startPos+j) { mitkThrow() << "Error while generating fitted parameter images. Number of sources is too low and does not match expected parameter number. Output size: "<< source->GetNumberOfOutputs()<<"; number of param names: "<GetOutput(startPos+j); mitk::CastToMitkImage(outputImg, paramImage); result.insert(std::make_pair(paramNames[j],paramImage)); } endPos = startPos + paramNames.size(); return result; } template void mitk::PixelBasedParameterFitImageGenerator::DoParameterFit(itk::Image* /*image*/) { using InputFrameImageType = itk::Image; using ParameterImageType = itk::Image; using FitFilterType = itk::MultiOutputNaryFunctorImageFilter; typename FitFilterType::Pointer fitFilter = FitFilterType::New(); typename ::itk::MemberCommand::Pointer spProgressCommand = ::itk::MemberCommand::New(); spProgressCommand->SetCallbackFunction(this, &Self::onFitProgressEvent); fitFilter->AddObserver(::itk::ProgressEvent(), spProgressCommand); //add the time frames to the fit filter mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(this->m_DynamicImage); std::vector frameCache; for (unsigned int i = 0; i < this->m_DynamicImage->GetTimeSteps(); ++i) { typename InputFrameImageType::Pointer frameImage; imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); Image::Pointer frameMITKImage = imageTimeSelector->GetOutput(); frameCache.push_back(frameMITKImage); mitk::CastToItkImage(frameMITKImage, frameImage); fitFilter->SetInput(i,frameImage); } ModelBaseType::TimeGridType timeGrid = ExtractTimeGrid(m_DynamicImage); if (m_TimeGridByParameterizer) { if (timeGrid.GetSize() != m_ModelParameterizer->GetDefaultTimeGrid().GetSize()) { mitkThrow() << "Cannot do fitting. Filter is set to use default time grid of the parameterizer, but grid size does not match the number of input image frames. Grid size: " << m_ModelParameterizer->GetDefaultTimeGrid().GetSize() << "; frame count: " << timeGrid.GetSize(); } } else { this->m_ModelParameterizer->SetDefaultTimeGrid(timeGrid); } ModelFitFunctorPolicy functor; functor.SetModelFitFunctor(this->m_FitFunctor); functor.SetModelParameterizer(this->m_ModelParameterizer); fitFilter->SetFunctor(functor); if (this->m_InternalMask.IsNotNull()) { fitFilter->SetMask(this->m_InternalMask); } //generate the fits fitFilter->Update(); //convert the outputs into mitk images and fill the parameter image map ModelBaseType::Pointer refModel = this->m_ModelParameterizer->GenerateParameterizedModel(); ModelFitFunctorBase::ParameterNamesType paramNames = refModel->GetParameterNames(); ModelFitFunctorBase::ParameterNamesType derivedParamNames = refModel->GetDerivedParameterNames(); ModelFitFunctorBase::ParameterNamesType criterionNames = this->m_FitFunctor->GetCriterionNames(); ModelFitFunctorBase::ParameterNamesType evaluationParamNames = this->m_FitFunctor->GetEvaluationParameterNames(); ModelFitFunctorBase::ParameterNamesType debugParamNames = this->m_FitFunctor->GetDebugParameterNames(); if (fitFilter->GetNumberOfOutputs() != (paramNames.size() + derivedParamNames.size() + criterionNames.size() + evaluationParamNames.size() + debugParamNames.size())) { mitkThrow() << "Error while generating fitted parameter images. Fit filter output size does not match expected parameter number. Output size: "<< fitFilter->GetNumberOfOutputs(); } ModelFitFunctorBase::ParameterNamesType::size_type resultPos = 0; this->m_TempResultMap = StoreResultImages(paramNames,fitFilter,resultPos, resultPos); this->m_TempDerivedResultMap = StoreResultImages(derivedParamNames,fitFilter,resultPos, resultPos); this->m_TempCriterionResultMap = StoreResultImages(criterionNames,fitFilter,resultPos, resultPos); this->m_TempEvaluationResultMap = StoreResultImages(evaluationParamNames,fitFilter,resultPos, resultPos); //also add debug params (if generated) to the evaluation result map mitk::PixelBasedParameterFitImageGenerator::ParameterImageMapType debugMap = StoreResultImages(debugParamNames, fitFilter, resultPos, resultPos); this->m_TempEvaluationResultMap.insert(debugMap.begin(), debugMap.end()); } bool mitk::PixelBasedParameterFitImageGenerator::HasOutdatedResult() const { bool result = Superclass::HasOutdatedResult(); if (m_ModelParameterizer.IsNotNull()) { if (m_ModelParameterizer->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } if (m_FitFunctor.IsNotNull()) { if (m_FitFunctor->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } if (m_DynamicImage.IsNotNull()) { if (m_DynamicImage->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } if (m_Mask.IsNotNull()) { if (m_Mask->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } return result; }; void mitk::PixelBasedParameterFitImageGenerator::CheckValidInputs() const { Superclass::CheckValidInputs(); if (m_DynamicImage.IsNull()) { mitkThrow() << "Cannot generate fitted parameter images. Input dynamic image is not set."; } }; void mitk::PixelBasedParameterFitImageGenerator::DoFitAndGetResults(ParameterImageMapType& parameterImages, ParameterImageMapType& derivedParameterImages, ParameterImageMapType& criterionImages, ParameterImageMapType& evaluationParameterImages) { this->m_Progress = 0; if(this->m_Mask.IsNotNull()) { AccessFixedDimensionByItk(m_Mask, mitk::PixelBasedParameterFitImageGenerator::DoPrepareMask, 3); } else { this->m_InternalMask = nullptr; } AccessFixedDimensionByItk(m_DynamicImage, mitk::PixelBasedParameterFitImageGenerator::DoParameterFit, 4); parameterImages = this->m_TempResultMap; derivedParameterImages = this->m_TempDerivedResultMap; criterionImages = this->m_TempCriterionResultMap; evaluationParameterImages = this->m_TempEvaluationResultMap; }; double mitk::PixelBasedParameterFitImageGenerator::GetProgress() const { return m_Progress; }; mitk::PixelBasedParameterFitImageGenerator::ParameterNamesType mitk::PixelBasedParameterFitImageGenerator::GetParameterNames() const { ParameterizerType::ModelBasePointer parameterizedModel = m_ModelParameterizer->GenerateParameterizedModel(); return parameterizedModel->GetParameterNames(); } mitk::PixelBasedParameterFitImageGenerator::ParameterNamesType mitk::PixelBasedParameterFitImageGenerator::GetDerivedParameterNames() const { ParameterizerType::ModelBasePointer parameterizedModel = m_ModelParameterizer->GenerateParameterizedModel(); return parameterizedModel->GetDerivedParameterNames(); } mitk::PixelBasedParameterFitImageGenerator::ParameterNamesType mitk::PixelBasedParameterFitImageGenerator::GetCriterionNames() const { return this->m_FitFunctor->GetCriterionNames(); } mitk::PixelBasedParameterFitImageGenerator::ParameterNamesType mitk::PixelBasedParameterFitImageGenerator::GetEvaluationParameterNames() const { auto evals = this->m_FitFunctor->GetEvaluationParameterNames(); auto debugs = this->m_FitFunctor->GetDebugParameterNames(); evals.insert(evals.end(), debugs.begin(), debugs.end()); return evals; } diff --git a/Modules/ModelFit/src/Common/mitkROIBasedParameterFitImageGenerator.cpp b/Modules/ModelFit/src/Common/mitkROIBasedParameterFitImageGenerator.cpp index 78fcf960fe..9cb6ff5928 100644 --- a/Modules/ModelFit/src/Common/mitkROIBasedParameterFitImageGenerator.cpp +++ b/Modules/ModelFit/src/Common/mitkROIBasedParameterFitImageGenerator.cpp @@ -1,264 +1,264 @@ /*============================================================================ 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 "itkChangeInformationImageFilter.h" #include "mitkROIBasedParameterFitImageGenerator.h" #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" void mitk::ROIBasedParameterFitImageGenerator:: onFitProgressEvent(::itk::Object* caller, const ::itk::EventObject& /*eventObject*/) { - this->InvokeEvent(::itk::ProgressEvent()); itk::ProcessObject* process = dynamic_cast(caller); if (process) { this->m_Progress = process->GetProgress(); } + this->InvokeEvent(::itk::ProgressEvent()); }; template void mitk::ROIBasedParameterFitImageGenerator::DoImageGeneration(itk::Image* image, double value) { typedef itk::Image MaskType; typedef itk::Image ParameterImageType; typedef itk::ChangeInformationImageFilter< ParameterImageType > OutputImageInformationFilterType; typename OutputImageInformationFilterType::Pointer copyGeoInfoFilter = OutputImageInformationFilterType::New(); typename ParameterImageType::Pointer paramImg = ParameterImageType::New(); copyGeoInfoFilter->ChangeDirectionOn(); copyGeoInfoFilter->SetOutputDirection(image->GetDirection()); copyGeoInfoFilter->ChangeOriginOn(); copyGeoInfoFilter->SetOutputOrigin(image->GetOrigin()); copyGeoInfoFilter->ChangeSpacingOn(); copyGeoInfoFilter->SetOutputSpacing(image->GetSpacing()); copyGeoInfoFilter->SetInput(paramImg); copyGeoInfoFilter->Update(); paramImg = copyGeoInfoFilter->GetOutput(); paramImg->SetRegions(image->GetLargestPossibleRegion()); paramImg->Allocate(); paramImg->FillBuffer(0.0); typedef itk::ImageRegionConstIterator MaskIteratorType; typedef itk::ImageRegionIterator ImageIteratorType; MaskIteratorType maskItr(image, image->GetLargestPossibleRegion()); ImageIteratorType imgItr(paramImg, image->GetLargestPossibleRegion()); maskItr.GoToBegin(); imgItr.GoToBegin(); while (!maskItr.IsAtEnd()) { if (maskItr.Get() > 0.0) { imgItr.Set(value); } ++maskItr; ++imgItr; } m_TempResultImage = Image::New(); mitk::CastToMitkImage(paramImg, m_TempResultImage); } bool mitk::ROIBasedParameterFitImageGenerator::HasOutdatedResult() const { bool result = Superclass::HasOutdatedResult(); if (m_ModelParameterizer.IsNotNull()) { if (m_ModelParameterizer->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } if (m_Mask.IsNotNull()) { if (m_Mask->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } if (m_FitFunctor.IsNotNull()) { if (m_FitFunctor->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } return result; }; void mitk::ROIBasedParameterFitImageGenerator::CheckValidInputs() const { Superclass::CheckValidInputs(); if (m_Mask.IsNull()) { mitkThrow() << "Cannot generate fitted parameter images. Input mask is not set."; } if (m_Signal.Size() != m_TimeGrid.Size()) { mitkThrow() << "Cannot generate fitted parameter images. Signal and TimeGrid do not match."; } }; void mitk::ROIBasedParameterFitImageGenerator::DoFitAndGetResults(ParameterImageMapType& parameterImages, ParameterImageMapType& derivedParameterImages, ParameterImageMapType& criterionImages, ParameterImageMapType& evaluationParameterImages) { this->m_Progress = 0; //fit the signal ModelParameterizerBase::IndexType index; index.Fill(0); this->m_ModelParameterizer->SetDefaultTimeGrid(m_TimeGrid); ParameterizerType::ModelBasePointer parameterizedModel = m_ModelParameterizer->GenerateParameterizedModel(index); ParameterizerType::ParametersType initialParameters = m_ModelParameterizer->GetInitialParameterization(index); ModelFitFunctorBase::InputPixelArrayType inputValues; for (SignalType::const_iterator pos = m_Signal.begin(); pos != m_Signal.end(); ++pos) { inputValues.push_back(*pos); } ModelFitFunctorBase::OutputPixelArrayType fitResult = m_FitFunctor->Compute(inputValues, parameterizedModel, initialParameters); //generate the results maps ParameterImageMapType tempResultMap; ParameterImageMapType tempDerivedResultMap; ParameterImageMapType tempEvaluationResultMap; ParameterImageMapType tempCriterionResultMap; ModelFitFunctorBase::ParameterNamesType paramNames = parameterizedModel->GetParameterNames(); ModelFitFunctorBase::ParameterNamesType derivedParamNames = parameterizedModel->GetDerivedParameterNames(); ModelFitFunctorBase::ParameterNamesType criterionNames = this->m_FitFunctor->GetCriterionNames(); ModelFitFunctorBase::ParameterNamesType evaluationParamNames = this->m_FitFunctor->GetEvaluationParameterNames(); ModelFitFunctorBase::ParameterNamesType debugParamNames = this->m_FitFunctor->GetDebugParameterNames(); if (fitResult.size() != (paramNames.size() + derivedParamNames.size() + criterionNames.size() + evaluationParamNames.size() + debugParamNames.size())) { mitkThrow() << "Error while generating fitted parameter images. Fit functor output size does not match expected parameter number. Output size: " << fitResult.size(); } for (ModelFitFunctorBase::ParameterNamesType::size_type j = 0; j < paramNames.size(); ++j) { ModelFitFunctorBase::OutputPixelArrayType::value_type value = fitResult[j]; AccessByItk_n(m_Mask, mitk::ROIBasedParameterFitImageGenerator::DoImageGeneration, (value)); tempResultMap.insert(std::make_pair(paramNames[j], m_TempResultImage)); } ModelFitFunctorBase::ParameterNamesType::size_type offset = paramNames.size(); for (ModelFitFunctorBase::ParameterNamesType::size_type j = 0; j < derivedParamNames.size(); ++j) { ModelFitFunctorBase::OutputPixelArrayType::value_type value = fitResult[j + offset]; AccessByItk_n(m_Mask, mitk::ROIBasedParameterFitImageGenerator::DoImageGeneration, (value)); tempDerivedResultMap.insert(std::make_pair(derivedParamNames[j], m_TempResultImage)); } offset += derivedParamNames.size(); for (ModelFitFunctorBase::ParameterNamesType::size_type j = 0; j < criterionNames.size(); ++j) { ModelFitFunctorBase::OutputPixelArrayType::value_type value = fitResult[j + offset]; AccessByItk_n(m_Mask, mitk::ROIBasedParameterFitImageGenerator::DoImageGeneration, (value)); tempCriterionResultMap.insert(std::make_pair(criterionNames[j], m_TempResultImage)); } offset += criterionNames.size(); for (ModelFitFunctorBase::ParameterNamesType::size_type j = 0; j < evaluationParamNames.size(); ++j) { ModelFitFunctorBase::OutputPixelArrayType::value_type value = fitResult[j + offset]; AccessByItk_n(m_Mask, mitk::ROIBasedParameterFitImageGenerator::DoImageGeneration, (value)); tempEvaluationResultMap.insert(std::make_pair(evaluationParamNames[j], m_TempResultImage)); } offset += evaluationParamNames.size(); for (ModelFitFunctorBase::ParameterNamesType::size_type j = 0; j < debugParamNames.size(); ++j) { //add debug params (if they are generated to the evaluation result map ModelFitFunctorBase::OutputPixelArrayType::value_type value = fitResult[j + offset]; AccessByItk_n(m_Mask, mitk::ROIBasedParameterFitImageGenerator::DoImageGeneration, (value)); tempEvaluationResultMap.insert(std::make_pair(debugParamNames[j], m_TempResultImage)); } parameterImages = tempResultMap; derivedParameterImages = tempDerivedResultMap; criterionImages = tempCriterionResultMap; evaluationParameterImages = tempEvaluationResultMap; }; double mitk::ROIBasedParameterFitImageGenerator::GetProgress() const { return m_Progress; }; mitk::ROIBasedParameterFitImageGenerator::ParameterNamesType mitk::ROIBasedParameterFitImageGenerator::GetParameterNames() const { ParameterizerType::ModelBasePointer parameterizedModel = m_ModelParameterizer->GenerateParameterizedModel(); return parameterizedModel->GetParameterNames(); } mitk::ROIBasedParameterFitImageGenerator::ParameterNamesType mitk::ROIBasedParameterFitImageGenerator::GetDerivedParameterNames() const { ParameterizerType::ModelBasePointer parameterizedModel = m_ModelParameterizer->GenerateParameterizedModel(); return parameterizedModel->GetDerivedParameterNames(); } mitk::ROIBasedParameterFitImageGenerator::ParameterNamesType mitk::ROIBasedParameterFitImageGenerator::GetCriterionNames() const { return this->m_FitFunctor->GetCriterionNames(); } mitk::ROIBasedParameterFitImageGenerator::ParameterNamesType mitk::ROIBasedParameterFitImageGenerator::GetEvaluationParameterNames() const { auto evals = this->m_FitFunctor->GetEvaluationParameterNames(); auto debugs = this->m_FitFunctor->GetDebugParameterNames(); evals.insert(evals.end(), debugs.begin(), debugs.end()); return evals; } diff --git a/Modules/ModelFit/src/Models/mitkExpDecayOffsetModel.cpp b/Modules/ModelFit/src/Models/mitkExpDecayOffsetModel.cpp index 4b9a687d65..19e19a1597 100644 --- a/Modules/ModelFit/src/Models/mitkExpDecayOffsetModel.cpp +++ b/Modules/ModelFit/src/Models/mitkExpDecayOffsetModel.cpp @@ -1,101 +1,167 @@ /*============================================================================ 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 "mitkExpDecayOffsetModel.h" + +const std::string mitk::ExpDecayOffsetModel::NAME_PARAMETER_y0 = "y-intercept"; +const std::string mitk::ExpDecayOffsetModel::NAME_PARAMETER_k = "rate"; +const std::string mitk::ExpDecayOffsetModel::NAME_PARAMETER_y_bl = "baseline"; + +const unsigned int mitk::ExpDecayOffsetModel::NUMBER_OF_PARAMETERS = 3; + +const std::string mitk::ExpDecayOffsetModel::UNIT_PARAMETER_y0 = "[unit of y]"; +const std::string mitk::ExpDecayOffsetModel::UNIT_PARAMETER_k = "1/[unit of x]"; +const std::string mitk::ExpDecayOffsetModel::UNIT_PARAMETER_y_bl = "[unit of y]"; + +const unsigned int mitk::ExpDecayOffsetModel::POSITION_PARAMETER_y0 = 0; +const unsigned int mitk::ExpDecayOffsetModel::POSITION_PARAMETER_k = 1; +const unsigned int mitk::ExpDecayOffsetModel::POSITION_PARAMETER_y_bl = 2; + +const unsigned int mitk::ExpDecayOffsetModel::NUMBER_OF_STATIC_PARAMETERS = 0; + +const std::string mitk::ExpDecayOffsetModel::MODEL_DISPLAY_NAME = "Exponential Decay Offset Model"; + +const std::string mitk::ExpDecayOffsetModel::MODEL_TYPE = "Generic"; + +const std::string mitk::ExpDecayOffsetModel::FUNCTION_STRING = "y(x) = y-intercept * exp(-rate*x) + baseline"; + +const std::string mitk::ExpDecayOffsetModel::X_NAME = "x"; + +const std::string mitk::ExpDecayOffsetModel::X_AXIS_NAME = "X"; + +const std::string mitk::ExpDecayOffsetModel::X_AXIS_UNIT = "unit of x"; + +const std::string mitk::ExpDecayOffsetModel::Y_AXIS_NAME = "Y"; + +const std::string mitk::ExpDecayOffsetModel::Y_AXIS_UNIT = "unit of y"; + +/////////// + std::string mitk::ExpDecayOffsetModel::GetModelDisplayName() const { - return "Exponential Decay Offset Model"; + return MODEL_DISPLAY_NAME; }; std::string mitk::ExpDecayOffsetModel::GetModelType() const { - return "Generic"; + return MODEL_TYPE; }; mitk::ExpDecayOffsetModel::FunctionStringType mitk::ExpDecayOffsetModel::GetFunctionString() const { - return "a*exp(-1.0*x*b)+c"; + return FUNCTION_STRING; }; std::string mitk::ExpDecayOffsetModel::GetXName() const { - return "x"; + return X_NAME; }; +std::string mitk::ExpDecayOffsetModel::GetXAxisName() const +{ + return X_AXIS_NAME; +}; + +std::string mitk::ExpDecayOffsetModel::GetXAxisUnit() const +{ + return X_AXIS_UNIT; +} + +std::string mitk::ExpDecayOffsetModel::GetYAxisName() const +{ + return Y_AXIS_NAME; +}; + +std::string mitk::ExpDecayOffsetModel::GetYAxisUnit() const +{ + return Y_AXIS_UNIT; +} + mitk::ExpDecayOffsetModel::ParameterNamesType mitk::ExpDecayOffsetModel::GetParameterNames() const { ParameterNamesType result; - result.push_back("a"); - result.push_back("b"); - result.push_back("c"); + result.push_back(NAME_PARAMETER_y0); + result.push_back(NAME_PARAMETER_k); + result.push_back(NAME_PARAMETER_y_bl); return result; }; +mitk::ExpDecayOffsetModel::ParamterUnitMapType mitk::ExpDecayOffsetModel::GetParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_PARAMETER_y0, UNIT_PARAMETER_y0)); + result.insert(std::make_pair(NAME_PARAMETER_k, UNIT_PARAMETER_k)); + result.insert(std::make_pair(NAME_PARAMETER_y_bl, UNIT_PARAMETER_y_bl)); + + return result; +} + mitk::ExpDecayOffsetModel::ParametersSizeType mitk::ExpDecayOffsetModel::GetNumberOfParameters() const { - return 3; + return NUMBER_OF_PARAMETERS; }; mitk::ExpDecayOffsetModel::ModelResultType mitk::ExpDecayOffsetModel::ComputeModelfunction(const ParametersType& parameters) const { ModelResultType signal(m_TimeGrid.GetSize()); const auto timeGridEnd = m_TimeGrid.end(); ModelResultType::iterator signalPos = signal.begin(); for (auto gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd; ++gridPos, ++signalPos) { *signalPos = parameters[0] * exp(-1.0 * (*gridPos) * parameters[1]) + parameters[2]; } return signal; }; mitk::ExpDecayOffsetModel::ParameterNamesType mitk::ExpDecayOffsetModel::GetStaticParameterNames() const { return {}; } mitk::ExpDecayOffsetModel::ParametersSizeType mitk::ExpDecayOffsetModel::GetNumberOfStaticParameters() const { - return 0; + return NUMBER_OF_STATIC_PARAMETERS; } void mitk::ExpDecayOffsetModel::SetStaticParameter(const ParameterNameType& /*name*/, const StaticParameterValuesType& /*values*/) { //do nothing }; mitk::ExpDecayOffsetModel::StaticParameterValuesType mitk::ExpDecayOffsetModel::GetStaticParameterValue( const ParameterNameType& /*name*/) const { StaticParameterValuesType result; //do nothing return result; }; itk::LightObject::Pointer mitk::ExpDecayOffsetModel::InternalClone() const { ExpDecayOffsetModel::Pointer newClone = ExpDecayOffsetModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); }; diff --git a/Modules/ModelFit/src/Models/mitkExponentialDecayModel.cpp b/Modules/ModelFit/src/Models/mitkExponentialDecayModel.cpp new file mode 100644 index 0000000000..ca96684b30 --- /dev/null +++ b/Modules/ModelFit/src/Models/mitkExponentialDecayModel.cpp @@ -0,0 +1,208 @@ +/*============================================================================ + +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 "mitkExponentialDecayModel.h" +#include "mitkNumericConstants.h" + +const std::string mitk::ExponentialDecayModel::NAME_PARAMETER_y0 = "y-intercept"; +const std::string mitk::ExponentialDecayModel::NAME_PARAMETER_lambda = "lambda"; + +const unsigned int mitk::ExponentialDecayModel::NUMBER_OF_PARAMETERS = 2; + +const std::string mitk::ExponentialDecayModel::UNIT_PARAMETER_y0 = "[unit of y]"; +const std::string mitk::ExponentialDecayModel::UNIT_PARAMETER_lambda = "[unit of x]"; + +const unsigned int mitk::ExponentialDecayModel::POSITION_PARAMETER_y0 = 0; +const unsigned int mitk::ExponentialDecayModel::POSITION_PARAMETER_lambda = 1; + +const std::string mitk::ExponentialDecayModel::NAME_DERIVED_PARAMETER_k = "rate"; + +const unsigned int mitk::ExponentialDecayModel::NUMBER_OF_DERIVED_PARAMETERS = 1; + +const std::string mitk::ExponentialDecayModel::UNIT_DERIVED_PARAMETER_k = "1/[unit of x]"; + +const unsigned int mitk::ExponentialDecayModel::NUMBER_OF_STATIC_PARAMETERS = 0; + +const std::string mitk::ExponentialDecayModel::MODEL_DISPLAY_NAME = "Exponential Decay Model"; + +const std::string mitk::ExponentialDecayModel::MODEL_TYPE = "Generic"; + +const std::string mitk::ExponentialDecayModel::FUNCTION_STRING = "y(x) = y-intercept * exp(-x/lambda)"; + +const std::string mitk::ExponentialDecayModel::X_NAME = "x"; + +const std::string mitk::ExponentialDecayModel::X_AXIS_NAME = "X"; + +const std::string mitk::ExponentialDecayModel::X_AXIS_UNIT = "unit of x"; + +const std::string mitk::ExponentialDecayModel::Y_AXIS_NAME = "Y"; + +const std::string mitk::ExponentialDecayModel::Y_AXIS_UNIT = "unit of y"; + + +std::string mitk::ExponentialDecayModel::GetModelDisplayName() const +{ + return MODEL_DISPLAY_NAME; +}; + +std::string mitk::ExponentialDecayModel::GetModelType() const +{ + return MODEL_TYPE; +}; + +mitk::ExponentialDecayModel::FunctionStringType mitk::ExponentialDecayModel::GetFunctionString() const +{ + return FUNCTION_STRING; +}; + +std::string mitk::ExponentialDecayModel::GetXName() const +{ + return X_NAME; +}; + +std::string mitk::ExponentialDecayModel::GetXAxisName() const +{ + return X_AXIS_NAME; +}; + +std::string mitk::ExponentialDecayModel::GetXAxisUnit() const +{ + return X_AXIS_UNIT; +} + +std::string mitk::ExponentialDecayModel::GetYAxisName() const +{ + return Y_AXIS_NAME; +}; + +std::string mitk::ExponentialDecayModel::GetYAxisUnit() const +{ + return Y_AXIS_UNIT; +} + +mitk::ExponentialDecayModel::ParameterNamesType +mitk::ExponentialDecayModel::GetParameterNames() const +{ + ParameterNamesType result; + result.push_back(NAME_PARAMETER_y0); + result.push_back(NAME_PARAMETER_lambda); + return result; +}; + +mitk::ExponentialDecayModel::ParamterUnitMapType mitk::ExponentialDecayModel::GetParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_PARAMETER_y0, UNIT_PARAMETER_y0)); + result.insert(std::make_pair(NAME_PARAMETER_lambda, UNIT_PARAMETER_lambda)); + + return result; +} + +mitk::ExponentialDecayModel::ParametersSizeType +mitk::ExponentialDecayModel::GetNumberOfParameters() const +{ + return NUMBER_OF_PARAMETERS; +}; + +mitk::ExponentialDecayModel::ParameterNamesType +mitk::ExponentialDecayModel::GetDerivedParameterNames() const +{ + ParameterNamesType result; + result.push_back(NAME_DERIVED_PARAMETER_k); + return result; +}; + +mitk::ExponentialDecayModel::ParametersSizeType +mitk::ExponentialDecayModel::GetNumberOfDerivedParameters() const +{ + return NUMBER_OF_DERIVED_PARAMETERS; +}; + +mitk::ExponentialDecayModel::ParamterUnitMapType mitk::ExponentialDecayModel::GetDerivedParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_k, UNIT_DERIVED_PARAMETER_k)); + + return result; +}; + +mitk::ExponentialDecayModel::ModelResultType +mitk::ExponentialDecayModel::ComputeModelfunction(const ParametersType& parameters) const +{ + double y0 = parameters[POSITION_PARAMETER_y0]; + double lambda = parameters[POSITION_PARAMETER_lambda]; + + ModelResultType signal(m_TimeGrid.GetSize()); + + ModelResultType::iterator signalPos = signal.begin(); + + for (const auto& gridPos : m_TimeGrid) + { + *signalPos = y0 * exp(-1.0 * gridPos/ lambda); + ++signalPos; + } + + return signal; +}; + +mitk::ExponentialDecayModel::ParameterNamesType mitk::ExponentialDecayModel::GetStaticParameterNames() const +{ + ParameterNamesType result; + + return result; +} + +mitk::ExponentialDecayModel::ParametersSizeType mitk::ExponentialDecayModel::GetNumberOfStaticParameters() const +{ + return NUMBER_OF_STATIC_PARAMETERS; +} + +void mitk::ExponentialDecayModel::SetStaticParameter(const ParameterNameType& /*name*/, + const StaticParameterValuesType& /*values*/) +{ + //do nothing +}; + +mitk::ExponentialDecayModel::StaticParameterValuesType mitk::ExponentialDecayModel::GetStaticParameterValue( + const ParameterNameType& /*name*/) const +{ + StaticParameterValuesType result; + + //do nothing + + return result; +}; + + +mitk::ModelBase::DerivedParameterMapType mitk::ExponentialDecayModel::ComputeDerivedParameters( + const mitk::ModelBase::ParametersType ¶meters) const +{ + DerivedParameterMapType result; + + //Model Parameters + double lambda = parameters[POSITION_PARAMETER_lambda]; + + double k = 1.0 / (lambda + mitk::eps); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_k, k)); + return result; +}; + +itk::LightObject::Pointer mitk::ExponentialDecayModel::InternalClone() const +{ + ExponentialDecayModel::Pointer newClone = ExponentialDecayModel::New(); + + newClone->SetTimeGrid(this->m_TimeGrid); + + return newClone.GetPointer(); +}; diff --git a/Modules/ModelFit/src/Models/mitkT2DecayModelFactory.cpp b/Modules/ModelFit/src/Models/mitkExponentialDecayModelFactory.cpp similarity index 53% rename from Modules/ModelFit/src/Models/mitkT2DecayModelFactory.cpp rename to Modules/ModelFit/src/Models/mitkExponentialDecayModelFactory.cpp index 8e843c4dea..a2ab3a559a 100644 --- a/Modules/ModelFit/src/Models/mitkT2DecayModelFactory.cpp +++ b/Modules/ModelFit/src/Models/mitkExponentialDecayModelFactory.cpp @@ -1,45 +1,45 @@ /*============================================================================ 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 "mitkT2DecayModelFactory.h" -#include "mitkT2DecayModelParameterizer.h" +#include "mitkExponentialDecayModelFactory.h" +#include "mitkExponentialDecayModelParameterizer.h" #include "mitkSimpleBarrierConstraintChecker.h" -mitk::T2DecayModelFactory::T2DecayModelFactory() +mitk::ExponentialDecayModelFactory::ExponentialDecayModelFactory() { }; -mitk::T2DecayModelFactory::~T2DecayModelFactory() +mitk::ExponentialDecayModelFactory::~ExponentialDecayModelFactory() { }; mitk::ModelParameterizerBase::ParametersType -mitk::T2DecayModelFactory::GetDefaultInitialParameterization() const +mitk::ExponentialDecayModelFactory::GetDefaultInitialParameterization() const { - return T2DecayModelParameterizer::New()->GetDefaultInitialParameterization(); + return ExponentialDecayModelParameterizer::New()->GetDefaultInitialParameterization(); }; -mitk::ConstraintCheckerBase::Pointer mitk::T2DecayModelFactory::CreateDefaultConstraints() const +mitk::ConstraintCheckerBase::Pointer mitk::ExponentialDecayModelFactory::CreateDefaultConstraints() const { mitk::SimpleBarrierConstraintChecker::Pointer constraints = SimpleBarrierConstraintChecker::New(); constraints->SetLowerBarrier(0, 0, 0); constraints->SetLowerBarrier(1, 0, 0); return constraints.GetPointer(); }; -mitk::ModelParameterizerBase::Pointer mitk::T2DecayModelFactory::DoCreateParameterizer( +mitk::ModelParameterizerBase::Pointer mitk::ExponentialDecayModelFactory::DoCreateParameterizer( const modelFit::ModelFitInfo* /*fit*/) const { - return T2DecayModelParameterizer::New().GetPointer(); + return ExponentialDecayModelParameterizer::New().GetPointer(); }; diff --git a/Modules/ModelFit/src/Models/mitkT2DecayModelParameterizer.cpp b/Modules/ModelFit/src/Models/mitkExponentialDecayModelParameterizer.cpp similarity index 53% rename from Modules/ModelFit/src/Models/mitkT2DecayModelParameterizer.cpp rename to Modules/ModelFit/src/Models/mitkExponentialDecayModelParameterizer.cpp index 890c5e25b1..f5d2e364d0 100644 --- a/Modules/ModelFit/src/Models/mitkT2DecayModelParameterizer.cpp +++ b/Modules/ModelFit/src/Models/mitkExponentialDecayModelParameterizer.cpp @@ -1,32 +1,32 @@ /*============================================================================ 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 "mitkT2DecayModelParameterizer.h" +#include "mitkExponentialDecayModelParameterizer.h" -mitk::T2DecayModelParameterizer::ParametersType -mitk::T2DecayModelParameterizer::GetDefaultInitialParameterization() const +mitk::ExponentialDecayModelParameterizer::ParametersType +mitk::ExponentialDecayModelParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(2); - initialParameters[0] = 10; //M0 - initialParameters[1] = 1000; //T2 + initialParameters[0] = 10; //y0 + initialParameters[1] = 1000; //lambda return initialParameters; }; -mitk::T2DecayModelParameterizer::T2DecayModelParameterizer() +mitk::ExponentialDecayModelParameterizer::ExponentialDecayModelParameterizer() { }; -mitk::T2DecayModelParameterizer::~T2DecayModelParameterizer() +mitk::ExponentialDecayModelParameterizer::~ExponentialDecayModelParameterizer() { }; diff --git a/Modules/ModelFit/src/Models/mitkExponentialSaturationModel.cpp b/Modules/ModelFit/src/Models/mitkExponentialSaturationModel.cpp index 51bcecc086..eb6608c68a 100644 --- a/Modules/ModelFit/src/Models/mitkExponentialSaturationModel.cpp +++ b/Modules/ModelFit/src/Models/mitkExponentialSaturationModel.cpp @@ -1,112 +1,179 @@ /*============================================================================ 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 "mitkExponentialSaturationModel.h" #include "mitkNumericConstants.h" +const std::string mitk::ExponentialSaturationModel::NAME_PARAMETER_BAT = "onset"; +const std::string mitk::ExponentialSaturationModel::NAME_PARAMETER_y_bl = "baseline"; +const std::string mitk::ExponentialSaturationModel::NAME_PARAMETER_y_fin = "y_final"; +const std::string mitk::ExponentialSaturationModel::NAME_PARAMETER_k = "rate"; + +const unsigned int mitk::ExponentialSaturationModel::NUMBER_OF_PARAMETERS = 4; + +const std::string mitk::ExponentialSaturationModel::UNIT_PARAMETER_BAT = "[unit of x]"; +const std::string mitk::ExponentialSaturationModel::UNIT_PARAMETER_y_bl = "[unit of y]"; +const std::string mitk::ExponentialSaturationModel::UNIT_PARAMETER_y_fin = "[unit of y]"; +const std::string mitk::ExponentialSaturationModel::UNIT_PARAMETER_k = "1/[unit of x]"; + +const unsigned int mitk::ExponentialSaturationModel::POSITION_PARAMETER_BAT = 0; +const unsigned int mitk::ExponentialSaturationModel::POSITION_PARAMETER_y_bl = 1; +const unsigned int mitk::ExponentialSaturationModel::POSITION_PARAMETER_y_fin = 2; +const unsigned int mitk::ExponentialSaturationModel::POSITION_PARAMETER_k = 3; + +const unsigned int mitk::ExponentialSaturationModel::NUMBER_OF_STATIC_PARAMETERS = 0; + +const std::string mitk::ExponentialSaturationModel::MODEL_DISPLAY_NAME = "Exponential Saturation Model"; + +const std::string mitk::ExponentialSaturationModel::MODEL_TYPE = "Generic"; + +const std::string mitk::ExponentialSaturationModel::FUNCTION_STRING = "if xSetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); }; diff --git a/Modules/ModelFit/src/Models/mitkLinearModel.cpp b/Modules/ModelFit/src/Models/mitkLinearModel.cpp index 25e6ed786a..beaaf10d40 100644 --- a/Modules/ModelFit/src/Models/mitkLinearModel.cpp +++ b/Modules/ModelFit/src/Models/mitkLinearModel.cpp @@ -1,125 +1,209 @@ /*============================================================================ 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 "mitkLinearModel.h" +const std::string mitk::LinearModel::NAME_PARAMETER_b = "slope"; +const std::string mitk::LinearModel::NAME_PARAMETER_y0 = "y-intercept"; + +const unsigned int mitk::LinearModel::NUMBER_OF_PARAMETERS = 2; + +const std::string mitk::LinearModel::UNIT_PARAMETER_b = "[unit of y]/[unit of x]"; +const std::string mitk::LinearModel::UNIT_PARAMETER_y0 = "[unit of y]"; + +const unsigned int mitk::LinearModel::POSITION_PARAMETER_b = 0; +const unsigned int mitk::LinearModel::POSITION_PARAMETER_y0 = 1; + +const std::string mitk::LinearModel::NAME_DERIVED_PARAMETER_x_intercept = "x-intercept"; + +const unsigned int mitk::LinearModel::NUMBER_OF_DERIVED_PARAMETERS = 1; + +const std::string mitk::LinearModel::UNIT_DERIVED_PARAMETER_x_intercept = "[unit of x]"; + +const unsigned int mitk::LinearModel::NUMBER_OF_STATIC_PARAMETERS = 0; + +const std::string mitk::LinearModel::MODEL_DISPLAY_NAME = "Linear Model"; + +const std::string mitk::LinearModel::MODEL_TYPE = "Generic"; + +const std::string mitk::LinearModel::FUNCTION_STRING = "y(x) = y-intercept + slope*x"; + +const std::string mitk::LinearModel::X_NAME = "x"; + +const std::string mitk::LinearModel::X_AXIS_NAME = "X"; + +const std::string mitk::LinearModel::X_AXIS_UNIT = "unit of x"; + +const std::string mitk::LinearModel::Y_AXIS_NAME = "Y"; + +const std::string mitk::LinearModel::Y_AXIS_UNIT = "unit of y"; + + std::string mitk::LinearModel::GetModelDisplayName() const { - return "Linear Model"; + return MODEL_DISPLAY_NAME; }; std::string mitk::LinearModel::GetModelType() const { - return "Generic"; + return MODEL_TYPE; }; mitk::LinearModel::FunctionStringType mitk::LinearModel::GetFunctionString() const { - return "slope*x+offset"; + return FUNCTION_STRING; }; std::string mitk::LinearModel::GetXName() const { - return "x"; + return X_NAME; +}; + +std::string mitk::LinearModel::GetXAxisName() const +{ + return X_AXIS_NAME; +}; + +std::string mitk::LinearModel::GetXAxisUnit() const +{ + return X_AXIS_UNIT; +} + +std::string mitk::LinearModel::GetYAxisName() const +{ + return Y_AXIS_NAME; }; +std::string mitk::LinearModel::GetYAxisUnit() const +{ + return Y_AXIS_UNIT; +} + mitk::LinearModel::ParameterNamesType mitk::LinearModel::GetParameterNames() const { ParameterNamesType result; - result.push_back("slope"); - result.push_back("offset"); + result.push_back(NAME_PARAMETER_b); + result.push_back(NAME_PARAMETER_y0); return result; }; +mitk::LinearModel::ParamterUnitMapType mitk::LinearModel::GetParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_PARAMETER_b, UNIT_PARAMETER_b)); + result.insert(std::make_pair(NAME_PARAMETER_y0, UNIT_PARAMETER_y0)); + + return result; +} + mitk::LinearModel::ParametersSizeType mitk::LinearModel::GetNumberOfParameters() const { - return 2; + return NUMBER_OF_PARAMETERS; }; mitk::LinearModel::ParameterNamesType mitk::LinearModel::GetDerivedParameterNames() const { ParameterNamesType result; - result.push_back("x-intercept"); + result.push_back(NAME_DERIVED_PARAMETER_x_intercept); return result; }; mitk::LinearModel::ParametersSizeType mitk::LinearModel::GetNumberOfDerivedParameters() const { - return 1; + return NUMBER_OF_DERIVED_PARAMETERS; +}; + +mitk::LinearModel::ParamterUnitMapType mitk::LinearModel::GetDerivedParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_x_intercept, UNIT_DERIVED_PARAMETER_x_intercept)); + + return result; }; mitk::LinearModel::ModelResultType mitk::LinearModel::ComputeModelfunction(const ParametersType& parameters) const { + //Model Parameters + double b = parameters[POSITION_PARAMETER_b]; + double y0 = parameters[POSITION_PARAMETER_y0]; + ModelResultType signal(m_TimeGrid.GetSize()); TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); ModelResultType::iterator signalPos = signal.begin(); for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd; ++gridPos, ++signalPos) { - *signalPos = parameters[0] * (*gridPos) + parameters[1]; + *signalPos = b * (*gridPos) + y0; } return signal; }; mitk::LinearModel::ParameterNamesType mitk::LinearModel::GetStaticParameterNames() const { ParameterNamesType result; return result; } mitk::LinearModel::ParametersSizeType mitk::LinearModel::GetNumberOfStaticParameters() const { - return 0; + return NUMBER_OF_STATIC_PARAMETERS; } void mitk::LinearModel::SetStaticParameter(const ParameterNameType& /*name*/, const StaticParameterValuesType& /*values*/) { //do nothing }; mitk::LinearModel::StaticParameterValuesType mitk::LinearModel::GetStaticParameterValue( const ParameterNameType& /*name*/) const { StaticParameterValuesType result; //do nothing return result; }; mitk::ModelBase::DerivedParameterMapType mitk::LinearModel::ComputeDerivedParameters( const mitk::ModelBase::ParametersType& parameters) const { DerivedParameterMapType result; - double intercept = -1 * parameters[1] / parameters[0]; - result.insert(std::make_pair("x-intercept", intercept)); + + //Model Parameters + double b = parameters[POSITION_PARAMETER_b]; + double y0 = parameters[POSITION_PARAMETER_y0]; + + double intercept = -1 * y0 / b; + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_x_intercept, intercept)); return result; }; itk::LightObject::Pointer mitk::LinearModel::InternalClone() const { LinearModel::Pointer newClone = LinearModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); }; diff --git a/Modules/ModelFit/src/Models/mitkT2DecayModel.cpp b/Modules/ModelFit/src/Models/mitkT2DecayModel.cpp deleted file mode 100644 index 900a5a1bc7..0000000000 --- a/Modules/ModelFit/src/Models/mitkT2DecayModel.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/*============================================================================ - -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 "mitkT2DecayModel.h" -#include "mitkNumericConstants.h" - -std::string mitk::T2DecayModel::GetModelDisplayName() const -{ - return "T2 Decay Model"; -}; - -std::string mitk::T2DecayModel::GetModelType() const -{ - return "MRSignal"; -}; - -mitk::T2DecayModel::FunctionStringType mitk::T2DecayModel::GetFunctionString() const -{ - return "M0 * exp(-t/T2)"; -}; - -std::string mitk::T2DecayModel::GetXName() const -{ - return "t"; -}; - -mitk::T2DecayModel::ParameterNamesType -mitk::T2DecayModel::GetParameterNames() const -{ - ParameterNamesType result; - result.push_back("M0"); - result.push_back("T2"); - return result; -}; - -mitk::T2DecayModel::ParametersSizeType -mitk::T2DecayModel::GetNumberOfParameters() const -{ - return 2; -}; - -mitk::T2DecayModel::ModelResultType -mitk::T2DecayModel::ComputeModelfunction(const ParametersType& parameters) const -{ - ModelResultType signal(m_TimeGrid.GetSize()); - - ModelResultType::iterator signalPos = signal.begin(); - - for (const auto& gridPos : m_TimeGrid) - { - *signalPos = parameters[0] * exp(-1.0 * gridPos/ parameters[1]); - ++signalPos; - } - - return signal; -}; - -mitk::T2DecayModel::ParameterNamesType mitk::T2DecayModel::GetStaticParameterNames() const -{ - ParameterNamesType result; - - return result; -} - -mitk::T2DecayModel::ParametersSizeType mitk::T2DecayModel::GetNumberOfStaticParameters() const -{ - return 0; -} - -void mitk::T2DecayModel::SetStaticParameter(const ParameterNameType& /*name*/, - const StaticParameterValuesType& /*values*/) -{ - //do nothing -}; - -mitk::T2DecayModel::StaticParameterValuesType mitk::T2DecayModel::GetStaticParameterValue( - const ParameterNameType& /*name*/) const -{ - StaticParameterValuesType result; - - //do nothing - - return result; -}; - -mitk::T2DecayModel::DerivedParametersSizeType mitk::T2DecayModel::GetNumberOfDerivedParameters() const -{ - return 1; -} - -mitk::T2DecayModel::DerivedParameterNamesType mitk::T2DecayModel::GetDerivedParameterNames() const -{ - ParameterNamesType result; - result.push_back("R2"); - return result; -}; - -mitk::ModelBase::DerivedParameterMapType mitk::T2DecayModel::ComputeDerivedParameters( - const mitk::ModelBase::ParametersType ¶meters) const -{ - DerivedParameterMapType result; - double inverse = 1.0 / (parameters[1] + mitk::eps); - result.insert(std::make_pair("R2", inverse)); - return result; -}; - -itk::LightObject::Pointer mitk::T2DecayModel::InternalClone() const -{ - T2DecayModel::Pointer newClone = T2DecayModel::New(); - - newClone->SetTimeGrid(this->m_TimeGrid); - - return newClone.GetPointer(); -}; diff --git a/Modules/ModelFit/src/Models/mitkThreeStepLinearModel.cpp b/Modules/ModelFit/src/Models/mitkThreeStepLinearModel.cpp new file mode 100644 index 0000000000..6ec5cd98dc --- /dev/null +++ b/Modules/ModelFit/src/Models/mitkThreeStepLinearModel.cpp @@ -0,0 +1,321 @@ +/*============================================================================ + +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 "mitkThreeStepLinearModel.h" +#include + +const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_y_bl = "baseline"; +const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_x0 = "x_changepoint1"; +const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_x1 = "x_changepoint2"; +const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_b0 = "slope1"; +const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_b1 = "slope2"; + +const unsigned int mitk::ThreeStepLinearModel::NUMBER_OF_PARAMETERS = 5; + +const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_y_bl = "[unit of y]"; +const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_x0 = "[unit of x]"; +const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_x1 = "[unit of x]"; +const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_b0 = "[unit of y]/[unit of x]"; +const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_b1 = "[unit of y]/[unit of x]"; + +const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_y_bl = 0; +const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_x0 = 1; +const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_x1 = 2; +const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_b0 = 3; +const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_b1 = 4; + +const std::string mitk::ThreeStepLinearModel::NAME_DERIVED_PARAMETER_auc = "auc"; +const std::string mitk::ThreeStepLinearModel::NAME_DERIVED_PARAMETER_x_fin = "x_final"; +const std::string mitk::ThreeStepLinearModel::NAME_DERIVED_PARAMETER_y_fin = "y_final"; +const std::string mitk::ThreeStepLinearModel::NAME_DERIVED_PARAMETER_y_max = "y_max"; +const std::string mitk::ThreeStepLinearModel::NAME_DERIVED_PARAMETER_y1 = "y-intercept1"; +const std::string mitk::ThreeStepLinearModel::NAME_DERIVED_PARAMETER_y2 = "y-intercept2"; + +const unsigned int mitk::ThreeStepLinearModel::NUMBER_OF_DERIVED_PARAMETERS = 6; + +const std::string mitk::ThreeStepLinearModel::UNIT_DERIVED_PARAMETER_auc = "[unit of x]*[unit of y]"; +const std::string mitk::ThreeStepLinearModel::UNIT_DERIVED_PARAMETER_x_fin = "[unit of x]"; +const std::string mitk::ThreeStepLinearModel::UNIT_DERIVED_PARAMETER_y_fin = "[unit of y]"; +const std::string mitk::ThreeStepLinearModel::UNIT_DERIVED_PARAMETER_y_max = "[unit of y]"; +const std::string mitk::ThreeStepLinearModel::UNIT_DERIVED_PARAMETER_y1 = "[unit of y]"; +const std::string mitk::ThreeStepLinearModel::UNIT_DERIVED_PARAMETER_y2 = "[unit of y]"; + +const unsigned int mitk::ThreeStepLinearModel::NUMBER_OF_STATIC_PARAMETERS = 0; + +const std::string mitk::ThreeStepLinearModel::MODEL_DISPLAY_NAME = "Three Step Linear Model"; + +const std::string mitk::ThreeStepLinearModel::MODEL_TYPE = "Generic"; + +const std::string mitk::ThreeStepLinearModel::FUNCTION_STRING = "if x < x_changepoint1: y(x) = baseline, else if x_changepoint1 <= x <= x_changepoint2: y(x) = y-intercept1 + slope1*x, else if x>x_changepoint2: y(x) = y-intercept2 + slope2*x"; + +const std::string mitk::ThreeStepLinearModel::X_NAME = "x"; + +const std::string mitk::ThreeStepLinearModel::X_AXIS_NAME = "X"; + +const std::string mitk::ThreeStepLinearModel::X_AXIS_UNIT = "unit of x"; + +const std::string mitk::ThreeStepLinearModel::Y_AXIS_NAME = "Y"; + +const std::string mitk::ThreeStepLinearModel::Y_AXIS_UNIT = "unit of y"; + + +std::string mitk::ThreeStepLinearModel::GetModelDisplayName() const +{ + return MODEL_DISPLAY_NAME; +}; + +std::string mitk::ThreeStepLinearModel::GetModelType() const +{ + return MODEL_TYPE; +}; + +mitk::ThreeStepLinearModel::FunctionStringType mitk::ThreeStepLinearModel::GetFunctionString() const +{ + return FUNCTION_STRING; +}; + +std::string mitk::ThreeStepLinearModel::GetXName() const +{ + return X_NAME; +}; + +std::string mitk::ThreeStepLinearModel::GetXAxisName() const +{ + return X_AXIS_NAME; +}; + +std::string mitk::ThreeStepLinearModel::GetXAxisUnit() const +{ + return X_AXIS_UNIT; +} + +std::string mitk::ThreeStepLinearModel::GetYAxisName() const +{ + return Y_AXIS_NAME; +}; + +std::string mitk::ThreeStepLinearModel::GetYAxisUnit() const +{ + return Y_AXIS_UNIT; +} + +mitk::ThreeStepLinearModel::ParameterNamesType +mitk::ThreeStepLinearModel::GetParameterNames() const +{ + ParameterNamesType result; + result.push_back(NAME_PARAMETER_y_bl); + result.push_back(NAME_PARAMETER_x0); + result.push_back(NAME_PARAMETER_x1); + result.push_back(NAME_PARAMETER_b0); + result.push_back(NAME_PARAMETER_b1); + return result; +}; + +mitk::ThreeStepLinearModel::ParamterUnitMapType mitk::ThreeStepLinearModel::GetParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_PARAMETER_y_bl, UNIT_PARAMETER_y_bl)); + result.insert(std::make_pair(NAME_PARAMETER_x0, UNIT_PARAMETER_x0)); + result.insert(std::make_pair(NAME_PARAMETER_x1, UNIT_PARAMETER_x1)); + result.insert(std::make_pair(NAME_PARAMETER_b0, UNIT_PARAMETER_b0)); + result.insert(std::make_pair(NAME_PARAMETER_b1, UNIT_PARAMETER_b1)); + + return result; +} + +mitk::ThreeStepLinearModel::ParametersSizeType +mitk::ThreeStepLinearModel::GetNumberOfParameters() const +{ + return NUMBER_OF_PARAMETERS; +}; + +mitk::ThreeStepLinearModel::ParameterNamesType +mitk::ThreeStepLinearModel::GetDerivedParameterNames() const +{ + ParameterNamesType result; + result.push_back(NAME_DERIVED_PARAMETER_auc); + result.push_back(NAME_DERIVED_PARAMETER_x_fin); + result.push_back(NAME_DERIVED_PARAMETER_y_fin); + result.push_back(NAME_DERIVED_PARAMETER_y_max); + result.push_back(NAME_DERIVED_PARAMETER_y1); + result.push_back(NAME_DERIVED_PARAMETER_y2); + return result; +}; + +mitk::ThreeStepLinearModel::ParametersSizeType +mitk::ThreeStepLinearModel::GetNumberOfDerivedParameters() const +{ + return NUMBER_OF_DERIVED_PARAMETERS; +}; + +mitk::ThreeStepLinearModel::ParamterUnitMapType mitk::ThreeStepLinearModel::GetDerivedParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_auc, UNIT_DERIVED_PARAMETER_auc)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_x_fin, UNIT_DERIVED_PARAMETER_x_fin)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y_fin, UNIT_DERIVED_PARAMETER_y_fin)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y_max, UNIT_DERIVED_PARAMETER_y_max)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y1, UNIT_DERIVED_PARAMETER_y1)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y2, UNIT_DERIVED_PARAMETER_y2)); + + return result; +}; + + +double mitk::ThreeStepLinearModel::ComputeSignalFromParameters(double x, double y_bl, double x0, double x1, double b0, double b1, double y1, double y2) +{ + double signal = 0.0; + + if (x < x0) + { + signal = y_bl; + } + else if (x >= x0 && x <= x1) + { + signal = b0 * x + y1; + } + else + { + signal = b1 * x + y2; + } + + + return signal; +}; + + +mitk::ThreeStepLinearModel::ModelResultType +mitk::ThreeStepLinearModel::ComputeModelfunction(const ParametersType& parameters) const +{ + //Model Parameters + const double y_bl = (double) parameters[POSITION_PARAMETER_y_bl]; + const double x0 = (double) parameters[POSITION_PARAMETER_x0] ; + const double x1 = (double) parameters[POSITION_PARAMETER_x1] ; + const double b0 = (double) parameters[POSITION_PARAMETER_b0] ; + const double b1 = (double) parameters[POSITION_PARAMETER_b1] ; + + double y1 = y_bl - b0 * x0; + double y2 = (b0 * x1 + y1) - (b1 * x1); + + ModelResultType signal(m_TimeGrid.GetSize()); + + TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); + + ModelResultType::iterator signalPos = signal.begin(); + + for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd; ++gridPos, ++signalPos) + { + *signalPos = ComputeSignalFromParameters(*gridPos, y_bl, x0, x1, b0, b1, y1, y2); + } + + return signal; +}; + +mitk::ThreeStepLinearModel::ParameterNamesType mitk::ThreeStepLinearModel::GetStaticParameterNames() const +{ + ParameterNamesType result; + + return result; +} + +mitk::ThreeStepLinearModel::ParametersSizeType mitk::ThreeStepLinearModel::GetNumberOfStaticParameters() const +{ + return 0; +} + +void mitk::ThreeStepLinearModel::SetStaticParameter(const ParameterNameType&, + const StaticParameterValuesType&) +{ + //do nothing +}; + +mitk::ThreeStepLinearModel::StaticParameterValuesType mitk::ThreeStepLinearModel::GetStaticParameterValue( + const ParameterNameType&) const +{ + StaticParameterValuesType result; + + //do nothing + + return result; +}; + +mitk::ModelBase::DerivedParameterMapType mitk::ThreeStepLinearModel::ComputeDerivedParameters( + const mitk::ModelBase::ParametersType& parameters) const +{ + const double y_bl = (double) parameters[POSITION_PARAMETER_y_bl]; + const double x0 = (double) parameters[POSITION_PARAMETER_x0] ; + const double x1 = (double) parameters[POSITION_PARAMETER_x1] ; + const double b0 = (double) parameters[POSITION_PARAMETER_b0] ; + const double b1 = (double) parameters[POSITION_PARAMETER_b1] ; + + const double y1 = y_bl - b0 * x0; + const double y2 = (b0 * x1 + y1) - (b1 * x1); + + unsigned int timeSteps = m_TimeGrid.GetSize(); + + const double x_fin = (m_TimeGrid.empty() == false) ? (m_TimeGrid.GetElement(timeSteps - 1)) : ( mitkThrow() << "An exception occured because time grid is empty, method can't continue."); + + const double y_fin = b1 * x_fin + y2; + + double y_max = y_fin; + if ((b0 >= 0) && (b1 >= 0)) + y_max = y_fin; + else if ((b0 < 0) && (b1 < 0)) + y_max = y_bl; + else if ((b0 > 0) && (b1 < 0)) + y_max = (b0 * x1 + y1); + else + { + if (abs(b0 * (x1 - x0)) >= abs(b1 * (x_fin - x1))) + y_max = y_bl; + else y_max = y_fin; + } + + double auc = 0.0; + TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); + + for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd - 1; ++gridPos) + { + double currentGridPos = *gridPos; + double nextGridPos = *(++gridPos); + double deltaX = nextGridPos - currentGridPos; + double deltaY = ComputeSignalFromParameters(nextGridPos, y_bl, x0, x1, b0, b1, y1, y2) - ComputeSignalFromParameters(currentGridPos, y_bl, x0, x1, b0, b1, y1, y2); + double Yi = ComputeSignalFromParameters(currentGridPos, y_bl, x0, x1, b0, b1, y1, y2 ); + double intI = 0.5 * deltaX * deltaY + Yi * deltaX; + auc += std::abs(intI); + --gridPos; + } + + + DerivedParameterMapType result; + + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_auc, auc)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_x_fin, x_fin)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y_fin, y_fin)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y_max, y_max)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y1, y1)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y2, y2)); + + + return result; +}; + +itk::LightObject::Pointer mitk::ThreeStepLinearModel::InternalClone() const +{ + ThreeStepLinearModel::Pointer newClone = ThreeStepLinearModel::New(); + + newClone->SetTimeGrid(this->m_TimeGrid); + + return newClone.GetPointer(); +}; diff --git a/Modules/Pharmacokinetics/src/Models/mitkThreeStepLinearModelFactory.cpp b/Modules/ModelFit/src/Models/mitkThreeStepLinearModelFactory.cpp similarity index 100% rename from Modules/Pharmacokinetics/src/Models/mitkThreeStepLinearModelFactory.cpp rename to Modules/ModelFit/src/Models/mitkThreeStepLinearModelFactory.cpp diff --git a/Modules/Pharmacokinetics/src/Models/mitkThreeStepLinearModelParameterizer.cpp b/Modules/ModelFit/src/Models/mitkThreeStepLinearModelParameterizer.cpp similarity index 92% rename from Modules/Pharmacokinetics/src/Models/mitkThreeStepLinearModelParameterizer.cpp rename to Modules/ModelFit/src/Models/mitkThreeStepLinearModelParameterizer.cpp index 6eb6bcf471..3c4dfda211 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkThreeStepLinearModelParameterizer.cpp +++ b/Modules/ModelFit/src/Models/mitkThreeStepLinearModelParameterizer.cpp @@ -1,29 +1,29 @@ /*============================================================================ 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 "mitkThreeStepLinearModelParameterizer.h" mitk::ThreeStepLinearModelParameterizer::ParametersType mitk::ThreeStepLinearModelParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(5); - initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_s0] = 0.0; - initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_t1] = 50.0; - initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_t2] = 100.0; - initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_a1] = 1.0; - initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_a2] = -1.0; + initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_y_bl] = 0.0; + initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_x0] = 50.0; + initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_x1] = 100.0; + initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_b0] = 1.0; + initialParameters[mitk:: ThreeStepLinearModel::POSITION_PARAMETER_b1] = -1.0; return initialParameters; }; diff --git a/Modules/ModelFit/src/Models/mitkTwoStepLinearModel.cpp b/Modules/ModelFit/src/Models/mitkTwoStepLinearModel.cpp new file mode 100644 index 0000000000..ab17e6770f --- /dev/null +++ b/Modules/ModelFit/src/Models/mitkTwoStepLinearModel.cpp @@ -0,0 +1,285 @@ +/*============================================================================ + +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 "mitkTwoStepLinearModel.h" +#include + + +const std::string mitk::TwoStepLinearModel::NAME_PARAMETER_y0 = "y-intercept"; +const std::string mitk::TwoStepLinearModel::NAME_PARAMETER_x0 = "x_changepoint"; +const std::string mitk::TwoStepLinearModel::NAME_PARAMETER_b0 = "slope1"; +const std::string mitk::TwoStepLinearModel::NAME_PARAMETER_b1 = "slope2"; + +const unsigned int mitk::TwoStepLinearModel::NUMBER_OF_PARAMETERS = 4; + +const std::string mitk::TwoStepLinearModel::UNIT_PARAMETER_y0 = "[unit of y]"; +const std::string mitk::TwoStepLinearModel::UNIT_PARAMETER_x0 = "[unit of x]"; +const std::string mitk::TwoStepLinearModel::UNIT_PARAMETER_b0 = "[unit of y]/[unit of x]"; +const std::string mitk::TwoStepLinearModel::UNIT_PARAMETER_b1 = "[unit of y]/[unit of x]"; + +const unsigned int mitk::TwoStepLinearModel::POSITION_PARAMETER_y0 = 0; +const unsigned int mitk::TwoStepLinearModel::POSITION_PARAMETER_x0 = 1; +const unsigned int mitk::TwoStepLinearModel::POSITION_PARAMETER_b0 = 2; +const unsigned int mitk::TwoStepLinearModel::POSITION_PARAMETER_b1 = 3; + +const std::string mitk::TwoStepLinearModel::NAME_DERIVED_PARAMETER_auc = "auc"; +const std::string mitk::TwoStepLinearModel::NAME_DERIVED_PARAMETER_y_fin = "y_final"; +const std::string mitk::TwoStepLinearModel::NAME_DERIVED_PARAMETER_y_max = "y_max"; +const std::string mitk::TwoStepLinearModel::NAME_DERIVED_PARAMETER_y1 = "y-intercept1"; + +const unsigned int mitk::TwoStepLinearModel::NUMBER_OF_DERIVED_PARAMETERS = 4; + +const std::string mitk::TwoStepLinearModel::UNIT_DERIVED_PARAMETER_auc = "[unit of x]*[unit of y]"; +const std::string mitk::TwoStepLinearModel::UNIT_DERIVED_PARAMETER_y_fin = "[unit of y]"; +const std::string mitk::TwoStepLinearModel::UNIT_DERIVED_PARAMETER_y_max = "[unit of y]"; +const std::string mitk::TwoStepLinearModel::UNIT_DERIVED_PARAMETER_y1 = "[unit of y]"; + +const unsigned int mitk::TwoStepLinearModel::NUMBER_OF_STATIC_PARAMETERS = 0; + +const std::string mitk::TwoStepLinearModel::MODEL_DISPLAY_NAME = "Two Step Linear Model"; + +const std::string mitk::TwoStepLinearModel::MODEL_TYPE = "Generic"; + +const std::string mitk::TwoStepLinearModel::FUNCTION_STRING = "if x < x_changepoint: y(x) = y-intercept + slope1*x, else: y(x) = y-intercept1 + slope2*x"; + +const std::string mitk::TwoStepLinearModel::X_NAME = "x"; + +const std::string mitk::TwoStepLinearModel::X_AXIS_NAME = "X"; + +const std::string mitk::TwoStepLinearModel::X_AXIS_UNIT = "unit of x"; + +const std::string mitk::TwoStepLinearModel::Y_AXIS_NAME = "Y"; + +const std::string mitk::TwoStepLinearModel::Y_AXIS_UNIT = "unit of y"; + + +std::string mitk::TwoStepLinearModel::GetModelDisplayName() const +{ + return MODEL_DISPLAY_NAME; +}; + +std::string mitk::TwoStepLinearModel::GetModelType() const +{ + return MODEL_TYPE; +}; + +mitk::TwoStepLinearModel::FunctionStringType mitk::TwoStepLinearModel::GetFunctionString() const +{ + return FUNCTION_STRING; +}; + +std::string mitk::TwoStepLinearModel::GetXName() const +{ + return X_NAME; +}; + +std::string mitk::TwoStepLinearModel::GetXAxisName() const +{ + return X_AXIS_NAME; +}; + +std::string mitk::TwoStepLinearModel::GetXAxisUnit() const +{ + return X_AXIS_UNIT; +} + +std::string mitk::TwoStepLinearModel::GetYAxisName() const +{ + return Y_AXIS_NAME; +}; + +std::string mitk::TwoStepLinearModel::GetYAxisUnit() const +{ + return Y_AXIS_UNIT; +} + +mitk::TwoStepLinearModel::ParameterNamesType +mitk::TwoStepLinearModel::GetParameterNames() const +{ + ParameterNamesType result; + result.push_back(NAME_PARAMETER_y0); + result.push_back(NAME_PARAMETER_x0); + result.push_back(NAME_PARAMETER_b0); + result.push_back(NAME_PARAMETER_b1); + return result; +}; + +mitk::TwoStepLinearModel::ParamterUnitMapType mitk::TwoStepLinearModel::GetParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_PARAMETER_y0, UNIT_PARAMETER_y0)); + result.insert(std::make_pair(NAME_PARAMETER_x0, UNIT_PARAMETER_x0)); + result.insert(std::make_pair(NAME_PARAMETER_b0, UNIT_PARAMETER_b0)); + result.insert(std::make_pair(NAME_PARAMETER_b1, UNIT_PARAMETER_b1)); + + return result; +} + +mitk::TwoStepLinearModel::ParametersSizeType +mitk::TwoStepLinearModel::GetNumberOfParameters() const +{ + return NUMBER_OF_PARAMETERS; +}; + +mitk::TwoStepLinearModel::ParameterNamesType +mitk::TwoStepLinearModel::GetDerivedParameterNames() const +{ + ParameterNamesType result; + result.push_back(NAME_DERIVED_PARAMETER_auc); + result.push_back(NAME_DERIVED_PARAMETER_y_fin); + result.push_back(NAME_DERIVED_PARAMETER_y_max); + result.push_back(NAME_DERIVED_PARAMETER_y1); + return result; +}; + +mitk::TwoStepLinearModel::ParametersSizeType +mitk::TwoStepLinearModel::GetNumberOfDerivedParameters() const +{ + return NUMBER_OF_DERIVED_PARAMETERS; +}; + +mitk::TwoStepLinearModel::ParamterUnitMapType mitk::TwoStepLinearModel::GetDerivedParameterUnits() const +{ + ParamterUnitMapType result; + + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_auc, UNIT_DERIVED_PARAMETER_auc)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y_fin, UNIT_DERIVED_PARAMETER_y_fin)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y_max, UNIT_DERIVED_PARAMETER_y_max)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y1, UNIT_DERIVED_PARAMETER_y1)); + + return result; +}; + +double mitk::TwoStepLinearModel::ComputeSignalFromParameters(double x, double x0, double b0, double b1, double y0, double y1) +{ + return (x < x0) ? (b0 * x + y0) : (b1 * x + y1); +}; + + + + +mitk::TwoStepLinearModel::ModelResultType +mitk::TwoStepLinearModel::ComputeModelfunction(const ParametersType& parameters) const +{ + + //Model Parameters + const auto y0 = parameters[POSITION_PARAMETER_y0]; + const auto x0 = parameters[POSITION_PARAMETER_x0] ; + const auto b0 = parameters[POSITION_PARAMETER_b0] ; + const auto b1 = parameters[POSITION_PARAMETER_b1] ; + + double y1 = (b0 - b1) * x0 + y0; + + ModelResultType signal(m_TimeGrid.GetSize()); + + TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); + + ModelResultType::iterator signalPos = signal.begin(); + + for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd; ++gridPos, ++signalPos) + { + *signalPos = ComputeSignalFromParameters(*gridPos, x0, b0, b1, y0, y1); + } + + return signal; +}; + +mitk::TwoStepLinearModel::ParameterNamesType mitk::TwoStepLinearModel::GetStaticParameterNames() const +{ + ParameterNamesType result; + + return result; +} + +mitk::TwoStepLinearModel::ParametersSizeType mitk::TwoStepLinearModel::GetNumberOfStaticParameters() const +{ + return 0; +} + +void mitk::TwoStepLinearModel::SetStaticParameter(const ParameterNameType& /*name*/, + const StaticParameterValuesType& /*values*/) +{ + //do nothing +}; + +mitk::TwoStepLinearModel::StaticParameterValuesType mitk::TwoStepLinearModel::GetStaticParameterValue( + const ParameterNameType& /*name*/) const +{ + StaticParameterValuesType result; + + //do nothing + + return result; +}; + +mitk::ModelBase::DerivedParameterMapType mitk::TwoStepLinearModel::ComputeDerivedParameters( + const mitk::ModelBase::ParametersType& parameters) const +{ + const auto y0 = parameters[POSITION_PARAMETER_y0]; + const auto x0 = parameters[POSITION_PARAMETER_x0] ; + const auto b0 = parameters[POSITION_PARAMETER_b0] ; + const auto b1 = parameters[POSITION_PARAMETER_b1] ; + const auto y1 = (b0 - b1) * x0 + y0; + + unsigned int timeSteps = m_TimeGrid.GetSize(); + + const double taq = (m_TimeGrid.empty() == false) ? (m_TimeGrid.GetElement(timeSteps - 1)) : (mitkThrow() << "An exception occured because time grid is empty, method can't continue."); + + const double y_fin = b1 * taq + y1; + + double y_max = y_fin; + if ((b0 >= 0) && (b1 >= 0)) + y_max = y_fin; + else if ((b0 < 0) && (b1 < 0)) + y_max = y0; + else if ((b0 > 0) && (b1 < 0)) + y_max = (b0 * x0 + y0); + else + { + if (abs(b0 * x0) >= abs(b1 * (taq - x0))) + y_max = y0; + else y_max = y_fin; + } + + double auc = 0.0; + TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); + for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd -1; ++gridPos) + { + double currentGridPos = *gridPos; + double nextGridPos = *(++gridPos); + double deltaX = nextGridPos - currentGridPos; + double deltaY = ComputeSignalFromParameters(nextGridPos, x0, b0, b1, y0, y1) - ComputeSignalFromParameters(currentGridPos, x0, b0, b1, y0, y1); + double Yi = ComputeSignalFromParameters(currentGridPos, x0, b0, b1, y0, y1); + double intI = 0.5 * deltaX * deltaY + Yi * deltaX; + auc += std::abs(intI); + --gridPos; + } + + DerivedParameterMapType result; + + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_auc, auc)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y_fin, y_fin)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y_max, y_max)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_y1, y1)); + + return result; +}; + +itk::LightObject::Pointer mitk::TwoStepLinearModel::InternalClone() const +{ + TwoStepLinearModel::Pointer newClone = TwoStepLinearModel::New(); + + newClone->SetTimeGrid(this->m_TimeGrid); + + return newClone.GetPointer(); +}; diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModelFactory.cpp b/Modules/ModelFit/src/Models/mitkTwoStepLinearModelFactory.cpp similarity index 100% rename from Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModelFactory.cpp rename to Modules/ModelFit/src/Models/mitkTwoStepLinearModelFactory.cpp diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModelParameterizer.cpp b/Modules/ModelFit/src/Models/mitkTwoStepLinearModelParameterizer.cpp similarity index 94% rename from Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModelParameterizer.cpp rename to Modules/ModelFit/src/Models/mitkTwoStepLinearModelParameterizer.cpp index 29f6b5287c..b41341ed65 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModelParameterizer.cpp +++ b/Modules/ModelFit/src/Models/mitkTwoStepLinearModelParameterizer.cpp @@ -1,28 +1,28 @@ /*============================================================================ 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 "mitkTwoStepLinearModelParameterizer.h" mitk::TwoStepLinearModelParameterizer::ParametersType mitk::TwoStepLinearModelParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(4); - initialParameters[mitk:: TwoStepLinearModel::POSITION_PARAMETER_y1] = 0.0; - initialParameters[mitk:: TwoStepLinearModel::POSITION_PARAMETER_t] = 50; - initialParameters[mitk:: TwoStepLinearModel::POSITION_PARAMETER_a1] = 1.0; - initialParameters[mitk:: TwoStepLinearModel::POSITION_PARAMETER_a2] = -1.0; + initialParameters[mitk:: TwoStepLinearModel::POSITION_PARAMETER_y0] = 0.0; + initialParameters[mitk:: TwoStepLinearModel::POSITION_PARAMETER_x0] = 50; + initialParameters[mitk:: TwoStepLinearModel::POSITION_PARAMETER_b0] = 1.0; + initialParameters[mitk:: TwoStepLinearModel::POSITION_PARAMETER_b1] = -1.0; return initialParameters; }; diff --git a/Modules/ModelFit/test/files.cmake b/Modules/ModelFit/test/files.cmake index e0b2725304..c201b63062 100644 --- a/Modules/ModelFit/test/files.cmake +++ b/Modules/ModelFit/test/files.cmake @@ -1,19 +1,22 @@ SET(MODULE_TESTS itkMultiOutputNaryFunctorImageFilterTest.cpp itkMaskedStatisticsImageFilterTest.cpp itkMaskedNaryStatisticsImageFilterTest.cpp mitkLevenbergMarquardtModelFitFunctorTest.cpp mitkPixelBasedParameterFitImageGeneratorTest.cpp mitkROIBasedParameterFitImageGeneratorTest.cpp mitkMaskedDynamicImageStatisticsGeneratorTest.cpp mitkModelFitInfoTest.cpp mitkModelFitStaticParameterMapTest.cpp mitkSimpleBarrierConstraintCheckerTest.cpp mitkMVConstrainedCostFunctionDecoratorTest.cpp mitkConcreteModelFactoryBaseTest.cpp mitkFormulaParserTest.cpp mitkModelFitResultRelationRuleTest.cpp - mitkT2DecayModelTest.cpp + mitkExponentialDecayModelTest.cpp mitkLinearModelTest.cpp mitkExpDecayOffsetModelTest.cpp + mitkTwoStepLinearModelTest.cpp + mitkThreeStepLinearModelTest.cpp + mitkExponentialSaturationModelTest.cpp ) diff --git a/Modules/ModelFit/test/mitkT2DecayModelTest.cpp b/Modules/ModelFit/test/mitkExponentialDecayModelTest.cpp similarity index 72% copy from Modules/ModelFit/test/mitkT2DecayModelTest.cpp copy to Modules/ModelFit/test/mitkExponentialDecayModelTest.cpp index b66b4f5398..4a2cfc9150 100644 --- a/Modules/ModelFit/test/mitkT2DecayModelTest.cpp +++ b/Modules/ModelFit/test/mitkExponentialDecayModelTest.cpp @@ -1,66 +1,66 @@ /*============================================================================ 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. ============================================================================*/ // Testing #include "mitkModelTestFixture.h" //MITK includes -#include "mitkT2DecayModel.h" +#include "mitkExponentialDecayModel.h" - class mitkT2DecayModelTestSuite : public mitk::mitkModelTestFixture + class mitkExponentialDecayModelTestSuite : public mitk::mitkModelTestFixture { - CPPUNIT_TEST_SUITE(mitkT2DecayModelTestSuite); + CPPUNIT_TEST_SUITE(mitkExponentialDecayModelTestSuite); MITK_TEST(GetModelInfoTest); MITK_TEST(ComputeModelfunctionTest); MITK_TEST(ComputeDerivedParametersTest); CPPUNIT_TEST_SUITE_END(); private: json m_profile_json_obj; json m_modelValues_json_obj; mitk::ModelBase::Pointer m_testmodel; public: void setUp() override { // Parse JSON files - m_profile_json_obj = ParseJSONFile("ModelFit/mitkT2DecayModelTest_profile.json"); - m_modelValues_json_obj = ParseJSONFile("ModelFit/mitkT2DecayModelTest_modelValues.json"); + m_profile_json_obj = ParseJSONFile("ModelFit/mitkExponentialDecayModelTest_profile.json"); + m_modelValues_json_obj = ParseJSONFile("ModelFit/mitkExponentialDecayModelTest_modelValues.json"); // Generate test model - m_testmodel = mitk::T2DecayModel::New(); + m_testmodel = mitk::ExponentialDecayModel::New(); } void tearDown() override { } void GetModelInfoTest() { // comparison of reference and testmodel profile CompareModelAndReferenceProfile(m_testmodel, m_profile_json_obj); } void ComputeModelfunctionTest() { CompareModelAndReferenceSignal(m_testmodel, m_modelValues_json_obj, m_profile_json_obj); } void ComputeDerivedParametersTest() { CompareModelAndReferenceDerivedParameters(m_testmodel, m_modelValues_json_obj); } }; -MITK_TEST_SUITE_REGISTRATION(mitkT2DecayModel) +MITK_TEST_SUITE_REGISTRATION(mitkExponentialDecayModel) diff --git a/Modules/ModelFit/test/mitkT2DecayModelTest.cpp b/Modules/ModelFit/test/mitkExponentialSaturationModelTest.cpp similarity index 71% rename from Modules/ModelFit/test/mitkT2DecayModelTest.cpp rename to Modules/ModelFit/test/mitkExponentialSaturationModelTest.cpp index b66b4f5398..88e36f007a 100644 --- a/Modules/ModelFit/test/mitkT2DecayModelTest.cpp +++ b/Modules/ModelFit/test/mitkExponentialSaturationModelTest.cpp @@ -1,66 +1,66 @@ /*============================================================================ 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. ============================================================================*/ // Testing #include "mitkModelTestFixture.h" //MITK includes -#include "mitkT2DecayModel.h" +#include "mitkExponentialSaturationModel.h" - class mitkT2DecayModelTestSuite : public mitk::mitkModelTestFixture + class mitkExponentialSaturationModelTestSuite : public mitk::mitkModelTestFixture { - CPPUNIT_TEST_SUITE(mitkT2DecayModelTestSuite); + CPPUNIT_TEST_SUITE(mitkExponentialSaturationModelTestSuite); MITK_TEST(GetModelInfoTest); MITK_TEST(ComputeModelfunctionTest); MITK_TEST(ComputeDerivedParametersTest); CPPUNIT_TEST_SUITE_END(); private: json m_profile_json_obj; json m_modelValues_json_obj; mitk::ModelBase::Pointer m_testmodel; public: void setUp() override { // Parse JSON files - m_profile_json_obj = ParseJSONFile("ModelFit/mitkT2DecayModelTest_profile.json"); - m_modelValues_json_obj = ParseJSONFile("ModelFit/mitkT2DecayModelTest_modelValues.json"); + m_profile_json_obj = ParseJSONFile("ModelFit/mitkExponentialSaturationModelTest_profile.json"); + m_modelValues_json_obj = ParseJSONFile("ModelFit/mitkExponentialSaturationModelTest_modelValues.json"); // Generate test model - m_testmodel = mitk::T2DecayModel::New(); + m_testmodel = mitk::ExponentialSaturationModel::New(); } void tearDown() override { } void GetModelInfoTest() { // comparison of reference and testmodel profile CompareModelAndReferenceProfile(m_testmodel, m_profile_json_obj); } void ComputeModelfunctionTest() { CompareModelAndReferenceSignal(m_testmodel, m_modelValues_json_obj, m_profile_json_obj); } void ComputeDerivedParametersTest() { CompareModelAndReferenceDerivedParameters(m_testmodel, m_modelValues_json_obj); } }; -MITK_TEST_SUITE_REGISTRATION(mitkT2DecayModel) +MITK_TEST_SUITE_REGISTRATION(mitkExponentialSaturationModel) diff --git a/Modules/ModelFit/test/mitkPixelBasedParameterFitImageGeneratorTest.cpp b/Modules/ModelFit/test/mitkPixelBasedParameterFitImageGeneratorTest.cpp index 021df68dee..2fa166c061 100644 --- a/Modules/ModelFit/test/mitkPixelBasedParameterFitImageGeneratorTest.cpp +++ b/Modules/ModelFit/test/mitkPixelBasedParameterFitImageGeneratorTest.cpp @@ -1,155 +1,155 @@ /*============================================================================ 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 #include "itkImageRegionIterator.h" #include "mitkTestingMacros.h" #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkPixelBasedParameterFitImageGenerator.h" #include "mitkLinearModelParameterizer.h" #include "mitkLevenbergMarquardtModelFitFunctor.h" #include "mitkTestDynamicImageGenerator.h" int mitkPixelBasedParameterFitImageGeneratorTest(int /*argc*/, char*[] /*argv[]*/) { // always start with this! MITK_TEST_BEGIN("mitkPixelBasedParameterFitImageGenerator") //Prepare test artifacts and helper itk::Index<3> testIndex1; testIndex1[0] = 0; testIndex1[1] = 0; testIndex1[2] = 0; itk::Index<3> testIndex2; testIndex2[0] = 2; testIndex2[1] = 0; testIndex2[2] = 1; itk::Index<3> testIndex3; testIndex3[0] = 1; testIndex3[1] = 1; testIndex3[2] = 2; itk::Index<3> testIndex4; testIndex4[0] = 2; testIndex4[1] = 2; testIndex4[2] = 0; itk::Index<3> testIndex5; testIndex5[0] = 1; testIndex5[1] = 1; testIndex5[2] = 1; itk::Index<3> testIndex6; testIndex6[0] = 2; testIndex6[1] = 1; testIndex6[2] = 1; mitk::Image::Pointer dynamicImage = mitk::GenerateDynamicTestImageMITK(); mitk::LinearModel::Pointer model = mitk::LinearModel::New(); mitk::LevenbergMarquardtModelFitFunctor::Pointer testFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); //Test default usage of filter mitk::PixelBasedParameterFitImageGenerator::Pointer generator = mitk::PixelBasedParameterFitImageGenerator::New(); mitk::LinearModelParameterizer::Pointer parameterizer = mitk::LinearModelParameterizer::New(); generator->SetDynamicImage(dynamicImage); generator->SetModelParameterizer(parameterizer); generator->SetFitFunctor(testFunctor); generator->Generate(); mitk::PixelBasedParameterFitImageGenerator::ParameterImageMapType resultImages = generator->GetParameterImages(); mitk::PixelBasedParameterFitImageGenerator::ParameterImageMapType derivedResultImages = generator->GetDerivedParameterImages(); CPPUNIT_ASSERT_MESSAGE("Check number of parameter images", 2 == resultImages.size()); MITK_TEST_CONDITION(resultImages.find("slope") != resultImages.end(),"Check if \"slope\" parameter image exists."); - MITK_TEST_CONDITION(resultImages.find("offset") != resultImages.end(),"Check if \"offset\" parameter image exists."); + MITK_TEST_CONDITION(resultImages.find("y-intercept") != resultImages.end(),"Check if \"y-intercept\" parameter image exists."); CPPUNIT_ASSERT_MESSAGE("Check number of derived parameter images", 1 == derivedResultImages.size()); MITK_TEST_CONDITION(derivedResultImages.find("x-intercept") != derivedResultImages.end(),"Check if \"x-intercept\" derived parameter image exists."); mitk::ImagePixelReadAccessor slopeAccessor(resultImages["slope"]); - mitk::ImagePixelReadAccessor offsetAccessor(resultImages["offset"]); + mitk::ImagePixelReadAccessor yinterceptAccessor(resultImages["y-intercept"]); double testValue = slopeAccessor.GetPixelByIndex(testIndex1); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #1 (slope) at index #1"); testValue = slopeAccessor.GetPixelByIndex(testIndex2); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(2000,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #2"); testValue = slopeAccessor.GetPixelByIndex(testIndex3); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(4000,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #3"); testValue = slopeAccessor.GetPixelByIndex(testIndex4); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(8000,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #4"); - testValue = offsetAccessor.GetPixelByIndex(testIndex1); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #1"); - testValue = offsetAccessor.GetPixelByIndex(testIndex2); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(10,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #2"); - testValue = offsetAccessor.GetPixelByIndex(testIndex3); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(20,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #3"); - testValue = offsetAccessor.GetPixelByIndex(testIndex4); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #4"); + testValue = yinterceptAccessor.GetPixelByIndex(testIndex1); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #1"); + testValue = yinterceptAccessor.GetPixelByIndex(testIndex2); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(10,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #2"); + testValue = yinterceptAccessor.GetPixelByIndex(testIndex3); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(20,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #3"); + testValue = yinterceptAccessor.GetPixelByIndex(testIndex4); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #4"); //Test with mask set mitk::Image::Pointer maskImage = mitk::GenerateTestMaskMITK(); generator->SetMask(maskImage); generator->Generate(); resultImages = generator->GetParameterImages(); derivedResultImages = generator->GetDerivedParameterImages(); CPPUNIT_ASSERT_MESSAGE("Check number of parameter images", 2 == resultImages.size()); MITK_TEST_CONDITION(resultImages.find("slope") != resultImages.end(),"Check if \"slope\" parameter image exists."); - MITK_TEST_CONDITION(resultImages.find("offset") != resultImages.end(),"Check if \"offset\" parameter image exists."); + MITK_TEST_CONDITION(resultImages.find("y-intercept") != resultImages.end(),"Check if \"y-intercept\" parameter image exists."); CPPUNIT_ASSERT_MESSAGE("Check number of derived parameter images", 1 == derivedResultImages.size()); MITK_TEST_CONDITION(derivedResultImages.find("x-intercept") != derivedResultImages.end(),"Check if \"x-intercept\" derived parameter image exists."); mitk::ImagePixelReadAccessor slopeAccessor2(resultImages["slope"]); - mitk::ImagePixelReadAccessor offsetAccessor2(resultImages["offset"]); + mitk::ImagePixelReadAccessor yinterceptAccessor2(resultImages["y-intercept"]); testValue = slopeAccessor2.GetPixelByIndex(testIndex1); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #1 (slope) at index #1"); testValue = slopeAccessor2.GetPixelByIndex(testIndex2); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(2000,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #2"); testValue = slopeAccessor2.GetPixelByIndex(testIndex3); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #1 (slope) at index #3"); testValue = slopeAccessor2.GetPixelByIndex(testIndex4); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(8000,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #4"); testValue = slopeAccessor2.GetPixelByIndex(testIndex5); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(4000,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #5"); testValue = slopeAccessor2.GetPixelByIndex(testIndex6); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #1 (slope) at index #6"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex1); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #1"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex2); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(10,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #2"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex3); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #3"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex4); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #4"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex5); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(10,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #5"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex6); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #6"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex1); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #1"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex2); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(10,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #2"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex3); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #3"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex4); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #4"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex5); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(10,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #5"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex6); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #6"); MITK_TEST_END() } diff --git a/Modules/ModelFit/test/mitkROIBasedParameterFitImageGeneratorTest.cpp b/Modules/ModelFit/test/mitkROIBasedParameterFitImageGeneratorTest.cpp index 8a7c122a57..43f24ca5dd 100644 --- a/Modules/ModelFit/test/mitkROIBasedParameterFitImageGeneratorTest.cpp +++ b/Modules/ModelFit/test/mitkROIBasedParameterFitImageGeneratorTest.cpp @@ -1,138 +1,138 @@ /*============================================================================ 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 #include "itkImageRegionIterator.h" #include "mitkTestingMacros.h" #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkROIBasedParameterFitImageGenerator.h" #include "mitkLinearModelParameterizer.h" #include "mitkLevenbergMarquardtModelFitFunctor.h" #include "mitkTestDynamicImageGenerator.h" int mitkROIBasedParameterFitImageGeneratorTest(int /*argc*/, char*[] /*argv[]*/) { // always start with this! MITK_TEST_BEGIN("mitkROIBasedParameterFitImageGenerator") //Prepare test artifacts and helper itk::Index<3> testIndex1; testIndex1[0] = 0; testIndex1[1] = 0; testIndex1[2] = 0; itk::Index<3> testIndex2; testIndex2[0] = 2; testIndex2[1] = 0; testIndex2[2] = 1; itk::Index<3> testIndex3; testIndex3[0] = 1; testIndex3[1] = 1; testIndex3[2] = 2; itk::Index<3> testIndex4; testIndex4[0] = 2; testIndex4[1] = 2; testIndex4[2] = 0; itk::Index<3> testIndex5; testIndex5[0] = 1; testIndex5[1] = 1; testIndex5[2] = 1; itk::Index<3> testIndex6; testIndex6[0] = 2; testIndex6[1] = 1; testIndex6[2] = 1; mitk::Image::Pointer maskImage = mitk::GenerateTestMaskMITK(); mitk::ROIBasedParameterFitImageGenerator::TimeGridType timeGrid; timeGrid.SetSize(5); timeGrid[0] = 0; timeGrid[1] = 1; timeGrid[2] = 2; timeGrid[3] = 3; timeGrid[4] = 4; mitk::ROIBasedParameterFitImageGenerator::SignalType signal; signal.SetSize(5); signal[0] = 3; signal[1] = 5; signal[2] = 7; signal[3] = 9; signal[4] = 11; mitk::LinearModel::Pointer model = mitk::LinearModel::New(); mitk::LevenbergMarquardtModelFitFunctor::Pointer testFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); //Test default usage of filter mitk::ROIBasedParameterFitImageGenerator::Pointer generator = mitk::ROIBasedParameterFitImageGenerator::New(); mitk::LinearModelParameterizer::Pointer parameterizer = mitk::LinearModelParameterizer::New(); generator->SetModelParameterizer(parameterizer); generator->SetFitFunctor(testFunctor); generator->SetMask(maskImage); generator->SetSignal(signal); generator->SetTimeGrid(timeGrid); generator->Generate(); mitk::ROIBasedParameterFitImageGenerator::ParameterImageMapType resultImages = generator->GetParameterImages(); mitk::ROIBasedParameterFitImageGenerator::ParameterImageMapType derivedResultImages = generator->GetDerivedParameterImages(); CPPUNIT_ASSERT_MESSAGE("Check number of parameter images", 2 == resultImages.size()); MITK_TEST_CONDITION(resultImages.find("slope") != resultImages.end(),"Check if \"slope\" parameter image exists."); - MITK_TEST_CONDITION(resultImages.find("offset") != resultImages.end(),"Check if \"offset\" parameter image exists."); + MITK_TEST_CONDITION(resultImages.find("y-intercept") != resultImages.end(),"Check if \"y-intercept\" parameter image exists."); CPPUNIT_ASSERT_MESSAGE("Check number of derived parameter images", 1 == derivedResultImages.size()); MITK_TEST_CONDITION(derivedResultImages.find("x-intercept") != derivedResultImages.end(),"Check if \"x-intercept\" derived parameter image exists."); mitk::ImagePixelReadAccessor slopeAccessor2(resultImages["slope"]); - mitk::ImagePixelReadAccessor offsetAccessor2(resultImages["offset"]); + mitk::ImagePixelReadAccessor yinterceptAccessor2(resultImages["y-intercept"]); double testValue = slopeAccessor2.GetPixelByIndex(testIndex1); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(2,testValue, 1e-5, true)==true, "Check param #1 (slope) at index #1"); testValue = slopeAccessor2.GetPixelByIndex(testIndex2); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(2,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #2"); testValue = slopeAccessor2.GetPixelByIndex(testIndex3); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #1 (slope) at index #3"); testValue = slopeAccessor2.GetPixelByIndex(testIndex4); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(2,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #4"); testValue = slopeAccessor2.GetPixelByIndex(testIndex5); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(2,testValue, 1e-4, true)==true, "Check param #1 (slope) at index #5"); testValue = slopeAccessor2.GetPixelByIndex(testIndex6); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #1 (slope) at index #6"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex1); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(3,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #1"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex2); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(3,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #2"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex3); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #3"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex4); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(3,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #4"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex5); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(3,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #5"); - testValue = offsetAccessor2.GetPixelByIndex(testIndex6); - MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (offset) at index #6"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex1); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(3,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #1"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex2); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(3,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #2"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex3); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #3"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex4); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(3,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #4"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex5); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(3,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #5"); + testValue = yinterceptAccessor2.GetPixelByIndex(testIndex6); + MITK_TEST_CONDITION_REQUIRED(mitk::Equal(0,testValue, 1e-5, true)==true, "Check param #2 (y-intercept) at index #6"); MITK_TEST_END() } diff --git a/Modules/Pharmacokinetics/test/mitkThreeStepLinearModelTest.cpp b/Modules/ModelFit/test/mitkThreeStepLinearModelTest.cpp similarity index 87% rename from Modules/Pharmacokinetics/test/mitkThreeStepLinearModelTest.cpp rename to Modules/ModelFit/test/mitkThreeStepLinearModelTest.cpp index 074f783c6b..ac5116f7fe 100644 --- a/Modules/Pharmacokinetics/test/mitkThreeStepLinearModelTest.cpp +++ b/Modules/ModelFit/test/mitkThreeStepLinearModelTest.cpp @@ -1,66 +1,66 @@ /*============================================================================ 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. ============================================================================*/ //Testing #include "mitkModelTestFixture.h" //MITK includes #include "mitkThreeStepLinearModel.h" class mitkThreeStepLinearModelTestSuite : public mitk::mitkModelTestFixture { CPPUNIT_TEST_SUITE(mitkThreeStepLinearModelTestSuite); MITK_TEST(GetModelInfoTest); MITK_TEST(ComputeModelfunctionTest); MITK_TEST(ComputeDerivedParametersTest); CPPUNIT_TEST_SUITE_END(); private: mitk::ThreeStepLinearModel::Pointer m_testmodel; json m_profile_json_obj; json m_modelValues_json_obj; public: void setUp() override { // Parse JSON files - m_profile_json_obj = ParseJSONFile("Pharmacokinetics/mitkThreeStepLinearModelTest_profile.json"); - m_modelValues_json_obj = ParseJSONFile("Pharmacokinetics/mitkThreeStepLinearModelTest_modelValues.json"); + m_profile_json_obj = ParseJSONFile("ModelFit/mitkThreeStepLinearModelTest_profile.json"); + m_modelValues_json_obj = ParseJSONFile("ModelFit/mitkThreeStepLinearModelTest_modelValues.json"); // Generate test model m_testmodel = mitk::ThreeStepLinearModel::New(); } void tearDown() override { } void GetModelInfoTest() { // comparison of reference and testmodel profile CompareModelAndReferenceProfile(m_testmodel, m_profile_json_obj); } void ComputeModelfunctionTest() { CompareModelAndReferenceSignal(m_testmodel, m_modelValues_json_obj, m_profile_json_obj); } void ComputeDerivedParametersTest() { CompareModelAndReferenceDerivedParameters(m_testmodel, m_modelValues_json_obj); } }; MITK_TEST_SUITE_REGISTRATION(mitkThreeStepLinearModel) diff --git a/Modules/Pharmacokinetics/test/mitkTwoStepLinearModelTest.cpp b/Modules/ModelFit/test/mitkTwoStepLinearModelTest.cpp similarity index 88% rename from Modules/Pharmacokinetics/test/mitkTwoStepLinearModelTest.cpp rename to Modules/ModelFit/test/mitkTwoStepLinearModelTest.cpp index de8b2e160f..5fcb2448a8 100644 --- a/Modules/Pharmacokinetics/test/mitkTwoStepLinearModelTest.cpp +++ b/Modules/ModelFit/test/mitkTwoStepLinearModelTest.cpp @@ -1,66 +1,66 @@ /*============================================================================ 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. ============================================================================*/ //Testing #include "mitkModelTestFixture.h" //MITK includes #include "mitkTwoStepLinearModel.h" class mitkTwoStepLinearModelTestSuite : public mitk::mitkModelTestFixture { CPPUNIT_TEST_SUITE(mitkTwoStepLinearModelTestSuite); MITK_TEST(GetModelInfoTest); MITK_TEST(ComputeModelfunctionTest); MITK_TEST(ComputeDerivedParametersTest); CPPUNIT_TEST_SUITE_END(); private: mitk::TwoStepLinearModel::Pointer m_testmodel; json m_profile_json_obj; json m_modelValues_json_obj; public: void setUp() override { // Parse JSON files - m_profile_json_obj = ParseJSONFile("Pharmacokinetics/mitkTwoStepLinearModelTest_profile.json"); - m_modelValues_json_obj = ParseJSONFile("Pharmacokinetics/mitkTwoStepLinearModelTest_modelValues.json"); + m_profile_json_obj = ParseJSONFile("ModelFit/mitkTwoStepLinearModelTest_profile.json"); + m_modelValues_json_obj = ParseJSONFile("ModelFit/mitkTwoStepLinearModelTest_modelValues.json"); // Generate test model m_testmodel = mitk::TwoStepLinearModel::New(); } void tearDown() override { } void GetModelInfoTest() { // comparison of reference and testmodel profile CompareModelAndReferenceProfile(m_testmodel, m_profile_json_obj); } void ComputeModelfunctionTest() { CompareModelAndReferenceSignal(m_testmodel, m_modelValues_json_obj, m_profile_json_obj); } void ComputeDerivedParametersTest() { CompareModelAndReferenceDerivedParameters(m_testmodel, m_modelValues_json_obj); } }; MITK_TEST_SUITE_REGISTRATION(mitkTwoStepLinearModel) diff --git a/Modules/Pharmacokinetics/autoload/Models/mitkPharmacokineticModelsActivator.cpp b/Modules/Pharmacokinetics/autoload/Models/mitkPharmacokineticModelsActivator.cpp index d67c683c15..f406aa87b1 100644 --- a/Modules/Pharmacokinetics/autoload/Models/mitkPharmacokineticModelsActivator.cpp +++ b/Modules/Pharmacokinetics/autoload/Models/mitkPharmacokineticModelsActivator.cpp @@ -1,82 +1,73 @@ /*============================================================================ 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 #include #include //MR perfusion models #include "mitkDescriptivePharmacokineticBrixModelFactory.h" #include "mitkExtendedToftsModelFactory.h" #include "mitkStandardToftsModelFactory.h" #include "mitkTwoCompartmentExchangeModelFactory.h" -#include "mitkNumericTwoCompartmentExchangeModelFactory.h" //PET perfusion models #include "mitkOneTissueCompartmentModelFactory.h" #include "mitkExtendedOneTissueCompartmentModelFactory.h" #include "mitkTwoTissueCompartmentModelFactory.h" #include "mitkTwoTissueCompartmentFDGModelFactory.h" -#include "mitkNumericTwoTissueCompartmentModelFactory.h" -//general models -#include "mitkTwoStepLinearModelFactory.h" -#include "mitkThreeStepLinearModelFactory.h" namespace mitk { /* * This is the module activator for the IO aspects of the "pharmacokinetics" module. */ class PharmacokineticModelsActivator : public us::ModuleActivator { public: template void RegisterProvider(us::ModuleContext* context) { auto provider = new TProvider(); provider->RegisterService(context); m_RegisteredProviders.push_back(std::unique_ptr(provider)); } void Load(us::ModuleContext* context) override { m_RegisteredProviders.clear(); RegisterProvider >(context); - RegisterProvider >(context); - RegisterProvider >(context); RegisterProvider >(context); RegisterProvider >(context); RegisterProvider >(context); - RegisterProvider >(context); RegisterProvider >(context); RegisterProvider >(context); RegisterProvider >(context); RegisterProvider >(context); - RegisterProvider >(context); } void Unload(us::ModuleContext* ) override { } private: std::vector > m_RegisteredProviders; }; } US_EXPORT_MODULE_ACTIVATOR(mitk::PharmacokineticModelsActivator) diff --git a/Modules/Pharmacokinetics/files.cmake b/Modules/Pharmacokinetics/files.cmake index 03780a2490..48ead4c7e1 100644 --- a/Modules/Pharmacokinetics/files.cmake +++ b/Modules/Pharmacokinetics/files.cmake @@ -1,67 +1,55 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES Common/mitkAterialInputFunctionGenerator.cpp Common/mitkAIFParametrizerHelper.cpp Common/mitkConcentrationCurveGenerator.cpp Common/mitkDescriptionParameterImageGeneratorBase.cpp Common/mitkPixelBasedDescriptionParameterImageGenerator.cpp DescriptionParameters/mitkCurveDescriptionParameterBase.cpp DescriptionParameters/mitkAreaUnderTheCurveDescriptionParameter.cpp DescriptionParameters/mitkAreaUnderFirstMomentDescriptionParameter.cpp DescriptionParameters/mitkMeanResidenceTimeDescriptionParameter.cpp DescriptionParameters/mitkTimeToPeakCurveDescriptionParameter.cpp DescriptionParameters/mitkMaximumCurveDescriptionParameter.cpp Functors/mitkCurveParameterFunctor.cpp Models/mitkAIFBasedModelBase.cpp Models/mitkDescriptivePharmacokineticBrixModel.cpp Models/mitkDescriptivePharmacokineticBrixModelFactory.cpp Models/mitkDescriptivePharmacokineticBrixModelValueBasedParameterizer.cpp Models/mitkDescriptivePharmacokineticBrixModelParameterizer.cpp - Models/mitkThreeStepLinearModel.cpp - Models/mitkThreeStepLinearModelFactory.cpp - Models/mitkThreeStepLinearModelParameterizer.cpp Models/mitkTwoCompartmentExchangeModel.cpp Models/mitkTwoCompartmentExchangeModelFactory.cpp Models/mitkTwoCompartmentExchangeModelParameterizer.cpp - Models/mitkNumericTwoCompartmentExchangeModel.cpp - Models/mitkNumericTwoCompartmentExchangeModelFactory.cpp - Models/mitkNumericTwoCompartmentExchangeModelParameterizer.cpp Models/mitkExtendedToftsModel.cpp Models/mitkExtendedToftsModelFactory.cpp Models/mitkExtendedToftsModelParameterizer.cpp Models/mitkStandardToftsModel.cpp Models/mitkStandardToftsModelFactory.cpp Models/mitkStandardToftsModelParameterizer.cpp Models/mitkOneTissueCompartmentModel.cpp Models/mitkOneTissueCompartmentModelFactory.cpp Models/mitkOneTissueCompartmentModelParameterizer.cpp Models/mitkExtendedOneTissueCompartmentModel.cpp Models/mitkExtendedOneTissueCompartmentModelFactory.cpp Models/mitkExtendedOneTissueCompartmentModelParameterizer.cpp - Models/mitkTwoStepLinearModel.cpp - Models/mitkTwoStepLinearModelFactory.cpp - Models/mitkTwoStepLinearModelParameterizer.cpp Models/mitkTwoTissueCompartmentModel.cpp Models/mitkTwoTissueCompartmentModelFactory.cpp Models/mitkTwoTissueCompartmentModelParameterizer.cpp Models/mitkTwoTissueCompartmentFDGModel.cpp Models/mitkTwoTissueCompartmentFDGModelFactory.cpp Models/mitkTwoTissueCompartmentFDGModelParameterizer.cpp - Models/mitkNumericTwoTissueCompartmentModel.cpp - Models/mitkNumericTwoTissueCompartmentModelFactory.cpp - Models/mitkNumericTwoTissueCompartmentModelParameterizer.cpp SimulationFramework/mitkImageGenerationHelper.cpp ) set(HXX_FILES mitkDICOMSegmentationConstants.h ) set(MOC_H_FILES ) diff --git a/Modules/Pharmacokinetics/include/mitkAIFBasedModelBase.h b/Modules/Pharmacokinetics/include/mitkAIFBasedModelBase.h index 057a7817c6..0a9a18b411 100644 --- a/Modules/Pharmacokinetics/include/mitkAIFBasedModelBase.h +++ b/Modules/Pharmacokinetics/include/mitkAIFBasedModelBase.h @@ -1,114 +1,124 @@ /*============================================================================ 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 mitkAIFBasedModelBase_h #define mitkAIFBasedModelBase_h #include "MitkPharmacokineticsExports.h" #include "mitkModelBase.h" #include "itkArray2D.h" namespace mitk { /** \class AIFBasedModelBase * \brief Base Class for all physiological perfusion models using an Aterial Input Function * All AIF based models come with an array of AIF values and the corresponding TimeGrid ( AIF(t)) * This class provides functions for setting the AIF Values and optionally a specific AIF TimeGrid. * It also provides a method for interpolation of the AIF source array to a specified Timegrid that differs from * AIFTimeGrid. The AIF must be set with an itk::Array. If no AIFTimeGrid is specified with the Setter, it is assumed * that the AIFTimeGrid is the same as the ModelTimegrid (e.g. AIF is derived from data set to be fitted). In this * case, AIFvalues must have the same length as ModelTimeGrid, otherwise an exception is generated*/ class MITKPHARMACOKINETICS_EXPORT AIFBasedModelBase : public mitk::ModelBase { public: typedef AIFBasedModelBase Self; typedef ModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro(PhysiologciModelBase, AIFBasedModelBase); static const std::string NAME_STATIC_PARAMETER_AIF; static const std::string NAME_STATIC_PARAMETER_AIFTimeGrid; static const std::string UNIT_STATIC_PARAMETER_AIF; static const std::string UNIT_STATIC_PARAMETER_AIFTimeGrid; + static const unsigned int NUMBER_OF_STATIC_PARAMETERS; + + static const std::string X_AXIS_NAME; + + static const std::string X_AXIS_UNIT; + + static const std::string Y_AXIS_NAME; + + static const std::string Y_AXIS_UNIT; + /** Typedef for Aterial InputFunction AIF(t)*/ typedef itk::Array AterialInputFunctionType; itkGetConstReferenceMacro(AterialInputFunctionValues, AterialInputFunctionType); itkGetConstReferenceMacro(AterialInputFunctionTimeGrid, TimeGridType); itkSetMacro(AterialInputFunctionValues, AterialInputFunctionType); itkSetMacro(AterialInputFunctionTimeGrid, TimeGridType); std::string GetXAxisName() const override; std::string GetXAxisUnit() const override; std::string GetYAxisName() const override; std::string GetYAxisUnit() const override; /** Returns the TimeGrid used for the AIF. Either the externally set AIF time grid * or the time grid of the model if nothing is set.*/ const TimeGridType& GetCurrentAterialInputFunctionTimeGrid() const; /** Returns the Aterial Input function matching currentTimeGrid * The original values are interpolated to the passed TimeGrid * if currentTimeGrid.Size() = 0 , the Original AIF will be returned*/ const AterialInputFunctionType GetAterialInputFunction(TimeGridType currentTimeGrid) const; ParameterNamesType GetStaticParameterNames() const override; ParametersSizeType GetNumberOfStaticParameters() const override; ParamterUnitMapType GetStaticParameterUnits() const override; protected: AIFBasedModelBase(); ~AIFBasedModelBase() override; /** Reimplementation that checks if AIF and timegrid settings are valid. * @param [out] error Set internally to indicate the error reason if method returns false. Is used by GetSignal() for the * exception comment. * @return Returns true if the model is valid and can compute a signal. Otherwise it returns false.*/ bool ValidateModel(std::string& error) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; void SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) override; StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const override; TimeGridType m_AterialInputFunctionTimeGrid; AterialInputFunctionType m_AterialInputFunctionValues; private: //No copy constructor allowed AIFBasedModelBase(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkDescriptivePharmacokineticBrixModel.h b/Modules/Pharmacokinetics/include/mitkDescriptivePharmacokineticBrixModel.h index 818cc01427..44c4f3fd8e 100644 --- a/Modules/Pharmacokinetics/include/mitkDescriptivePharmacokineticBrixModel.h +++ b/Modules/Pharmacokinetics/include/mitkDescriptivePharmacokineticBrixModel.h @@ -1,131 +1,143 @@ /*============================================================================ 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 mitkDescriptivePharmacokineticBrixModel_h #define mitkDescriptivePharmacokineticBrixModel_h #include #include "mitkModelBase.h" #include "MitkPharmacokineticsExports.h" namespace mitk { class MITKPHARMACOKINETICS_EXPORT DescriptivePharmacokineticBrixModel : public ModelBase { public: typedef DescriptivePharmacokineticBrixModel Self; typedef ModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(DescriptivePharmacokineticBrixModel, ModelBase); static const std::string MODEL_DISPLAY_NAME; static const std::string NAME_PARAMETER_A; static const std::string NAME_PARAMETER_kep; static const std::string NAME_PARAMETER_kel; - static const std::string NAME_PARAMETER_tlag; - static const std::string NAME_STATIC_PARAMETER_Tau; - static const std::string NAME_STATIC_PARAMETER_S0; + static const std::string NAME_PARAMETER_BAT; + + static const std::string NAME_STATIC_PARAMETER_tau; + static const std::string NAME_STATIC_PARAMETER_s0; static const std::string UNIT_PARAMETER_A; static const std::string UNIT_PARAMETER_kep; static const std::string UNIT_PARAMETER_kel; - static const std::string UNIT_PARAMETER_tlag; - static const std::string UNIT_STATIC_PARAMETER_Tau; - static const std::string UNIT_STATIC_PARAMETER_S0; + static const std::string UNIT_PARAMETER_BAT; + + static const std::string UNIT_STATIC_PARAMETER_tau; + static const std::string UNIT_STATIC_PARAMETER_s0; static const unsigned int POSITION_PARAMETER_A; static const unsigned int POSITION_PARAMETER_kep; static const unsigned int POSITION_PARAMETER_kel; - - //tlag in minutes - static const unsigned int POSITION_PARAMETER_tlag; + static const unsigned int POSITION_PARAMETER_BAT; static const unsigned int NUMBER_OF_PARAMETERS; + static const unsigned int NUMBER_OF_STATIC_PARAMETERS; + + static const std::string MODEL_TYPE; + + static const std::string X_AXIS_NAME; + + static const std::string X_AXIS_UNIT; + + static const std::string Y_AXIS_NAME; + + static const std::string Y_AXIS_UNIT; + itkSetMacro(Tau, double); itkGetConstReferenceMacro(Tau, double); itkSetMacro(S0, double); itkGetConstReferenceMacro(S0, double); std::string GetModelDisplayName() const override; std::string GetModelType() const override; std::string GetXAxisName() const override; std::string GetXAxisUnit() const override; std::string GetYAxisName() const override; std::string GetYAxisUnit() const override; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; ParameterNamesType GetStaticParameterNames() const override; ParametersSizeType GetNumberOfStaticParameters() const override; ParamterUnitMapType GetStaticParameterUnits() const override; protected: DescriptivePharmacokineticBrixModel(); ~DescriptivePharmacokineticBrixModel() override; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) override; StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; private: /**injection time Tau in minutes [min]*/ double m_Tau; /**Value of the first time step, thus base value to scale the signal. * Default is 1.*/ double m_S0; //No copy constructor allowed DescriptivePharmacokineticBrixModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkExtendedOneTissueCompartmentModel.h b/Modules/Pharmacokinetics/include/mitkExtendedOneTissueCompartmentModel.h index 05c5b21d2c..00420e355f 100644 --- a/Modules/Pharmacokinetics/include/mitkExtendedOneTissueCompartmentModel.h +++ b/Modules/Pharmacokinetics/include/mitkExtendedOneTissueCompartmentModel.h @@ -1,96 +1,94 @@ /*============================================================================ 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 mitkExtendedOneTissueCompartmentModel_h #define mitkExtendedOneTissueCompartmentModel_h #include "mitkAIFBasedModelBase.h" #include "MitkPharmacokineticsExports.h" namespace mitk { - /** @class OneTissueCompartmentModel - * @brief Implementation of the Model function of the Tofts pharmacokinetic model, using an Aterial Input Function - * The Model calculates the Concentration-Time-Curve as a convolution of the plasma curve Cp (the AIF) and a tissue specific - * residue function (in this case an exponential: R(t) = ktrans * exp(-ktrans/ve * (t)) ). - * C(t) = vp * Cp(t) + conv(Cp(t),R(t)) - * The parameters ktrans, ve and ve are subject to the fitting routine*/ + class MITKPHARMACOKINETICS_EXPORT ExtendedOneTissueCompartmentModel : public AIFBasedModelBase { public: typedef ExtendedOneTissueCompartmentModel Self; typedef AIFBasedModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(ExtendedOneTissueCompartmentModel, ModelBase); static const std::string MODEL_DISPLAY_NAME; - static const std::string NAME_PARAMETER_k1; + static const std::string NAME_PARAMETER_K1; static const std::string NAME_PARAMETER_k2; - static const std::string NAME_PARAMETER_VB; + static const std::string NAME_PARAMETER_vb; - static const std::string UNIT_PARAMETER_k1; + static const std::string UNIT_PARAMETER_K1; static const std::string UNIT_PARAMETER_k2; - static const std::string UNIT_PARAMETER_VB; + static const std::string UNIT_PARAMETER_vb; - static const unsigned int POSITION_PARAMETER_k1; + static const unsigned int POSITION_PARAMETER_K1; static const unsigned int POSITION_PARAMETER_k2; - static const unsigned int POSITION_PARAMETER_VB; + static const unsigned int POSITION_PARAMETER_vb; static const unsigned int NUMBER_OF_PARAMETERS; + static const std::string MODEL_TYPE; + std::string GetModelDisplayName() const override; std::string GetModelType() const override; ParameterNamesType GetParameterNames() const override; + ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; protected: ExtendedOneTissueCompartmentModel(); ~ExtendedOneTissueCompartmentModel() override; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; private: //No copy constructor allowed ExtendedOneTissueCompartmentModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkExtendedToftsModel.h b/Modules/Pharmacokinetics/include/mitkExtendedToftsModel.h index 64f03b7aff..9a85e67f69 100644 --- a/Modules/Pharmacokinetics/include/mitkExtendedToftsModel.h +++ b/Modules/Pharmacokinetics/include/mitkExtendedToftsModel.h @@ -1,106 +1,115 @@ /*============================================================================ 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 mitkExtendedToftsModel_h #define mitkExtendedToftsModel_h #include "mitkAIFBasedModelBase.h" #include "MitkPharmacokineticsExports.h" namespace mitk { /** @class ExtendedToftsModel * @brief Implementation of the Model function of the Tofts pharmacokinetic model, using an Aterial Input Function * The Model calculates the Concentration-Time-Curve as a convolution of the plasma curve Cp (the AIF) and a tissue specific * residue function (in this case an exponential: R(t) = ktrans * exp(-ktrans/ve * (t)) ). * C(t) = vp * Cp(t) + conv(Cp(t),R(t)) * The parameters ktrans, ve and ve are subject to the fitting routine*/ class MITKPHARMACOKINETICS_EXPORT ExtendedToftsModel : public AIFBasedModelBase { public: typedef ExtendedToftsModel Self; typedef AIFBasedModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(ExtendedToftsModel, ModelBase); - static const std::string MODEL_DISPLAY_NAME; - static const std::string NAME_PARAMETER_Ktrans; static const std::string NAME_PARAMETER_ve; static const std::string NAME_PARAMETER_vp; static const std::string UNIT_PARAMETER_Ktrans; static const std::string UNIT_PARAMETER_ve; static const std::string UNIT_PARAMETER_vp; static const unsigned int POSITION_PARAMETER_Ktrans; static const unsigned int POSITION_PARAMETER_ve; static const unsigned int POSITION_PARAMETER_vp; static const unsigned int NUMBER_OF_PARAMETERS; + static const std::string NAME_DERIVED_PARAMETER_kep; + + static const unsigned int NUMBER_OF_DERIVED_PARAMETERS; + + static const std::string UNIT_DERIVED_PARAMETER_kep; + + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + + std::string GetModelDisplayName() const override; std::string GetModelType() const override; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; ParameterNamesType GetDerivedParameterNames() const override; ParametersSizeType GetNumberOfDerivedParameters() const override; ParamterUnitMapType GetDerivedParameterUnits() const override; protected: ExtendedToftsModel(); ~ExtendedToftsModel() override; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; DerivedParameterMapType ComputeDerivedParameters(const mitk::ModelBase::ParametersType& parameters) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; private: //No copy constructor allowed ExtendedToftsModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModel.h b/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModel.h deleted file mode 100644 index b8bcc20432..0000000000 --- a/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModel.h +++ /dev/null @@ -1,128 +0,0 @@ -/*============================================================================ - -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 mitkNumericTwoCompartmentExchangeModel_h -#define mitkNumericTwoCompartmentExchangeModel_h - -#include "mitkAIFBasedModelBase.h" -#include "MitkPharmacokineticsExports.h" - - -namespace mitk -{ - /** @class NumericTwoCompartmentExchangeModel - * @brief Implementation of the numeric model function of the 2 Compartment Exchange model, using an Aterial Input Function - * The Model calculates the measured Concentration-Time-Curve from the mass balance equations of the 2-tissue compartent Model - * - * vp * dCp(t)/dt = F * (CA(t) - Cp(t)) - PS * (Cp(t) - Ci(t)) - * ve * dCi(t)/dt = PS * (Cp(t) - Ci(t)) - * - * with concentration curve Cp(t) of the Blood Plasma p and Ce(t) of the Extracellular Extravascular Space(EES)(interstitial volume). CA(t) is the aterial concentration, i.e. the AIF - * Cp(t) and Ce(t) are found numerical via Runge-Kutta methode, implemented in Boosts numeric library ODEINT. Here we use a runge_kutta_cash_karp54 stepper with - * adaptive step size and error controll. - * From the resulting curves Cp(t) and Ce(t) the measured concentration Ctotal(t) is found vial - * - * Ctotal(t) = vp * Cp(t) + ve * Ce(t) - * - * where vp=Vp/VT and ve=Ve/VT are the portion of Plasma/EES volume Vp/Ve of the total volume VT respectively. - * The parameters PS, F, vp and ve are subject to the fitting routine*/ - - class MITKPHARMACOKINETICS_EXPORT NumericTwoCompartmentExchangeModel : public AIFBasedModelBase - { - - public: - typedef NumericTwoCompartmentExchangeModel Self; - typedef AIFBasedModelBase Superclass; - typedef itk::SmartPointer< Self > Pointer; - typedef itk::SmartPointer< const Self > ConstPointer; - - - /** Method for creation through the object factory. */ - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); - - /** Run-time type information (and related methods). */ - itkTypeMacro(NumericTwoCompartmentExchangeModel, ModelBase); - - typedef std::vector state_type; - - - static const std::string MODEL_DISPLAY_NAME; - - static const std::string NAME_PARAMETER_F; - static const std::string NAME_PARAMETER_PS; - static const std::string NAME_PARAMETER_ve; - static const std::string NAME_PARAMETER_vp; - static const std::string NAME_STATIC_PARAMETER_ODEINTStepSize; - - static const std::string UNIT_PARAMETER_F; - static const std::string UNIT_PARAMETER_PS; - static const std::string UNIT_PARAMETER_ve; - static const std::string UNIT_PARAMETER_vp; - - static const unsigned int POSITION_PARAMETER_F; - static const unsigned int POSITION_PARAMETER_PS; - static const unsigned int POSITION_PARAMETER_ve; - static const unsigned int POSITION_PARAMETER_vp; - - static const unsigned int NUMBER_OF_PARAMETERS; - - std::string GetModelDisplayName() const override; - - std::string GetModelType() const override; - - itkGetConstReferenceMacro(ODEINTStepSize, double); - itkSetMacro(ODEINTStepSize, double); - - - ParameterNamesType GetParameterNames() const override; - ParametersSizeType GetNumberOfParameters() const override; - - ParamterUnitMapType GetParameterUnits() const override; - - ParameterNamesType GetStaticParameterNames() const override; - ParametersSizeType GetNumberOfStaticParameters() const override; - - - protected: - NumericTwoCompartmentExchangeModel(); - ~NumericTwoCompartmentExchangeModel() override; - - /** - * Actual implementation of the clone method. This method should be reimplemeted - * in subclasses to clone the extra required parameters. - */ - itk::LightObject::Pointer InternalClone() const override; - - ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; - - void SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) override; - StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const override; - - void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; - - private: - - - - //No copy constructor allowed - NumericTwoCompartmentExchangeModel(const Self& source); - void operator=(const Self&); //purposely not implemented - - double m_ODEINTStepSize; - - - - }; -} - -#endif diff --git a/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModelFactory.h b/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModelFactory.h deleted file mode 100644 index f94e55ef59..0000000000 --- a/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModelFactory.h +++ /dev/null @@ -1,46 +0,0 @@ -/*============================================================================ - -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 mitkNumericTwoCompartmentExchangeModelFactory_h -#define mitkNumericTwoCompartmentExchangeModelFactory_h - -#include "mitkTwoCompartmentExchangeModelFactoryBase.h" -#include "mitkNumericTwoCompartmentExchangeModelParameterizer.h" - -namespace mitk -{ - - class MITKPHARMACOKINETICS_EXPORT NumericTwoCompartmentExchangeModelFactory : public - mitk::TwoCompartmentExchangeModelFactoryBase - { - public: - mitkClassMacro(NumericTwoCompartmentExchangeModelFactory, - TwoCompartmentExchangeModelFactoryBase); - itkFactorylessNewMacro(Self); - - protected: - - ModelParameterizerBase::Pointer DoCreateParameterizer(const modelFit::ModelFitInfo* fit) const override; - - NumericTwoCompartmentExchangeModelFactory(); - - ~NumericTwoCompartmentExchangeModelFactory() override; - - private: - - //No copy constructor allowed - NumericTwoCompartmentExchangeModelFactory(const Self& source); - void operator=(const Self&); //purposely not implemented - - }; - -} -#endif diff --git a/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModelParameterizer.h b/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModelParameterizer.h deleted file mode 100644 index 076952c6c3..0000000000 --- a/Modules/Pharmacokinetics/include/mitkNumericTwoCompartmentExchangeModelParameterizer.h +++ /dev/null @@ -1,77 +0,0 @@ -/*============================================================================ - -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 mitkNumericTwoCompartmentExchangeModelParameterizer_h -#define mitkNumericTwoCompartmentExchangeModelParameterizer_h - -#include "mitkAIFBasedModelParameterizerBase.h" -#include "mitkNumericTwoCompartmentExchangeModel.h" - -#include "MitkPharmacokineticsExports.h" - -namespace mitk -{ - - class MITKPHARMACOKINETICS_EXPORT NumericTwoCompartmentExchangeModelParameterizer : public - mitk::AIFBasedModelParameterizerBase - { - public: - typedef NumericTwoCompartmentExchangeModelParameterizer Self; - typedef mitk::AIFBasedModelParameterizerBase Superclass; - typedef itk::SmartPointer< Self > Pointer; - typedef itk::SmartPointer< const Self > ConstPointer; - - itkTypeMacro(NumericTwoCompartmentExchangeModelParameterizer, - mitk::AIFBasedModelParameterizerBase); - itkFactorylessNewMacro(Self); - - typedef Superclass::ModelBaseType ModelBaseType; - typedef Superclass::ModelBasePointer ModelBasePointer; - - typedef Superclass::ModelType ModelType; - typedef ModelType::Pointer ModelPointer; - - typedef Superclass::StaticParameterValueType StaticParameterValueType; - typedef Superclass::StaticParameterValuesType StaticParameterValuesType; - typedef Superclass::StaticParameterMapType StaticParameterMapType; - - typedef Superclass::IndexType IndexType; - - itkSetMacro(ODEINTStepSize, double); - itkGetConstReferenceMacro(ODEINTStepSize, double); - - /** Returns the global static parameters for the model. - * @remark this default implementation assumes only AIF and its timegrid as static parameters. - * Reimplement in derived classes to change this behavior.*/ - StaticParameterMapType GetGlobalStaticParameters() const override; - - - /** This function returns the default parameterization (e.g. initial parametrization for fitting) - defined by the model developer for for the given model.*/ - ParametersType GetDefaultInitialParameterization() const override; - - protected: - - double m_ODEINTStepSize; - - NumericTwoCompartmentExchangeModelParameterizer(); - - ~NumericTwoCompartmentExchangeModelParameterizer() override; - - private: - - //No copy constructor allowed - NumericTwoCompartmentExchangeModelParameterizer(const Self& source); - void operator=(const Self&); //purposely not implemented - }; -} -#endif diff --git a/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModel.h b/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModel.h deleted file mode 100644 index 0364852861..0000000000 --- a/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModel.h +++ /dev/null @@ -1,97 +0,0 @@ -/*============================================================================ - -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 mitkNumericTwoTissueCompartmentModel_h -#define mitkNumericTwoTissueCompartmentModel_h - -#include "mitkAIFBasedModelBase.h" -#include "MitkPharmacokineticsExports.h" - - -namespace mitk -{ - class MITKPHARMACOKINETICS_EXPORT NumericTwoTissueCompartmentModel : public AIFBasedModelBase - { - - public: - typedef NumericTwoTissueCompartmentModel Self; - typedef AIFBasedModelBase Superclass; - typedef itk::SmartPointer< Self > Pointer; - typedef itk::SmartPointer< const Self > ConstPointer; - - /** Method for creation through the object factory. */ - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); - - /** Run-time type information (and related methods). */ - itkTypeMacro(NumericTwoTissueCompartmentModel, ModelBase); - - typedef std::vector state_type; - - - /** Model Specifications */ - static const std::string MODEL_DISPLAY_NAME; - - static const std::string NAME_PARAMETER_K1; - static const std::string NAME_PARAMETER_k2; - static const std::string NAME_PARAMETER_k3; - static const std::string NAME_PARAMETER_k4; - static const std::string NAME_PARAMETER_VB; - - static const std::string UNIT_PARAMETER_K1; - static const std::string UNIT_PARAMETER_k2; - static const std::string UNIT_PARAMETER_k3; - static const std::string UNIT_PARAMETER_k4; - static const std::string UNIT_PARAMETER_VB; - - static const unsigned int POSITION_PARAMETER_K1; - static const unsigned int POSITION_PARAMETER_k2; - static const unsigned int POSITION_PARAMETER_k3; - static const unsigned int POSITION_PARAMETER_k4; - static const unsigned int POSITION_PARAMETER_VB; - - static const unsigned int NUMBER_OF_PARAMETERS; - - std::string GetModelDisplayName() const override; - - std::string GetModelType() const override; - - ParameterNamesType GetParameterNames() const override; - ParametersSizeType GetNumberOfParameters() const override; - - ParamterUnitMapType GetParameterUnits() const override; - - protected: - NumericTwoTissueCompartmentModel(); - ~NumericTwoTissueCompartmentModel() override; - - /** - * Actual implementation of the clone method. This method should be reimplemeted - * in subclasses to clone the extra required parameters. - */ - itk::LightObject::Pointer InternalClone() const override; - - ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; - - void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; - - private: - - - //No copy constructor allowed - NumericTwoTissueCompartmentModel(const Self& source); - void operator=(const Self&); //purposely not implemented - - }; -} - -#endif diff --git a/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModelFactory.h b/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModelFactory.h deleted file mode 100644 index 6157d8b36a..0000000000 --- a/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModelFactory.h +++ /dev/null @@ -1,48 +0,0 @@ -/*============================================================================ - -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 mitkNumericTwoTissueCompartmentModelFactory_h -#define mitkNumericTwoTissueCompartmentModelFactory_h - -#include "mitkTwoTissueCompartmentModelFactoryBase.h" -#include "mitkNumericTwoTissueCompartmentModelParameterizer.h" - -namespace mitk -{ - - - class MITKPHARMACOKINETICS_EXPORT NumericTwoTissueCompartmentModelFactory : public - mitk::TwoTissueCompartmentModelFactoryBase - { - public: - mitkClassMacro(NumericTwoTissueCompartmentModelFactory, - TwoTissueCompartmentModelFactoryBase); - itkFactorylessNewMacro(Self); - - protected: - - NumericTwoTissueCompartmentModelFactory(); - - ~NumericTwoTissueCompartmentModelFactory() override; - - private: - - //No copy constructor allowed - NumericTwoTissueCompartmentModelFactory(const Self& source); - void operator=(const Self&); //purposely not implemented - - }; - -} - - -#endif diff --git a/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModelParameterizer.h b/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModelParameterizer.h deleted file mode 100644 index 07f71e2720..0000000000 --- a/Modules/Pharmacokinetics/include/mitkNumericTwoTissueCompartmentModelParameterizer.h +++ /dev/null @@ -1,65 +0,0 @@ -/*============================================================================ - -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 mitkNumericTwoTissueCompartmentModelParameterizer_h -#define mitkNumericTwoTissueCompartmentModelParameterizer_h - -#include "mitkAIFBasedModelParameterizerBase.h" -#include "mitkNumericTwoTissueCompartmentModel.h" - -#include "MitkPharmacokineticsExports.h" - -namespace mitk -{ - - class MITKPHARMACOKINETICS_EXPORT NumericTwoTissueCompartmentModelParameterizer : public - mitk::AIFBasedModelParameterizerBase - { - public: - typedef NumericTwoTissueCompartmentModelParameterizer Self; - typedef mitk::AIFBasedModelParameterizerBase Superclass; - typedef itk::SmartPointer< Self > Pointer; - typedef itk::SmartPointer< const Self > ConstPointer; - - itkTypeMacro(NumericTwoTissueCompartmentModelParameterizer, - mitk::AIFBasedModelParameterizerBase); - itkFactorylessNewMacro(Self); - - typedef Superclass::ModelBaseType ModelBaseType; - typedef Superclass::ModelBasePointer ModelBasePointer; - - typedef Superclass::ModelType ModelType; - typedef ModelType::Pointer ModelPointer; - - typedef Superclass::StaticParameterValueType StaticParameterValueType; - typedef Superclass::StaticParameterValuesType StaticParameterValuesType; - typedef Superclass::StaticParameterMapType StaticParameterMapType; - - typedef Superclass::IndexType IndexType; - - /** This function returns the default parameterization (e.g. initial parametrization for fitting) - defined by the model developer for for the given model.*/ - ParametersType GetDefaultInitialParameterization() const override; - - protected: - NumericTwoTissueCompartmentModelParameterizer(); - - ~NumericTwoTissueCompartmentModelParameterizer() override; - - private: - - //No copy constructor allowed - NumericTwoTissueCompartmentModelParameterizer(const Self& source); - void operator=(const Self&); //purposely not implemented - }; -} -#endif diff --git a/Modules/Pharmacokinetics/include/mitkOneTissueCompartmentModel.h b/Modules/Pharmacokinetics/include/mitkOneTissueCompartmentModel.h index 6da9c3a278..1211729ddb 100644 --- a/Modules/Pharmacokinetics/include/mitkOneTissueCompartmentModel.h +++ b/Modules/Pharmacokinetics/include/mitkOneTissueCompartmentModel.h @@ -1,94 +1,88 @@ /*============================================================================ 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 mitkOneTissueCompartmentModel_h #define mitkOneTissueCompartmentModel_h #include "mitkAIFBasedModelBase.h" #include "MitkPharmacokineticsExports.h" namespace mitk { - /** @class OneTissueCompartmentModel - * @brief Implementation of the Model function of the Tofts pharmacokinetic model, using an Aterial Input Function - * The Model calculates the Concentration-Time-Curve as a convolution of the plasma curve Cp (the AIF) and a tissue specific - * residue function (in this case an exponential: R(t) = ktrans * exp(-ktrans/ve * (t)) ). - * C(t) = vp * Cp(t) + conv(Cp(t),R(t)) - * The parameters ktrans, ve and ve are subject to the fitting routine*/ - class MITKPHARMACOKINETICS_EXPORT OneTissueCompartmentModel : public AIFBasedModelBase { public: typedef OneTissueCompartmentModel Self; typedef AIFBasedModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(OneTissueCompartmentModel, ModelBase); - static const std::string MODEL_DISPLAY_NAME; - - static const std::string NAME_PARAMETER_k1; + static const std::string NAME_PARAMETER_K1; static const std::string NAME_PARAMETER_k2; - static const std::string UNIT_PARAMETER_k1; + static const std::string UNIT_PARAMETER_K1; static const std::string UNIT_PARAMETER_k2; - static const unsigned int POSITION_PARAMETER_k1; + static const unsigned int POSITION_PARAMETER_K1; static const unsigned int POSITION_PARAMETER_k2; static const unsigned int NUMBER_OF_PARAMETERS; + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + std::string GetModelDisplayName() const override; std::string GetModelType() const override; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; - protected: OneTissueCompartmentModel(); ~OneTissueCompartmentModel() override; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; private: //No copy constructor allowed OneTissueCompartmentModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkStandardToftsModel.h b/Modules/Pharmacokinetics/include/mitkStandardToftsModel.h index 209bc84646..bea02f08d2 100644 --- a/Modules/Pharmacokinetics/include/mitkStandardToftsModel.h +++ b/Modules/Pharmacokinetics/include/mitkStandardToftsModel.h @@ -1,106 +1,113 @@ /*============================================================================ 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 mitkStandardToftsModel_h #define mitkStandardToftsModel_h #include "mitkAIFBasedModelBase.h" #include "MitkPharmacokineticsExports.h" namespace mitk { /** @class StandardToftsModel * @brief Implementation of the Model function of the Tofts pharmacokinetic model, using an Aterial Input Function * The Model calculates the Concentration-Time-Curve as a convolution of the plasma curve Cp (the AIF) and a tissue specific * residue function (in this case an exponential: R(t) = ktrans * exp(-ktrans/ve * (t)) ). * C(t) = vp * Cp(t) + conv(Cp(t),R(t)) * The parameters ktrans, ve and ve are subject to the fitting routine*/ class MITKPHARMACOKINETICS_EXPORT StandardToftsModel : public AIFBasedModelBase { public: typedef StandardToftsModel Self; typedef AIFBasedModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(StandardToftsModel, ModelBase); - static const std::string MODEL_DISPLAY_NAME; - static const std::string NAME_PARAMETER_Ktrans; static const std::string NAME_PARAMETER_ve; - static const std::string NAME_PARAMETER_vp; static const std::string UNIT_PARAMETER_Ktrans; static const std::string UNIT_PARAMETER_ve; - static const std::string UNIT_PARAMETER_vp; static const unsigned int POSITION_PARAMETER_Ktrans; static const unsigned int POSITION_PARAMETER_ve; - static const unsigned int POSITION_PARAMETER_vp; static const unsigned int NUMBER_OF_PARAMETERS; + static const std::string NAME_DERIVED_PARAMETER_kep; + + static const unsigned int NUMBER_OF_DERIVED_PARAMETERS; + + static const std::string UNIT_DERIVED_PARAMETER_kep; + + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + + + std::string GetModelDisplayName() const override; std::string GetModelType() const override; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; ParameterNamesType GetDerivedParameterNames() const override; ParametersSizeType GetNumberOfDerivedParameters() const override; ParamterUnitMapType GetDerivedParameterUnits() const override; protected: StandardToftsModel(); ~StandardToftsModel() override; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; DerivedParameterMapType ComputeDerivedParameters(const mitk::ModelBase::ParametersType& parameters) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; private: //No copy constructor allowed StandardToftsModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoCompartmentExchangeModel.h b/Modules/Pharmacokinetics/include/mitkTwoCompartmentExchangeModel.h index d01d5b51c4..bb4071d24d 100644 --- a/Modules/Pharmacokinetics/include/mitkTwoCompartmentExchangeModel.h +++ b/Modules/Pharmacokinetics/include/mitkTwoCompartmentExchangeModel.h @@ -1,113 +1,116 @@ /*============================================================================ 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 mitkTwoCompartmentExchangeModel_h #define mitkTwoCompartmentExchangeModel_h #include "mitkAIFBasedModelBase.h" #include "MitkPharmacokineticsExports.h" namespace mitk { /** @class TwoCompartmentExchangeModel * @brief Implementation of the analystical model function of the Physiological Pharmacokinetic Brix model, using an Aterial Input Function * The Model calculates the Concentration-Time-Curve as a convolution of the Aterial Input funciton CA(t) and a tissue specific * residue function R(t). The Residue funktion consists of two parts: The Residue funktion Qp(t) of the Blood Plasma p and the residue funktion Qi(t) of the * interstitial volume I. * Ctotal(t) = vp * Cp(t) + fi * Ci(t) = [vp * Qp(t) + fi * Qi(t)] conv CA(t) * = Qtotal(t) conv CA(t) * where vp=Vp/VT and fi=Vi/VT are the portion of Plasma/interstitial volume Vp/VI of the total volume VT respectively. * The Residuefunctions are described by * Qp(t) = F/Vp * PS/Vp * 1/(l2 - l1) *[ µ2 exp(l1*t) - µ1 exp(l2*t)]* sig(t) * Qi(t) = F/Vp * PS/Vi * 1/(l1 - l2) *[ exp(l1*t) - exp(l2*t)]* sig(t) * = F/Vp * PS/Vp * vp/fi * 1/(l1 - l2) *[ exp(l1*t) - exp(l2*t)]* sig(t) * with * l1/2 = -1/2 (PS/Vp * vp/fi + PS/Vp + F/Vp) +/- sqrt((PS/Vp * vp/fi + PS/Vp + F/Vp)² - 4* F/Vp * PS/Vp * vp/fi) * µ1/2 = F/Vp * Vp/PS + 1 + Vp/PS* l1/2 * * The parameters PS/Vp, F/Vp, vp and fi are subject to the fitting routine*/ class MITKPHARMACOKINETICS_EXPORT TwoCompartmentExchangeModel : public AIFBasedModelBase { public: typedef TwoCompartmentExchangeModel Self; typedef AIFBasedModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(TwoCompartmentExchangeModel, ModelBase); /** Model Specifications */ - static const std::string MODEL_DISPLAY_NAME; static const std::string NAME_PARAMETER_F; static const std::string NAME_PARAMETER_PS; static const std::string NAME_PARAMETER_ve; static const std::string NAME_PARAMETER_vp; static const unsigned int POSITION_PARAMETER_F; static const unsigned int POSITION_PARAMETER_PS; static const unsigned int POSITION_PARAMETER_ve; static const unsigned int POSITION_PARAMETER_vp; static const std::string UNIT_PARAMETER_F; static const std::string UNIT_PARAMETER_PS; static const std::string UNIT_PARAMETER_ve; static const std::string UNIT_PARAMETER_vp; static const unsigned int NUMBER_OF_PARAMETERS; + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + std::string GetModelDisplayName() const override; std::string GetModelType() const override; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; protected: TwoCompartmentExchangeModel(); ~TwoCompartmentExchangeModel() override; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; private: //No copy constructor allowed TwoCompartmentExchangeModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoCompartmentExchangeModelDifferentialEquations.h b/Modules/Pharmacokinetics/include/mitkTwoCompartmentExchangeModelDifferentialEquations.h deleted file mode 100644 index f9e4b461fa..0000000000 --- a/Modules/Pharmacokinetics/include/mitkTwoCompartmentExchangeModelDifferentialEquations.h +++ /dev/null @@ -1,114 +0,0 @@ -/*============================================================================ - -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 mitkTwoCompartmentExchangeModelDifferentialEquations_h -#define mitkTwoCompartmentExchangeModelDifferentialEquations_h - -#include "mitkNumericTwoCompartmentExchangeModel.h" - -namespace mitk{ -/** @class TwoCompartmentExchangeModelDifferentialEquations - * @brief Helper Class for NumericTwoCompartmentExchangeModel: Defines the differential equations (Mass Balance Equations) in the 2 Compartment Exchange model. - * The 2 Compartment Exchange model is defined via the mass balance equations - * vp * dCp(t)/dt = F * (CA(t) - Cp(t)) - PS * (Cp(t) - Ce(t)) - * ve * dCe(t)/dt = PS * (Cp(t) - Ce(t)) - * Boost ODEINT performs a stepwise numeric integration (e.g. via Runge-Kutta method) of the initial value problem - * x' = dx/dt = f(x,t) - * It needs an operator () (a functor) that calculates dx/dt = dxdt for a given x and t. - * Parameters are F, PS, ve and vp and the time dependent Ca(t) =AIF, that is interpolated to the current step t -*/ - -class TwoCompartmentExchangeModelDifferentialEquations -{ -public: - - typedef std::vector< double > AIFType; - - /** @brief Functor for differential equation of Physiological Pharmacokinetic Brix Model - * Takes current state x = x(t) and time t and calculates the corresponding dxdt = dx/dt - */ - void operator() (const mitk::NumericTwoCompartmentExchangeModel::state_type &x, mitk::NumericTwoCompartmentExchangeModel::state_type &dxdt, const double t) - { - double Ca_t = InterpolateAIFToCurrentTimeStep(t); - -// dxdt[0] = -(this->FVP + this->PSVP)*x[0] - this->PSVP*x[1]+this->FVP*Ca_t; - dxdt[0] = (1/this->vp) * ( this->F*(Ca_t - x[0]) - this->PS*(x[0] - x[1]) ); - dxdt[1] = (1/this->ve) * this->PS * (x[0] - x[1]); - - } - - TwoCompartmentExchangeModelDifferentialEquations() : F(0), PS(0), ve(0), vp(0), m_AIF(0), m_AIFTimeGrid(0) - { - } - - /** @brief Initialize class with parameters F/Vp, PS/Vp, fi and fp that are free fit parameters*/ - void initialize(double Fp, double ps, double fi, double fp) - { - this->F = Fp; - this->PS = ps; - this->ve = fi; - this->vp = fp; - } - - - void setAIF(AIFType &aif) - { - this->m_AIF = aif; - } - - - void setAIFTimeGrid(AIFType &grid) - { - this->m_AIFTimeGrid = grid; - } - -private: - - double F; - double PS; - double ve; - double vp; - - AIFType m_AIF; - AIFType m_AIFTimeGrid; - - - /** @brief Internal routine to interpolate the AIF to the current time point t used for integration - * The numerical integration of ODEINT is performed on an adaptive timegrid (adaptive step size dt) different from the time grid of the AIF and model function. - * Thus, the AIF value Ca(t) has to be interpolated from the set AIF - */ - double InterpolateAIFToCurrentTimeStep(double t) - { - double lastValue = m_AIF[0]; - double lastTime = std::numeric_limits::min(); - - AIFType::const_iterator posITime = m_AIFTimeGrid.begin(); - AIFType::const_iterator posValue = m_AIF.begin(); - - while(t > *posITime) - { - lastValue = *posValue; - lastTime = *posITime; - ++posValue; - ++posITime; - } - double weightLast = 1 - (t - lastTime)/(*posITime - lastTime); - double weightNext = 1- (*posITime - t)/(*posITime - lastTime); - double result = weightLast * lastValue + weightNext * (*posValue); - - return result; - } - -}; -} - -#endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoStepLinearModel.h b/Modules/Pharmacokinetics/include/mitkTwoStepLinearModel.h deleted file mode 100644 index 92b03e5903..0000000000 --- a/Modules/Pharmacokinetics/include/mitkTwoStepLinearModel.h +++ /dev/null @@ -1,106 +0,0 @@ -/*============================================================================ - -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 mitkTwoStepLinearModel_h -#define mitkTwoStepLinearModel_h - -#include "mitkModelBase.h" - -#include "MitkPharmacokineticsExports.h" - -namespace mitk -{ - - class MITKPHARMACOKINETICS_EXPORT TwoStepLinearModel : public mitk::ModelBase - { - - public: - typedef TwoStepLinearModel Self; - typedef mitk::ModelBase Superclass; - typedef itk::SmartPointer< Self > Pointer; - typedef itk::SmartPointer< const Self > ConstPointer; - - typedef Superclass::ParameterNameType ParameterNameType; - typedef Superclass::ParametersSizeType ParametersSizeType; - - /** Method for creation through the object factory. */ - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); - - /** Run-time type information (and related methods). */ - itkTypeMacro(TwoStepLinearModel, ModelBase) - - static const std::string MODELL_NAME; - static const std::string NAME_PARAMETER_y1; - static const std::string NAME_PARAMETER_t; - static const std::string NAME_PARAMETER_a1; - static const std::string NAME_PARAMETER_a2; - - static const unsigned int POSITION_PARAMETER_y1; - static const unsigned int POSITION_PARAMETER_t; - static const unsigned int POSITION_PARAMETER_a1; - static const unsigned int POSITION_PARAMETER_a2; - - static const unsigned int NUMBER_OF_PARAMETERS; - - virtual std::string GetModelDisplayName() const override; - - virtual std::string GetModelType() const override; - - virtual FunctionStringType GetFunctionString() const override; - - virtual std::string GetXName() const override; - - virtual ParameterNamesType GetParameterNames() const override; - - virtual ParametersSizeType GetNumberOfParameters() const override; - - virtual ParameterNamesType GetStaticParameterNames() const override; - - virtual ParametersSizeType GetNumberOfStaticParameters() const override; - - virtual ParameterNamesType GetDerivedParameterNames() const override; - - virtual ParametersSizeType GetNumberOfDerivedParameters() const override; - - - protected: - TwoStepLinearModel() {}; - virtual ~TwoStepLinearModel(){}; - - - /** - * Actual implementation of the clone method. This method should be reimplemeted - * in subclasses to clone the extra required parameters. - */ - virtual itk::LightObject::Pointer InternalClone() const; - - virtual ModelResultType ComputeModelfunction(const ParametersType& parameters) const; - virtual DerivedParameterMapType ComputeDerivedParameters(const mitk::ModelBase::ParametersType& - parameters) const; - - virtual void SetStaticParameter(const ParameterNameType& name, - const StaticParameterValuesType& values); - virtual StaticParameterValuesType GetStaticParameterValue(const ParameterNameType& name) const; - - static double ComputeSignalFromParameters(double x, double t, double a1, double a2, double b1, double b2); - - private: - - //No copy constructor allowed - TwoStepLinearModel(const Self& source); - void operator=(const Self&); //purposely not implemented - }; -} - - -#endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentFDGModel.h b/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentFDGModel.h index d6e2240302..981d44cd0e 100644 --- a/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentFDGModel.h +++ b/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentFDGModel.h @@ -1,92 +1,94 @@ /*============================================================================ 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 mitkTwoTissueCompartmentFDGModel_h #define mitkTwoTissueCompartmentFDGModel_h #include "mitkAIFBasedModelBase.h" #include "MitkPharmacokineticsExports.h" namespace mitk { class MITKPHARMACOKINETICS_EXPORT TwoTissueCompartmentFDGModel : public AIFBasedModelBase { public: typedef TwoTissueCompartmentFDGModel Self; typedef AIFBasedModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(TwoTissueCompartmentFDGModel, ModelBase); /** Model Specifications */ static const std::string MODEL_DISPLAY_NAME; static const std::string NAME_PARAMETER_K1; static const std::string NAME_PARAMETER_k2; static const std::string NAME_PARAMETER_k3; - static const std::string NAME_PARAMETER_VB; + static const std::string NAME_PARAMETER_vb; static const std::string UNIT_PARAMETER_K1; static const std::string UNIT_PARAMETER_k2; static const std::string UNIT_PARAMETER_k3; - static const std::string UNIT_PARAMETER_VB; + static const std::string UNIT_PARAMETER_vb; static const unsigned int POSITION_PARAMETER_K1; static const unsigned int POSITION_PARAMETER_k2; static const unsigned int POSITION_PARAMETER_k3; - static const unsigned int POSITION_PARAMETER_VB; + static const unsigned int POSITION_PARAMETER_vb; static const unsigned int NUMBER_OF_PARAMETERS; + static const std::string MODEL_TYPE; + std::string GetModelDisplayName() const override; std::string GetModelType() const override; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; protected: TwoTissueCompartmentFDGModel(); ~TwoTissueCompartmentFDGModel() override; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; private: //No copy constructor allowed TwoTissueCompartmentFDGModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModel.h b/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModel.h index a20c922009..5f1ebe6506 100644 --- a/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModel.h +++ b/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModel.h @@ -1,94 +1,97 @@ /*============================================================================ 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 mitkTwoTissueCompartmentModel_h #define mitkTwoTissueCompartmentModel_h #include "mitkAIFBasedModelBase.h" #include "MitkPharmacokineticsExports.h" namespace mitk { class MITKPHARMACOKINETICS_EXPORT TwoTissueCompartmentModel : public AIFBasedModelBase { public: typedef TwoTissueCompartmentModel Self; typedef AIFBasedModelBase Superclass; typedef itk::SmartPointer< Self > Pointer; typedef itk::SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(TwoTissueCompartmentModel, ModelBase); /** Model Specifications */ - static const std::string MODEL_DISPLAY_NAME; static const std::string NAME_PARAMETER_K1; static const std::string NAME_PARAMETER_k2; static const std::string NAME_PARAMETER_k3; static const std::string NAME_PARAMETER_k4; - static const std::string NAME_PARAMETER_VB; + static const std::string NAME_PARAMETER_vb; static const std::string UNIT_PARAMETER_K1; static const std::string UNIT_PARAMETER_k2; static const std::string UNIT_PARAMETER_k3; static const std::string UNIT_PARAMETER_k4; - static const std::string UNIT_PARAMETER_VB; + static const std::string UNIT_PARAMETER_vb; static const unsigned int POSITION_PARAMETER_K1; static const unsigned int POSITION_PARAMETER_k2; static const unsigned int POSITION_PARAMETER_k3; static const unsigned int POSITION_PARAMETER_k4; - static const unsigned int POSITION_PARAMETER_VB; + static const unsigned int POSITION_PARAMETER_vb; static const unsigned int NUMBER_OF_PARAMETERS; + static const std::string MODEL_DISPLAY_NAME; + + static const std::string MODEL_TYPE; + std::string GetModelDisplayName() const override; std::string GetModelType() const override; ParameterNamesType GetParameterNames() const override; ParametersSizeType GetNumberOfParameters() const override; ParamterUnitMapType GetParameterUnits() const override; protected: TwoTissueCompartmentModel(); ~TwoTissueCompartmentModel() override; /** * Actual implementation of the clone method. This method should be reimplemeted * in subclasses to clone the extra required parameters. */ itk::LightObject::Pointer InternalClone() const override; ModelResultType ComputeModelfunction(const ParametersType& parameters) const override; void PrintSelf(std::ostream& os, ::itk::Indent indent) const override; private: //No copy constructor allowed TwoTissueCompartmentModel(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModelDifferentialEquations.h b/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModelDifferentialEquations.h deleted file mode 100644 index b892bef899..0000000000 --- a/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModelDifferentialEquations.h +++ /dev/null @@ -1,114 +0,0 @@ -/*============================================================================ - -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 mitkTwoTissueCompartmentModelDifferentialEquations_h -#define mitkTwoTissueCompartmentModelDifferentialEquations_h -#include "mitkNumericTwoTissueCompartmentModel.h" - -namespace mitk{ -/** @class TwoTissueCompartmentModelDifferentialEquations - * @brief Helper Class for NumericTwoTissueCompartment Model: Defines the differential equations (Mass Balance Equations) in the - * 2-tissue-compartment model for dynamic PET data modeling. - * The 2-Tissue Compartment model is defined via the mass balance equations - * dC1(t)/dt = K1*Ca(t) - (k2 + k3)*C1(t) + k4*C2(t) - * dC2(t)/dt = k3*C1(t) - k4*C2(t) - * CT(t) = C_a(t)*VB + (1-VB)*(C1(t)+C2(t) - * where Ca(t) is the plasma concentration(aterial input function) - * Boost ODEINT performs a stepwise numeric integration (e.g. via Runge-Kutta method) of the initial value problem - * x' = dx/dt = f(x,t) - * It needs an operator () (a functor) that calculates dx/dt = dxdt for a given x and t. - * Parameters are K1,k2,k3,k4, VB and the time dependent Ca(t) =AIF, that is interpolated to the current step t -*/ - -class TwoTissueCompartmentModelDifferentialEquations -{ -public: - - typedef std::vector< double > AIFType; - - /** @brief Functor for differential equation of Two Tissue Compartment Model - * Takes current state x = x(t) and time t and calculates the corresponding dxdt = dx/dt - */ - void operator() (const mitk::NumericTwoTissueCompartmentModel::state_type &x, mitk::NumericTwoTissueCompartmentModel::state_type &dxdt, const double t) - { - double Ca_t = InterpolateAIFToCurrentTimeStep(t); - - dxdt[0] = this->K1*Ca_t-(this->k2+this->k3)*x[0] + this->k4*x[1]; - dxdt[1] = this->k3*x[0] - this->k4*x[1]; - } - - TwoTissueCompartmentModelDifferentialEquations() : K1(0), k2(0), k3(0), k4(0), m_AIF(0), m_AIFTimeGrid(0) - { - } - - /** @brief Initialize class with parameters K1, k2, k3 and k4 that are free fit parameters*/ - void initialize(double k_1, double k_2, double k_3, double k_4) - { - this->K1 = k_1; - this->k2 = k_2; - this->k3 = k_3; - this->k4 = k_4; - } - - - void setAIF(AIFType &aif) - { - this->m_AIF = aif; - } - - - void setAIFTimeGrid(AIFType &grid) - { - this->m_AIFTimeGrid = grid; - } - -private: - - double K1; - double k2; - double k3; - double k4; - - AIFType m_AIF; - AIFType m_AIFTimeGrid; - - - /** @brief Internal routine to interpolate the AIF to the current time point t used for integration - * The numerical integration of ODEINT is performed on an adaptive timegrid (adaptive step size dt) different from the time grid of the AIF and model function. - * Thus, the AIF value Ca(t) has to be interpolated from the set AIF - */ - double InterpolateAIFToCurrentTimeStep(double t) - { - double lastValue = m_AIF[0]; - double lastTime = std::numeric_limits::min(); - - AIFType::const_iterator posITime = m_AIFTimeGrid.begin(); - AIFType::const_iterator posValue = m_AIF.begin(); - - while(t > *posITime) - { - lastValue = *posValue; - lastTime = *posITime; - ++posValue; - ++posITime; - } - double weightLast = 1 - (t - lastTime)/(*posITime - lastTime); - double weightNext = 1- (*posITime - t)/(*posITime - lastTime); - double result = weightLast * lastValue + weightNext * (*posValue); - - return result; - } - -}; -} - -#endif diff --git a/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModelFactoryBase.h b/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModelFactoryBase.h index 2430ab8a15..ad8047cf3b 100644 --- a/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModelFactoryBase.h +++ b/Modules/Pharmacokinetics/include/mitkTwoTissueCompartmentModelFactoryBase.h @@ -1,81 +1,81 @@ /*============================================================================ 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 mitkTwoTissueCompartmentModelFactoryBase_h #define mitkTwoTissueCompartmentModelFactoryBase_h #include "mitkConcreteAIFBasedModelFactory.h" #include "mitkAIFBasedModelParameterizerBase.h" #include "mitkSimpleBarrierConstraintChecker.h" namespace mitk { template class TwoTissueCompartmentModelFactoryBase : public mitk::ConcreteAIFBasedModelFactory< TModelParameterizer > { public: mitkClassMacro(TwoTissueCompartmentModelFactoryBase, ConcreteAIFBasedModelFactory< TModelParameterizer >); itkFactorylessNewMacro(Self); typedef typename Superclass::ModelType ModelType; typedef typename Superclass::ModelParameterizerType ModelParameterizerType; typedef typename Superclass::ParametersType ParametersType; ConstraintCheckerBase::Pointer CreateDefaultConstraints() const override { SimpleBarrierConstraintChecker::Pointer constraints = SimpleBarrierConstraintChecker::New(); /**@todo Mit Charlie klaren ob es eine sinnvolle default Einstellung gibt.*/ constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_K1, 0, 0); constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k2, 0, 0); constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k3, 0, 0); constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k4, 0, 0); - constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_VB, 0, 0); - constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_VB, 1, 0); + constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_vb, 0, 0); + constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_vb, 1, 0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_K1, 1.0, 0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_k2, 1.0, 0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_k3, 1.0, 0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_k4, 1.0, 0); return constraints.GetPointer(); }; ParametersType GetDefaultInitialParameterization() const override { typename ModelParameterizerType::Pointer modelParameterizer = ModelParameterizerType::New(); return modelParameterizer->GetDefaultInitialParameterization(); }; protected: TwoTissueCompartmentModelFactoryBase() { }; ~TwoTissueCompartmentModelFactoryBase() override { }; private: //No copy constructor allowed TwoTissueCompartmentModelFactoryBase(const Self& source); void operator=(const Self&); //purposely not implemented }; } #endif diff --git a/Modules/Pharmacokinetics/src/Common/mitkPixelBasedDescriptionParameterImageGenerator.cpp b/Modules/Pharmacokinetics/src/Common/mitkPixelBasedDescriptionParameterImageGenerator.cpp index 287ca01c4a..301fd846cb 100644 --- a/Modules/Pharmacokinetics/src/Common/mitkPixelBasedDescriptionParameterImageGenerator.cpp +++ b/Modules/Pharmacokinetics/src/Common/mitkPixelBasedDescriptionParameterImageGenerator.cpp @@ -1,191 +1,191 @@ /*============================================================================ 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 "itkCommand.h" #include "itkMultiOutputNaryFunctorImageFilter.h" #include "mitkPixelBasedDescriptionParameterImageGenerator.h" #include "mitkImageTimeSelector.h" #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" #include "mitkSimpleFunctorPolicy.h" #include "mitkModelBase.h" void mitk::PixelBasedDescriptionParameterImageGenerator:: onFitProgressEvent(::itk::Object* caller, const ::itk::EventObject& /*eventObject*/) { - this->InvokeEvent(::itk::ProgressEvent()); itk::ProcessObject* process = dynamic_cast(caller); if (process) { this->m_Progress = process->GetProgress(); } + this->InvokeEvent(::itk::ProgressEvent()); }; template void mitk::PixelBasedDescriptionParameterImageGenerator::DoPrepareMask(itk::Image* image) { m_InternalMask = dynamic_cast(image); if (m_InternalMask.IsNull()) { MITK_INFO << "Parameter Fit Generator. Need to cast mask for parameter fit."; typedef itk::Image InputImageType; typedef itk::CastImageFilter< InputImageType, InternalMaskType > CastFilterType; typename CastFilterType::Pointer spImageCaster = CastFilterType::New(); spImageCaster->SetInput(image); m_InternalMask = spImageCaster->GetOutput(); spImageCaster->Update(); } } template mitk::PixelBasedDescriptionParameterImageGenerator::ParameterImageMapType StoreResultImages(const mitk::CurveParameterFunctor::ParameterNamesType ¶mNames, itk::ImageSource* source) { if (source->GetNumberOfOutputs() != paramNames.size()) { mitkThrow() << "Error while generating fitted parameter images. Number of sources does not match expected parameter number. Output size: " << source->GetNumberOfOutputs() << "; number of param names: " << paramNames.size(); } mitk::PixelBasedDescriptionParameterImageGenerator::ParameterImageMapType result; for (mitk::CurveParameterFunctor::ParameterNamesType::size_type j = 0; j < paramNames.size(); ++j) { mitk::Image::Pointer paramImage = mitk::Image::New(); typename TImage::ConstPointer outputImg = source->GetOutput(j); mitk::CastToMitkImage(outputImg, paramImage); result.insert(std::make_pair(paramNames[j],paramImage)); } return result; } template void mitk::PixelBasedDescriptionParameterImageGenerator::DoParameterCalculation(itk::Image* /*image*/) { typedef itk::Image InputFrameImageType; typedef itk::Image ParameterImageType; typedef itk::MultiOutputNaryFunctorImageFilter DescriptorFilterType; typename DescriptorFilterType::Pointer descFilter = DescriptorFilterType::New(); typename ::itk::MemberCommand::Pointer spProgressCommand = ::itk::MemberCommand::New(); spProgressCommand->SetCallbackFunction(this, &Self::onFitProgressEvent); descFilter->AddObserver(::itk::ProgressEvent(), spProgressCommand); //add the time frames to the descriptor filter std::vector frameCache; for (unsigned int i = 0; i < this->m_DynamicImage->GetTimeSteps(); ++i) { typename InputFrameImageType::Pointer frameImage; mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(this->m_DynamicImage); imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); Image::Pointer frameMITKImage = imageTimeSelector->GetOutput(); frameCache.push_back(frameMITKImage); mitk::CastToItkImage(frameMITKImage, frameImage); descFilter->SetInput(i,frameImage); } SimpleFunctorPolicy functor; functor.SetFunctor(this->m_Functor); descFilter->SetFunctor(functor); if (this->m_InternalMask.IsNotNull()) { descFilter->SetMask(this->m_InternalMask); } //generate the fits descFilter->Update(); //convert the outputs into mitk images and fill the parameter image map CurveParameterFunctor::ParameterNamesType paramNames = this->m_Functor->GetDescriptionParameterNames(); if (descFilter->GetNumberOfOutputs() != (paramNames.size())) { mitkThrow() << "Error while generating fitted parameter images. Fit filter output size does not match expected parameter number. Output size: "<< descFilter->GetNumberOfOutputs(); } this->m_TempResultMap = StoreResultImages(paramNames,descFilter); } bool mitk::PixelBasedDescriptionParameterImageGenerator::HasOutdatedResult() const { bool result = Superclass::HasOutdatedResult(); if (m_DynamicImage.IsNotNull()) { if (m_DynamicImage->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } if (m_Mask.IsNotNull()) { if (m_Mask->GetMTime() > this->m_GenerationTimeStamp) { result = true; } } return result; }; void mitk::PixelBasedDescriptionParameterImageGenerator::CheckValidInputs() const { Superclass::CheckValidInputs(); if (m_DynamicImage.IsNull()) { mitkThrow() << "Cannot generate fitted parameter images. Input dynamic image is not set."; } }; void mitk::PixelBasedDescriptionParameterImageGenerator::DoParameterCalculationAndGetResults(ParameterImageMapType& parameterImages) { this->m_Progress = 0; if(this->m_Mask.IsNotNull()) { AccessFixedDimensionByItk(m_Mask, mitk::PixelBasedDescriptionParameterImageGenerator::DoPrepareMask, 3); } else { this->m_InternalMask = nullptr; } AccessFixedDimensionByItk(m_DynamicImage, mitk::PixelBasedDescriptionParameterImageGenerator::DoParameterCalculation, 4); parameterImages = this->m_TempResultMap; }; double mitk::PixelBasedDescriptionParameterImageGenerator::GetProgress() const { return m_Progress; }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkAIFBasedModelBase.cpp b/Modules/Pharmacokinetics/src/Models/mitkAIFBasedModelBase.cpp index b746b38fec..78fe64e9b3 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkAIFBasedModelBase.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkAIFBasedModelBase.cpp @@ -1,183 +1,192 @@ /*============================================================================ 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 "mitkAIFBasedModelBase.h" #include "mitkTimeGridHelper.h" #include "mitkAIFParametrizerHelper.h" #include "itkArray2D.h" +const unsigned int mitk::AIFBasedModelBase::NUMBER_OF_STATIC_PARAMETERS = 2; -const std::string mitk::AIFBasedModelBase::NAME_STATIC_PARAMETER_AIF = "Aterial Input Function"; +const std::string mitk::AIFBasedModelBase::NAME_STATIC_PARAMETER_AIF = "Arterial Input Function"; const std::string mitk::AIFBasedModelBase::NAME_STATIC_PARAMETER_AIFTimeGrid = - "Aterial Input Function Timegrid"; + "Arterial Input Function Timegrid"; //Assumed AIF is always extracted from concentration image -const std::string mitk::AIFBasedModelBase::UNIT_STATIC_PARAMETER_AIF = "C"; +const std::string mitk::AIFBasedModelBase::UNIT_STATIC_PARAMETER_AIF = "mM"; const std::string mitk::AIFBasedModelBase::UNIT_STATIC_PARAMETER_AIFTimeGrid = "s"; +const std::string mitk::AIFBasedModelBase::X_AXIS_NAME = "Time"; + +const std::string mitk::AIFBasedModelBase::X_AXIS_UNIT = "s"; + +const std::string mitk::AIFBasedModelBase::Y_AXIS_NAME = "Concentration"; + +const std::string mitk::AIFBasedModelBase::Y_AXIS_UNIT = "mM"; + std::string mitk::AIFBasedModelBase::GetXAxisName() const { - return "Time"; + return X_AXIS_NAME; }; std::string mitk::AIFBasedModelBase::GetXAxisUnit() const { - return "s"; + return X_AXIS_UNIT; } std::string mitk::AIFBasedModelBase::GetYAxisName() const { - return ""; + return Y_AXIS_NAME; }; std::string mitk::AIFBasedModelBase::GetYAxisUnit() const { - return ""; + return Y_AXIS_UNIT; } mitk::AIFBasedModelBase::AIFBasedModelBase() { } mitk::AIFBasedModelBase::~AIFBasedModelBase() { } const mitk::AIFBasedModelBase::TimeGridType& mitk::AIFBasedModelBase::GetCurrentAterialInputFunctionTimeGrid() const { if (!m_AterialInputFunctionTimeGrid.empty()) { return m_AterialInputFunctionTimeGrid; } else { return m_TimeGrid; } }; const mitk::AIFBasedModelBase::AterialInputFunctionType mitk::AIFBasedModelBase::GetAterialInputFunction(TimeGridType CurrentTimeGrid) const { if (CurrentTimeGrid.GetSize() == 0) { return this->m_AterialInputFunctionValues; } else { return mitk::InterpolateSignalToNewTimeGrid(m_AterialInputFunctionValues, GetCurrentAterialInputFunctionTimeGrid(), CurrentTimeGrid); } } mitk::AIFBasedModelBase::ParameterNamesType mitk::AIFBasedModelBase::GetStaticParameterNames() const { ParameterNamesType result; result.push_back(NAME_STATIC_PARAMETER_AIF); result.push_back(NAME_STATIC_PARAMETER_AIFTimeGrid); return result; } mitk::AIFBasedModelBase::ParametersSizeType mitk::AIFBasedModelBase::GetNumberOfStaticParameters() const { - return 2; + return NUMBER_OF_STATIC_PARAMETERS; } mitk::AIFBasedModelBase::ParamterUnitMapType mitk::AIFBasedModelBase::GetStaticParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair(NAME_STATIC_PARAMETER_AIF, UNIT_STATIC_PARAMETER_AIF)); result.insert(std::make_pair(NAME_STATIC_PARAMETER_AIFTimeGrid, UNIT_STATIC_PARAMETER_AIFTimeGrid)); return result; }; void mitk::AIFBasedModelBase::SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) { if (name == NAME_STATIC_PARAMETER_AIF) { AterialInputFunctionType aif = mitk::convertParameterToArray(values); SetAterialInputFunctionValues(aif); } if (name == NAME_STATIC_PARAMETER_AIFTimeGrid) { TimeGridType timegrid = mitk::convertParameterToArray(values); SetAterialInputFunctionTimeGrid(timegrid); } }; mitk::AIFBasedModelBase::StaticParameterValuesType mitk::AIFBasedModelBase::GetStaticParameterValue( const ParameterNameType& name) const { StaticParameterValuesType result; if (name == NAME_STATIC_PARAMETER_AIF) { result = mitk::convertArrayToParameter(this->m_AterialInputFunctionValues); } if (name == NAME_STATIC_PARAMETER_AIFTimeGrid) { result = mitk::convertArrayToParameter(this->m_AterialInputFunctionTimeGrid); } return result; }; bool mitk::AIFBasedModelBase::ValidateModel(std::string& error) const { bool result = Superclass::ValidateModel(error); if (result) { if (m_AterialInputFunctionTimeGrid.empty()) { if (this->m_TimeGrid.GetSize() != m_AterialInputFunctionValues.GetSize()) { result = false; error = "Number of elements of Model Time Grid does not match number of elements in Aterial Input Function! Set valid aif or aif time grid."; } } else { if (m_AterialInputFunctionTimeGrid.GetSize() != m_AterialInputFunctionValues.GetSize()) { result = false; error = "Number of elements of Aterial Input Function Time Grid does not match number of elements of Aterial Input Function Values! Set valid curve"; } } } return result; }; void mitk::AIFBasedModelBase::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); - os << indent << "Aterial Input Function: " << m_AterialInputFunctionValues; - os << indent << "Aterial Input Function Time Grid: " << m_AterialInputFunctionTimeGrid; + os << indent << "Arterial Input Function: " << m_AterialInputFunctionValues; + os << indent << "Arterial Input Function Time Grid: " << m_AterialInputFunctionTimeGrid; }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModel.cpp index 438f0353c3..81aef2e2ba 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModel.cpp @@ -1,263 +1,271 @@ /*============================================================================ 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 "mitkDescriptivePharmacokineticBrixModel.h" const std::string mitk::DescriptivePharmacokineticBrixModel::MODEL_DISPLAY_NAME = "Descriptive Pharmacokinetic Brix Model"; +const std::string mitk::DescriptivePharmacokineticBrixModel::MODEL_TYPE = +"Perfusion.MR"; + const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_PARAMETER_A = "A"; -const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_PARAMETER_kep = "kep"; -const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_PARAMETER_kel = "kel"; -//tlag in minutes -const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_PARAMETER_tlag = "tlag"; +const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_PARAMETER_kep = "k_{e->p}"; +const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_PARAMETER_kel = "k_{el}"; +const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_PARAMETER_BAT = "BAT"; const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_PARAMETER_A = "a.u."; const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_PARAMETER_kep = "1/min"; const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_PARAMETER_kel = "1/min"; -//tlag in minutes -const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_PARAMETER_tlag = "min"; +const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_PARAMETER_BAT = "min"; -const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_STATIC_PARAMETER_Tau = "Tau"; -const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_STATIC_PARAMETER_S0 = "S0"; +const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_STATIC_PARAMETER_tau = "Injection_time"; +const std::string mitk::DescriptivePharmacokineticBrixModel::NAME_STATIC_PARAMETER_s0 = "Pre_contrast_signal"; -const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_STATIC_PARAMETER_Tau = "min"; -const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_STATIC_PARAMETER_S0 = "I"; +const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_STATIC_PARAMETER_tau = "min"; +const std::string mitk::DescriptivePharmacokineticBrixModel::UNIT_STATIC_PARAMETER_s0 = "a.u."; const unsigned int mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_A = 0; const unsigned int mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_kep = 1; const unsigned int mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_kel = 2; -const unsigned int mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_tlag = 3; +const unsigned int mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_BAT = 3; const unsigned int mitk::DescriptivePharmacokineticBrixModel::NUMBER_OF_PARAMETERS = 4; +const unsigned int mitk::DescriptivePharmacokineticBrixModel::NUMBER_OF_STATIC_PARAMETERS = 2; + +const std::string mitk::DescriptivePharmacokineticBrixModel::X_AXIS_NAME = "Time"; +const std::string mitk::DescriptivePharmacokineticBrixModel::X_AXIS_UNIT = "s"; +const std::string mitk::DescriptivePharmacokineticBrixModel::Y_AXIS_NAME = "Signal"; +const std::string mitk::DescriptivePharmacokineticBrixModel::Y_AXIS_UNIT = "a.u."; + std::string mitk::DescriptivePharmacokineticBrixModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::DescriptivePharmacokineticBrixModel::GetModelType() const { - return "Perfusion.MR"; + return MODEL_TYPE; }; std::string mitk::DescriptivePharmacokineticBrixModel::GetXAxisName() const { - return "Time"; + return X_AXIS_NAME; }; std::string mitk::DescriptivePharmacokineticBrixModel::GetXAxisUnit() const { - return "s"; + return X_AXIS_UNIT; } std::string mitk::DescriptivePharmacokineticBrixModel::GetYAxisName() const { - return ""; + return Y_AXIS_NAME; }; std::string mitk::DescriptivePharmacokineticBrixModel::GetYAxisUnit() const { - return ""; + return Y_AXIS_UNIT; } mitk::DescriptivePharmacokineticBrixModel::DescriptivePharmacokineticBrixModel(): m_Tau(0), m_S0(1) { } mitk::DescriptivePharmacokineticBrixModel::~DescriptivePharmacokineticBrixModel() { } mitk::DescriptivePharmacokineticBrixModel::ParameterNamesType mitk::DescriptivePharmacokineticBrixModel::GetParameterNames() const { ParameterNamesType result; result.push_back(NAME_PARAMETER_A); result.push_back(NAME_PARAMETER_kep); result.push_back(NAME_PARAMETER_kel); - result.push_back(NAME_PARAMETER_tlag); + result.push_back(NAME_PARAMETER_BAT); return result; } mitk::DescriptivePharmacokineticBrixModel::ParametersSizeType mitk::DescriptivePharmacokineticBrixModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } mitk::DescriptivePharmacokineticBrixModel::ParamterUnitMapType mitk::DescriptivePharmacokineticBrixModel::GetParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair(NAME_PARAMETER_A, UNIT_PARAMETER_A)); result.insert(std::make_pair(NAME_PARAMETER_kep, UNIT_PARAMETER_kep)); result.insert(std::make_pair(NAME_PARAMETER_kel, UNIT_PARAMETER_kel)); - result.insert(std::make_pair(NAME_PARAMETER_tlag, UNIT_PARAMETER_tlag)); + result.insert(std::make_pair(NAME_PARAMETER_BAT, UNIT_PARAMETER_BAT)); return result; }; mitk::DescriptivePharmacokineticBrixModel::ParameterNamesType mitk::DescriptivePharmacokineticBrixModel::GetStaticParameterNames() const { ParameterNamesType result; - result.push_back(NAME_STATIC_PARAMETER_Tau); - result.push_back(NAME_STATIC_PARAMETER_S0); + result.push_back(NAME_STATIC_PARAMETER_tau); + result.push_back(NAME_STATIC_PARAMETER_s0); return result; } mitk::DescriptivePharmacokineticBrixModel::ParamterUnitMapType mitk::DescriptivePharmacokineticBrixModel::GetStaticParameterUnits() const { ParamterUnitMapType result; - result.insert(std::make_pair(NAME_STATIC_PARAMETER_Tau, UNIT_STATIC_PARAMETER_Tau)); - result.insert(std::make_pair(NAME_STATIC_PARAMETER_S0, UNIT_STATIC_PARAMETER_S0)); + result.insert(std::make_pair(NAME_STATIC_PARAMETER_tau, UNIT_STATIC_PARAMETER_tau)); + result.insert(std::make_pair(NAME_STATIC_PARAMETER_s0, UNIT_STATIC_PARAMETER_s0)); return result; }; mitk::DescriptivePharmacokineticBrixModel::ParametersSizeType mitk::DescriptivePharmacokineticBrixModel::GetNumberOfStaticParameters() const { - return 2; + return NUMBER_OF_STATIC_PARAMETERS; } mitk::DescriptivePharmacokineticBrixModel::ModelResultType mitk::DescriptivePharmacokineticBrixModel::ComputeModelfunction(const ParametersType& parameters) const { if (m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } if (m_Tau == 0) { itkExceptionMacro("Injection time is 0! Cannot Calculate Signal"); } ModelResultType signal(m_TimeGrid.GetSize()); double tx = 0; double amplitude = parameters[POSITION_PARAMETER_A]; double kel = parameters[POSITION_PARAMETER_kel]; double kep = parameters[POSITION_PARAMETER_kep]; - double tlag = parameters[POSITION_PARAMETER_tlag]; + double bat = parameters[POSITION_PARAMETER_BAT]; if (kep == kel) { itkExceptionMacro("(kep-kel) is 0! Cannot Calculate Signal"); } TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); ModelResultType::iterator signalPos = signal.begin(); for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd; ++gridPos, ++signalPos) { double t = (*gridPos) / 60.0; //convert from [sec] to [min] - if (t <= tlag) + if (t <= bat) { tx = 0; } - else if ((t > tlag) && (t < (m_Tau + tlag))) + else if ((t > bat) && (t < (m_Tau + bat))) { - tx = t - tlag; + tx = t - bat; } - else if (t >= (m_Tau + tlag)) + else if (t >= (m_Tau + bat)) { tx = m_Tau; } double kDiff = kep - kel; - double tDiff = t - tlag; + double tDiff = t - bat; double expkel = (kep * exp(-kel * tDiff)); double expkeltx = exp(kel * tx); double expkep = exp(-kep * tDiff); double expkeptx = exp(kep * tx); double value = 1 + (amplitude / m_Tau) * (((expkel / (kel * kDiff)) * (expkeltx - 1)) - (( expkep / kDiff) * (expkeptx - 1))); *signalPos = value * m_S0; } return signal; } void mitk::DescriptivePharmacokineticBrixModel::SetStaticParameter(const ParameterNameType& name, const StaticParameterValuesType& values) { - if (name == NAME_STATIC_PARAMETER_Tau) + if (name == NAME_STATIC_PARAMETER_tau) { SetTau(values[0]); } - if (name == NAME_STATIC_PARAMETER_S0) + if (name == NAME_STATIC_PARAMETER_s0) { SetS0(values[0]); } }; mitk::DescriptivePharmacokineticBrixModel::StaticParameterValuesType mitk::DescriptivePharmacokineticBrixModel::GetStaticParameterValue(const ParameterNameType& name) const { StaticParameterValuesType result; - if (name == NAME_STATIC_PARAMETER_Tau) + if (name == NAME_STATIC_PARAMETER_tau) { result.push_back(GetTau()); } - if (name == NAME_STATIC_PARAMETER_S0) + if (name == NAME_STATIC_PARAMETER_s0) { result.push_back(GetS0()); } return result; }; itk::LightObject::Pointer mitk::DescriptivePharmacokineticBrixModel::InternalClone() const { DescriptivePharmacokineticBrixModel::Pointer newClone = DescriptivePharmacokineticBrixModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); newClone->SetTau(this->m_Tau); newClone->SetS0(this->m_S0); return newClone.GetPointer(); }; void mitk::DescriptivePharmacokineticBrixModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Tau (injection time): " << m_Tau; - os << indent << "S0 (base value): " << m_S0; + os << indent << "S0 (baseline value): " << m_S0; }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelFactory.cpp b/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelFactory.cpp index 906a9bc909..14be13fc5b 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelFactory.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelFactory.cpp @@ -1,90 +1,90 @@ /*============================================================================ 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 #include #include "mitkDescriptivePharmacokineticBrixModelFactory.h" #include "mitkDescriptivePharmacokineticBrixModelParameterizer.h" #include "mitkDescriptivePharmacokineticBrixModelValueBasedParameterizer.h" mitk::DescriptivePharmacokineticBrixModelFactory::DescriptivePharmacokineticBrixModelFactory() { }; mitk::DescriptivePharmacokineticBrixModelFactory::~DescriptivePharmacokineticBrixModelFactory() { }; mitk::ModelParameterizerBase::ParametersType mitk::DescriptivePharmacokineticBrixModelFactory::GetDefaultInitialParameterization() const { return DescriptivePharmacokineticBrixModelParameterizer::New()->GetDefaultInitialParameterization(); }; mitk::ModelParameterizerBase::Pointer mitk::DescriptivePharmacokineticBrixModelFactory::DoCreateParameterizer( const mitk::modelFit::ModelFitInfo* fit) const { mitk::ModelParameterizerBase::Pointer result; if (fit->fitType == ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED()) { DescriptivePharmacokineticBrixModelParameterizer::Pointer modelParameterizer = DescriptivePharmacokineticBrixModelParameterizer::New(); modelFit::StaticParameterMap::ValueType tau = fit->staticParamMap.Get( - DescriptivePharmacokineticBrixModel::NAME_STATIC_PARAMETER_Tau); + DescriptivePharmacokineticBrixModel::NAME_STATIC_PARAMETER_tau); modelParameterizer->SetTau(tau[0]); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(fit->inputImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::DescriptivePharmacokineticBrixModelParameterizer::BaseImageType::Pointer baseImage; mitk::CastToItkImage(imageTimeSelector->GetOutput(), baseImage); modelParameterizer->SetBaseImage(baseImage); result = modelParameterizer.GetPointer(); } else if (fit->fitType == ModelFitConstants::FIT_TYPE_VALUE_ROIBASED()) { DescriptivePharmacokineticBrixModelValueBasedParameterizer::Pointer modelParameterizer = DescriptivePharmacokineticBrixModelValueBasedParameterizer::New(); modelFit::StaticParameterMap::ValueType tau = fit->staticParamMap.Get( - DescriptivePharmacokineticBrixModel::NAME_STATIC_PARAMETER_Tau); + DescriptivePharmacokineticBrixModel::NAME_STATIC_PARAMETER_tau); modelParameterizer->SetTau(tau[0]); if (!fit->inputData.ValueExists("ROI")) { mitkThrow() << "Cannot generate parameterizer for fit of type ROIbased. Input data with the lable \"ROI\" is missing in fit."; } ScalarListLookupTable::ValueType signal = fit->inputData.GetTableValue("ROI"); if (signal.empty()) { mitkThrow() << "Cannot generate parameterizer for fit of type ROIbased. Input data with the lable \"ROI\" is invalid: No values available."; } modelParameterizer->SetBaseValue(signal[0]); result = modelParameterizer.GetPointer(); } return result; }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelParameterizer.cpp b/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelParameterizer.cpp index 9ca922d049..0b75907320 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelParameterizer.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelParameterizer.cpp @@ -1,62 +1,62 @@ /*============================================================================ 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 #include "mitkDescriptivePharmacokineticBrixModel.h" #include "mitkDescriptivePharmacokineticBrixModelParameterizer.h" mitk::DescriptivePharmacokineticBrixModelParameterizer::StaticParameterMapType mitk::DescriptivePharmacokineticBrixModelParameterizer::GetGlobalStaticParameters() const { StaticParameterMapType result; StaticParameterValuesType values; values.push_back(m_Tau); - result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_Tau, values)); + result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_tau, values)); return result; }; mitk::DescriptivePharmacokineticBrixModelParameterizer::StaticParameterMapType mitk::DescriptivePharmacokineticBrixModelParameterizer::GetLocalStaticParameters( const IndexType& currentPosition) const { StaticParameterMapType result; double s0 = m_BaseImage->GetPixel(currentPosition); StaticParameterValuesType values; values.push_back(s0); - result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_S0, values)); + result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_s0, values)); return result; }; mitk::DescriptivePharmacokineticBrixModelParameterizer::ParametersType mitk::DescriptivePharmacokineticBrixModelParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(4); initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_A] = 1.0; initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_kep] = 4.0; initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_kel] = 0.2; - initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_tlag] = 1.0; + initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_BAT] = 1.0; return initialParameters; } mitk::DescriptivePharmacokineticBrixModelParameterizer::DescriptivePharmacokineticBrixModelParameterizer() { }; mitk::DescriptivePharmacokineticBrixModelParameterizer::~DescriptivePharmacokineticBrixModelParameterizer() { }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelValueBasedParameterizer.cpp b/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelValueBasedParameterizer.cpp index da6f2a4acd..767c1f42a0 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelValueBasedParameterizer.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkDescriptivePharmacokineticBrixModelValueBasedParameterizer.cpp @@ -1,61 +1,61 @@ /*============================================================================ 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 #include "mitkDescriptivePharmacokineticBrixModel.h" #include "mitkDescriptivePharmacokineticBrixModelValueBasedParameterizer.h" mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::StaticParameterMapType mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::GetGlobalStaticParameters() const { StaticParameterMapType result; StaticParameterValuesType values; values.push_back(m_Tau); - result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_Tau, values)); + result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_tau, values)); return result; }; mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::StaticParameterMapType mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::GetLocalStaticParameters( const IndexType&) const { StaticParameterMapType result; StaticParameterValuesType values; values.push_back(m_BaseValue); - result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_S0, values)); + result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_s0, values)); return result; }; mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::ParametersType mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(4); initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_A] = 1.0; initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_kep] = 4.0; initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_kel] = 0.2; - initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_tlag] = 1.0; + initialParameters[mitk::DescriptivePharmacokineticBrixModel::POSITION_PARAMETER_BAT] = 1.0; return initialParameters; } mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::DescriptivePharmacokineticBrixModelValueBasedParameterizer() { }; mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::~DescriptivePharmacokineticBrixModelValueBasedParameterizer() { }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModel.cpp index 7cfa46a0c3..355683f1cb 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModel.cpp @@ -1,144 +1,146 @@ /*============================================================================ 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 "mitkExtendedOneTissueCompartmentModel.h" #include "mitkConvolutionHelper.h" #include #include const std::string mitk::ExtendedOneTissueCompartmentModel::MODEL_DISPLAY_NAME = "Extended One Tissue Compartment Model (with blood volume)"; -const std::string mitk::ExtendedOneTissueCompartmentModel::NAME_PARAMETER_k1 = "K1"; -const std::string mitk::ExtendedOneTissueCompartmentModel::NAME_PARAMETER_k2 = "k2"; -const std::string mitk::ExtendedOneTissueCompartmentModel::NAME_PARAMETER_VB = "VB"; +const std::string mitk::ExtendedOneTissueCompartmentModel::NAME_PARAMETER_K1 = "K_1"; +const std::string mitk::ExtendedOneTissueCompartmentModel::NAME_PARAMETER_k2 = "k_2"; +const std::string mitk::ExtendedOneTissueCompartmentModel::NAME_PARAMETER_vb = "v_b"; -const std::string mitk::ExtendedOneTissueCompartmentModel::UNIT_PARAMETER_k1 = "1/min"; +const std::string mitk::ExtendedOneTissueCompartmentModel::UNIT_PARAMETER_K1 = "1/min"; const std::string mitk::ExtendedOneTissueCompartmentModel::UNIT_PARAMETER_k2 = "1/min"; -const std::string mitk::ExtendedOneTissueCompartmentModel::UNIT_PARAMETER_VB = "ml/ml"; +const std::string mitk::ExtendedOneTissueCompartmentModel::UNIT_PARAMETER_vb = "ml/ml"; -const unsigned int mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_k1 = 0; +const unsigned int mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_K1 = 0; const unsigned int mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_k2 = 1; -const unsigned int mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_VB = 2; +const unsigned int mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_vb = 2; const unsigned int mitk::ExtendedOneTissueCompartmentModel::NUMBER_OF_PARAMETERS = 3; +const std::string mitk::ExtendedOneTissueCompartmentModel::MODEL_TYPE = "Dynamic.PET"; + std::string mitk::ExtendedOneTissueCompartmentModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::ExtendedOneTissueCompartmentModel::GetModelType() const { - return "Dynamic.PET"; + return MODEL_TYPE; }; mitk::ExtendedOneTissueCompartmentModel::ExtendedOneTissueCompartmentModel() { } mitk::ExtendedOneTissueCompartmentModel::~ExtendedOneTissueCompartmentModel() { } mitk::ExtendedOneTissueCompartmentModel::ParameterNamesType mitk::ExtendedOneTissueCompartmentModel::GetParameterNames() const { ParameterNamesType result; - result.push_back(NAME_PARAMETER_k1); + result.push_back(NAME_PARAMETER_K1); result.push_back(NAME_PARAMETER_k2); - result.push_back(NAME_PARAMETER_VB); + result.push_back(NAME_PARAMETER_vb); return result; } mitk::ExtendedOneTissueCompartmentModel::ParametersSizeType mitk::ExtendedOneTissueCompartmentModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } mitk::ExtendedOneTissueCompartmentModel::ParamterUnitMapType mitk::ExtendedOneTissueCompartmentModel::GetParameterUnits() const { ParamterUnitMapType result; - result.insert(std::make_pair(NAME_PARAMETER_k1, UNIT_PARAMETER_k1)); + result.insert(std::make_pair(NAME_PARAMETER_K1, UNIT_PARAMETER_K1)); result.insert(std::make_pair(NAME_PARAMETER_k2, UNIT_PARAMETER_k2)); - result.insert(std::make_pair(NAME_PARAMETER_VB, UNIT_PARAMETER_VB)); + result.insert(std::make_pair(NAME_PARAMETER_vb, UNIT_PARAMETER_vb)); return result; }; mitk::ExtendedOneTissueCompartmentModel::ModelResultType mitk::ExtendedOneTissueCompartmentModel::ComputeModelfunction( const ParametersType& parameters) const { if (this->m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } AterialInputFunctionType aterialInputFunction; aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); unsigned int timeSteps = this->m_TimeGrid.GetSize(); //Model Parameters - double K1 = (double) parameters[POSITION_PARAMETER_k1] / 60.0; + double K1 = (double) parameters[POSITION_PARAMETER_K1] / 60.0; double k2 = (double) parameters[POSITION_PARAMETER_k2] / 60.0; - double VB = parameters[POSITION_PARAMETER_VB]; + double vb = parameters[POSITION_PARAMETER_vb]; mitk::ModelBase::ModelResultType convolution = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction, k2); //Signal that will be returned by ComputeModelFunction mitk::ModelBase::ModelResultType signal(timeSteps); signal.fill(0.0); mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); AterialInputFunctionType::const_iterator aifPos = aterialInputFunction.begin(); for (mitk::ModelBase::ModelResultType::const_iterator res = convolution.begin(); res != convolution.end(); ++res, ++signalPos, ++aifPos) { - *signalPos = VB * (*aifPos) + (1 - VB) * K1 * (*res); + *signalPos = vb * (*aifPos) + (1 - vb) * K1 * (*res); } return signal; } itk::LightObject::Pointer mitk::ExtendedOneTissueCompartmentModel::InternalClone() const { ExtendedOneTissueCompartmentModel::Pointer newClone = ExtendedOneTissueCompartmentModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); }; void mitk::ExtendedOneTissueCompartmentModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModelFactory.cpp b/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModelFactory.cpp index d3ec6b0bdb..1fa785b5b1 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModelFactory.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModelFactory.cpp @@ -1,53 +1,53 @@ /*============================================================================ 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 "mitkExtendedOneTissueCompartmentModelFactory.h" #include #include #include mitk::ConstraintCheckerBase::Pointer mitk::ExtendedOneTissueCompartmentModelFactory::CreateDefaultConstraints() const { SimpleBarrierConstraintChecker::Pointer constraints = SimpleBarrierConstraintChecker::New(); - constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k1, 0.0); + constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_K1, 0.0); constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k2, 0.0); - constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_VB, 0.0); + constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_vb, 0.0); - constraints->SetUpperBarrier (ModelType::POSITION_PARAMETER_k1, 1.0); + constraints->SetUpperBarrier (ModelType::POSITION_PARAMETER_K1, 1.0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_k2, 1.0); - constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_VB, 1.0); + constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_vb, 1.0); SimpleBarrierConstraintChecker::ParameterIndexVectorType indices; - indices.push_back(ModelType::POSITION_PARAMETER_k1); + indices.push_back(ModelType::POSITION_PARAMETER_K1); indices.push_back(ModelType::POSITION_PARAMETER_k2); - indices.push_back(ModelType::POSITION_PARAMETER_VB); + indices.push_back(ModelType::POSITION_PARAMETER_vb); return constraints.GetPointer(); }; mitk::ModelParameterizerBase::ParametersType mitk::ExtendedOneTissueCompartmentModelFactory::GetDefaultInitialParameterization() const { return ExtendedOneTissueCompartmentModelParameterizer::New()->GetDefaultInitialParameterization(); }; mitk::ExtendedOneTissueCompartmentModelFactory::ExtendedOneTissueCompartmentModelFactory() { }; mitk::ExtendedOneTissueCompartmentModelFactory::~ExtendedOneTissueCompartmentModelFactory() { }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModelParameterizer.cpp b/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModelParameterizer.cpp index 575ebf12d0..9a5cc1948f 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModelParameterizer.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkExtendedOneTissueCompartmentModelParameterizer.cpp @@ -1,34 +1,34 @@ /*============================================================================ 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 "mitkExtendedOneTissueCompartmentModelParameterizer.h" mitk::ExtendedOneTissueCompartmentModelParameterizer::ParametersType mitk::ExtendedOneTissueCompartmentModelParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(3); - initialParameters[mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_k1] = 0.5; + initialParameters[mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_K1] = 0.5; initialParameters[mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_k2] = 0.5; - initialParameters[mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_VB] = 0.5; + initialParameters[mitk::ExtendedOneTissueCompartmentModel::POSITION_PARAMETER_vb] = 0.5; return initialParameters; }; mitk::ExtendedOneTissueCompartmentModelParameterizer::ExtendedOneTissueCompartmentModelParameterizer() { }; mitk::ExtendedOneTissueCompartmentModelParameterizer::~ExtendedOneTissueCompartmentModelParameterizer() { }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp index dedc6d3917..d178fa721c 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp @@ -1,182 +1,191 @@ /*============================================================================ 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 "mitkExtendedToftsModel.h" #include "mitkConvolutionHelper.h" #include #include const std::string mitk::ExtendedToftsModel::MODEL_DISPLAY_NAME = "Extended Tofts Model"; -const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_Ktrans = "KTrans"; -const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_ve = "ve"; -const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_vp = "vp"; +const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_Ktrans = "K^trans"; +const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_ve = "v_e"; +const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_vp = "v_p"; const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_Ktrans = "ml/min/100ml"; const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_ve = "ml/ml"; const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_vp = "ml/ml"; const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_Ktrans = 0; const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_ve = 1; const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_vp = 2; const unsigned int mitk::ExtendedToftsModel::NUMBER_OF_PARAMETERS = 3; +const std::string mitk::ExtendedToftsModel::NAME_DERIVED_PARAMETER_kep = "k_{e->p}"; + +const unsigned int mitk::ExtendedToftsModel::NUMBER_OF_DERIVED_PARAMETERS = 1; + +const std::string mitk::ExtendedToftsModel::UNIT_DERIVED_PARAMETER_kep = "1/min"; + +const std::string mitk::ExtendedToftsModel::MODEL_TYPE = "Perfusion.MR"; + + std::string mitk::ExtendedToftsModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::ExtendedToftsModel::GetModelType() const { - return "Perfusion.MR"; + return MODEL_TYPE; }; mitk::ExtendedToftsModel::ExtendedToftsModel() { } mitk::ExtendedToftsModel::~ExtendedToftsModel() { } mitk::ExtendedToftsModel::ParameterNamesType mitk::ExtendedToftsModel::GetParameterNames() const { ParameterNamesType result; result.push_back(NAME_PARAMETER_Ktrans); result.push_back(NAME_PARAMETER_ve); result.push_back(NAME_PARAMETER_vp); return result; } mitk::ExtendedToftsModel::ParametersSizeType mitk::ExtendedToftsModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } mitk::ExtendedToftsModel::ParamterUnitMapType mitk::ExtendedToftsModel::GetParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair(NAME_PARAMETER_Ktrans, UNIT_PARAMETER_Ktrans)); result.insert(std::make_pair(NAME_PARAMETER_vp, UNIT_PARAMETER_vp)); result.insert(std::make_pair(NAME_PARAMETER_ve, UNIT_PARAMETER_ve)); return result; }; mitk::ExtendedToftsModel::ParameterNamesType mitk::ExtendedToftsModel::GetDerivedParameterNames() const { ParameterNamesType result; - result.push_back("kep"); + result.push_back(NAME_DERIVED_PARAMETER_kep); return result; }; mitk::ExtendedToftsModel::ParametersSizeType mitk::ExtendedToftsModel::GetNumberOfDerivedParameters() const { - return 1; + return NUMBER_OF_DERIVED_PARAMETERS; }; mitk::ExtendedToftsModel::ParamterUnitMapType mitk::ExtendedToftsModel::GetDerivedParameterUnits() const { ParamterUnitMapType result; - result.insert(std::make_pair("kep", "1/min")); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_kep, UNIT_DERIVED_PARAMETER_kep)); return result; }; mitk::ExtendedToftsModel::ModelResultType mitk::ExtendedToftsModel::ComputeModelfunction( const ParametersType& parameters) const { if (this->m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } AterialInputFunctionType aterialInputFunction; aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); unsigned int timeSteps = this->m_TimeGrid.GetSize(); //Model Parameters double ktrans = parameters[POSITION_PARAMETER_Ktrans] / 6000.0; double ve = parameters[POSITION_PARAMETER_ve]; double vp = parameters[POSITION_PARAMETER_vp]; if (ve == 0.0) { itkExceptionMacro("ve is 0! Cannot calculate signal"); } double lambda = ktrans / ve; mitk::ModelBase::ModelResultType convolution = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction, lambda); //Signal that will be returned by ComputeModelFunction mitk::ModelBase::ModelResultType signal(timeSteps); signal.fill(0.0); mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); mitk::ModelBase::ModelResultType::const_iterator res = convolution.begin(); for (AterialInputFunctionType::iterator Cp = aterialInputFunction.begin(); Cp != aterialInputFunction.end(); ++res, ++signalPos, ++Cp) { *signalPos = (*Cp) * vp + ktrans * (*res); } return signal; } mitk::ModelBase::DerivedParameterMapType mitk::ExtendedToftsModel::ComputeDerivedParameters( const mitk::ModelBase::ParametersType& parameters) const { DerivedParameterMapType result; double kep = parameters[POSITION_PARAMETER_Ktrans] / parameters[POSITION_PARAMETER_ve]; - result.insert(std::make_pair("kep", kep)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_kep, kep)); return result; }; itk::LightObject::Pointer mitk::ExtendedToftsModel::InternalClone() const { ExtendedToftsModel::Pointer newClone = ExtendedToftsModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); }; void mitk::ExtendedToftsModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModel.cpp deleted file mode 100644 index 2d95cd5e57..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModel.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/*============================================================================ - -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 "mitkNumericTwoCompartmentExchangeModel.h" -#include "mitkAIFParametrizerHelper.h" -#include "mitkTimeGridHelper.h" -#include "mitkTwoCompartmentExchangeModelDifferentialEquations.h" -#include -#include -#include - -const std::string mitk::NumericTwoCompartmentExchangeModel::MODEL_DISPLAY_NAME = - "Numeric Two Compartment Exchange Model"; - -const std::string mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_F = "F"; -const std::string mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_PS = "PS"; -const std::string mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_ve = "ve"; -const std::string mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_vp = "vp"; - -const std::string mitk::NumericTwoCompartmentExchangeModel::UNIT_PARAMETER_F = "ml/min/100ml"; -const std::string mitk::NumericTwoCompartmentExchangeModel::UNIT_PARAMETER_PS = "ml/min/100ml"; -const std::string mitk::NumericTwoCompartmentExchangeModel::UNIT_PARAMETER_ve = "ml/ml"; -const std::string mitk::NumericTwoCompartmentExchangeModel::UNIT_PARAMETER_vp = "ml/ml"; - -const unsigned int mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_F = 0; -const unsigned int mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_PS = 1; -const unsigned int mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_ve = 2; -const unsigned int mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_vp = 3; - -const unsigned int mitk::NumericTwoCompartmentExchangeModel::NUMBER_OF_PARAMETERS = 4; - -const std::string mitk::NumericTwoCompartmentExchangeModel::NAME_STATIC_PARAMETER_ODEINTStepSize = "ODEIntStepSize"; - - -std::string mitk::NumericTwoCompartmentExchangeModel::GetModelDisplayName() const -{ - return MODEL_DISPLAY_NAME; -}; - -std::string mitk::NumericTwoCompartmentExchangeModel::GetModelType() const -{ - return "Perfusion.MR"; -}; - - -mitk::NumericTwoCompartmentExchangeModel::NumericTwoCompartmentExchangeModel() -{ - -} - -mitk::NumericTwoCompartmentExchangeModel::~NumericTwoCompartmentExchangeModel() -{ - -} - -mitk::NumericTwoCompartmentExchangeModel::ParameterNamesType mitk::NumericTwoCompartmentExchangeModel::GetStaticParameterNames() const -{ - ParameterNamesType result; - - result.push_back(NAME_STATIC_PARAMETER_AIF); - result.push_back(NAME_STATIC_PARAMETER_AIFTimeGrid); - result.push_back(NAME_STATIC_PARAMETER_ODEINTStepSize); - - return result; -} - -mitk::NumericTwoCompartmentExchangeModel::ParametersSizeType mitk::NumericTwoCompartmentExchangeModel::GetNumberOfStaticParameters() -const -{ - return 3; -} - - -void mitk::NumericTwoCompartmentExchangeModel::SetStaticParameter(const ParameterNameType& name, - const StaticParameterValuesType& values) -{ - if (name == NAME_STATIC_PARAMETER_AIF) - { - AterialInputFunctionType aif = mitk::convertParameterToArray(values); - - SetAterialInputFunctionValues(aif); - } - - if (name == NAME_STATIC_PARAMETER_AIFTimeGrid) - { - TimeGridType timegrid = mitk::convertParameterToArray(values); - - SetAterialInputFunctionTimeGrid(timegrid); - } - - if (name == NAME_STATIC_PARAMETER_ODEINTStepSize) - { - SetODEINTStepSize(values[0]); - } -}; - -mitk::NumericTwoCompartmentExchangeModel::StaticParameterValuesType mitk::NumericTwoCompartmentExchangeModel::GetStaticParameterValue( - const ParameterNameType& name) const -{ - StaticParameterValuesType result; - - if (name == NAME_STATIC_PARAMETER_AIF) - { - result = mitk::convertArrayToParameter(this->m_AterialInputFunctionValues); - } - - if (name == NAME_STATIC_PARAMETER_AIFTimeGrid) - { - result = mitk::convertArrayToParameter(this->m_AterialInputFunctionTimeGrid); - } - if (name == NAME_STATIC_PARAMETER_ODEINTStepSize) - { - result.push_back(GetODEINTStepSize()); - } - - return result; -}; - - -mitk::NumericTwoCompartmentExchangeModel::ParameterNamesType -mitk::NumericTwoCompartmentExchangeModel::GetParameterNames() const -{ - ParameterNamesType result; - - result.push_back(NAME_PARAMETER_F); - result.push_back(NAME_PARAMETER_PS); - result.push_back(NAME_PARAMETER_ve); - result.push_back(NAME_PARAMETER_vp); - - return result; -} - -mitk::NumericTwoCompartmentExchangeModel::ParametersSizeType -mitk::NumericTwoCompartmentExchangeModel::GetNumberOfParameters() const -{ - return NUMBER_OF_PARAMETERS; -} - - -mitk::NumericTwoCompartmentExchangeModel::ParamterUnitMapType -mitk::NumericTwoCompartmentExchangeModel::GetParameterUnits() const -{ - ParamterUnitMapType result; - - result.insert(std::make_pair(NAME_PARAMETER_F, UNIT_PARAMETER_F)); - result.insert(std::make_pair(NAME_PARAMETER_PS, UNIT_PARAMETER_PS)); - result.insert(std::make_pair(NAME_PARAMETER_vp, UNIT_PARAMETER_vp)); - result.insert(std::make_pair(NAME_PARAMETER_ve, UNIT_PARAMETER_ve)); - - return result; -}; - -mitk::NumericTwoCompartmentExchangeModel::ModelResultType -mitk::NumericTwoCompartmentExchangeModel::ComputeModelfunction(const ParametersType& parameters) -const -{ - typedef itk::Array ConcentrationCurveType; - typedef std::vector ConcentrationVectorType; - - if (this->m_TimeGrid.GetSize() == 0) - { - itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); - } - - AterialInputFunctionType aterialInputFunction; - aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); - - unsigned int timeSteps = this->m_TimeGrid.GetSize(); - - /** @brief Boost::numeric::odeint works with type std::vector thus, aif and grid are converted to ModelParameters( of type std::vector) - */ - mitk::TwoCompartmentExchangeModelDifferentialEquations::AIFType aif = mitk::convertArrayToParameter( - aterialInputFunction); - mitk::TwoCompartmentExchangeModelDifferentialEquations::AIFType grid = - mitk::convertArrayToParameter(m_TimeGrid); - - mitk::TwoCompartmentExchangeModelDifferentialEquations::AIFType aifODE = aif; - aifODE.push_back(aif[timeSteps - 1]); - mitk::TwoCompartmentExchangeModelDifferentialEquations::AIFType gridODE = grid; - gridODE.push_back(grid[timeSteps - 1] + (grid[timeSteps - 1] - grid[timeSteps - 2])); - - - - //Model Parameters - double F = (double) parameters[POSITION_PARAMETER_F] / 6000.0; - double PS = (double) parameters[POSITION_PARAMETER_PS] / 6000.0; - double ve = (double) parameters[POSITION_PARAMETER_ve]; - double vp = (double) parameters[POSITION_PARAMETER_vp]; - - - /** @brief Initialize class TwoCompartmentExchangeModelDifferentialEquations defining the differential equations. AIF and Grid must be set so that at step t the aterial Concentration Ca(t) can be interpolated from AIF*/ - mitk::TwoCompartmentExchangeModelDifferentialEquations ode; - ode.initialize(F, PS, ve, vp); - ode.setAIF(aifODE); - ode.setAIFTimeGrid(gridODE); - - state_type x(2); - x[0] = 0.0; - x[1] = 0.0; - typedef boost::numeric::odeint::runge_kutta_cash_karp54 error_stepper_type; - //typedef boost::numeric::odeint::runge_kutta4< state_type > stepper_type; - - /** @brief Results of odeeint x[0] and x[1]*/ - ConcentrationVectorType Cp; - ConcentrationVectorType Ce; - ConcentrationVectorType odeTimeGrid; - - error_stepper_type stepper; - - - /** @brief Stepsize. Should be adapted by stepper (runge_kutta_cash_karp54) */ -// const double dt = 0.05; - const double dt = this->m_ODEINTStepSize; - - - /** @brief perform Step t -> t+dt to calculate approximate value x(t+dt)*/ - for (double t = 0.0; t < this->m_TimeGrid(this->m_TimeGrid.GetSize() - 1) - 2*dt; t += dt) - { - stepper.do_step(ode, x, t, dt); - Cp.push_back(x[0]); - Ce.push_back(x[1]); - odeTimeGrid.push_back(t); - } - - /** @brief transfom result of Differential equations back to itk::Array and interpolate to m_TimeGrid (they are calculated on a different grid defined by stepsize of odeint)*/ - ConcentrationCurveType plasmaConcentration = mitk::convertParameterToArray(Cp); - ConcentrationCurveType EESConcentration = mitk::convertParameterToArray(Ce); - ConcentrationCurveType rungeKuttaTimeGrid = mitk::convertParameterToArray(odeTimeGrid); - - mitk::ModelBase::ModelResultType C_Plasma = mitk::InterpolateSignalToNewTimeGrid(plasmaConcentration, rungeKuttaTimeGrid, m_TimeGrid); - mitk::ModelBase::ModelResultType C_EES = mitk::InterpolateSignalToNewTimeGrid(EESConcentration, rungeKuttaTimeGrid, m_TimeGrid); - - - //Signal that will be returned by ComputeModelFunction - mitk::ModelBase::ModelResultType signal(timeSteps); - signal.fill(0.0); - - mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); - mitk::ModelBase::ModelResultType::const_iterator CePos = C_EES.begin(); - - mitk::ModelBase::ModelResultType::const_iterator t = this->m_TimeGrid.begin(); - mitk::ModelBase::ModelResultType::const_iterator Cin = aterialInputFunction.begin(); - - - - for (mitk::ModelBase::ModelResultType::const_iterator CpPos = C_Plasma.begin(); - CpPos != C_Plasma.end(); ++CpPos, ++CePos, ++signalPos, ++t, ++Cin) - { - *signalPos = vp * (*CpPos) + ve * (*CePos); - - } - - return signal; - -} - - - - -itk::LightObject::Pointer mitk::NumericTwoCompartmentExchangeModel::InternalClone() const -{ - NumericTwoCompartmentExchangeModel::Pointer newClone = NumericTwoCompartmentExchangeModel::New(); - - newClone->SetTimeGrid(this->m_TimeGrid); - - return newClone.GetPointer(); -} - -void mitk::NumericTwoCompartmentExchangeModel::PrintSelf(std::ostream& os, - ::itk::Indent indent) const -{ - Superclass::PrintSelf(os, indent); - - -} - - diff --git a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModelFactory.cpp b/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModelFactory.cpp deleted file mode 100644 index ef04fa136a..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModelFactory.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*============================================================================ - -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 "mitkNumericTwoCompartmentExchangeModelFactory.h" - - -#include "mitkNumericTwoCompartmentExchangeModelParameterizer.h" -#include "mitkAIFParametrizerHelper.h" - -mitk::NumericTwoCompartmentExchangeModelFactory::NumericTwoCompartmentExchangeModelFactory() -{ -}; - -mitk::NumericTwoCompartmentExchangeModelFactory::~NumericTwoCompartmentExchangeModelFactory() -{ -}; - -mitk::ModelParameterizerBase::Pointer -mitk::NumericTwoCompartmentExchangeModelFactory::DoCreateParameterizer( - const modelFit::ModelFitInfo* fit) -const -{ - mitk::ModelParameterizerBase::Pointer result; - - ModelParameterizerType::Pointer modelParameterizer = - ModelParameterizerType::New(); - - modelFit::StaticParameterMap::ValueType aif = fit->staticParamMap.Get( - ModelType::NAME_STATIC_PARAMETER_AIF); - - modelParameterizer->SetAIF(mitk::convertParameterToArray(aif)); - - modelFit::StaticParameterMap::ValueType aifGrid = fit->staticParamMap.Get( - ModelType::NAME_STATIC_PARAMETER_AIFTimeGrid); - modelParameterizer->SetAIFTimeGrid(mitk::convertParameterToArray(aifGrid)); - - modelFit::StaticParameterMap::ValueType odeStepSize = fit->staticParamMap.Get( - ModelType::NAME_STATIC_PARAMETER_ODEINTStepSize); - modelParameterizer->SetODEINTStepSize(odeStepSize[0]); - - - result = modelParameterizer.GetPointer(); - - return result; -}; diff --git a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModelParameterizer.cpp b/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModelParameterizer.cpp deleted file mode 100644 index 25910af578..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoCompartmentExchangeModelParameterizer.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/*============================================================================ - -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 "mitkNumericTwoCompartmentExchangeModelParameterizer.h" - -mitk::NumericTwoCompartmentExchangeModelParameterizer::ParametersType -mitk::NumericTwoCompartmentExchangeModelParameterizer::GetDefaultInitialParameterization() const -{ - ParametersType initialParameters; - initialParameters.SetSize(4); - initialParameters[mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_PS] = 5.0; - initialParameters[mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_F] = 20.0; - initialParameters[mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_ve] = 0.1; - initialParameters[mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_vp] = 0.04; - - return initialParameters; -}; - -mitk::NumericTwoCompartmentExchangeModelParameterizer::NumericTwoCompartmentExchangeModelParameterizer() -{ -}; - -mitk::NumericTwoCompartmentExchangeModelParameterizer::~NumericTwoCompartmentExchangeModelParameterizer() -{ -}; - -mitk::NumericTwoCompartmentExchangeModelParameterizer::StaticParameterMapType mitk::NumericTwoCompartmentExchangeModelParameterizer::GetGlobalStaticParameters() const -{ - StaticParameterMapType result; - StaticParameterValuesType valuesAIF = mitk::convertArrayToParameter(this->m_AIF); - StaticParameterValuesType valuesAIFGrid = mitk::convertArrayToParameter(this->m_AIFTimeGrid); - StaticParameterValuesType values; - values.push_back(m_ODEINTStepSize); - - result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_AIF, valuesAIF)); - result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_AIFTimeGrid, valuesAIFGrid)); - result.insert(std::make_pair(ModelType::NAME_STATIC_PARAMETER_ODEINTStepSize, values)); - - return result; -}; diff --git a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModel.cpp deleted file mode 100644 index bb7226a2d9..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModel.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/*============================================================================ - -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 "mitkNumericTwoTissueCompartmentModel.h" -#include "mitkAIFParametrizerHelper.h" -#include "mitkTimeGridHelper.h" -#include "mitkTwoTissueCompartmentModelDifferentialEquations.h" -#include -#include -#include - -const std::string mitk::NumericTwoTissueCompartmentModel::MODEL_DISPLAY_NAME = - "Numeric Two Tissue Compartment Model"; - -const std::string mitk::NumericTwoTissueCompartmentModel::NAME_PARAMETER_K1 = "K1"; -const std::string mitk::NumericTwoTissueCompartmentModel::NAME_PARAMETER_k2 = "k2"; -const std::string mitk::NumericTwoTissueCompartmentModel::NAME_PARAMETER_k3 = "k3"; -const std::string mitk::NumericTwoTissueCompartmentModel::NAME_PARAMETER_k4 = "k4"; -const std::string mitk::NumericTwoTissueCompartmentModel::NAME_PARAMETER_VB = "V_B"; - -const std::string mitk::NumericTwoTissueCompartmentModel::UNIT_PARAMETER_K1 = "1/min"; -const std::string mitk::NumericTwoTissueCompartmentModel::UNIT_PARAMETER_k2 = "1/min"; -const std::string mitk::NumericTwoTissueCompartmentModel::UNIT_PARAMETER_k3 = "1/min"; -const std::string mitk::NumericTwoTissueCompartmentModel::UNIT_PARAMETER_k4 = "1/min"; -const std::string mitk::NumericTwoTissueCompartmentModel::UNIT_PARAMETER_VB = "ml/ml"; - -const unsigned int mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_K1 = 0; -const unsigned int mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_k2 = 1; -const unsigned int mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_k3 = 2; -const unsigned int mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_k4 = 3; -const unsigned int mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_VB = 4; - -const unsigned int mitk::NumericTwoTissueCompartmentModel::NUMBER_OF_PARAMETERS = 5; - - -std::string mitk::NumericTwoTissueCompartmentModel::GetModelDisplayName() const -{ - return MODEL_DISPLAY_NAME; -}; - -std::string mitk::NumericTwoTissueCompartmentModel::GetModelType() const -{ - return "Dynamic.PET"; -}; - -mitk::NumericTwoTissueCompartmentModel::NumericTwoTissueCompartmentModel() -{ - -} - -mitk::NumericTwoTissueCompartmentModel::~NumericTwoTissueCompartmentModel() -{ - -} - -mitk::NumericTwoTissueCompartmentModel::ParameterNamesType -mitk::NumericTwoTissueCompartmentModel::GetParameterNames() const -{ - ParameterNamesType result; - - result.push_back(NAME_PARAMETER_K1); - result.push_back(NAME_PARAMETER_k2); - result.push_back(NAME_PARAMETER_k3); - result.push_back(NAME_PARAMETER_k4); - result.push_back(NAME_PARAMETER_VB); - - return result; -} - -mitk::NumericTwoTissueCompartmentModel::ParametersSizeType -mitk::NumericTwoTissueCompartmentModel::GetNumberOfParameters() const -{ - return NUMBER_OF_PARAMETERS; -} - -mitk::NumericTwoTissueCompartmentModel::ParamterUnitMapType -mitk::NumericTwoTissueCompartmentModel::GetParameterUnits() const -{ - ParamterUnitMapType result; - - result.insert(std::make_pair(NAME_PARAMETER_K1, UNIT_PARAMETER_K1)); - result.insert(std::make_pair(NAME_PARAMETER_k2, UNIT_PARAMETER_k2)); - result.insert(std::make_pair(NAME_PARAMETER_k3, UNIT_PARAMETER_k3)); - result.insert(std::make_pair(NAME_PARAMETER_k4, UNIT_PARAMETER_k4)); - result.insert(std::make_pair(NAME_PARAMETER_VB, UNIT_PARAMETER_VB)); - - return result; -}; - - -mitk::NumericTwoTissueCompartmentModel::ModelResultType -mitk::NumericTwoTissueCompartmentModel::ComputeModelfunction(const ParametersType& parameters) const -{ - typedef itk::Array ConcentrationCurveType; - typedef std::vector ConcentrationVectorType; - - if (this->m_TimeGrid.GetSize() == 0) - { - itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); - } - - AterialInputFunctionType aterialInputFunction; - aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); - - unsigned int timeSteps = this->m_TimeGrid.GetSize(); - - /** @brief Boost::numeric::odeint works with type std::vector thus, aif and grid are converted to ModelParameters( of type std::vector) - */ - mitk::TwoTissueCompartmentModelDifferentialEquations::AIFType aif = mitk::convertArrayToParameter( - aterialInputFunction); - mitk::TwoTissueCompartmentModelDifferentialEquations::AIFType grid = mitk::convertArrayToParameter( - m_TimeGrid); - - mitk::TwoTissueCompartmentModelDifferentialEquations::AIFType aifODE = aif; - aifODE.push_back(aif[timeSteps - 1]); - mitk::TwoTissueCompartmentModelDifferentialEquations::AIFType gridODE = grid; - gridODE.push_back(grid[timeSteps - 1] + (grid[timeSteps - 1] - grid[timeSteps - 2])); - - //Model Parameters - double K1 = (double)parameters[POSITION_PARAMETER_K1] / 60.0; - double k2 = (double)parameters[POSITION_PARAMETER_k2] / 60.0; - double k3 = (double)parameters[POSITION_PARAMETER_k3] / 60.0; - double k4 = (double)parameters[POSITION_PARAMETER_k4] / 60.0; - double VB = parameters[POSITION_PARAMETER_VB]; - - - /** @brief Initialize class TwpTissueCompartmentModelDifferentialEquations defining the differential equations. AIF and Grid must be set so that at step t the aterial Concentration Ca(t) can be interpolated from AIF*/ - mitk::TwoTissueCompartmentModelDifferentialEquations ode; - ode.initialize(K1, k2, k3, k4); - ode.setAIF(aifODE); - ode.setAIFTimeGrid(gridODE); - - state_type x(2); - x[0] = 0.0; - x[1] = 0.0; - typedef boost::numeric::odeint::runge_kutta_cash_karp54 error_stepper_type; - //typedef boost::numeric::odeint::runge_kutta4< state_type > stepper_type; - - /** @brief Results of odeeint x[0] and x[1]*/ - ConcentrationVectorType C1; - ConcentrationVectorType C2; - ConcentrationVectorType odeTimeGrid; - - error_stepper_type stepper; - /** @brief Stepsize. Should be adapted by stepper (runge_kutta_cash_karp54) */ - const double dt = 0.1; - /** @brief perform Step t -> t+dt to calculate approximate value x(t+dt)*/ - - double T = this->m_TimeGrid(timeSteps - 1) + (grid[timeSteps - 1] - grid[timeSteps - 2]); - - for (double t = 0.0; t < T; t += dt) - { - stepper.do_step(ode, x, t, dt); - C1.push_back(x[0]); - C2.push_back(x[1]); - odeTimeGrid.push_back(t); - - } - - /** @brief transfom result of Differential equations back to itk::Array and interpolate to m_TimeGrid (they are calculated on a different grid defined by stepsize of odeint)*/ - ConcentrationCurveType ConcentrationCompartment1 = mitk::convertParameterToArray(C1); - ConcentrationCurveType ConcentrationCompartment2 = mitk::convertParameterToArray(C2); - ConcentrationCurveType rungeKuttaTimeGrid = mitk::convertParameterToArray(odeTimeGrid); - - mitk::ModelBase::ModelResultType C_1 = mitk::InterpolateSignalToNewTimeGrid( - ConcentrationCompartment1, rungeKuttaTimeGrid, m_TimeGrid); - mitk::ModelBase::ModelResultType C_2 = mitk::InterpolateSignalToNewTimeGrid( - ConcentrationCompartment2, rungeKuttaTimeGrid, m_TimeGrid); - - - //Signal that will be returned by ComputeModelFunction - mitk::ModelBase::ModelResultType signal(timeSteps); - signal.fill(0.0); - mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); - mitk::ModelBase::ModelResultType::const_iterator C1Pos = C_1.begin(); - mitk::ModelBase::ModelResultType::const_iterator C2Pos = C_2.begin(); - - - for (AterialInputFunctionType::const_iterator aifpos = aterialInputFunction.begin(); - aifpos != aterialInputFunction.end(); ++aifpos, ++C1Pos, ++C2Pos, ++signalPos) - { - *signalPos = VB * (*aifpos) + (1 - VB) * (*C1Pos + *C2Pos); - } - - return signal; - -} - -itk::LightObject::Pointer mitk::NumericTwoTissueCompartmentModel::InternalClone() const -{ - NumericTwoTissueCompartmentModel::Pointer newClone = NumericTwoTissueCompartmentModel::New(); - - newClone->SetTimeGrid(this->m_TimeGrid); - - return newClone.GetPointer(); -} - -void mitk::NumericTwoTissueCompartmentModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const -{ - Superclass::PrintSelf(os, indent); - - -} - - - - diff --git a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModelFactory.cpp b/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModelFactory.cpp deleted file mode 100644 index d00b9d3370..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModelFactory.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/*============================================================================ - -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 "mitkNumericTwoTissueCompartmentModelFactory.h" - -#include "mitkNumericTwoTissueCompartmentModelParameterizer.h" -#include "mitkAIFParametrizerHelper.h" - -mitk::NumericTwoTissueCompartmentModelFactory::NumericTwoTissueCompartmentModelFactory() -{ -}; - -mitk::NumericTwoTissueCompartmentModelFactory::~NumericTwoTissueCompartmentModelFactory() -{ -}; - diff --git a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModelParameterizer.cpp b/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModelParameterizer.cpp deleted file mode 100644 index 32bc61366e..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkNumericTwoTissueCompartmentModelParameterizer.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/*============================================================================ - -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 "mitkNumericTwoTissueCompartmentModelParameterizer.h" - -mitk::NumericTwoTissueCompartmentModelParameterizer::ParametersType -mitk::NumericTwoTissueCompartmentModelParameterizer::GetDefaultInitialParameterization() const -{ - ParametersType initialParameters; - initialParameters.SetSize(5); - initialParameters[mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_K1] = 0.23; - initialParameters[mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_k2] = 0.4; - initialParameters[mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_k3] = 0.13; - initialParameters[mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_k4] = 0.15; - initialParameters[mitk::NumericTwoTissueCompartmentModel::POSITION_PARAMETER_VB] = 0.03; - - return initialParameters; -}; - -mitk::NumericTwoTissueCompartmentModelParameterizer::NumericTwoTissueCompartmentModelParameterizer() -{ -}; - -mitk::NumericTwoTissueCompartmentModelParameterizer::~NumericTwoTissueCompartmentModelParameterizer() -{ -}; diff --git a/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModel.cpp index a4d455583e..49deb33fac 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModel.cpp @@ -1,138 +1,141 @@ /*============================================================================ 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 "mitkOneTissueCompartmentModel.h" #include "mitkConvolutionHelper.h" #include #include const std::string mitk::OneTissueCompartmentModel::MODEL_DISPLAY_NAME = "One Tissue Compartment Model"; -const std::string mitk::OneTissueCompartmentModel::NAME_PARAMETER_k1 = "K1"; -const std::string mitk::OneTissueCompartmentModel::NAME_PARAMETER_k2 = "k2"; +const std::string mitk::OneTissueCompartmentModel::NAME_PARAMETER_K1 = "K_1"; +const std::string mitk::OneTissueCompartmentModel::NAME_PARAMETER_k2 = "k_2"; -const std::string mitk::OneTissueCompartmentModel::UNIT_PARAMETER_k1 = "1/min"; +const std::string mitk::OneTissueCompartmentModel::UNIT_PARAMETER_K1 = "1/min"; const std::string mitk::OneTissueCompartmentModel::UNIT_PARAMETER_k2 = "1/min"; -const unsigned int mitk::OneTissueCompartmentModel::POSITION_PARAMETER_k1 = 0; +const unsigned int mitk::OneTissueCompartmentModel::POSITION_PARAMETER_K1 = 0; const unsigned int mitk::OneTissueCompartmentModel::POSITION_PARAMETER_k2 = 1; const unsigned int mitk::OneTissueCompartmentModel::NUMBER_OF_PARAMETERS = 2; +const std::string mitk::OneTissueCompartmentModel::MODEL_TYPE = "Dynamic.PET"; + std::string mitk::OneTissueCompartmentModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::OneTissueCompartmentModel::GetModelType() const { - return "Dynamic.PET"; + return MODEL_TYPE; }; mitk::OneTissueCompartmentModel::OneTissueCompartmentModel() { } mitk::OneTissueCompartmentModel::~OneTissueCompartmentModel() { } mitk::OneTissueCompartmentModel::ParameterNamesType mitk::OneTissueCompartmentModel::GetParameterNames() const { ParameterNamesType result; - result.push_back(NAME_PARAMETER_k1); + result.push_back(NAME_PARAMETER_K1); result.push_back(NAME_PARAMETER_k2); return result; } mitk::OneTissueCompartmentModel::ParametersSizeType mitk::OneTissueCompartmentModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } mitk::OneTissueCompartmentModel::ParamterUnitMapType mitk::OneTissueCompartmentModel::GetParameterUnits() const { ParamterUnitMapType result; - result.insert(std::make_pair(NAME_PARAMETER_k1, UNIT_PARAMETER_k1)); + result.insert(std::make_pair(NAME_PARAMETER_K1, UNIT_PARAMETER_K1)); result.insert(std::make_pair(NAME_PARAMETER_k2, UNIT_PARAMETER_k2)); return result; }; + mitk::OneTissueCompartmentModel::ModelResultType mitk::OneTissueCompartmentModel::ComputeModelfunction( const ParametersType& parameters) const { if (this->m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } AterialInputFunctionType aterialInputFunction; aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); unsigned int timeSteps = this->m_TimeGrid.GetSize(); //Model Parameters - double K1 = (double) parameters[POSITION_PARAMETER_k1] / 60.0; + double K1 = (double) parameters[POSITION_PARAMETER_K1] / 60.0; double k2 = (double) parameters[POSITION_PARAMETER_k2] / 60.0; mitk::ModelBase::ModelResultType convolution = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction, k2); //Signal that will be returned by ComputeModelFunction mitk::ModelBase::ModelResultType signal(timeSteps); signal.fill(0.0); mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); for (mitk::ModelBase::ModelResultType::const_iterator res = convolution.begin(); res != convolution.end(); ++res, ++signalPos) { *signalPos = K1 * (*res); } return signal; } itk::LightObject::Pointer mitk::OneTissueCompartmentModel::InternalClone() const { OneTissueCompartmentModel::Pointer newClone = OneTissueCompartmentModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); }; void mitk::OneTissueCompartmentModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModelFactory.cpp b/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModelFactory.cpp index b9c28d3295..5a2b2c9d1e 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModelFactory.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModelFactory.cpp @@ -1,46 +1,46 @@ /*============================================================================ 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 "mitkOneTissueCompartmentModelFactory.h" #include #include #include mitk::ConstraintCheckerBase::Pointer mitk::OneTissueCompartmentModelFactory::CreateDefaultConstraints() const { SimpleBarrierConstraintChecker::Pointer constraints = SimpleBarrierConstraintChecker::New(); - constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k1, 0.0); + constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_K1, 0.0); constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k2, 0.0); - constraints->SetUpperBarrier (ModelType::POSITION_PARAMETER_k1, 1.0); + constraints->SetUpperBarrier (ModelType::POSITION_PARAMETER_K1, 1.0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_k2, 1.0); return constraints.GetPointer(); }; mitk::ModelParameterizerBase::ParametersType mitk::OneTissueCompartmentModelFactory::GetDefaultInitialParameterization() const { return OneTissueCompartmentModelParameterizer::New()->GetDefaultInitialParameterization(); }; mitk::OneTissueCompartmentModelFactory::OneTissueCompartmentModelFactory() { }; mitk::OneTissueCompartmentModelFactory::~OneTissueCompartmentModelFactory() { }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModelParameterizer.cpp b/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModelParameterizer.cpp index 017db227a0..1dc058f326 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModelParameterizer.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkOneTissueCompartmentModelParameterizer.cpp @@ -1,32 +1,32 @@ /*============================================================================ 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 "mitkOneTissueCompartmentModelParameterizer.h" mitk::OneTissueCompartmentModelParameterizer::ParametersType mitk::OneTissueCompartmentModelParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(2); - initialParameters[mitk::OneTissueCompartmentModel::POSITION_PARAMETER_k1] = 0.5; + initialParameters[mitk::OneTissueCompartmentModel::POSITION_PARAMETER_K1] = 0.5; initialParameters[mitk::OneTissueCompartmentModel::POSITION_PARAMETER_k2] = 0.5; return initialParameters; }; mitk::OneTissueCompartmentModelParameterizer::OneTissueCompartmentModelParameterizer() { }; mitk::OneTissueCompartmentModelParameterizer::~OneTissueCompartmentModelParameterizer() { }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkStandardToftsModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkStandardToftsModel.cpp index 99600b4559..2dcc396a01 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkStandardToftsModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkStandardToftsModel.cpp @@ -1,168 +1,178 @@ /*============================================================================ 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 "mitkStandardToftsModel.h" #include "mitkConvolutionHelper.h" #include #include const std::string mitk::StandardToftsModel::MODEL_DISPLAY_NAME = "Standard Tofts Model"; -const std::string mitk::StandardToftsModel::NAME_PARAMETER_Ktrans = "KTrans"; -const std::string mitk::StandardToftsModel::NAME_PARAMETER_ve = "ve"; +const std::string mitk::StandardToftsModel::NAME_PARAMETER_Ktrans = "K^trans"; +const std::string mitk::StandardToftsModel::NAME_PARAMETER_ve = "v_e"; const std::string mitk::StandardToftsModel::UNIT_PARAMETER_Ktrans = "ml/min/100ml"; const std::string mitk::StandardToftsModel::UNIT_PARAMETER_ve = "ml/ml"; const unsigned int mitk::StandardToftsModel::POSITION_PARAMETER_Ktrans = 0; const unsigned int mitk::StandardToftsModel::POSITION_PARAMETER_ve = 1; const unsigned int mitk::StandardToftsModel::NUMBER_OF_PARAMETERS = 2; +const std::string mitk::StandardToftsModel::NAME_DERIVED_PARAMETER_kep = "k_{e->p}"; + +const unsigned int mitk::StandardToftsModel::NUMBER_OF_DERIVED_PARAMETERS = 1; + +const std::string mitk::StandardToftsModel::UNIT_DERIVED_PARAMETER_kep = "1/min"; + +const std::string mitk::StandardToftsModel::MODEL_TYPE = "Perfusion.MR"; + + + std::string mitk::StandardToftsModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::StandardToftsModel::GetModelType() const { - return "Perfusion.MR"; + return MODEL_TYPE; }; mitk::StandardToftsModel::StandardToftsModel() { } mitk::StandardToftsModel::~StandardToftsModel() { } mitk::StandardToftsModel::ParameterNamesType mitk::StandardToftsModel::GetParameterNames() const { ParameterNamesType result; result.push_back(NAME_PARAMETER_Ktrans); result.push_back(NAME_PARAMETER_ve); return result; } mitk::StandardToftsModel::ParametersSizeType mitk::StandardToftsModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } mitk::StandardToftsModel::ParamterUnitMapType mitk::StandardToftsModel::GetParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair(NAME_PARAMETER_Ktrans, UNIT_PARAMETER_Ktrans)); result.insert(std::make_pair(NAME_PARAMETER_ve, UNIT_PARAMETER_ve)); return result; }; mitk::StandardToftsModel::ParameterNamesType mitk::StandardToftsModel::GetDerivedParameterNames() const { ParameterNamesType result; - result.push_back("kep"); + result.push_back(NAME_DERIVED_PARAMETER_kep); return result; }; mitk::StandardToftsModel::ParametersSizeType mitk::StandardToftsModel::GetNumberOfDerivedParameters() const { - return 1; + return NUMBER_OF_DERIVED_PARAMETERS; }; mitk::StandardToftsModel::ParamterUnitMapType mitk::StandardToftsModel::GetDerivedParameterUnits() const { ParamterUnitMapType result; - result.insert(std::make_pair("kep", "1/min")); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_kep, UNIT_DERIVED_PARAMETER_kep)); return result; }; mitk::StandardToftsModel::ModelResultType mitk::StandardToftsModel::ComputeModelfunction( const ParametersType& parameters) const { if (this->m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } AterialInputFunctionType aterialInputFunction; aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); unsigned int timeSteps = this->m_TimeGrid.GetSize(); //Model Parameters double ktrans = parameters[POSITION_PARAMETER_Ktrans] / 6000.0; double ve = parameters[POSITION_PARAMETER_ve]; double lambda = ktrans / ve; mitk::ModelBase::ModelResultType convolution = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction, lambda); //Signal that will be returned by ComputeModelFunction mitk::ModelBase::ModelResultType signal(timeSteps); signal.fill(0.0); mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); mitk::ModelBase::ModelResultType::const_iterator res = convolution.begin(); for (AterialInputFunctionType::iterator Cp = aterialInputFunction.begin(); Cp != aterialInputFunction.end(); ++res, ++signalPos, ++Cp) { *signalPos = ktrans * (*res); } return signal; } mitk::ModelBase::DerivedParameterMapType mitk::StandardToftsModel::ComputeDerivedParameters( const mitk::ModelBase::ParametersType& parameters) const { DerivedParameterMapType result; double kep = parameters[POSITION_PARAMETER_Ktrans] / parameters[POSITION_PARAMETER_ve]; - result.insert(std::make_pair("kep", kep)); + result.insert(std::make_pair(NAME_DERIVED_PARAMETER_kep, kep)); return result; }; itk::LightObject::Pointer mitk::StandardToftsModel::InternalClone() const { StandardToftsModel::Pointer newClone = StandardToftsModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); }; void mitk::StandardToftsModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkThreeStepLinearModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkThreeStepLinearModel.cpp deleted file mode 100644 index 3c7483f464..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkThreeStepLinearModel.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/*============================================================================ - -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 "mitkThreeStepLinearModel.h" -#include - - -const std::string mitk::ThreeStepLinearModel::MODEL_DISPLAY_NAME = "Three Step Linear Model"; - -const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_s0 = "Baseline"; -const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_t1 = "Time_point_1"; -const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_t2 = "Time_point_2"; -const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_a1 = "Slope_1"; -const std::string mitk::ThreeStepLinearModel::NAME_PARAMETER_a2 = "Slope_2"; - -// Assuming that Model is calculated on Signal intensities I -const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_s0 = "I"; -const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_t1 = "s"; -const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_t2 = "s"; -const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_a1 = "I/s"; -const std::string mitk::ThreeStepLinearModel::UNIT_PARAMETER_a2 = "I/s"; - -const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_s0 = 0; -const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_t1 = 1; -const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_t2 = 2; -const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_a1 = 3; -const unsigned int mitk::ThreeStepLinearModel::POSITION_PARAMETER_a2 = 4; - -const unsigned int mitk::ThreeStepLinearModel::NUMBER_OF_PARAMETERS = 5; - -std::string mitk::ThreeStepLinearModel::GetModelDisplayName() const -{ - return MODEL_DISPLAY_NAME; -}; - -std::string mitk::ThreeStepLinearModel::GetModelType() const -{ - return "Generic"; -}; - -mitk::ThreeStepLinearModel::FunctionStringType mitk::ThreeStepLinearModel::GetFunctionString() const -{ - return "Baseline if t= t1 && x <= t2) - { - signal = a1 * x + b1; - } - else - { - signal = a2 * x + b2; - } - - - return signal; -}; - -mitk::ThreeStepLinearModel::ParamterUnitMapType mitk::ThreeStepLinearModel::GetDerivedParameterUnits() const -{ - ParamterUnitMapType result; - - result.insert(std::make_pair("AUC", "I*s")); - result.insert(std::make_pair("FinalTimePoint", "s")); - result.insert(std::make_pair("FinalUptake", "I")); - result.insert(std::make_pair("Smax", "I")); - result.insert(std::make_pair("y-intercept1", "I")); - result.insert(std::make_pair("y-intercept2", "I")); - - - - - return result; -}; - -mitk::ThreeStepLinearModel::ModelResultType -mitk::ThreeStepLinearModel::ComputeModelfunction(const ParametersType& parameters) const -{ - //Model Parameters - const double s0 = (double) parameters[POSITION_PARAMETER_s0]; - const double t1 = (double) parameters[POSITION_PARAMETER_t1] ; - const double t2 = (double) parameters[POSITION_PARAMETER_t2] ; - const double a1 = (double) parameters[POSITION_PARAMETER_a1] ; - const double a2 = (double) parameters[POSITION_PARAMETER_a2] ; - - double b1 = s0 - a1 * t1; - double b2 = (a1 * t2 + b1) - (a2 * t2); - - ModelResultType signal(m_TimeGrid.GetSize()); - - TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); - - ModelResultType::iterator signalPos = signal.begin(); - - for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd; ++gridPos, ++signalPos) - { - *signalPos = ComputeSignalFromParameters(*gridPos, s0, t1, t2, a1, a2, b1, b2); - } - - return signal; -}; - -mitk::ThreeStepLinearModel::ParameterNamesType mitk::ThreeStepLinearModel::GetStaticParameterNames() const -{ - ParameterNamesType result; - - return result; -} - -mitk::ThreeStepLinearModel::ParametersSizeType mitk::ThreeStepLinearModel::GetNumberOfStaticParameters() const -{ - return 0; -} - -void mitk::ThreeStepLinearModel::SetStaticParameter(const ParameterNameType&, - const StaticParameterValuesType&) -{ - //do nothing -}; - -mitk::ThreeStepLinearModel::StaticParameterValuesType mitk::ThreeStepLinearModel::GetStaticParameterValue( - const ParameterNameType&) const -{ - StaticParameterValuesType result; - - //do nothing - - return result; -}; - -mitk::ModelBase::DerivedParameterMapType mitk::ThreeStepLinearModel::ComputeDerivedParameters( - const mitk::ModelBase::ParametersType& parameters) const -{ - const double s0 = (double) parameters[POSITION_PARAMETER_s0]; - const double t1 = (double) parameters[POSITION_PARAMETER_t1] ; - const double t2 = (double) parameters[POSITION_PARAMETER_t2] ; - const double a1 = (double) parameters[POSITION_PARAMETER_a1] ; - const double a2 = (double) parameters[POSITION_PARAMETER_a2] ; - - const double b1 = s0 - a1 * t1; - const double b2 = (a1 * t2 + b1) - (a2 * t2); - - unsigned int timeSteps = m_TimeGrid.GetSize(); - - const double taq = (m_TimeGrid.empty() == false) ? (m_TimeGrid.GetElement(timeSteps - 1)) : ( mitkThrow() << "An exception occured because time grid is empty, method can't continue."); - - const double sfin = a2 * taq + b2; - - double smax = sfin; - if ((a1 >= 0) && (a2 >= 0)) - smax = sfin; - else if ((a1 < 0) && (a2 < 0)) - smax = s0; - else if ((a1 > 0) && (a2 < 0)) - smax = (a1 * t2 + b1); - else - { - if (abs(a1 * (t2 - t1)) >= abs(a2 * (taq - t2))) - smax = s0; - else smax = sfin; - } - - double auc = 0.0; - TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); - - for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd - 1; ++gridPos) - { - double currentGridPos = *gridPos; - double nextGridPos = *(++gridPos); - double deltaX = nextGridPos - currentGridPos; - double deltaY = ComputeSignalFromParameters(nextGridPos, s0, t1, t2, a1, a2, b1, b2) - ComputeSignalFromParameters(currentGridPos, s0, t1, t2, a1, a2, b1, b2); - double Yi = ComputeSignalFromParameters(currentGridPos, s0, t1, t2, a1, a2, b1, b2 ); - double intI = 0.5 * deltaX * deltaY + Yi * deltaX; - auc += std::abs(intI); - --gridPos; - } - - - DerivedParameterMapType result; - - result.insert(std::make_pair("AUC", auc)); - result.insert(std::make_pair("FinalTimePoint", taq)); - result.insert(std::make_pair("FinalUptake", sfin)); - result.insert(std::make_pair("Smax", smax)); - result.insert(std::make_pair("y-intercept1", b1)); - result.insert(std::make_pair("y-intercept2", b2)); - - - return result; -}; - -itk::LightObject::Pointer mitk::ThreeStepLinearModel::InternalClone() const -{ - ThreeStepLinearModel::Pointer newClone = ThreeStepLinearModel::New(); - - newClone->SetTimeGrid(this->m_TimeGrid); - - return newClone.GetPointer(); -}; diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoCompartmentExchangeModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkTwoCompartmentExchangeModel.cpp index f59e917bed..18cc53af40 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoCompartmentExchangeModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkTwoCompartmentExchangeModel.cpp @@ -1,180 +1,183 @@ /*============================================================================ 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 "mitkTwoCompartmentExchangeModel.h" #include "mitkConvolutionHelper.h" #include -const std::string mitk::TwoCompartmentExchangeModel::MODEL_DISPLAY_NAME = - "Two Compartment Exchange Model"; +const std::string mitk::TwoCompartmentExchangeModel::MODEL_DISPLAY_NAME = "Two Compartment Exchange Model"; -const std::string mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_F = "F"; +const std::string mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_F = "F_p"; const std::string mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_PS = "PS"; -const std::string mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_ve = "ve"; -const std::string mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_vp = "vp"; +const std::string mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_ve = "v_e"; +const std::string mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_vp = "v_p"; const std::string mitk::TwoCompartmentExchangeModel::UNIT_PARAMETER_F = "ml/min/100ml"; const std::string mitk::TwoCompartmentExchangeModel::UNIT_PARAMETER_PS = "ml/min/100ml"; const std::string mitk::TwoCompartmentExchangeModel::UNIT_PARAMETER_ve = "ml/ml"; const std::string mitk::TwoCompartmentExchangeModel::UNIT_PARAMETER_vp = "ml/ml"; const unsigned int mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_F = 0; const unsigned int mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_PS = 1; const unsigned int mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_ve = 2; const unsigned int mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_vp = 3; const unsigned int mitk::TwoCompartmentExchangeModel::NUMBER_OF_PARAMETERS = 4; +const std::string mitk::TwoCompartmentExchangeModel::MODEL_TYPE = "Perfusion.MR"; + + + inline double square(double a) { return a * a; } std::string mitk::TwoCompartmentExchangeModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::TwoCompartmentExchangeModel::GetModelType() const { - return "Perfusion.MR"; + return MODEL_TYPE; }; mitk::TwoCompartmentExchangeModel::TwoCompartmentExchangeModel() { } mitk::TwoCompartmentExchangeModel::~TwoCompartmentExchangeModel() { } mitk::TwoCompartmentExchangeModel::ParameterNamesType mitk::TwoCompartmentExchangeModel::GetParameterNames() const { ParameterNamesType result; result.push_back(NAME_PARAMETER_F); result.push_back(NAME_PARAMETER_PS); result.push_back(NAME_PARAMETER_ve); result.push_back(NAME_PARAMETER_vp); return result; } mitk::TwoCompartmentExchangeModel::ParametersSizeType mitk::TwoCompartmentExchangeModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } mitk::TwoCompartmentExchangeModel::ParamterUnitMapType mitk::TwoCompartmentExchangeModel::GetParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair(NAME_PARAMETER_F, UNIT_PARAMETER_F)); result.insert(std::make_pair(NAME_PARAMETER_PS, UNIT_PARAMETER_PS)); result.insert(std::make_pair(NAME_PARAMETER_vp, UNIT_PARAMETER_vp)); result.insert(std::make_pair(NAME_PARAMETER_ve, UNIT_PARAMETER_ve)); return result; }; mitk::TwoCompartmentExchangeModel::ModelResultType mitk::TwoCompartmentExchangeModel::ComputeModelfunction(const ParametersType& parameters) const { typedef mitk::ModelBase::ModelResultType ConvolutionResultType; if (this->m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } AterialInputFunctionType aterialInputFunction; aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); unsigned int timeSteps = this->m_TimeGrid.GetSize(); mitk::ModelBase::ModelResultType signal(timeSteps); signal.fill(0.0); //Model Parameters double F = parameters[POSITION_PARAMETER_F] / 6000.0; double PS = parameters[POSITION_PARAMETER_PS] / 6000.0; double ve = parameters[POSITION_PARAMETER_ve]; double vp = parameters[POSITION_PARAMETER_vp]; if(PS != 0) { double Tp = vp/(PS + F); double Te = ve/PS; double Tb = vp/F; double Kp = 0.5 *( 1/Tp + 1/Te + sqrt(( 1/Tp + 1/Te )*( 1/Tp + 1/Te ) - 4 * 1/Te*1/Tb) ); double Km = 0.5 *( 1/Tp + 1/Te - sqrt(( 1/Tp + 1/Te )*( 1/Tp + 1/Te ) - 4 * 1/Te*1/Tb) ); double E = ( Kp - 1/Tb )/( Kp - Km ); ConvolutionResultType expp = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction,Kp); ConvolutionResultType expm = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction,Km); //Signal that will be returned by ComputeModelFunction mitk::ModelBase::ModelResultType::const_iterator exppPos = expp.begin(); mitk::ModelBase::ModelResultType::const_iterator expmPos = expm.begin(); for( mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); signalPos!=signal.end(); ++exppPos,++expmPos, ++signalPos) { *signalPos = F * ( *exppPos + E*(*expmPos - *exppPos) ); } } else { double Kp = F/vp; ConvolutionResultType exp = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction,Kp); mitk::ModelBase::ModelResultType::const_iterator expPos = exp.begin(); for( mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); signalPos!=signal.end(); ++expPos, ++signalPos) { *signalPos = F * ( *expPos ); } } return signal; } itk::LightObject::Pointer mitk::TwoCompartmentExchangeModel::InternalClone() const { TwoCompartmentExchangeModel::Pointer newClone = TwoCompartmentExchangeModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); } void mitk::TwoCompartmentExchangeModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); } diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModel.cpp deleted file mode 100644 index 19191106fa..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModel.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/*============================================================================ - -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 "mitkTwoStepLinearModel.h" -#include - -const std::string mitk::TwoStepLinearModel::MODELL_NAME = "Two Step Linear Model"; - -const std::string mitk::TwoStepLinearModel::NAME_PARAMETER_y1 = "BaseValue"; -const std::string mitk::TwoStepLinearModel::NAME_PARAMETER_a1 = "Slope_1"; -const std::string mitk::TwoStepLinearModel::NAME_PARAMETER_t = "Change_Point"; -const std::string mitk::TwoStepLinearModel::NAME_PARAMETER_a2 = "Slope_2"; - -const unsigned int mitk::TwoStepLinearModel::POSITION_PARAMETER_y1 = 0; -const unsigned int mitk::TwoStepLinearModel::POSITION_PARAMETER_t = 1; -const unsigned int mitk::TwoStepLinearModel::POSITION_PARAMETER_a1 = 2; -const unsigned int mitk::TwoStepLinearModel::POSITION_PARAMETER_a2 = 3; - -const unsigned int mitk::TwoStepLinearModel::NUMBER_OF_PARAMETERS = 4; - -std::string mitk::TwoStepLinearModel::GetModelDisplayName() const -{ - return MODELL_NAME; -}; - -std::string mitk::TwoStepLinearModel::GetModelType() const -{ - return "Generic"; -}; - -mitk::TwoStepLinearModel::FunctionStringType mitk::TwoStepLinearModel::GetFunctionString() const -{ - return "Slope_1*t+Y_intercept_1 if t= 0) && (a2 >= 0)) - smax = sfin; - else if ((a1 < 0) && (a2 < 0)) - smax = b1; - else if ((a1 > 0) && (a2 < 0)) - smax = (a1 * t + b1); - else - { - if (abs(a1 * t) >= abs(a2 * (taq - t))) - smax = b1; - else smax = sfin; - } - - double auc = 0.0; - TimeGridType::const_iterator timeGridEnd = m_TimeGrid.end(); - for (TimeGridType::const_iterator gridPos = m_TimeGrid.begin(); gridPos != timeGridEnd -1; ++gridPos) - { - double currentGridPos = *gridPos; - double nextGridPos = *(++gridPos); - double deltaX = nextGridPos - currentGridPos; - double deltaY = ComputeSignalFromParameters(nextGridPos, t, a1, a2, b1, b2) - ComputeSignalFromParameters(currentGridPos, t, a1, a2, b1, b2); - double Yi = ComputeSignalFromParameters(currentGridPos, t, a1, a2, b1, b2); - double intI = 0.5 * deltaX * deltaY + Yi * deltaX; - auc += std::abs(intI); - --gridPos; - } - - DerivedParameterMapType result; - - result.insert(std::make_pair("AUC", auc)); - result.insert(std::make_pair("FinalUptake", sfin)); - result.insert(std::make_pair("Smax", smax)); - result.insert(std::make_pair("y-intercept2", b2)); - - return result; -}; - -itk::LightObject::Pointer mitk::TwoStepLinearModel::InternalClone() const -{ - TwoStepLinearModel::Pointer newClone = TwoStepLinearModel::New(); - - newClone->SetTimeGrid(this->m_TimeGrid); - - return newClone.GetPointer(); -}; diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModelTest.cpp b/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModelTest.cpp deleted file mode 100644 index de8b2e160f..0000000000 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoStepLinearModelTest.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/*============================================================================ - -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. - -============================================================================*/ - - //Testing -#include "mitkModelTestFixture.h" - -//MITK includes -#include "mitkTwoStepLinearModel.h" - - - class mitkTwoStepLinearModelTestSuite : public mitk::mitkModelTestFixture -{ - CPPUNIT_TEST_SUITE(mitkTwoStepLinearModelTestSuite); - MITK_TEST(GetModelInfoTest); - MITK_TEST(ComputeModelfunctionTest); - MITK_TEST(ComputeDerivedParametersTest); - CPPUNIT_TEST_SUITE_END(); - -private: - mitk::TwoStepLinearModel::Pointer m_testmodel; - - json m_profile_json_obj; - json m_modelValues_json_obj; - -public: - void setUp() override - { - // Parse JSON files - m_profile_json_obj = ParseJSONFile("Pharmacokinetics/mitkTwoStepLinearModelTest_profile.json"); - m_modelValues_json_obj = ParseJSONFile("Pharmacokinetics/mitkTwoStepLinearModelTest_modelValues.json"); - - // Generate test model - m_testmodel = mitk::TwoStepLinearModel::New(); - } - - void tearDown() override - { - } - - void GetModelInfoTest() - { - // comparison of reference and testmodel profile - CompareModelAndReferenceProfile(m_testmodel, m_profile_json_obj); - } - - void ComputeModelfunctionTest() - { - CompareModelAndReferenceSignal(m_testmodel, m_modelValues_json_obj, m_profile_json_obj); - } - - void ComputeDerivedParametersTest() - { - CompareModelAndReferenceDerivedParameters(m_testmodel, m_modelValues_json_obj); - } -}; - -MITK_TEST_SUITE_REGISTRATION(mitkTwoStepLinearModel) diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModel.cpp index c7c36c53b5..d978c4fdad 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModel.cpp @@ -1,155 +1,158 @@ /*============================================================================ 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 "mitkTwoTissueCompartmentFDGModel.h" #include "mitkConvolutionHelper.h" #include const std::string mitk::TwoTissueCompartmentFDGModel::MODEL_DISPLAY_NAME = "Two Tissue Compartment Model for FDG (Sokoloff Model)"; -const std::string mitk::TwoTissueCompartmentFDGModel::NAME_PARAMETER_K1 = "K1"; -const std::string mitk::TwoTissueCompartmentFDGModel::NAME_PARAMETER_k2 = "k2"; -const std::string mitk::TwoTissueCompartmentFDGModel::NAME_PARAMETER_k3 = "k3"; -const std::string mitk::TwoTissueCompartmentFDGModel::NAME_PARAMETER_VB = "V_B"; +const std::string mitk::TwoTissueCompartmentFDGModel::NAME_PARAMETER_K1 = "K_1"; +const std::string mitk::TwoTissueCompartmentFDGModel::NAME_PARAMETER_k2 = "k_2"; +const std::string mitk::TwoTissueCompartmentFDGModel::NAME_PARAMETER_k3 = "k_3"; +const std::string mitk::TwoTissueCompartmentFDGModel::NAME_PARAMETER_vb = "v_b"; const std::string mitk::TwoTissueCompartmentFDGModel::UNIT_PARAMETER_K1 = "1/min"; const std::string mitk::TwoTissueCompartmentFDGModel::UNIT_PARAMETER_k2 = "1/min"; const std::string mitk::TwoTissueCompartmentFDGModel::UNIT_PARAMETER_k3 = "1/min"; -const std::string mitk::TwoTissueCompartmentFDGModel::UNIT_PARAMETER_VB = "ml/ml"; +const std::string mitk::TwoTissueCompartmentFDGModel::UNIT_PARAMETER_vb = "ml/ml"; const unsigned int mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_K1 = 0; const unsigned int mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_k2 = 1; const unsigned int mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_k3 = 2; -const unsigned int mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_VB = 3; +const unsigned int mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_vb = 3; const unsigned int mitk::TwoTissueCompartmentFDGModel::NUMBER_OF_PARAMETERS = 4; +const std::string mitk::TwoTissueCompartmentFDGModel::MODEL_TYPE = "Dynamic.PET"; + std::string mitk::TwoTissueCompartmentFDGModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::TwoTissueCompartmentFDGModel::GetModelType() const { - return "Dynamic.PET"; + return MODEL_TYPE; }; mitk::TwoTissueCompartmentFDGModel::TwoTissueCompartmentFDGModel() { } mitk::TwoTissueCompartmentFDGModel::~TwoTissueCompartmentFDGModel() { } mitk::TwoTissueCompartmentFDGModel::ParameterNamesType mitk::TwoTissueCompartmentFDGModel::GetParameterNames() const { ParameterNamesType result; result.push_back(NAME_PARAMETER_K1); result.push_back(NAME_PARAMETER_k2); result.push_back(NAME_PARAMETER_k3); - result.push_back(NAME_PARAMETER_VB); + result.push_back(NAME_PARAMETER_vb); return result; } mitk::TwoTissueCompartmentFDGModel::ParametersSizeType mitk::TwoTissueCompartmentFDGModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } + mitk::TwoTissueCompartmentFDGModel::ParamterUnitMapType mitk::TwoTissueCompartmentFDGModel::GetParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair(NAME_PARAMETER_K1, UNIT_PARAMETER_K1)); result.insert(std::make_pair(NAME_PARAMETER_k2, UNIT_PARAMETER_k2)); result.insert(std::make_pair(NAME_PARAMETER_k3, UNIT_PARAMETER_k3)); - result.insert(std::make_pair(NAME_PARAMETER_VB, UNIT_PARAMETER_VB)); + result.insert(std::make_pair(NAME_PARAMETER_vb, UNIT_PARAMETER_vb)); return result; }; mitk::TwoTissueCompartmentFDGModel::ModelResultType mitk::TwoTissueCompartmentFDGModel::ComputeModelfunction(const ParametersType& parameters) const { if (this->m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } AterialInputFunctionType aterialInputFunction; aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); unsigned int timeSteps = this->m_TimeGrid.GetSize(); //Model Parameters - double k1 = (double)parameters[POSITION_PARAMETER_K1] / 60.0; + double K1 = (double)parameters[POSITION_PARAMETER_K1] / 60.0; double k2 = (double)parameters[POSITION_PARAMETER_k2] / 60.0; double k3 = (double)parameters[POSITION_PARAMETER_k3] / 60.0; - double VB = parameters[POSITION_PARAMETER_VB]; + double vb = parameters[POSITION_PARAMETER_vb]; double lambda = k2+k3; mitk::ModelBase::ModelResultType exp = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction, lambda); mitk::ModelBase::ModelResultType CA = mitk::convoluteAIFWithConstant(this->m_TimeGrid, aterialInputFunction, k3); //Signal that will be returned by ComputeModelFunction mitk::ModelBase::ModelResultType signal(timeSteps); signal.fill(0.0); mitk::ModelBase::ModelResultType::const_iterator expPos = exp.begin(); mitk::ModelBase::ModelResultType::const_iterator CAPos = CA.begin(); AterialInputFunctionType::const_iterator aifPos = aterialInputFunction.begin(); for (mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); signalPos != signal.end(); ++expPos, ++signalPos, ++aifPos) { - double Ci = k1 * k2 /lambda *(*expPos) + k1*k3/lambda*(*CAPos); - *signalPos = VB * (*aifPos) + (1 - VB) * Ci; + double Ci = K1 * k2 /lambda *(*expPos) + K1*k3/lambda*(*CAPos); + *signalPos = vb * (*aifPos) + (1 - vb) * Ci; } return signal; } itk::LightObject::Pointer mitk::TwoTissueCompartmentFDGModel::InternalClone() const { TwoTissueCompartmentFDGModel::Pointer newClone = TwoTissueCompartmentFDGModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); } void mitk::TwoTissueCompartmentFDGModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); } diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModelFactory.cpp b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModelFactory.cpp index 8ada9c010b..cc2d11d4b7 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModelFactory.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModelFactory.cpp @@ -1,50 +1,50 @@ /*============================================================================ 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 "mitkTwoTissueCompartmentFDGModelFactory.h" #include #include #include mitk::ConstraintCheckerBase::Pointer mitk::TwoTissueCompartmentFDGModelFactory::CreateDefaultConstraints() const { SimpleBarrierConstraintChecker::Pointer constraints = SimpleBarrierConstraintChecker::New(); constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_K1, 0.0); constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k2, 0, 0); constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_k3, 0, 0); - constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_VB, 0, 0); + constraints->SetLowerBarrier(ModelType::POSITION_PARAMETER_vb, 0, 0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_K1, 1.0, 0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_k2, 1.0, 0); constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_k3, 1.0, 0); - constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_VB, 1, 0); + constraints->SetUpperBarrier(ModelType::POSITION_PARAMETER_vb, 1, 0); return constraints.GetPointer(); }; mitk::ModelParameterizerBase::ParametersType mitk::TwoTissueCompartmentFDGModelFactory::GetDefaultInitialParameterization() const { return TwoTissueCompartmentFDGModelParameterizer::New()->GetDefaultInitialParameterization(); }; mitk::TwoTissueCompartmentFDGModelFactory::TwoTissueCompartmentFDGModelFactory() { }; mitk::TwoTissueCompartmentFDGModelFactory::~TwoTissueCompartmentFDGModelFactory() { }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModelParameterizer.cpp b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModelParameterizer.cpp index 328dfaa4d8..360b1aeab0 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModelParameterizer.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentFDGModelParameterizer.cpp @@ -1,34 +1,34 @@ /*============================================================================ 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 "mitkTwoTissueCompartmentFDGModelParameterizer.h" mitk::TwoTissueCompartmentFDGModelParameterizer::ParametersType mitk::TwoTissueCompartmentFDGModelParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(4); initialParameters[mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_K1] = 0.5; initialParameters[mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_k2] = 0.5; initialParameters[mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_k3] = 0.5; - initialParameters[mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_VB] = 0.5; + initialParameters[mitk::TwoTissueCompartmentFDGModel::POSITION_PARAMETER_vb] = 0.5; return initialParameters; }; mitk::TwoTissueCompartmentFDGModelParameterizer::TwoTissueCompartmentFDGModelParameterizer() { }; mitk::TwoTissueCompartmentFDGModelParameterizer::~TwoTissueCompartmentFDGModelParameterizer() { }; diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentModel.cpp index a00a006665..9fccbe1f83 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentModel.cpp @@ -1,170 +1,173 @@ /*============================================================================ 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 "mitkTwoTissueCompartmentModel.h" #include "mitkConvolutionHelper.h" #include const std::string mitk::TwoTissueCompartmentModel::MODEL_DISPLAY_NAME = "Two Tissue Compartment Model"; -const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_K1 = "K1"; -const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k2 = "k2"; -const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k3 = "k3"; -const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k4 = "k4"; -const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_VB = "V_B"; +const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_K1 = "K_1"; +const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k2 = "k_2"; +const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k3 = "k_3"; +const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k4 = "k_4"; +const std::string mitk::TwoTissueCompartmentModel::NAME_PARAMETER_vb = "v_b"; const std::string mitk::TwoTissueCompartmentModel::UNIT_PARAMETER_K1 = "1/min"; const std::string mitk::TwoTissueCompartmentModel::UNIT_PARAMETER_k2 = "1/min"; const std::string mitk::TwoTissueCompartmentModel::UNIT_PARAMETER_k3 = "1/min"; const std::string mitk::TwoTissueCompartmentModel::UNIT_PARAMETER_k4 = "1/min"; -const std::string mitk::TwoTissueCompartmentModel::UNIT_PARAMETER_VB = "ml/ml"; +const std::string mitk::TwoTissueCompartmentModel::UNIT_PARAMETER_vb = "ml/ml"; const unsigned int mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_K1 = 0; const unsigned int mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k2 = 1; const unsigned int mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k3 = 2; const unsigned int mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k4 = 3; -const unsigned int mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_VB = 4; +const unsigned int mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_vb = 4; const unsigned int mitk::TwoTissueCompartmentModel::NUMBER_OF_PARAMETERS = 5; +const std::string mitk::TwoTissueCompartmentModel::MODEL_TYPE = "Dynamic.PET"; + inline double square(double a) { return a * a; } std::string mitk::TwoTissueCompartmentModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::TwoTissueCompartmentModel::GetModelType() const { - return "Dynamic.PET"; + return MODEL_TYPE; }; mitk::TwoTissueCompartmentModel::TwoTissueCompartmentModel() { } mitk::TwoTissueCompartmentModel::~TwoTissueCompartmentModel() { } mitk::TwoTissueCompartmentModel::ParameterNamesType mitk::TwoTissueCompartmentModel::GetParameterNames() const { ParameterNamesType result; result.push_back(NAME_PARAMETER_K1); result.push_back(NAME_PARAMETER_k2); result.push_back(NAME_PARAMETER_k3); result.push_back(NAME_PARAMETER_k4); - result.push_back(NAME_PARAMETER_VB); + result.push_back(NAME_PARAMETER_vb); return result; } mitk::TwoTissueCompartmentModel::ParametersSizeType mitk::TwoTissueCompartmentModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } + mitk::TwoTissueCompartmentModel::ParamterUnitMapType mitk::TwoTissueCompartmentModel::GetParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair(NAME_PARAMETER_K1, UNIT_PARAMETER_K1)); result.insert(std::make_pair(NAME_PARAMETER_k2, UNIT_PARAMETER_k2)); result.insert(std::make_pair(NAME_PARAMETER_k3, UNIT_PARAMETER_k3)); result.insert(std::make_pair(NAME_PARAMETER_k4, UNIT_PARAMETER_k4)); - result.insert(std::make_pair(NAME_PARAMETER_VB, UNIT_PARAMETER_VB)); + result.insert(std::make_pair(NAME_PARAMETER_vb, UNIT_PARAMETER_vb)); return result; }; mitk::TwoTissueCompartmentModel::ModelResultType mitk::TwoTissueCompartmentModel::ComputeModelfunction(const ParametersType& parameters) const { if (this->m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } AterialInputFunctionType aterialInputFunction; aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); unsigned int timeSteps = this->m_TimeGrid.GetSize(); //Model Parameters - double k1 = (double)parameters[POSITION_PARAMETER_K1] / 60.0; + double K1 = (double)parameters[POSITION_PARAMETER_K1] / 60.0; double k2 = (double)parameters[POSITION_PARAMETER_k2] / 60.0; double k3 = (double)parameters[POSITION_PARAMETER_k3] / 60.0; double k4 = (double)parameters[POSITION_PARAMETER_k4] / 60.0; - double VB = parameters[POSITION_PARAMETER_VB]; + double vb = parameters[POSITION_PARAMETER_vb]; double alpha1 = 0.5 * ((k2 + k3 + k4) - sqrt(square(k2 + k3 + k4) - 4 * k2 * k4)); double alpha2 = 0.5 * ((k2 + k3 + k4) + sqrt(square(k2 + k3 + k4) - 4 * k2 * k4)); mitk::ModelBase::ModelResultType exp1 = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction, alpha1); mitk::ModelBase::ModelResultType exp2 = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction, alpha2); //Signal that will be returned by ComputeModelFunction mitk::ModelBase::ModelResultType signal(timeSteps); signal.fill(0.0); mitk::ModelBase::ModelResultType::const_iterator exp1Pos = exp1.begin(); mitk::ModelBase::ModelResultType::const_iterator exp2Pos = exp2.begin(); AterialInputFunctionType::const_iterator aifPos = aterialInputFunction.begin(); for (mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); signalPos != signal.end(); ++exp1Pos, ++exp2Pos, ++signalPos, ++aifPos) { - double Ci = k1 / (alpha2 - alpha1) * ((k4 - alpha1 + k3) * (*exp1Pos) + (alpha2 - k4 - k3) * + double Ci = K1 / (alpha2 - alpha1) * ((k4 - alpha1 + k3) * (*exp1Pos) + (alpha2 - k4 - k3) * (*exp2Pos)); - *signalPos = VB * (*aifPos) + (1 - VB) * Ci; + *signalPos = vb * (*aifPos) + (1 - vb) * Ci; } return signal; } itk::LightObject::Pointer mitk::TwoTissueCompartmentModel::InternalClone() const { TwoTissueCompartmentModel::Pointer newClone = TwoTissueCompartmentModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); } void mitk::TwoTissueCompartmentModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); } diff --git a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentModelParameterizer.cpp b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentModelParameterizer.cpp index e724bb2d1e..7ddb0abd61 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentModelParameterizer.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkTwoTissueCompartmentModelParameterizer.cpp @@ -1,35 +1,35 @@ /*============================================================================ 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 "mitkTwoTissueCompartmentModelParameterizer.h" mitk::TwoTissueCompartmentModelParameterizer::ParametersType mitk::TwoTissueCompartmentModelParameterizer::GetDefaultInitialParameterization() const { ParametersType initialParameters; initialParameters.SetSize(5); initialParameters[mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_K1] = 0.5; initialParameters[mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k2] = 0.5; initialParameters[mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k3] = 0.5; initialParameters[mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k4] = 0.5; - initialParameters[mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_VB] = 0.5; + initialParameters[mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_vb] = 0.5; return initialParameters; }; mitk::TwoTissueCompartmentModelParameterizer::TwoTissueCompartmentModelParameterizer() { }; mitk::TwoTissueCompartmentModelParameterizer::~TwoTissueCompartmentModelParameterizer() { }; diff --git a/Modules/Pharmacokinetics/test/files.cmake b/Modules/Pharmacokinetics/test/files.cmake index 41a9258c17..0af3ec8b4a 100644 --- a/Modules/Pharmacokinetics/test/files.cmake +++ b/Modules/Pharmacokinetics/test/files.cmake @@ -1,14 +1,12 @@ SET(MODULE_TESTS mitkDescriptivePharmacokineticBrixModelTest.cpp mitkStandardToftsModelTest.cpp mitkTwoCompartmentExchangeModelTest.cpp mitkExtendedToftsModelTest.cpp mitkConvertSignalToConcentrationTest.cpp mitkCurveDescriptiveParametersTest.cpp - mitkTwoStepLinearModelTest.cpp - mitkThreeStepLinearModelTest.cpp mitkOneTissueCompartmentModelTest.cpp mitkExtendedOneTissueCompartmentModelTest.cpp mitkTwoTissueCompartmentModelTest.cpp mitkTwoTissueCompartmentFDGModelTest.cpp ) diff --git a/Modules/QtWidgets/include/QmitkLevelWindowWidget.h b/Modules/QtWidgets/include/QmitkLevelWindowWidget.h index 573165361b..1dce4bebdc 100644 --- a/Modules/QtWidgets/include/QmitkLevelWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkLevelWindowWidget.h @@ -1,37 +1,49 @@ /*============================================================================ 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 QmitkLevelWindowWidget_h #define QmitkLevelWindowWidget_h #include - -#include "ui_QmitkLevelWindowWidget.h" +#include #include +// Forward declarations +namespace Ui +{ + class QmitkLevelWindow; +} + /// \ingroup QmitkModule -class MITKQTWIDGETS_EXPORT QmitkLevelWindowWidget : public QWidget, public Ui::QmitkLevelWindow +class MITKQTWIDGETS_EXPORT QmitkLevelWindowWidget : public QWidget { Q_OBJECT public: QmitkLevelWindowWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr); + ~QmitkLevelWindowWidget() override; + mitk::LevelWindowManager *GetManager(); public slots: void SetDataStorage(mitk::DataStorage *ds); protected: // unsigned long m_ObserverTag; mitk::LevelWindowManager::Pointer m_Manager; + +private: + // GUI controls of this plugin + Ui::QmitkLevelWindow* ui; + }; #endif diff --git a/Modules/QtWidgets/include/QmitkNodeSelectionButton.h b/Modules/QtWidgets/include/QmitkNodeSelectionButton.h index 2b400c5900..111c63a34a 100644 --- a/Modules/QtWidgets/include/QmitkNodeSelectionButton.h +++ b/Modules/QtWidgets/include/QmitkNodeSelectionButton.h @@ -1,71 +1,71 @@ /*============================================================================ 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 QmitkNodeSelectionButton_h #define QmitkNodeSelectionButton_h #include #include #include #include /** * @class QmitkNodeSelectionButton * @brief Button class that can be used to display information about a given node. * If the given node is a nullptr the node info text will be shown. -* The node info can be formated text (e.g. HTML code; like the tooltip text). +* The node info can be formatted text (e.g. HTML code; like the tooltip text). */ class MITKQTWIDGETS_EXPORT QmitkNodeSelectionButton : public QPushButton { Q_OBJECT public: explicit QmitkNodeSelectionButton(QWidget *parent = nullptr); ~QmitkNodeSelectionButton() override; const mitk::DataNode* GetSelectedNode() const; bool GetSelectionIsOptional() const; public Q_SLOTS: virtual void SetSelectedNode(const mitk::DataNode* node); virtual void SetNodeInfo(QString info); /** Set the widget into an optional mode. Optional means that the selection of no valid node does not mean an invalid state. Thus no node is a valid "node" selection too. The state influences if the info text is handled as an information (optional) or a warning (optiona==false).*/ void SetSelectionIsOptional(bool isOptional); protected: void paintEvent(QPaintEvent *p) override; void changeEvent(QEvent *event) override; void AddNodeObserver(); void RemoveNodeObserver(); void OnNodeModified(const itk::Object * /*caller*/, const itk::EventObject &); mitk::DataNode::ConstPointer m_SelectedNode; QString m_Info; bool m_OutDatedThumbNail; QPixmap m_ThumbNail; itk::ModifiedTimeType m_DataMTime; itk::ModifiedTimeType m_SelectionPropMTime; bool m_IsOptional; unsigned long m_NodeModifiedObserverTag; bool m_NodeObserved; }; #endif diff --git a/Modules/QtWidgets/include/QmitkSingleNodeSelectionWidget.h b/Modules/QtWidgets/include/QmitkSingleNodeSelectionWidget.h index 2ce34485c9..44130cb7e6 100644 --- a/Modules/QtWidgets/include/QmitkSingleNodeSelectionWidget.h +++ b/Modules/QtWidgets/include/QmitkSingleNodeSelectionWidget.h @@ -1,97 +1,97 @@ /*============================================================================ 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 QmitkSingleNodeSelectionWidget_h #define QmitkSingleNodeSelectionWidget_h #include #include #include #include #include #include #include class QmitkAbstractDataStorageModel; /** * @class QmitkSingleNodeSelectionWidget * @brief Widget that represents a node selection of (max) one node. It acts like a button. Clicking on it * allows to change the selection. * * @remark This class provides a public function 'SetAutoSelectNewNodes' that can be used to enable * the auto selection mode (default is false). * The user of this class calling this function has to make sure that the base-class Q_SIGNAL * 'CurrentSelectionChanged', which will be emitted by this function, is already * connected to a receiving slot, if the initial valid auto selection should not get lost. */ class MITKQTWIDGETS_EXPORT QmitkSingleNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget { Q_OBJECT public: explicit QmitkSingleNodeSelectionWidget(QWidget* parent = nullptr); mitk::DataNode::Pointer GetSelectedNode() const; bool GetAutoSelectNewNodes() const; using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; public Q_SLOTS: void SetCurrentSelectedNode(mitk::DataNode* selectedNode); /** * Sets the auto selection mode (default is false). - * If auto select is true and the following conditions are fullfilled, the widget will + * If auto select is true and the following conditions are fulfilled, the widget will * select a node automatically from the data storage: * - a data storage is set * - data storage contains at least one node that matches the given predicate * - no selection is set * * @remark Enabling the auto selection mode by calling 'SetAutoSelectNewNodes(true)' * will directly emit a 'QmitkSingleNodeSelectionWidget::CurrentSelectionChanged' Q_SIGNAL * if a valid auto selection was made. * If this initial emission should not get lost, auto selection mode needs to be enabled after this * selection widget has been connected via the 'QmitkSingleNodeSelectionWidget::CurrentSelectionChanged' * Q_SIGNAL to a receiving function. */ void SetAutoSelectNewNodes(bool autoSelect); protected Q_SLOTS: virtual void OnClearSelection(); protected: void ReviseSelectionChanged(const NodeList& oldInternalSelection, NodeList& newInternalSelection) override; bool eventFilter(QObject *obj, QEvent *ev) override; void EditSelection(); void UpdateInfo() override; void OnDataStorageChanged() override; void OnNodeAddedToStorage(const mitk::DataNode* node) override; void AutoSelectNodes(); /** Helper function that gets a suitable auto selected node from the datastorage that fits to the predicate settings. - @param ignoreNodes You may pass a list of nodes that must not be choosen as auto selected node. */ + @param ignoreNodes You may pass a list of nodes that must not be chosen as auto selected node. */ mitk::DataNode::Pointer DetermineAutoSelectNode(const NodeList& ignoreNodes = {}); /** See documentation of SetAutoSelectNewNodes for details*/ bool m_AutoSelectNodes; Ui_QmitkSingleNodeSelectionWidget m_Controls; }; #endif diff --git a/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp b/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp index 851cf60a9e..75cd50eac3 100644 --- a/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp @@ -1,416 +1,415 @@ /*============================================================================ 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. ============================================================================*/ // mitk qt widgets module #include "QmitkAbstractMultiWidget.h" -#include "QmitkLevelWindowWidget.h" #include "QmitkMultiWidgetLayoutManager.h" #include "QmitkRenderWindowWidget.h" // mitk core #include #include // qt #include // c++ #include struct QmitkAbstractMultiWidget::Impl final { Impl(QmitkAbstractMultiWidget* multiWidget, const QString& multiWidgetName); ~Impl(); void SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; // set new data storage for the render window widgets for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->SetDataStorage(m_DataStorage); } } void InitializeDisplayActionEventHandling() { m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); } mitk::DataStorage::Pointer m_DataStorage; QString m_MultiWidgetName; RenderWindowWidgetMap m_RenderWindowWidgets; RenderWindowWidgetPointer m_ActiveRenderWindowWidget; int m_MultiWidgetRows; int m_MultiWidgetColumns; // interaction unsigned long m_RenderWindowFocusObserverTag; mitk::DisplayActionEventBroadcast::Pointer m_DisplayActionEventBroadcast; std::unique_ptr m_DisplayActionEventHandler; QmitkMultiWidgetLayoutManager* m_LayoutManager; }; QmitkAbstractMultiWidget::Impl::Impl(QmitkAbstractMultiWidget* multiWidget, const QString& multiWidgetName) : m_DataStorage(nullptr) , m_MultiWidgetName(multiWidgetName) , m_MultiWidgetRows(0) , m_MultiWidgetColumns(0) , m_RenderWindowFocusObserverTag(0) , m_DisplayActionEventBroadcast(nullptr) , m_DisplayActionEventHandler(nullptr) , m_LayoutManager(new QmitkMultiWidgetLayoutManager(multiWidget)) { auto command = itk::MemberCommand::New(); command->SetCallbackFunction(multiWidget, &QmitkAbstractMultiWidget::OnFocusChanged); m_RenderWindowFocusObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::FocusChangedEvent(), command); InitializeDisplayActionEventHandling(); } QmitkAbstractMultiWidget::Impl::~Impl() { mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderWindowFocusObserverTag); } QmitkAbstractMultiWidget::QmitkAbstractMultiWidget(QWidget* parent, Qt::WindowFlags f/* = 0*/, const QString& multiWidgetName/* = "multiwidget"*/) : QWidget(parent, f) , m_Impl(std::make_unique(this, multiWidgetName)) { // nothing here } QmitkAbstractMultiWidget::~QmitkAbstractMultiWidget() { } void QmitkAbstractMultiWidget::SetDataStorage(mitk::DataStorage* dataStorage) { m_Impl->SetDataStorage(dataStorage); } mitk::DataStorage* QmitkAbstractMultiWidget::GetDataStorage() const { return m_Impl->m_DataStorage; } int QmitkAbstractMultiWidget::GetRowCount() const { return m_Impl->m_MultiWidgetRows; } int QmitkAbstractMultiWidget::GetColumnCount() const { return m_Impl->m_MultiWidgetColumns; } void QmitkAbstractMultiWidget::SetLayout(int row, int column) { m_Impl->m_MultiWidgetRows = row; m_Impl->m_MultiWidgetColumns = column; SetLayoutImpl(); } void QmitkAbstractMultiWidget::SetInteractionScheme(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) { auto interactionSchemeSwitcher = mitk::InteractionSchemeSwitcher::New(); auto interactionEventHandler = GetInteractionEventHandler(); try { interactionSchemeSwitcher->SetInteractionScheme(interactionEventHandler, scheme); } catch (const mitk::Exception&) { return; } SetInteractionSchemeImpl(); } mitk::InteractionEventHandler* QmitkAbstractMultiWidget::GetInteractionEventHandler() { return m_Impl->m_DisplayActionEventBroadcast.GetPointer(); } void QmitkAbstractMultiWidget::SetDisplayActionEventHandler(std::unique_ptr displayActionEventHandler) { m_Impl->m_DisplayActionEventHandler = std::move(displayActionEventHandler); m_Impl->m_DisplayActionEventHandler->SetObservableBroadcast(m_Impl->m_DisplayActionEventBroadcast); } mitk::DisplayActionEventHandler* QmitkAbstractMultiWidget::GetDisplayActionEventHandler() { return m_Impl->m_DisplayActionEventHandler.get(); } QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::GetRenderWindowWidgets() const { return m_Impl->m_RenderWindowWidgets; } QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::Get2DRenderWindowWidgets() const { RenderWindowWidgetMap renderWindowWidgets2D; auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { auto renderWindow = renderWindowWidget.second->GetRenderWindow(); if(mitk::BaseRenderer::Standard2D == mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow())->GetMapperID()) { renderWindowWidgets2D.insert(std::make_pair(renderWindowWidget.first, renderWindowWidget.second)); } } return renderWindowWidgets2D; } QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::Get3DRenderWindowWidgets() const { RenderWindowWidgetMap renderWindowWidgets3D; auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { auto renderWindow = renderWindowWidget.second->GetRenderWindow(); if (mitk::BaseRenderer::Standard3D == mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow())->GetMapperID()) { renderWindowWidgets3D.insert(std::make_pair(renderWindowWidget.first, renderWindowWidget.second)); } } return renderWindowWidgets3D; } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(int row, int column) const { return GetRenderWindowWidget(GetNameFromIndex(row, column)); } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(const QString& widgetName) const { RenderWindowWidgetMap::const_iterator it = m_Impl->m_RenderWindowWidgets.find(widgetName); if (it != m_Impl->m_RenderWindowWidgets.end()) { return it->second; } return nullptr; } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(const QmitkRenderWindow* renderWindow) const { auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { if (renderWindowWidget.second->GetRenderWindow() == renderWindow) { return renderWindowWidget.second; } } return nullptr; } QmitkAbstractMultiWidget::RenderWindowHash QmitkAbstractMultiWidget::GetRenderWindows() const { RenderWindowHash result; // create QHash on demand auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { result.insert(renderWindowWidget.first, renderWindowWidget.second->GetRenderWindow()); } return result; } QmitkRenderWindow* QmitkAbstractMultiWidget::GetRenderWindow(int row, int column) const { return GetRenderWindow(GetNameFromIndex(row, column)); } QmitkRenderWindow* QmitkAbstractMultiWidget::GetRenderWindow(const QString& widgetName) const { RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetRenderWindow(); } return nullptr; } void QmitkAbstractMultiWidget::SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) { m_Impl->m_ActiveRenderWindowWidget = activeRenderWindowWidget; emit ActiveRenderWindowChanged(); } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetActiveRenderWindowWidget() const { return m_Impl->m_ActiveRenderWindowWidget; } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetFirstRenderWindowWidget() const { if (!m_Impl->m_RenderWindowWidgets.empty()) { return m_Impl->m_RenderWindowWidgets.begin()->second; } else { return nullptr; } } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetLastRenderWindowWidget() const { if (!m_Impl->m_RenderWindowWidgets.empty()) { return m_Impl->m_RenderWindowWidgets.rbegin()->second; } else { return nullptr; } } QString QmitkAbstractMultiWidget::GetNameFromIndex(int row, int column) const { if (0 <= row && m_Impl->m_MultiWidgetRows > row && 0 <= column && m_Impl->m_MultiWidgetColumns > column) { return GetNameFromIndex(row * m_Impl->m_MultiWidgetColumns + column); } return QString(); } QString QmitkAbstractMultiWidget::GetNameFromIndex(size_t index) const { if (index <= m_Impl->m_RenderWindowWidgets.size()) { return m_Impl->m_MultiWidgetName + ".widget" + QString::number(index); } return QString(); } unsigned int QmitkAbstractMultiWidget::GetNumberOfRenderWindowWidgets() const { return m_Impl->m_RenderWindowWidgets.size(); } void QmitkAbstractMultiWidget::RequestUpdate(const QString& widgetName) { RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); if (nullptr != renderWindowWidget) { return renderWindowWidget->RequestUpdate(); } } void QmitkAbstractMultiWidget::RequestUpdateAll() { for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) { renderWindowWidget.second->RequestUpdate(); } } void QmitkAbstractMultiWidget::ForceImmediateUpdate(const QString& widgetName) { RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); if (nullptr != renderWindowWidget) { renderWindowWidget->ForceImmediateUpdate(); } } void QmitkAbstractMultiWidget::ForceImmediateUpdateAll() { for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) { renderWindowWidget.second->ForceImmediateUpdate(); } } void QmitkAbstractMultiWidget::ActivateMenuWidget(bool state) { for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) { auto renderWindow = renderWindowWidget.second->GetRenderWindow(); renderWindow->ActivateMenuWidget(state); } } bool QmitkAbstractMultiWidget::IsMenuWidgetEnabled() const { return m_Impl->m_ActiveRenderWindowWidget->GetRenderWindow()->GetActivateMenuWidgetFlag(); } QmitkMultiWidgetLayoutManager* QmitkAbstractMultiWidget::GetMultiWidgetLayoutManager() const { return m_Impl->m_LayoutManager; } void QmitkAbstractMultiWidget::OnFocusChanged(itk::Object*, const itk::EventObject& event) { auto focusEvent = dynamic_cast(&event); if (nullptr == focusEvent) { return; } auto focusedRenderWindow = mitk::RenderingManager::GetInstance()->GetFocusedRenderWindow(); RenderWindowWidgetMap renderWindowWidgets = this->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { const auto vtkRenderWindow = renderWindowWidget.second->GetRenderWindow()->GetVtkRenderWindow(); if (vtkRenderWindow == focusedRenderWindow) { this->SetActiveRenderWindowWidget(renderWindowWidget.second); break; } } } void QmitkAbstractMultiWidget::AddRenderWindowWidget(const QString& widgetName, RenderWindowWidgetPointer renderWindowWidget) { m_Impl->m_RenderWindowWidgets.insert(std::make_pair(widgetName, renderWindowWidget)); } void QmitkAbstractMultiWidget::RemoveRenderWindowWidget() { auto iterator = m_Impl->m_RenderWindowWidgets.find(this->GetNameFromIndex(this->GetNumberOfRenderWindowWidgets() - 1)); if (iterator == m_Impl->m_RenderWindowWidgets.end()) { return; } // disconnect each signal of this render window widget RenderWindowWidgetPointer renderWindowWidgetToRemove = iterator->second; disconnect(renderWindowWidgetToRemove.get(), 0, 0, 0); // erase the render window from the map m_Impl->m_RenderWindowWidgets.erase(iterator); } diff --git a/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp index fa45000ca7..212a214bcb 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp @@ -1,378 +1,382 @@ /*============================================================================ 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 #include #include // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" QmitkDataStorageSimpleTreeModel::QmitkDataStorageSimpleTreeModel(QObject *parent) : QmitkAbstractDataStorageModel(parent) , m_Root(nullptr) { ResetTree(); } QmitkDataStorageSimpleTreeModel::~QmitkDataStorageSimpleTreeModel() { m_Root->Delete(); m_Root = nullptr; } void QmitkDataStorageSimpleTreeModel::ResetTree() { mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Storage"); m_Root = new TreeItem(rootDataNode, nullptr); } void QmitkDataStorageSimpleTreeModel::DataStorageChanged() { if (m_Root) { m_Root->Delete(); } beginResetModel(); ResetTree(); UpdateModelData(); endResetModel(); } void QmitkDataStorageSimpleTreeModel::NodePredicateChanged() { beginResetModel(); ResetTree(); UpdateModelData(); endResetModel(); } void QmitkDataStorageSimpleTreeModel::NodeAdded(const mitk::DataNode *node) { auto dataStorage = m_DataStorage.Lock(); if (node == nullptr || dataStorage.IsNull() || !dataStorage->Exists(node) || m_Root->Find(node) != nullptr) return; if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)) { this->AddNodeInternal(node); } } void QmitkDataStorageSimpleTreeModel::NodeChanged(const mitk::DataNode *node) { TreeItem *treeItem = m_Root->Find(node); if (treeItem) { TreeItem *parentTreeItem = treeItem->GetParent(); // as the root node should not be removed one should always have a parent item if (!parentTreeItem) return; QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); // now emit the dataChanged signal emit dataChanged(index, index); } } void QmitkDataStorageSimpleTreeModel::NodeRemoved(const mitk::DataNode *node) { if (node == nullptr || !m_Root) return; TreeItem *treeItem = m_Root->Find(node); if (!treeItem) return; // return because there is no treeitem containing this node TreeItem *parentTreeItem = treeItem->GetParent(); QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); // remove node std::vector children = treeItem->GetChildren(); m_TreeItems.remove(treeItem); delete treeItem; //delete in tree if (!children.empty()) { //if not empty we have to rebuild the whole representation, //because the children could be now top level, or at another //source/parent. this->UpdateModelData(); } } QModelIndex QmitkDataStorageSimpleTreeModel::index(int row, int column, const QModelIndex &parent) const { TreeItem *parentItem; if (!parent.isValid() || parent.model() != this) parentItem = m_Root; else parentItem = static_cast(parent.internalPointer()); if (parentItem) { TreeItem *childItem = parentItem->GetChild(row); if (childItem) return createIndex(row, column, childItem); } return QModelIndex(); } QModelIndex QmitkDataStorageSimpleTreeModel::parent(const QModelIndex &child) const { if (!child.isValid() || !m_Root || child.model() != this) return QModelIndex(); TreeItem *childItem = this->TreeItemFromIndex(child); if (!childItem) return QModelIndex(); TreeItem *parentItem = childItem->GetParent(); if (parentItem == m_Root) return QModelIndex(); return this->createIndex(parentItem->GetIndex(), 0, parentItem); } QmitkDataStorageSimpleTreeModel::TreeItem *QmitkDataStorageSimpleTreeModel::TreeItemFromIndex( const QModelIndex &index) const { if (index.isValid() && index.model() == this) { auto item = static_cast(index.internalPointer()); auto finding = std::find(std::begin(m_TreeItems), std::end(m_TreeItems), item); if (finding == std::end(m_TreeItems)) { return nullptr; } return item; } else return m_Root; } int QmitkDataStorageSimpleTreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); if (parentTreeItem) return parentTreeItem->GetChildCount(); else return 0; } int QmitkDataStorageSimpleTreeModel::columnCount(const QModelIndex &/*parent*/) const { return 1; } QVariant QmitkDataStorageSimpleTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.model() != this) { return QVariant(); } auto treeItem = this->TreeItemFromIndex(index); if (!treeItem) return QVariant(); mitk::DataNode *dataNode = treeItem->GetDataNode(); + // No need to access dataNode if that is pointing to nullptr, it will always give segfault + if (!dataNode) + return QModelIndex(); + QString nodeName = QString::fromStdString(dataNode->GetName()); if (nodeName.isEmpty()) { nodeName = "unnamed"; } if (role == Qt::DisplayRole) return nodeName; else if (role == Qt::ToolTipRole) return nodeName; else if (role == Qt::DecorationRole) { QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } else if (role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } return QVariant(); } bool QmitkDataStorageSimpleTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || index.model() != this) return false; auto treeItem = this->TreeItemFromIndex(index); if (!treeItem) return false; mitk::DataNode *dataNode = treeItem->GetDataNode(); if (!dataNode) return false; if (role == Qt::EditRole && !value.toString().isEmpty()) { dataNode->SetName(value.toString().toStdString().c_str()); } else if (role == Qt::CheckStateRole) { // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. // Therefore the checkstate is being estimated again here. QVariant qcheckstate = index.data(Qt::CheckStateRole); int checkstate = qcheckstate.toInt(); bool isVisible = bool(checkstate); dataNode->SetVisibility(!isVisible); } // inform listeners about changes emit dataChanged(index, index); return true; } QVariant QmitkDataStorageSimpleTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) return QString::fromStdString(m_Root->GetDataNode()->GetName()); return QVariant(); } Qt::ItemFlags QmitkDataStorageSimpleTreeModel::flags(const QModelIndex &index) const { if (index.isValid() && index.model() == this) { auto treeItem = this->TreeItemFromIndex(index); if (!treeItem) return Qt::NoItemFlags; const auto dataNode = treeItem->GetDataNode(); if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode)) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; } else { return Qt::NoItemFlags; } } return Qt::NoItemFlags; } mitk::DataNode *QmitkDataStorageSimpleTreeModel::GetParentNode(const mitk::DataNode *node) const { mitk::DataNode *dataNode = nullptr; mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); if (_Sources->Size() > 0) dataNode = _Sources->front(); return dataNode; } void QmitkDataStorageSimpleTreeModel::AddNodeInternal(const mitk::DataNode *node) { auto dataStorage = m_DataStorage.Lock(); if (node == nullptr || dataStorage.IsNull() || !dataStorage->Exists(node) || m_Root->Find(node) != nullptr) return; // find out if we have a root node TreeItem *parentTreeItem = m_Root; QModelIndex index; mitk::DataNode *parentDataNode = this->GetParentNode(node); if (parentDataNode) // no top level data node { parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item if (!parentTreeItem) { this->NodeAdded(parentDataNode); parentTreeItem = m_Root->Find(parentDataNode); if (!parentTreeItem) return; } // get the index of this parent with the help of the grand parent index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); } int firstRowWithASiblingBelow = 0; int nodeLayer = -1; node->GetIntProperty("layer", nodeLayer); for (TreeItem *siblingTreeItem : parentTreeItem->GetChildren()) { int siblingLayer = -1; if (mitk::DataNode *siblingNode = siblingTreeItem->GetDataNode()) { siblingNode->GetIntProperty("layer", siblingLayer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); auto newNode = new TreeItem(const_cast(node)); parentTreeItem->InsertChild(newNode, firstRowWithASiblingBelow); m_TreeItems.push_back(newNode); endInsertRows(); } QModelIndex QmitkDataStorageSimpleTreeModel::IndexFromTreeItem(TreeItem *item) const { if (item == m_Root) return QModelIndex(); else return this->createIndex(item->GetIndex(), 0, item); } void QmitkDataStorageSimpleTreeModel::UpdateModelData() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { auto nodeset = m_NodePredicate != nullptr ? dataStorage->GetSubset(m_NodePredicate) : dataStorage->GetAll(); for (const auto& node : *nodeset) { this->AddNodeInternal(node); } } } diff --git a/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp b/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp index 422c98ccaf..6e04d83594 100644 --- a/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp @@ -1,33 +1,41 @@ /*============================================================================ 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 "QmitkLevelWindowWidget.h" #include "QmitkSliderLevelWindowWidget.h" -QmitkLevelWindowWidget::QmitkLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) +#include + +QmitkLevelWindowWidget::QmitkLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) + : QWidget(parent, f), ui(new Ui::QmitkLevelWindow) { - this->setupUi(this); + ui->setupUi(this); m_Manager = mitk::LevelWindowManager::New(); - SliderLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer()); - LineEditLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer()); + ui->SliderLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer()); + ui->LineEditLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer()); +} + +QmitkLevelWindowWidget::~QmitkLevelWindowWidget() +{ + delete ui; } void QmitkLevelWindowWidget::SetDataStorage(mitk::DataStorage *ds) { m_Manager->SetDataStorage(ds); } mitk::LevelWindowManager *QmitkLevelWindowWidget::GetManager() { return m_Manager.GetPointer(); } diff --git a/Modules/Segmentation/Interactions/mitkProcessExecutor.h b/Modules/Segmentation/Interactions/mitkProcessExecutor.h index 56aaed7dde..f67567de25 100644 --- a/Modules/Segmentation/Interactions/mitkProcessExecutor.h +++ b/Modules/Segmentation/Interactions/mitkProcessExecutor.h @@ -1,116 +1,116 @@ /*============================================================================ 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 mitkProcessExecutor_h #define mitkProcessExecutor_h #include #include #include #include namespace mitk { // Class is adapted from MatchPoint ProcessExecutor class ExternalProcessOutputEvent : public itk::AnyEvent { public: typedef ExternalProcessOutputEvent Self; typedef itk::AnyEvent Superclass; explicit ExternalProcessOutputEvent(const std::string &output = "") : m_Output(output) {} ~ExternalProcessOutputEvent() override {} const char *GetEventName() const override { return "ExternalProcessOutputEvent"; } bool CheckEvent(const ::itk::EventObject *e) const override { return dynamic_cast(e); } itk::EventObject *MakeObject() const override { return new Self(m_Output); } std::string GetOutput() const { return m_Output; } private: std::string m_Output; }; #define mitkProcessExecutorEventMacro(classname) \ class classname : public ExternalProcessOutputEvent \ { \ public: \ typedef classname Self; \ typedef ExternalProcessOutputEvent Superclass; \ \ explicit classname(const std::string &output) : Superclass(output) {} \ ~classname() override {} \ \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(this->GetOutput()); } \ }; mitkProcessExecutorEventMacro(ExternalProcessStdOutEvent); mitkProcessExecutorEventMacro(ExternalProcessStdErrEvent); /** * @brief You may register an observer for an ExternalProcessOutputEvent, ExternalProcessStdOutEvent or * ExternalProcessStdErrEvent in order to get notified of any output. * @remark The events will only be invoked if the pipes are NOT(!) shared. By default the pipes are not shared. * */ class MITKSEGMENTATION_EXPORT ProcessExecutor : public itk::Object { public: using Self = ProcessExecutor; using Superclass = ::itk::Object; using Pointer = ::itk::SmartPointer; using ConstPointer = ::itk::SmartPointer; itkTypeMacro(ProcessExecutor, ::itk::Object); itkFactorylessNewMacro(Self); itkSetMacro(SharedOutputPipes, bool); itkGetConstMacro(SharedOutputPipes, bool); using ArgumentListType = std::vector; bool Execute(const std::string &executionPath, const std::string &executableName, ArgumentListType &argumentList); /** * @brief Executes the process. This version assumes that the executable name is the first argument in the argument * list and has already been converted to its OS dependent name via the static convert function of this class. */ - bool Execute(const std::string &executionPath, const ArgumentListType &argumentList); + virtual bool Execute(const std::string &executionPath, const ArgumentListType &argumentList); int GetExitValue(); static std::string EnsureCorrectOSPathSeparator(const std::string &); static std::string GetOSDependendExecutableName(const std::string &name); void KillProcess(); protected: ProcessExecutor(); ~ProcessExecutor() override; int m_ExitValue; /** * @brief Specifies if the child process should share the output pipes (true) or not (false). * If pipes are not shared the output will be passed by invoking ExternalProcessOutputEvents * @remark The events will only be invoked if the pipes are NOT(!) shared. */ bool m_SharedOutputPipes; private: itksysProcess *m_ProcessID = nullptr; }; } // namespace mitk #endif diff --git a/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp b/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp index 9ff48f4df5..77ffb417cd 100644 --- a/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp +++ b/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp @@ -1,819 +1,842 @@ /*============================================================================ 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 "mitkSegWithPreviewTool.h" #include "mitkToolManager.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkDataStorage.h" #include "mitkRenderingManager.h" #include #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" #include "mitkLabelSetImage.h" #include "mitkMaskAndCutRoiImageFilter.h" #include "mitkPadImageFilter.h" #include "mitkNodePredicateGeometry.h" #include "mitkSegTool2D.h" mitk::SegWithPreviewTool::SegWithPreviewTool(bool lazyDynamicPreviews): Tool("dummy"), m_LazyDynamicPreviews(lazyDynamicPreviews) { m_ProgressCommand = ToolCommand::New(); } mitk::SegWithPreviewTool::SegWithPreviewTool(bool lazyDynamicPreviews, const char* interactorType, const us::Module* interactorModule) : Tool(interactorType, interactorModule), m_LazyDynamicPreviews(lazyDynamicPreviews) { m_ProgressCommand = ToolCommand::New(); } mitk::SegWithPreviewTool::~SegWithPreviewTool() { } void mitk::SegWithPreviewTool::SetMergeStyle(MultiLabelSegmentation::MergeStyle mergeStyle) { m_MergeStyle = mergeStyle; this->Modified(); } void mitk::SegWithPreviewTool::SetOverwriteStyle(MultiLabelSegmentation::OverwriteStyle overwriteStyle) { m_OverwriteStyle = overwriteStyle; this->Modified(); } void mitk::SegWithPreviewTool::SetLabelTransferScope(LabelTransferScope labelTransferScope) { m_LabelTransferScope = labelTransferScope; this->Modified(); } void mitk::SegWithPreviewTool::SetLabelTransferMode(LabelTransferMode labelTransferMode) { m_LabelTransferMode = labelTransferMode; this->Modified(); } void mitk::SegWithPreviewTool::SetSelectedLabels(const SelectedLabelVectorType& labelsToTransfer) { m_SelectedLabels = labelsToTransfer; this->Modified(); } bool mitk::SegWithPreviewTool::CanHandle(const BaseData* referenceData, const BaseData* workingData) const { if (!Superclass::CanHandle(referenceData, workingData)) return false; if (workingData == nullptr) return false; auto* referenceImage = dynamic_cast(referenceData); if (referenceImage == nullptr) return false; auto* labelSet = dynamic_cast(workingData); if (labelSet != nullptr) return true; auto* workingImage = dynamic_cast(workingData); if (workingImage == nullptr) return false; // If the working image is a normal image and not a label set image // it must have the same pixel type as a label set. return MakeScalarPixelType< DefaultSegmentationDataType >() == workingImage->GetPixelType(); } void mitk::SegWithPreviewTool::Activated() { Superclass::Activated(); this->GetToolManager()->RoiDataChanged += MessageDelegate(this, &SegWithPreviewTool::OnRoiDataChanged); this->GetToolManager()->SelectedTimePointChanged += MessageDelegate(this, &SegWithPreviewTool::OnTimePointChanged); m_ReferenceDataNode = this->GetToolManager()->GetReferenceData(0); m_SegmentationInputNode = m_ReferenceDataNode; m_LastTimePointOfUpdate = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); if (m_PreviewSegmentationNode.IsNull()) { m_PreviewSegmentationNode = DataNode::New(); m_PreviewSegmentationNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0)); m_PreviewSegmentationNode->SetProperty("name", StringProperty::New(std::string(this->GetName())+" preview")); m_PreviewSegmentationNode->SetProperty("opacity", FloatProperty::New(0.3)); m_PreviewSegmentationNode->SetProperty("binary", BoolProperty::New(true)); m_PreviewSegmentationNode->SetProperty("helper object", BoolProperty::New(true)); } if (m_SegmentationInputNode.IsNotNull()) { this->ResetPreviewNode(); this->InitiateToolByInput(); } else { this->GetToolManager()->ActivateTool(-1); } } void mitk::SegWithPreviewTool::Deactivated() { this->GetToolManager()->RoiDataChanged -= MessageDelegate(this, &SegWithPreviewTool::OnRoiDataChanged); this->GetToolManager()->SelectedTimePointChanged -= MessageDelegate(this, &SegWithPreviewTool::OnTimePointChanged); m_SegmentationInputNode = nullptr; m_ReferenceDataNode = nullptr; m_WorkingPlaneGeometry = nullptr; try { if (DataStorage *storage = this->GetToolManager()->GetDataStorage()) { storage->Remove(m_PreviewSegmentationNode); RenderingManager::GetInstance()->RequestUpdateAll(); } } catch (...) { // don't care } if (m_PreviewSegmentationNode.IsNotNull()) { m_PreviewSegmentationNode->SetData(nullptr); } Superclass::Deactivated(); } void mitk::SegWithPreviewTool::ConfirmSegmentation() { bool labelChanged = this->EnsureUpToDateUserDefinedActiveLabel(); if ((m_LazyDynamicPreviews && m_CreateAllTimeSteps) || labelChanged) { // The tool should create all time steps but is currently in lazy mode, // thus ensure that a preview for all time steps is available. this->UpdatePreview(true); } CreateResultSegmentationFromPreview(); RenderingManager::GetInstance()->RequestUpdateAll(); if (!m_KeepActiveAfterAccept) { this->GetToolManager()->ActivateTool(-1); } + this->ConfirmCleanUp(); } void mitk::SegWithPreviewTool::InitiateToolByInput() { //default implementation does nothing. //implement in derived classes to change behavior } mitk::LabelSetImage* mitk::SegWithPreviewTool::GetPreviewSegmentation() { if (m_PreviewSegmentationNode.IsNull()) { return nullptr; } return dynamic_cast(m_PreviewSegmentationNode->GetData()); } const mitk::LabelSetImage* mitk::SegWithPreviewTool::GetPreviewSegmentation() const { if (m_PreviewSegmentationNode.IsNull()) { return nullptr; } return dynamic_cast(m_PreviewSegmentationNode->GetData()); } mitk::DataNode* mitk::SegWithPreviewTool::GetPreviewSegmentationNode() { return m_PreviewSegmentationNode; } const mitk::Image* mitk::SegWithPreviewTool::GetSegmentationInput() const { if (m_SegmentationInputNode.IsNull()) { return nullptr; } return dynamic_cast(m_SegmentationInputNode->GetData()); } const mitk::Image* mitk::SegWithPreviewTool::GetReferenceData() const { if (m_ReferenceDataNode.IsNull()) { return nullptr; } return dynamic_cast(m_ReferenceDataNode->GetData()); } template void ClearBufferProcessing(ImageType* itkImage) { itkImage->FillBuffer(0); } void mitk::SegWithPreviewTool::ResetPreviewContentAtTimeStep(unsigned int timeStep) { auto previewImage = GetImageByTimeStep(this->GetPreviewSegmentation(), timeStep); if (nullptr != previewImage) { AccessByItk(previewImage, ClearBufferProcessing); } } void mitk::SegWithPreviewTool::ResetPreviewContent() { auto previewImage = this->GetPreviewSegmentation(); if (nullptr != previewImage) { auto castedPreviewImage = dynamic_cast(previewImage); if (nullptr == castedPreviewImage) mitkThrow() << "Application is on wrong state / invalid tool implementation. Preview image should always be of type LabelSetImage now."; castedPreviewImage->ClearBuffer(); } } void mitk::SegWithPreviewTool::ResetPreviewNode() { if (m_IsUpdating) { mitkThrow() << "Used tool is implemented incorrectly. ResetPreviewNode is called while preview update is ongoing. Check implementation!"; } itk::RGBPixel previewColor; previewColor[0] = 0.0f; previewColor[1] = 1.0f; previewColor[2] = 0.0f; const auto image = this->GetSegmentationInput(); if (nullptr != image) { LabelSetImage::ConstPointer workingImage = dynamic_cast(this->GetToolManager()->GetWorkingData(0)->GetData()); if (workingImage.IsNotNull()) { auto newPreviewImage = workingImage->Clone(); if (this->GetResetsToEmptyPreview()) { newPreviewImage->ClearBuffer(); } if (newPreviewImage.IsNull()) { MITK_ERROR << "Cannot create preview helper objects. Unable to clone working image"; return; } m_PreviewSegmentationNode->SetData(newPreviewImage); auto* activeLabelSet = newPreviewImage->GetActiveLabelSet(); if (nullptr == activeLabelSet) { newPreviewImage->AddLayer(); activeLabelSet = newPreviewImage->GetActiveLabelSet(); } auto* activeLabel = activeLabelSet->GetActiveLabel(); if (nullptr == activeLabel) { activeLabel = activeLabelSet->AddLabel("toolresult", previewColor); activeLabelSet = newPreviewImage->GetActiveLabelSet(); activeLabelSet->UpdateLookupTable(activeLabel->GetValue()); } else if (m_UseSpecialPreviewColor) { // Let's paint the feedback node green... activeLabel->SetColor(previewColor); activeLabelSet->UpdateLookupTable(activeLabel->GetValue()); } activeLabel->SetVisible(true); } else { Image::ConstPointer workingImageBin = dynamic_cast(this->GetToolManager()->GetWorkingData(0)->GetData()); if (workingImageBin.IsNotNull()) { Image::Pointer newPreviewImage; if (this->GetResetsToEmptyPreview()) { newPreviewImage = Image::New(); newPreviewImage->Initialize(workingImageBin); } else { auto newPreviewImage = workingImageBin->Clone(); } if (newPreviewImage.IsNull()) { MITK_ERROR << "Cannot create preview helper objects. Unable to clone working image"; return; } m_PreviewSegmentationNode->SetData(newPreviewImage); } else { mitkThrow() << "Tool is an invalid state. Cannot setup preview node. Working data is an unsupported class and should have not been accepted by CanHandle()."; } } m_PreviewSegmentationNode->SetColor(previewColor); m_PreviewSegmentationNode->SetOpacity(0.5); int layer(50); m_ReferenceDataNode->GetIntProperty("layer", layer); m_PreviewSegmentationNode->SetIntProperty("layer", layer + 1); if (DataStorage *ds = this->GetToolManager()->GetDataStorage()) { if (!ds->Exists(m_PreviewSegmentationNode)) ds->Add(m_PreviewSegmentationNode, m_ReferenceDataNode); } } } mitk::SegWithPreviewTool::LabelMappingType mitk::SegWithPreviewTool::GetLabelMapping() const { LabelSetImage::LabelValueType offset = 0; if (LabelTransferMode::AddLabel == m_LabelTransferMode && LabelTransferScope::ActiveLabel!=m_LabelTransferScope) { //If we are not just working on active label and transfer mode is add, we need to compute an offset for adding the //preview labels instat of just mapping them to existing segmentation labels. const auto segmentation = this->GetTargetSegmentation(); if (nullptr == segmentation) mitkThrow() << "Invalid state of SegWithPreviewTool. Cannot GetLabelMapping if no target segmentation is set."; auto labels = segmentation->GetLabels(); auto maxLabelIter = std::max_element(std::begin(labels), std::end(labels), [](const Label::Pointer& a, const Label::Pointer& b) { return a->GetValue() < b->GetValue(); }); if (maxLabelIter != labels.end()) { offset = maxLabelIter->GetPointer()->GetValue(); } } LabelMappingType labelMapping = {}; switch (this->m_LabelTransferScope) { case LabelTransferScope::SelectedLabels: { for (auto label : this->m_SelectedLabels) { labelMapping.push_back({label, label + offset}); } } break; case LabelTransferScope::AllLabels: { const auto labelSet = this->GetPreviewSegmentation()->GetActiveLabelSet(); for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter) { labelMapping.push_back({labelIter->second->GetValue(), labelIter->second->GetValue() + offset}); } } break; default: { if (m_SelectedLabels.empty()) mitkThrow() << "Failed to generate label transfer mapping. Tool is in an invalid state, as " "LabelTransferScope==ActiveLabel but no label is indicated as selected label. Check " "implementation of derived tool class."; if (m_SelectedLabels.size() > 1) mitkThrow() << "Failed to generate label transfer mapping. Tool is in an invalid state, as " "LabelTransferScope==ActiveLabel but more then one selected label is indicated." "Should be only one. Check implementation of derived tool class."; labelMapping.push_back({m_SelectedLabels.front(), this->GetUserDefinedActiveLabel()}); } break; } return labelMapping; } void mitk::SegWithPreviewTool::TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep, const LabelMappingType& labelMapping) { try { Image::ConstPointer sourceImageAtTimeStep = this->GetImageByTimeStep(sourceImage, timeStep); if (sourceImageAtTimeStep->GetPixelType() != destinationImage->GetPixelType()) { mitkThrow() << "Cannot transfer images. Tool is in an invalid state, source image and destination image do not have the same pixel type. " << "Source pixel type: " << sourceImage->GetPixelType().GetTypeAsString() << "; destination pixel type: " << destinationImage->GetPixelType().GetTypeAsString(); } if (!Equal(*(sourceImage->GetGeometry(timeStep)), *(destinationImage->GetGeometry(timeStep)), NODE_PREDICATE_GEOMETRY_DEFAULT_CHECK_COORDINATE_PRECISION, NODE_PREDICATE_GEOMETRY_DEFAULT_CHECK_DIRECTION_PRECISION, false)) { mitkThrow() << "Cannot transfer images. Tool is in an invalid state, source image and destination image do not have the same geometry."; } if (nullptr != this->GetWorkingPlaneGeometry()) { auto sourceSlice = SegTool2D::GetAffectedImageSliceAs2DImage(this->GetWorkingPlaneGeometry(), sourceImage, timeStep); - SegTool2D::WriteBackSegmentationResult(this->GetTargetSegmentationNode(), m_WorkingPlaneGeometry, sourceSlice, timeStep); + auto resultSlice = + SegTool2D::GetAffectedImageSliceAs2DImage(this->GetWorkingPlaneGeometry(), destinationImage, timeStep)->Clone(); + auto destLSImage = dynamic_cast(destinationImage); + //We need to transfer explictly to a copy of the current working image to ensure that labelMapping is done and things + //like merge style, overwrite style and locks are regarded. + TransferLabelContentAtTimeStep(sourceSlice, + resultSlice, + destLSImage->GetActiveLabelSet(), + timeStep, + 0, + 0, + destLSImage->GetUnlabeledLabelLock(), + labelMapping, + m_MergeStyle, + m_OverwriteStyle); + //We use WriteBackSegmentationResult to ensure undo/redo is supported also by derived tools of this class. + SegTool2D::WriteBackSegmentationResult(this->GetTargetSegmentationNode(), m_WorkingPlaneGeometry, resultSlice, timeStep); } else { //take care of the full segmentation volume auto sourceLSImage = dynamic_cast(sourceImage); auto destLSImage = dynamic_cast(destinationImage); TransferLabelContentAtTimeStep(sourceLSImage, destLSImage, timeStep, labelMapping, m_MergeStyle, m_OverwriteStyle); } } catch (mitk::Exception& e) { Tool::ErrorMessage(e.GetDescription()); mitkReThrow(e); } } void mitk::SegWithPreviewTool::CreateResultSegmentationFromPreview() { const auto segInput = this->GetSegmentationInput(); auto previewImage = this->GetPreviewSegmentation(); if (nullptr != segInput && nullptr != previewImage) { DataNode::Pointer resultSegmentationNode = GetTargetSegmentationNode(); if (resultSegmentationNode.IsNotNull()) { const TimePointType timePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); auto resultSegmentation = dynamic_cast(resultSegmentationNode->GetData()); // REMARK: the following code in this scope assumes that previewImage and resultSegmentation // are clones of the working referenceImage (segmentation provided to the tool). Therefore they have // the same time geometry. if (previewImage->GetTimeSteps() != resultSegmentation->GetTimeSteps()) { mitkThrow() << "Cannot confirm/transfer segmentation. Internal tool state is invalid." << " Preview segmentation and segmentation result image have different time geometries."; } auto labelMapping = this->GetLabelMapping(); this->PreparePreviewToResultTransfer(labelMapping); if (m_CreateAllTimeSteps) { for (unsigned int timeStep = 0; timeStep < previewImage->GetTimeSteps(); ++timeStep) { this->TransferImageAtTimeStep(previewImage, resultSegmentation, timeStep, labelMapping); } } else { const auto timeStep = resultSegmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint); this->TransferImageAtTimeStep(previewImage, resultSegmentation, timeStep, labelMapping); } // since we are maybe working on a smaller referenceImage, pad it to the size of the original referenceImage if (m_ReferenceDataNode.GetPointer() != m_SegmentationInputNode.GetPointer()) { PadImageFilter::Pointer padFilter = PadImageFilter::New(); padFilter->SetInput(0, resultSegmentation); padFilter->SetInput(1, dynamic_cast(m_ReferenceDataNode->GetData())); padFilter->SetBinaryFilter(true); padFilter->SetUpperThreshold(1); padFilter->SetLowerThreshold(1); padFilter->Update(); resultSegmentationNode->SetData(padFilter->GetOutput()); } this->EnsureTargetSegmentationNodeInDataStorage(); } } } void mitk::SegWithPreviewTool::OnRoiDataChanged() { DataNode::ConstPointer node = this->GetToolManager()->GetRoiData(0); if (node.IsNotNull()) { MaskAndCutRoiImageFilter::Pointer roiFilter = MaskAndCutRoiImageFilter::New(); Image::Pointer image = dynamic_cast(m_SegmentationInputNode->GetData()); if (image.IsNull()) return; roiFilter->SetInput(image); roiFilter->SetRegionOfInterest(node->GetData()); roiFilter->Update(); DataNode::Pointer tmpNode = DataNode::New(); tmpNode->SetData(roiFilter->GetOutput()); m_SegmentationInputNode = tmpNode; } else m_SegmentationInputNode = m_ReferenceDataNode; this->ResetPreviewNode(); this->InitiateToolByInput(); this->UpdatePreview(); } void mitk::SegWithPreviewTool::OnTimePointChanged() { if (m_IsTimePointChangeAware && m_PreviewSegmentationNode.IsNotNull() && m_SegmentationInputNode.IsNotNull()) { const TimePointType timePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); const bool isStaticSegOnDynamicImage = m_PreviewSegmentationNode->GetData()->GetTimeSteps() == 1 && m_SegmentationInputNode->GetData()->GetTimeSteps() > 1; if (timePoint!=m_LastTimePointOfUpdate && (isStaticSegOnDynamicImage || m_LazyDynamicPreviews)) { //we only need to update either because we are lazzy //or because we have a static segmentation with a dynamic referenceImage this->UpdatePreview(); } } } bool mitk::SegWithPreviewTool::EnsureUpToDateUserDefinedActiveLabel() { bool labelChanged = true; const auto workingImage = dynamic_cast(this->GetToolManager()->GetWorkingData(0)->GetData()); if (const auto& labelSetImage = dynamic_cast(workingImage)) { // this is a fix for T28131 / T28986, which should be refactored if T28524 is being worked on auto newLabel = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue(); labelChanged = newLabel != m_UserDefinedActiveLabel; m_UserDefinedActiveLabel = newLabel; } else { m_UserDefinedActiveLabel = 1; labelChanged = false; } return labelChanged; } void mitk::SegWithPreviewTool::UpdatePreview(bool ignoreLazyPreviewSetting) { const auto inputImage = this->GetSegmentationInput(); auto previewImage = this->GetPreviewSegmentation(); int progress_steps = 200; const auto workingImage = dynamic_cast(this->GetToolManager()->GetWorkingData(0)->GetData()); this->EnsureUpToDateUserDefinedActiveLabel(); this->CurrentlyBusy.Send(true); m_IsUpdating = true; this->UpdatePrepare(); const TimePointType timePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); try { if (nullptr != inputImage && nullptr != previewImage) { m_ProgressCommand->AddStepsToDo(progress_steps); if (previewImage->GetTimeSteps() > 1 && (ignoreLazyPreviewSetting || !m_LazyDynamicPreviews)) { for (unsigned int timeStep = 0; timeStep < previewImage->GetTimeSteps(); ++timeStep) { Image::ConstPointer feedBackImage; Image::ConstPointer currentSegImage; auto previewTimePoint = previewImage->GetTimeGeometry()->TimeStepToTimePoint(timeStep); auto inputTimeStep = inputImage->GetTimeGeometry()->TimePointToTimeStep(previewTimePoint); if (nullptr != this->GetWorkingPlaneGeometry()) { //only extract a specific slice defined by the working plane as feedback referenceImage. feedBackImage = SegTool2D::GetAffectedImageSliceAs2DImage(this->GetWorkingPlaneGeometry(), inputImage, inputTimeStep); currentSegImage = SegTool2D::GetAffectedImageSliceAs2DImageByTimePoint(this->GetWorkingPlaneGeometry(), workingImage, previewTimePoint); } else { //work on the whole feedback referenceImage feedBackImage = this->GetImageByTimeStep(inputImage, inputTimeStep); currentSegImage = this->GetImageByTimePoint(workingImage, previewTimePoint); } this->DoUpdatePreview(feedBackImage, currentSegImage, previewImage, timeStep); } } else { Image::ConstPointer feedBackImage; Image::ConstPointer currentSegImage; if (nullptr != this->GetWorkingPlaneGeometry()) { feedBackImage = SegTool2D::GetAffectedImageSliceAs2DImageByTimePoint(this->GetWorkingPlaneGeometry(), inputImage, timePoint); currentSegImage = SegTool2D::GetAffectedImageSliceAs2DImageByTimePoint(this->GetWorkingPlaneGeometry(), workingImage, timePoint); } else { feedBackImage = this->GetImageByTimePoint(inputImage, timePoint); currentSegImage = this->GetImageByTimePoint(workingImage, timePoint); } auto timeStep = previewImage->GetTimeGeometry()->TimePointToTimeStep(timePoint); this->DoUpdatePreview(feedBackImage, currentSegImage, previewImage, timeStep); } RenderingManager::GetInstance()->RequestUpdateAll(); } } catch (itk::ExceptionObject & excep) { MITK_ERROR << "Exception caught: " << excep.GetDescription(); m_ProgressCommand->SetProgress(progress_steps); std::string msg = excep.GetDescription(); ErrorMessage.Send(msg); } catch (...) { m_ProgressCommand->SetProgress(progress_steps); m_IsUpdating = false; CurrentlyBusy.Send(false); throw; } this->UpdateCleanUp(); m_LastTimePointOfUpdate = timePoint; m_ProgressCommand->SetProgress(progress_steps); m_IsUpdating = false; CurrentlyBusy.Send(false); } bool mitk::SegWithPreviewTool::IsUpdating() const { return m_IsUpdating; } void mitk::SegWithPreviewTool::UpdatePrepare() { // default implementation does nothing //reimplement in derived classes for special behavior } void mitk::SegWithPreviewTool::UpdateCleanUp() { // default implementation does nothing //reimplement in derived classes for special behavior } +void mitk::SegWithPreviewTool::ConfirmCleanUp() +{ + // default implementation does nothing + // reimplement in derived classes for special behavior +} + void mitk::SegWithPreviewTool::TransferLabelInformation(const LabelMappingType& labelMapping, const mitk::LabelSetImage* source, mitk::LabelSetImage* target) { for (const auto& [sourceLabel, targetLabel] : labelMapping) { if (LabelSetImage::UnlabeledValue != sourceLabel && LabelSetImage::UnlabeledValue != targetLabel && !target->ExistLabel(targetLabel, target->GetActiveLayer())) { if (!source->ExistLabel(sourceLabel, source->GetActiveLayer())) { mitkThrow() << "Cannot prepare segmentation for preview transfer. Preview seems invalid as label is missing. Missing label: " << sourceLabel; } auto clonedLabel = source->GetLabel(sourceLabel)->Clone(); clonedLabel->SetValue(targetLabel); target->GetActiveLabelSet()->AddLabel(clonedLabel); } } } void mitk::SegWithPreviewTool::PreparePreviewToResultTransfer(const LabelMappingType& labelMapping) { DataNode::Pointer resultSegmentationNode = GetTargetSegmentationNode(); if (resultSegmentationNode.IsNotNull()) { auto resultSegmentation = dynamic_cast(resultSegmentationNode->GetData()); if (nullptr == resultSegmentation) { mitkThrow() << "Cannot prepare segmentation for preview transfer. Tool is in invalid state as segmentation is not existing or of right type"; } auto preview = this->GetPreviewSegmentation(); TransferLabelInformation(labelMapping, preview, resultSegmentation); } } mitk::TimePointType mitk::SegWithPreviewTool::GetLastTimePointOfUpdate() const { return m_LastTimePointOfUpdate; } mitk::LabelSetImage::LabelValueType mitk::SegWithPreviewTool::GetActiveLabelValueOfPreview() const { const auto previewImage = this->GetPreviewSegmentation(); const auto activeLabel = previewImage->GetActiveLabel(previewImage->GetActiveLayer()); if (nullptr == activeLabel) mitkThrow() << this->GetNameOfClass() <<" is in an invalid state, as " "preview has no active label indicated. Check " "implementation of the class."; return activeLabel->GetValue(); } const char* mitk::SegWithPreviewTool::GetGroup() const { return "autoSegmentation"; } mitk::Image::ConstPointer mitk::SegWithPreviewTool::GetImageByTimeStep(const mitk::Image* image, TimeStepType timestep) { return SelectImageByTimeStep(image, timestep); } mitk::Image::Pointer mitk::SegWithPreviewTool::GetImageByTimeStep(mitk::Image* image, TimeStepType timestep) { return SelectImageByTimeStep(image, timestep); } mitk::Image::ConstPointer mitk::SegWithPreviewTool::GetImageByTimePoint(const mitk::Image* image, TimePointType timePoint) { return SelectImageByTimePoint(image, timePoint); } void mitk::SegWithPreviewTool::EnsureTargetSegmentationNodeInDataStorage() const { auto targetNode = this->GetTargetSegmentationNode(); auto dataStorage = this->GetToolManager()->GetDataStorage(); if (!dataStorage->Exists(targetNode)) { dataStorage->Add(targetNode, this->GetToolManager()->GetReferenceData(0)); } } std::string mitk::SegWithPreviewTool::GetCurrentSegmentationName() { auto workingData = this->GetToolManager()->GetWorkingData(0); return nullptr != workingData ? workingData->GetName() : ""; } mitk::DataNode* mitk::SegWithPreviewTool::GetTargetSegmentationNode() const { return this->GetToolManager()->GetWorkingData(0); } mitk::LabelSetImage* mitk::SegWithPreviewTool::GetTargetSegmentation() const { auto node = this->GetTargetSegmentationNode(); if (nullptr == node) return nullptr; return dynamic_cast(node->GetData()); } void mitk::SegWithPreviewTool::TransferLabelSetImageContent(const LabelSetImage* source, LabelSetImage* target, TimeStepType timeStep) { mitk::ImageReadAccessor newMitkImgAcc(source); LabelMappingType labelMapping; const auto labelSet = source->GetActiveLabelSet(); for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter) { labelMapping.push_back({ labelIter->second->GetValue(),labelIter->second->GetValue() }); } TransferLabelInformation(labelMapping, source, target); target->SetVolume(newMitkImgAcc.GetData(), timeStep); } diff --git a/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.h b/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.h index a4141de0b1..109fb9370e 100644 --- a/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.h +++ b/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.h @@ -1,321 +1,326 @@ /*============================================================================ 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 mitkSegWithPreviewTool_h #define mitkSegWithPreviewTool_h #include "mitkTool.h" #include "mitkCommon.h" #include "mitkDataNode.h" #include "mitkToolCommand.h" #include namespace mitk { /** \brief Base class for any auto segmentation tool that provides a preview of the new segmentation. This tool class implements a lot basic logic to handle auto segmentation tools with preview, Time point and ROI support. Derived classes will ask to update the segmentation preview if needed (e.g. because the ROI or the current time point has changed) or because derived tools indicated the need to update themselves. This class also takes care to properly transfer a confirmed preview into the segementation result. \ingroup ToolManagerEtAl \sa mitk::Tool \sa QmitkInteractiveSegmentation */ class MITKSEGMENTATION_EXPORT SegWithPreviewTool : public Tool { public: mitkClassMacro(SegWithPreviewTool, Tool); void Activated() override; void Deactivated() override; void ConfirmSegmentation(); itkSetMacro(CreateAllTimeSteps, bool); itkGetMacro(CreateAllTimeSteps, bool); itkBooleanMacro(CreateAllTimeSteps); itkSetMacro(KeepActiveAfterAccept, bool); itkGetMacro(KeepActiveAfterAccept, bool); itkBooleanMacro(KeepActiveAfterAccept); itkSetMacro(IsTimePointChangeAware, bool); itkGetMacro(IsTimePointChangeAware, bool); itkBooleanMacro(IsTimePointChangeAware); itkSetMacro(ResetsToEmptyPreview, bool); itkGetMacro(ResetsToEmptyPreview, bool); itkBooleanMacro(ResetsToEmptyPreview); itkSetMacro(UseSpecialPreviewColor, bool); itkGetMacro(UseSpecialPreviewColor, bool); itkBooleanMacro(UseSpecialPreviewColor); /*itk macro was not used on purpose, to aviod the change of mtime.*/ void SetMergeStyle(MultiLabelSegmentation::MergeStyle mergeStyle); itkGetMacro(MergeStyle, MultiLabelSegmentation::MergeStyle); /*itk macro was not used on purpose, to aviod the change of mtime.*/ void SetOverwriteStyle(MultiLabelSegmentation::OverwriteStyle overwriteStyle); itkGetMacro(OverwriteStyle, MultiLabelSegmentation::OverwriteStyle); enum class LabelTransferScope { ActiveLabel, //Only the selected label will be transfered from the preview segmentation //to the result segmentation. //If this mode is selected the class expects that GetSelectedLabels indicate //the label in the preview. SelectedLabels, //The labels defined as selected labels will be transfered. AllLabels //Transfer all labels of the preview }; /*itk macro was not used on purpose, to aviod the change of mtime.*/ void SetLabelTransferScope(LabelTransferScope labelTransferScope); itkGetMacro(LabelTransferScope, LabelTransferScope); using SelectedLabelVectorType = std::vector; /** Specifies the labels that should be transfered form preview to the working image, if the segmentation is confirmed. The setting will be used, if LabelTransferScope is set to "ActiveLabel" or "SelectedLabels". @remark If the LabelTransferScope=="ActiveLabel", the class expects only one label to be selected. @remark The selected label IDs corespond to the labels of the preview image.*/ void SetSelectedLabels(const SelectedLabelVectorType& labelsToTransfer); itkGetMacro(SelectedLabels, SelectedLabelVectorType); enum class LabelTransferMode { MapLabel, //Only the active label will be transfered from preview to segmentation. AddLabel //The labels defined as selected labels will be transfered. }; /*itk macro was not used on purpose, to aviod the change of mtime.*/ void SetLabelTransferMode(LabelTransferMode labelTransferMode); itkGetMacro(LabelTransferMode, LabelTransferMode); bool CanHandle(const BaseData* referenceData, const BaseData* workingData) const override; /** Triggers the actualization of the preview * @param ignoreLazyPreviewSetting If set true UpdatePreview will always * generate the preview for all time steps. If set to false, UpdatePreview * will regard the setting specified by the constructor. * To define the update generation for time steps implement DoUpdatePreview. * To alter what should be done directly before or after the update of the preview, * reimplement UpdatePrepare() or UpdateCleanUp().*/ void UpdatePreview(bool ignoreLazyPreviewSetting = false); /** Indicate if currently UpdatePreview is triggered (true) or not (false).*/ bool IsUpdating() const; /** * @brief Gets the name of the currently selected segmentation node * @return the name of the segmentation node or an empty string if * none is selected */ std::string GetCurrentSegmentationName(); /** * @brief Returns the currently selected segmentation node * @return a mitk::DataNode which contains a segmentation image */ virtual DataNode* GetTargetSegmentationNode() const; LabelSetImage* GetTargetSegmentation() const; /** Returns the image that contains the preview of the current segmentation. * Returns null if the node is not set or does not contain an image.*/ LabelSetImage* GetPreviewSegmentation(); const LabelSetImage* GetPreviewSegmentation() const; DataNode* GetPreviewSegmentationNode(); protected: ToolCommand::Pointer m_ProgressCommand; SegWithPreviewTool(bool lazyDynamicPreviews = false); // purposely hidden SegWithPreviewTool(bool lazyDynamicPreviews, const char* interactorType, const us::Module* interactorModule = nullptr); // purposely hidden ~SegWithPreviewTool() override; const char* GetGroup() const override; /** Helper that extracts the image for the passed timestep, if the image has multiple time steps.*/ static Image::ConstPointer GetImageByTimeStep(const Image* image, TimeStepType timestep); /** Helper that extracts the image for the passed timestep, if the image has multiple time steps.*/ static Image::Pointer GetImageByTimeStep(Image* image, TimeStepType timestep); /** Helper that extracts the image for the passed time point, if the image has multiple time steps.*/ static Image::ConstPointer GetImageByTimePoint(const Image* image, TimePointType timePoint); void EnsureTargetSegmentationNodeInDataStorage() const; /** Member is always called if GetSegmentationInput() has changed * (e.g. because a new ROI was defined, or on activation) to give derived * classes the posibility to initiate their state accordingly. * Reimplement this function to implement special behavior. */ virtual void InitiateToolByInput(); /** This member function offers derived classes the possibility to alter what should happen directly before the update of the preview is performed. It is called by UpdatePreview. Default implementation does nothing.*/ virtual void UpdatePrepare(); /** This member function offers derived classes the possibility to alter what should happen directly after the update of the preview is performed. It is called by UpdatePreview. Default implementation does nothing.*/ virtual void UpdateCleanUp(); + /** This member function offers derived classes the possibility to alter what should + happen directly after the Confirmation of the preview is performed. It is called by + ConfirmSegmentation. Default implementation does nothing.*/ + virtual void ConfirmCleanUp(); + using LabelMappingType = std::vector >; /** This member function offers derived classes the possibility to alter what should happen directly before the content of the preview is transfered to the segmentation, when the segmentation is confirmed. It is called by CreateResultSegmentationFromPreview. Default implementation ensure that all labels that will be transfered, exist in the segmentation. If they are not existing before the transfer, the will be added by cloning the label information of the preview. @param labelMapping the mapping that should be used for transfering the labels. */ virtual void PreparePreviewToResultTransfer(const LabelMappingType& labelMapping); static void TransferLabelInformation(const LabelMappingType& labelMapping, const mitk::LabelSetImage* source, mitk::LabelSetImage* target); /**Helper function that can be used to move the content of an LabelSetImage (the pixels of the active source layer and the labels). This is e.g. helpfull if you generate an LabelSetImage content in DoUpdatePreview and you want to transfer it into the preview image.*/ static void TransferLabelSetImageContent(const LabelSetImage* source, LabelSetImage* target, TimeStepType timeStep); /** This function does the real work. Here the preview for a given * input image should be computed and stored in the also passed * preview image at the passed time step. * It also provides the current/old segmentation at the time point, * which can be used, if the preview depends on the the segmenation so far. */ virtual void DoUpdatePreview(const Image* inputAtTimeStep, const Image* oldSegAtTimeStep, LabelSetImage* previewImage, TimeStepType timeStep) = 0; /** Returns the input that should be used for any segmentation/preview or tool update. * It is either the data of ReferenceDataNode itself or a part of it defined by a ROI mask * provided by the tool manager. Derived classes should regard this as the relevant * input data for any processing. * Returns null if the node is not set or does not contain an image.*/ const Image* GetSegmentationInput() const; /** Returns the image that is provided by the ReferenceDataNode. * Returns null if the node is not set or does not contain an image.*/ const Image* GetReferenceData() const; /** Resets the preview node so it is empty and ready to be filled by the tool @remark Calling this function will generate a new preview image, and the old might be invalidated. Therefore this function should not be used within the scope of UpdatePreview (m_IsUpdating == true).*/ void ResetPreviewNode(); /** Resets the complete content of the preview image. The instance of the preview image and its settings * stay the same.*/ void ResetPreviewContent(); /** Resets only the image content of the specified timeStep of the preview image. If the preview image or the specified time step does not exist, nothing happens.*/ void ResetPreviewContentAtTimeStep(unsigned int timeStep); TimePointType GetLastTimePointOfUpdate() const; LabelSetImage::LabelValueType GetActiveLabelValueOfPreview() const; itkGetConstMacro(UserDefinedActiveLabel, Label::PixelType); itkSetObjectMacro(WorkingPlaneGeometry, PlaneGeometry); itkGetConstObjectMacro(WorkingPlaneGeometry, PlaneGeometry); private: void TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep, const LabelMappingType& labelMapping); void CreateResultSegmentationFromPreview(); void OnRoiDataChanged(); void OnTimePointChanged(); /**Internal helper that ensures that the stored active label is up to date. This is a fix for T28131 / T28986. It should be refactored if T28524 is being worked on. On the long run, the active label will be communicated/set by the user/toolmanager as a state of the tool and the tool should react accordingly (like it does for other external state changes). @return indicates if the label has changed (true) or not. */ bool EnsureUpToDateUserDefinedActiveLabel(); /**Returns that label mapping between preview segmentation (first element of pair) and result segmentation (second element of pair). The content depends on the settings of LabelTransferMode and LabelTransferScope*/ LabelMappingType GetLabelMapping() const; /** Node that containes the preview data generated and managed by this class or derived ones.*/ DataNode::Pointer m_PreviewSegmentationNode; /** The reference data recieved from ToolManager::GetReferenceData when tool was activated.*/ DataNode::Pointer m_ReferenceDataNode; /** Node that containes the data that should be used as input for any auto segmentation. It might * be the same like m_ReferenceDataNode (if no ROI is set) or a sub region (if ROI is set).*/ DataNode::Pointer m_SegmentationInputNode; /** Indicates if Accepting the threshold should transfer/create the segmentations of all time steps (true) or only of the currently selected timepoint (false).*/ bool m_CreateAllTimeSteps = false; /** Indicates if the tool should kept active after accepting the segmentation or not.*/ bool m_KeepActiveAfterAccept = false; /** Relevant if the working data / preview image has multiple time steps (dynamic segmentations). * This flag has to be set by derived classes accordingly to there way to generate dynamic previews. * If LazyDynamicPreview is true, the tool generates only the preview for the current time step. * Therefore it always has to update the preview if current time point has changed and it has to (re)compute * all timeframes if ConfirmSegmentation() is called.*/ bool m_LazyDynamicPreviews = false; bool m_IsTimePointChangeAware = true; /** Controls if ResetPreviewNode generates an empty content (true) or clones the current segmentation (false).*/ bool m_ResetsToEmptyPreview = false; /** Controls if for the preview of the active label a special preview color is used. * If set to false, coloring will stay in the preview like it is in the working image.*/ bool m_UseSpecialPreviewColor = true; TimePointType m_LastTimePointOfUpdate = 0.; bool m_IsUpdating = false; Label::PixelType m_UserDefinedActiveLabel = 1; /** This variable indicates if for the tool a working plane geometry is defined. * If a working plane is defined the tool will only work an the slice of the input * and the segmentation. Thus only the relevant input slice will be passed to * DoUpdatePreview(...) and only the relevant slice of the preview will be transfered when * ConfirmSegmentation() is called.*/ PlaneGeometry::Pointer m_WorkingPlaneGeometry; /** This variable controles how the label pixel content of the preview should be transfered into the segmentation- For more details of the behavior see documentation of MultiLabelSegmentation::MergeStyle. */ MultiLabelSegmentation::MergeStyle m_MergeStyle = MultiLabelSegmentation::MergeStyle::Replace; /** This variable controles how the label pixel content of the preview should be transfered into the segmentation- For more details of the behavior see documentation of MultiLabelSegmentation::OverwriteStyle. */ MultiLabelSegmentation::OverwriteStyle m_OverwriteStyle = MultiLabelSegmentation::OverwriteStyle::RegardLocks; LabelTransferScope m_LabelTransferScope = LabelTransferScope::ActiveLabel; SelectedLabelVectorType m_SelectedLabels = {}; LabelTransferMode m_LabelTransferMode = LabelTransferMode::MapLabel; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkSegmentAnythingProcessExecutor.cpp b/Modules/Segmentation/Interactions/mitkSegmentAnythingProcessExecutor.cpp new file mode 100644 index 0000000000..517628a279 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkSegmentAnythingProcessExecutor.cpp @@ -0,0 +1,83 @@ +/*============================================================================ + +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 "mitkSegmentAnythingProcessExecutor.h" + +#include + +bool mitk::SegmentAnythingProcessExecutor::Execute(const std::string &executionPath, const ArgumentListType &argumentList) +{ + std::vector pArguments_(argumentList.size() + 1); + + for (ArgumentListType::size_type index = 0; index < argumentList.size(); ++index) + { + pArguments_[index] = argumentList[index].c_str(); + } + pArguments_.push_back(nullptr); // terminating null element as required by ITK + bool normalExit = false; + try + { + m_ProcessID = itksysProcess_New(); + itksysProcess_SetCommand(m_ProcessID, pArguments_.data()); + + /* Place the process in a new process group for seamless interruption when required. */ + itksysProcess_SetOption(m_ProcessID, itksysProcess_Option_CreateProcessGroup, 1); + + itksysProcess_SetWorkingDirectory(m_ProcessID, executionPath.c_str()); + if (this->m_SharedOutputPipes) + { + itksysProcess_SetPipeShared(m_ProcessID, itksysProcess_Pipe_STDOUT, 1); + itksysProcess_SetPipeShared(m_ProcessID, itksysProcess_Pipe_STDERR, 1); + } + itksysProcess_Execute(m_ProcessID); + char *rawOutput = nullptr; + int outputLength = 0; + double timer = m_Timeout; + while (!m_Stop) + { + double *timeout = &timer; + *timeout = m_Timeout; //re-assigning timeout since itksysProcess calls will tamper with input timeout argument. + int dataStatus = itksysProcess_WaitForData(m_ProcessID, &rawOutput, &outputLength, timeout); + if (dataStatus == itksysProcess_Pipe_STDOUT) + { + std::string data(rawOutput, outputLength); + this->InvokeEvent(ExternalProcessStdOutEvent(data)); + } + else if (dataStatus == itksysProcess_Pipe_STDERR) + { + std::string data(rawOutput, outputLength); + this->InvokeEvent(ExternalProcessStdErrEvent(data)); + } + } + timer = m_Timeout; //re-assigning timeout since itksysProcess calls will tamper with input timeout argument. + itksysProcess_Kill(m_ProcessID); + itksysProcess_WaitForExit(m_ProcessID, &timer); + auto state = static_cast(itksysProcess_GetState(m_ProcessID)); + normalExit = (state == itksysProcess_State_Exited); + this->m_ExitValue = itksysProcess_GetExitValue(m_ProcessID); + } + catch (...) + { + throw; + } + return normalExit; +}; + +mitk::SegmentAnythingProcessExecutor::SegmentAnythingProcessExecutor(double &timeout) +{ + this->SetTimeout(timeout); +} + +void mitk::SegmentAnythingProcessExecutor::SetTimeout(double &timeout) +{ + m_Timeout = timeout; +} diff --git a/Modules/Segmentation/Interactions/mitkSegmentAnythingProcessExecutor.h b/Modules/Segmentation/Interactions/mitkSegmentAnythingProcessExecutor.h new file mode 100644 index 0000000000..9e45db8452 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkSegmentAnythingProcessExecutor.h @@ -0,0 +1,64 @@ +/*============================================================================ + +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 mitkSegmentAnythingProcessExecutor_h +#define mitkSegmentAnythingProcessExecutor_h + +#include +#include +#include +#include + +namespace mitk +{ + /** + * @brief You may register an observer for an ExternalProcessOutputEvent, ExternalProcessStdOutEvent or + * ExternalProcessStdErrEvent in order to get notified of any output. + * @remark The events will only be invoked if the pipes are NOT(!) shared. By default the pipes are not shared. + * + */ + class MITKSEGMENTATION_EXPORT SegmentAnythingProcessExecutor : public mitk::ProcessExecutor + { + public: + using Self = SegmentAnythingProcessExecutor; + using Superclass = mitk::ProcessExecutor; + using Pointer = ::itk::SmartPointer; + using ConstPointer = ::itk::SmartPointer; + using mitk::ProcessExecutor::Execute; + + itkTypeMacro(SegmentAnythingProcessExecutor, mitk::ProcessExecutor); + mitkNewMacro1Param(SegmentAnythingProcessExecutor, double&); + + itkSetMacro(Stop, bool); + itkGetConstMacro(Stop, bool); + + /** + * @brief Executes the process. This version assumes that the executable name is the first argument in the argument + * list and has already been converted to its OS dependent name via the static convert function of this class. + */ + bool Execute(const std::string &executionPath, const ArgumentListType &argumentList); + + void SetTimeout(double &timeout); + + protected: + SegmentAnythingProcessExecutor() = delete; + SegmentAnythingProcessExecutor(double &); + ~SegmentAnythingProcessExecutor() = default; + + private: + itksysProcess *m_ProcessID = nullptr; + double m_Timeout; + bool m_Stop = false; // Exit token to force stop the daemon. + }; + +} // namespace mitk +#endif diff --git a/Modules/Segmentation/Interactions/mitkSegmentAnythingPythonService.cpp b/Modules/Segmentation/Interactions/mitkSegmentAnythingPythonService.cpp new file mode 100644 index 0000000000..13674f1066 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkSegmentAnythingPythonService.cpp @@ -0,0 +1,265 @@ +/*============================================================================ + +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 "mitkSegmentAnythingPythonService.h" + +#include "mitkIOUtil.h" +#include +#include +#include +#include +#include +#include +#include "mitkImageAccessByItk.h" +#include + +using namespace std::chrono_literals; +using sys_clock = std::chrono::system_clock; + +namespace mitk +{ + const std::string SIGNALCONSTANTS::READY = "READY"; + const std::string SIGNALCONSTANTS::KILL = "KILL"; + const std::string SIGNALCONSTANTS::OFF = "OFF"; + const std::string SIGNALCONSTANTS::CUDA_OUT_OF_MEMORY_ERROR = "CudaOutOfMemoryError"; + const std::string SIGNALCONSTANTS::TIMEOUT_ERROR = "TimeOut"; + SegmentAnythingPythonService::Status SegmentAnythingPythonService::CurrentStatus = + SegmentAnythingPythonService::Status::OFF; +} + +mitk::SegmentAnythingPythonService::SegmentAnythingPythonService( + std::string workingDir, std::string modelType, std::string checkPointPath, unsigned int gpuId) + : m_PythonPath(workingDir), + m_ModelType(modelType), + m_CheckpointPath(checkPointPath), + m_GpuId(gpuId) +{ + this->CreateTempDirs(PARENT_TEMP_DIR_PATTERN); +} + +mitk::SegmentAnythingPythonService::~SegmentAnythingPythonService() +{ + if (CurrentStatus == Status::READY) + { + this->StopAsyncProcess(); + } + CurrentStatus = Status::OFF; + std::filesystem::remove_all(this->GetMitkTempDir()); + } + +void mitk::SegmentAnythingPythonService::onPythonProcessEvent(itk::Object*, const itk::EventObject &e, void*) +{ + std::string testCOUT,testCERR; + const auto *pEvent = dynamic_cast(&e); + if (pEvent) + { + testCOUT = testCOUT + pEvent->GetOutput(); + testCOUT.erase(std::find_if(testCOUT.rbegin(), testCOUT.rend(), [](unsigned char ch) { + return !std::isspace(ch);}).base(), testCOUT.end()); // remove trailing whitespaces, if any + if (SIGNALCONSTANTS::READY == testCOUT) + { + CurrentStatus = Status::READY; + } + if (SIGNALCONSTANTS::KILL == testCOUT) + { + CurrentStatus = Status::KILLED; + } + if (SIGNALCONSTANTS::CUDA_OUT_OF_MEMORY_ERROR == testCOUT) + { + CurrentStatus = Status::CUDAError; + } + MITK_INFO << testCOUT; + } + const auto *pErrEvent = dynamic_cast(&e); + if (pErrEvent) + { + testCERR = testCERR + pErrEvent->GetOutput(); + MITK_ERROR << testCERR; + } +} + +void mitk::SegmentAnythingPythonService::StopAsyncProcess() +{ + std::stringstream controlStream; + controlStream << SIGNALCONSTANTS::KILL; + this->WriteControlFile(controlStream); + m_DaemonExec->SetStop(true); + m_Future.get(); +} + +void mitk::SegmentAnythingPythonService::StartAsyncProcess() +{ + if (nullptr != m_DaemonExec) + { + this->StopAsyncProcess(); + } + if (this->GetMitkTempDir().empty()) + { + this->CreateTempDirs(PARENT_TEMP_DIR_PATTERN); + } + std::stringstream controlStream; + controlStream << SIGNALCONSTANTS::READY; + this->WriteControlFile(controlStream); + double timeout = 1; + m_DaemonExec = SegmentAnythingProcessExecutor::New(timeout); + itk::CStyleCommand::Pointer spCommand = itk::CStyleCommand::New(); + spCommand->SetCallback(&mitk::SegmentAnythingPythonService::onPythonProcessEvent); + m_DaemonExec->AddObserver(ExternalProcessOutputEvent(), spCommand); + m_Future = std::async(std::launch::async, &mitk::SegmentAnythingPythonService::start_python_daemon, this); + } + +void mitk::SegmentAnythingPythonService::TransferPointsToProcess(std::stringstream &triggerCSV) +{ + this->CheckStatus(); + std::string triggerFilePath = m_InDir + IOUtil::GetDirectorySeparator() + TRIGGER_FILENAME; + std::ofstream csvfile; + csvfile.open(triggerFilePath, std::ofstream::out | std::ofstream::trunc); + csvfile << triggerCSV.rdbuf(); + csvfile.close(); +} + +void mitk::SegmentAnythingPythonService::WriteControlFile(std::stringstream &statusStream) +{ + std::string controlFilePath = m_InDir + IOUtil::GetDirectorySeparator() + "control.txt"; + std::ofstream controlFile; + controlFile.open(controlFilePath, std::ofstream::out | std::ofstream::trunc); + controlFile << statusStream.rdbuf(); + controlFile.close(); +} + +void mitk::SegmentAnythingPythonService::start_python_daemon() +{ + ProcessExecutor::ArgumentListType args; + std::string command = "python"; + args.push_back("-u"); + + args.push_back(SAM_PYTHON_FILE_NAME); + + args.push_back("--input-folder"); + args.push_back(m_InDir); + + args.push_back("--output-folder"); + args.push_back(m_OutDir); + + args.push_back("--trigger-file"); + args.push_back(TRIGGER_FILENAME); + + args.push_back("--model-type"); + args.push_back(m_ModelType); + + args.push_back("--checkpoint"); + args.push_back(m_CheckpointPath); + + args.push_back("--device"); + if (m_GpuId == -1) + { + args.push_back("cpu"); + } + else + { + args.push_back("cuda"); + std::string cudaEnv = "CUDA_VISIBLE_DEVICES=" + std::to_string(m_GpuId); + itksys::SystemTools::PutEnv(cudaEnv.c_str()); + } + + try + { + std::stringstream logStream; + for (const auto &arg : args) + logStream << arg << " "; + logStream << m_PythonPath; + MITK_INFO << logStream.str(); + m_DaemonExec->Execute(m_PythonPath, command, args); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + return; + } + MITK_INFO << "Python process ended."; +} + +bool mitk::SegmentAnythingPythonService::CheckStatus() +{ + switch (CurrentStatus) + { + case mitk::SegmentAnythingPythonService::Status::READY: + return true; + case mitk::SegmentAnythingPythonService::Status::CUDAError: + mitkThrow() << "Error: Cuda Out of Memory. Change your model type in Preferences and Activate Segment Anything tool again."; + case mitk::SegmentAnythingPythonService::Status::KILLED: + mitkThrow() << "Error: Python process is already terminated. Cannot load requested segmentation. Activate Segment Anything tool again."; + default: + return false; + } +} + +void mitk::SegmentAnythingPythonService::CreateTempDirs(const std::string &dirPattern) +{ + this->SetMitkTempDir(IOUtil::CreateTemporaryDirectory(dirPattern)); + m_InDir = IOUtil::CreateTemporaryDirectory("sam-in-XXXXXX", m_MitkTempDir); + m_OutDir = IOUtil::CreateTemporaryDirectory("sam-out-XXXXXX", m_MitkTempDir); +} + +mitk::LabelSetImage::Pointer mitk::SegmentAnythingPythonService::RetrieveImageFromProcess(long timeOut) +{ + std::string outputImagePath = m_OutDir + IOUtil::GetDirectorySeparator() + m_CurrentUId + ".nrrd"; + auto start = sys_clock::now(); + while (!std::filesystem::exists(outputImagePath)) + { + this->CheckStatus(); + std::this_thread::sleep_for(100ms); + if (timeOut != -1 && std::chrono::duration_cast(sys_clock::now() - start).count() > timeOut) + { + CurrentStatus = Status::OFF; + m_DaemonExec->SetStop(true); + mitkThrow() << SIGNALCONSTANTS::TIMEOUT_ERROR; + + } + } + LabelSetImage::Pointer outputBuffer = mitk::IOUtil::Load(outputImagePath); + return outputBuffer; +} + +void mitk::SegmentAnythingPythonService::TransferImageToProcess(const Image *inputAtTimeStep, std::string &UId) +{ + std::string inputImagePath = m_InDir + IOUtil::GetDirectorySeparator() + UId + ".nrrd"; + if (inputAtTimeStep->GetPixelType().GetNumberOfComponents() < 2) + { + AccessByItk_n(inputAtTimeStep, ITKWriter, (inputImagePath)); + } + else + { + mitk::IOUtil::Save(inputAtTimeStep, inputImagePath); + } + m_CurrentUId = UId; +} + +template +void mitk::SegmentAnythingPythonService::ITKWriter(const itk::Image *image, std::string& outputFilename) +{ + typedef itk::Image ImageType; + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + mitk::LocaleSwitch localeSwitch("C"); + writer->SetFileName(outputFilename); + writer->SetInput(image); + try + { + writer->Update(); + } + catch (const itk::ExceptionObject &error) + { + MITK_ERROR << "Error: " << error << std::endl; + mitkThrow() << "Error: " << error; + } +} diff --git a/Modules/Segmentation/Interactions/mitkSegmentAnythingPythonService.h b/Modules/Segmentation/Interactions/mitkSegmentAnythingPythonService.h new file mode 100644 index 0000000000..1e54928e6b --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkSegmentAnythingPythonService.h @@ -0,0 +1,151 @@ +/*============================================================================ + +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 mitkSegmentAnythingPythonService_h +#define mitkSegmentAnythingPythonService_h + +#include +#include +#include +#include +#include +#include +#include + +namespace mitk +{ + /** + * @brief Segment Anything Model Python process handler class. + * + */ + class MITKSEGMENTATION_EXPORT SegmentAnythingPythonService : public itk::Object + { + public: + enum Status + { + READY, + OFF, + KILLED, + CUDAError + }; + + SegmentAnythingPythonService(std::string, std::string, std::string, unsigned int); + ~SegmentAnythingPythonService(); + + itkSetMacro(MitkTempDir, std::string); + itkGetConstMacro(MitkTempDir, std::string); + + /** + * @brief Static function to print out everything from itk::EventObject. + * Used as callback in mitk::ProcessExecutor object. + * + */ + static void onPythonProcessEvent(itk::Object*, const itk::EventObject&, void*); + + /** + * @brief Checks CurrentStatus enum variable and returns + * true if daemon is READY (to read files) state, false is OFF state or + * throws exception if daemon is found KILL or Cuda error state. + * + * @return bool + */ + static bool CheckStatus() /*throw(mitk::Exception)*/; + + /** + * @brief Creates temp directories and calls start_python_daemon + * function async. + * + */ + void StartAsyncProcess(); + + /** + * @brief Writes KILL to the control file to stop the daemon process. + * + */ + void StopAsyncProcess(); + + /** + * @brief Writes image as nifity file with unique id (UId) as file name. + * + */ + void TransferImageToProcess(const Image*, std::string &UId); + + /** + * @brief Writes csv stringstream of points to a csv file for + * python daemon to read. + * + */ + void TransferPointsToProcess(std::stringstream&); + + /** + * @brief Waits for output nifity file from the daemon to appear and + * reads it as a mitk::Image + * + * @return Image::Pointer + */ + LabelSetImage::Pointer RetrieveImageFromProcess(long timeOut= -1); + + static Status CurrentStatus; + + private: + /** + * @brief Runs SAM python daemon using mitk::ProcessExecutor + * + */ + void start_python_daemon(); + + /** + * @brief Writes stringstream content into control file. + * + */ + void WriteControlFile(std::stringstream&); + + /** + * @brief Create a Temp Dirs + * + */ + void CreateTempDirs(const std::string&); + + /** + * @brief ITK-based file writer for dumping inputs into python daemon + * + */ + template + void ITKWriter(const itk::Image *image, std::string& outputFilename); + + + std::string m_MitkTempDir; + std::string m_PythonPath; + std::string m_ModelType; + std::string m_CheckpointPath; + std::string m_InDir, m_OutDir; + std::string m_CurrentUId; + int m_GpuId = 0; + const std::string PARENT_TEMP_DIR_PATTERN = "mitk-sam-XXXXXX"; + const std::string TRIGGER_FILENAME = "trigger.csv"; + const std::string SAM_PYTHON_FILE_NAME = "run_inference_daemon.py"; + std::future m_Future; + SegmentAnythingProcessExecutor::Pointer m_DaemonExec; + }; + + struct SIGNALCONSTANTS + { + static const std::string READY; + static const std::string KILL; + static const std::string OFF; + static const std::string CUDA_OUT_OF_MEMORY_ERROR; + static const std::string TIMEOUT_ERROR; + }; + +} // namespace + +#endif diff --git a/Modules/Segmentation/Interactions/mitkSegmentAnythingTool.cpp b/Modules/Segmentation/Interactions/mitkSegmentAnythingTool.cpp new file mode 100644 index 0000000000..94b63e8320 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkSegmentAnythingTool.cpp @@ -0,0 +1,411 @@ +/*============================================================================ + +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 "mitkSegmentAnythingTool.h" + +#include +#include +#include +#include "mitkInteractionPositionEvent.h" +#include "mitkPointSetShapeProperty.h" +#include "mitkProperties.h" +#include "mitkToolManager.h" +#include +// us +#include +#include +#include +#include + +#include +#include "mitkImageAccessByItk.h" + +using namespace std::chrono_literals; + +namespace mitk +{ + MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, SegmentAnythingTool, "SegmentAnythingTool"); +} + +mitk::SegmentAnythingTool::SegmentAnythingTool() : SegWithPreviewTool(true, "PressMoveReleaseAndPointSetting") +{ + this->ResetsToEmptyPreviewOn(); + this->IsTimePointChangeAwareOff(); + this->KeepActiveAfterAcceptOn(); +} + +const char **mitk::SegmentAnythingTool::GetXPM() const +{ + return nullptr; +} + +const char *mitk::SegmentAnythingTool::GetName() const +{ + return "Segment Anything"; +} + +us::ModuleResource mitk::SegmentAnythingTool::GetIconResource() const +{ + us::Module *module = us::GetModuleContext()->GetModule(); + us::ModuleResource resource = module->GetResource("AI.svg"); + return resource; +} + +void mitk::SegmentAnythingTool::Activated() +{ + Superclass::Activated(); + m_PointSetPositive = mitk::PointSet::New(); + m_PointSetNodePositive = mitk::DataNode::New(); + m_PointSetNodePositive->SetData(m_PointSetPositive); + m_PointSetNodePositive->SetName(std::string(this->GetName()) + "_PointSetPositive"); + m_PointSetNodePositive->SetBoolProperty("helper object", true); + m_PointSetNodePositive->SetColor(0.0, 1.0, 0.0); + m_PointSetNodePositive->SetVisibility(true); + m_PointSetNodePositive->SetProperty("Pointset.2D.shape", + mitk::PointSetShapeProperty::New(mitk::PointSetShapeProperty::CIRCLE)); + m_PointSetNodePositive->SetProperty("Pointset.2D.fill shape", mitk::BoolProperty::New(true)); + this->GetDataStorage()->Add(m_PointSetNodePositive, this->GetToolManager()->GetWorkingData(0)); + + m_PointSetNegative = mitk::PointSet::New(); + m_PointSetNodeNegative = mitk::DataNode::New(); + m_PointSetNodeNegative->SetData(m_PointSetNegative); + m_PointSetNodeNegative->SetName(std::string(this->GetName()) + "_PointSetNegative"); + m_PointSetNodeNegative->SetBoolProperty("helper object", true); + m_PointSetNodeNegative->SetColor(1.0, 0.0, 0.0); + m_PointSetNodeNegative->SetVisibility(true); + m_PointSetNodeNegative->SetProperty("Pointset.2D.shape", + mitk::PointSetShapeProperty::New(mitk::PointSetShapeProperty::CIRCLE)); + m_PointSetNodeNegative->SetProperty("Pointset.2D.fill shape", mitk::BoolProperty::New(true)); + this->GetDataStorage()->Add(m_PointSetNodeNegative, this->GetToolManager()->GetWorkingData(0)); + + this->SetLabelTransferScope(LabelTransferScope::ActiveLabel); + this->SetLabelTransferMode(LabelTransferMode::MapLabel); +} + +void mitk::SegmentAnythingTool::Deactivated() +{ + this->ClearSeeds(); + GetDataStorage()->Remove(m_PointSetNodePositive); + GetDataStorage()->Remove(m_PointSetNodeNegative); + m_PointSetNodePositive = nullptr; + m_PointSetNodeNegative = nullptr; + m_PointSetPositive = nullptr; + m_PointSetNegative = nullptr; + m_PythonService.reset(); + Superclass::Deactivated(); +} + +void mitk::SegmentAnythingTool::ConnectActionsAndFunctions() +{ + CONNECT_FUNCTION("ShiftSecondaryButtonPressed", OnAddNegativePoint); + CONNECT_FUNCTION("ShiftPrimaryButtonPressed", OnAddPositivePoint); + CONNECT_FUNCTION("DeletePoint", OnDelete); +} + +void mitk::SegmentAnythingTool::InitSAMPythonProcess() +{ + if (nullptr != m_PythonService) + { + m_PythonService.reset(); + } + this->ClearPicks(); + m_PythonService = std::make_unique( + this->GetPythonPath(), this->GetModelType(), this->GetCheckpointPath(), this->GetGpuId()); + m_PythonService->StartAsyncProcess(); +} + +bool mitk::SegmentAnythingTool::IsPythonReady() const +{ + return m_PythonService->CheckStatus(); +} + +void mitk::SegmentAnythingTool::OnAddNegativePoint(StateMachineAction *, InteractionEvent *interactionEvent) +{ + if (!this->GetIsReady() || m_PointSetPositive->GetSize() == 0 || nullptr == this->GetWorkingPlaneGeometry() || + !mitk::Equal(*(interactionEvent->GetSender()->GetCurrentWorldPlaneGeometry()), *(this->GetWorkingPlaneGeometry()))) + { + return; + } + if (!this->IsUpdating() && m_PointSetNegative.IsNotNull()) + { + const auto positionEvent = dynamic_cast(interactionEvent); + if (positionEvent != nullptr) + { + m_PointSetNegative->InsertPoint(m_PointSetCount, positionEvent->GetPositionInWorld()); + m_PointSetCount++; + this->UpdatePreview(); + } + } +} + +void mitk::SegmentAnythingTool::OnAddPositivePoint(StateMachineAction *, InteractionEvent *interactionEvent) +{ + if (!this->GetIsReady()) + { + return; + } + m_IsGenerateEmbeddings = false; + if ((nullptr == this->GetWorkingPlaneGeometry()) || + !mitk::Equal(*(interactionEvent->GetSender()->GetCurrentWorldPlaneGeometry()), + *(this->GetWorkingPlaneGeometry()))) + { + m_IsGenerateEmbeddings = true; + this->ClearSeeds(); + this->SetWorkingPlaneGeometry(interactionEvent->GetSender()->GetCurrentWorldPlaneGeometry()->Clone()); + } + if (!this->IsUpdating() && m_PointSetPositive.IsNotNull()) + { + const auto positionEvent = dynamic_cast(interactionEvent); + if (positionEvent != nullptr) + { + m_PointSetPositive->InsertPoint(m_PointSetCount, positionEvent->GetPositionInWorld()); + ++m_PointSetCount; + this->UpdatePreview(); + } + } +} + +void mitk::SegmentAnythingTool::OnDelete(StateMachineAction *, InteractionEvent *) +{ + if (!this->IsUpdating() && m_PointSetPositive.IsNotNull() && m_PointSetNegative.IsNotNull()) + { + PointSet::Pointer removeSet = m_PointSetPositive; + decltype(m_PointSetPositive->GetMaxId().Index()) maxId = 0; + if (m_PointSetPositive->GetSize() > 0) + { + maxId = m_PointSetPositive->GetMaxId().Index(); + } + if (m_PointSetNegative->GetSize() > 0 && (maxId < m_PointSetNegative->GetMaxId().Index())) + { + removeSet = m_PointSetNegative; + } + removeSet->RemovePointAtEnd(0); + --m_PointSetCount; + this->UpdatePreview(); + } +} + +void mitk::SegmentAnythingTool::ClearPicks() +{ + this->ClearSeeds(); + this->UpdatePreview(); +} + +bool mitk::SegmentAnythingTool::HasPicks() const +{ + return this->m_PointSetPositive.IsNotNull() && this->m_PointSetPositive->GetSize() > 0; +} + +void mitk::SegmentAnythingTool::ClearSeeds() +{ + if (this->m_PointSetPositive.IsNotNull()) + { + m_PointSetCount -= m_PointSetPositive->GetSize(); + this->m_PointSetPositive = mitk::PointSet::New(); // renew pointset + this->m_PointSetNodePositive->SetData(this->m_PointSetPositive); + } + if (this->m_PointSetNegative.IsNotNull()) + { + m_PointSetCount -= m_PointSetNegative->GetSize(); + this->m_PointSetNegative = mitk::PointSet::New(); // renew pointset + this->m_PointSetNodeNegative->SetData(this->m_PointSetNegative); + } +} + +void mitk::SegmentAnythingTool::ConfirmCleanUp() +{ + auto previewImage = this->GetPreviewSegmentation(); + for (unsigned int timeStep = 0; timeStep < previewImage->GetTimeSteps(); ++timeStep) + { + this->ResetPreviewContentAtTimeStep(timeStep); + } + this->ClearSeeds(); + RenderingManager::GetInstance()->RequestUpdateAll(); +} + +template +void mitk::SegmentAnythingTool::ITKWindowing(const itk::Image *inputImage, + Image *mitkImage, + ScalarType min, + ScalarType max) +{ + typedef itk::Image ImageType; + typedef itk::IntensityWindowingImageFilter IntensityFilterType; + typename IntensityFilterType::Pointer filter = IntensityFilterType::New(); + filter->SetInput(inputImage); + filter->SetWindowMinimum(min); + filter->SetWindowMaximum(max); + filter->SetOutputMinimum(min); + filter->SetOutputMaximum(max); + filter->Update(); + + mitkImage->SetImportVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), 0, 0, Image::ManageMemory); + filter->GetOutput()->GetPixelContainer()->ContainerManageMemoryOff(); +} + +void mitk::SegmentAnythingTool::DoUpdatePreview(const Image *inputAtTimeStep, + const Image * /*oldSegAtTimeStep*/, + LabelSetImage *previewImage, + TimeStepType timeStep) +{ + if (nullptr != previewImage && m_PointSetPositive.IsNotNull()) + { + if (this->HasPicks() && nullptr != m_PythonService) + { + mitk::LevelWindow levelWindow; + this->GetToolManager()->GetReferenceData(0)->GetLevelWindow(levelWindow); + std::string uniquePlaneID = GetHashForCurrentPlane(levelWindow); + m_ProgressCommand->SetProgress(20); + try + { + std::stringstream csvStream; + this->EmitSAMStatusMessageEvent("Prompting Segment Anything Model..."); + m_ProgressCommand->SetProgress(50); + if (inputAtTimeStep->GetPixelType().GetNumberOfComponents() < 2) + { + auto filteredImage = mitk::Image::New(); + filteredImage->Initialize(inputAtTimeStep); + AccessByItk_n(inputAtTimeStep, ITKWindowing, // apply level window filter + (filteredImage, levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound())); + m_PythonService->TransferImageToProcess(filteredImage, uniquePlaneID); + csvStream = this->GetPointsAsCSVString(filteredImage->GetGeometry()); + } + else + { + m_PythonService->TransferImageToProcess(inputAtTimeStep, uniquePlaneID); + csvStream = this->GetPointsAsCSVString(inputAtTimeStep->GetGeometry()); + } + m_ProgressCommand->SetProgress(100); + m_PythonService->TransferPointsToProcess(csvStream); + m_ProgressCommand->SetProgress(150); + std::this_thread::sleep_for(100ms); + mitk::LabelSetImage::Pointer outputBuffer = m_PythonService->RetrieveImageFromProcess(this->GetTimeOutLimit()); + m_ProgressCommand->SetProgress(180); + mitk::SegTool2D::WriteSliceToVolume(previewImage, this->GetWorkingPlaneGeometry(), outputBuffer.GetPointer(), timeStep, false); + this->SetSelectedLabels({MASK_VALUE}); + this->EmitSAMStatusMessageEvent("Successfully generated segmentation."); + } + catch (const mitk::Exception &e) + { + this->ClearPicks(); + this->EmitSAMStatusMessageEvent(e.GetDescription()); + mitkThrow() << e.GetDescription(); + } + } + else if (nullptr != this->GetWorkingPlaneGeometry()) + { + this->ResetPreviewContentAtTimeStep(timeStep); + RenderingManager::GetInstance()->ForceImmediateUpdateAll(); + } + } +} + +std::string mitk::SegmentAnythingTool::GetHashForCurrentPlane(const mitk::LevelWindow &levelWindow) +{ + mitk::Vector3D normal = this->GetWorkingPlaneGeometry()->GetNormal(); + mitk::Point3D center = this->GetWorkingPlaneGeometry()->GetCenter(); + std::stringstream hashstream; + hashstream << std::setprecision(3) << std::fixed << normal[0]; //Consider only 3 digits after decimal + hashstream << std::setprecision(3) << std::fixed << normal[1]; + hashstream << std::setprecision(3) << std::fixed << normal[2]; + hashstream << std::setprecision(3) << std::fixed << center[0]; + hashstream << std::setprecision(3) << std::fixed << center[1]; + hashstream << std::setprecision(3) << std::fixed << center[2]; + hashstream << levelWindow.GetLowerWindowBound(); + hashstream << levelWindow.GetUpperWindowBound(); + size_t hashVal = std::hash{}(hashstream.str()); + return std::to_string(hashVal); +} + +std::stringstream mitk::SegmentAnythingTool::GetPointsAsCSVString(const mitk::BaseGeometry *baseGeometry) +{ + MITK_INFO << "No.of points: " << m_PointSetPositive->GetSize(); + std::stringstream pointsAndLabels; + pointsAndLabels << "Point,Label\n"; + mitk::PointSet::PointsConstIterator pointSetItPos = m_PointSetPositive->Begin(); + mitk::PointSet::PointsConstIterator pointSetItNeg = m_PointSetNegative->Begin(); + const char SPACE = ' '; + while (pointSetItPos != m_PointSetPositive->End() || pointSetItNeg != m_PointSetNegative->End()) + { + if (pointSetItPos != m_PointSetPositive->End()) + { + mitk::Point3D point = pointSetItPos.Value(); + if (baseGeometry->IsInside(point)) + { + Point2D p2D = Get2DIndicesfrom3DWorld(baseGeometry, point); + pointsAndLabels << static_cast(p2D[0]) << SPACE << static_cast(p2D[1]) << ",1" << std::endl; + } + ++pointSetItPos; + } + if (pointSetItNeg != m_PointSetNegative->End()) + { + mitk::Point3D point = pointSetItNeg.Value(); + if (baseGeometry->IsInside(point)) + { + Point2D p2D = Get2DIndicesfrom3DWorld(baseGeometry, point); + pointsAndLabels << static_cast(p2D[0]) << SPACE << static_cast(p2D[1]) << ",0" << std::endl; + } + ++pointSetItNeg; + } + } + return pointsAndLabels; +} + +std::vector> mitk::SegmentAnythingTool::GetPointsAsVector( + const mitk::BaseGeometry *baseGeometry) +{ + std::vector> clickVec; + clickVec.reserve(m_PointSetPositive->GetSize() + m_PointSetNegative->GetSize()); + mitk::PointSet::PointsConstIterator pointSetItPos = m_PointSetPositive->Begin(); + mitk::PointSet::PointsConstIterator pointSetItNeg = m_PointSetNegative->Begin(); + while (pointSetItPos != m_PointSetPositive->End() || pointSetItNeg != m_PointSetNegative->End()) + { + if (pointSetItPos != m_PointSetPositive->End()) + { + mitk::Point3D point = pointSetItPos.Value(); + if (baseGeometry->IsInside(point)) + { + Point2D p2D = Get2DIndicesfrom3DWorld(baseGeometry, point); + clickVec.push_back(std::pair(p2D, "1")); + } + ++pointSetItPos; + } + if (pointSetItNeg != m_PointSetNegative->End()) + { + mitk::Point3D point = pointSetItNeg.Value(); + if (baseGeometry->IsInside(point)) + { + Point2D p2D = Get2DIndicesfrom3DWorld(baseGeometry, point); + clickVec.push_back(std::pair(p2D, "0")); + } + ++pointSetItNeg; + } + } + return clickVec; +} + +mitk::Point2D mitk::SegmentAnythingTool::Get2DIndicesfrom3DWorld(const mitk::BaseGeometry *baseGeometry, + const mitk::Point3D &point3d) +{ + mitk::Point3D index3D; + baseGeometry->WorldToIndex(point3d, index3D); + MITK_INFO << index3D[0] << " " << index3D[1] << " " << index3D[2]; // remove + Point2D point2D; + point2D.SetElement(0, index3D[0]); + point2D.SetElement(1, index3D[1]); + return point2D; +} + +void mitk::SegmentAnythingTool::EmitSAMStatusMessageEvent(const std::string& status) +{ + SAMStatusMessageEvent.Send(status); +} diff --git a/Modules/Segmentation/Interactions/mitkSegmentAnythingTool.h b/Modules/Segmentation/Interactions/mitkSegmentAnythingTool.h new file mode 100644 index 0000000000..e096072cc2 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkSegmentAnythingTool.h @@ -0,0 +1,226 @@ +/*============================================================================ + +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 mitkSegmentAnythingTool_h +#define mitkSegmentAnythingTool_h + +#include "mitkSegWithPreviewTool.h" +#include "mitkPointSet.h" +#include "mitkProcessExecutor.h" +#include "mitkSegmentAnythingPythonService.h" +#include +#include +#include + +namespace us +{ + class ModuleResource; +} + +namespace mitk +{ + /** + \brief Segment Anything Model interactive 2D tool class. + + \ingroup ToolManagerEtAl + \sa mitk::Tool + \sa QmitkInteractiveSegmentation + + */ + class MITKSEGMENTATION_EXPORT SegmentAnythingTool : public SegWithPreviewTool + { + public: + mitkClassMacro(SegmentAnythingTool, SegWithPreviewTool); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + const char **GetXPM() const override; + const char *GetName() const override; + us::ModuleResource GetIconResource() const override; + + void Activated() override; + void Deactivated() override; + + /** + * @brief Clears all picks and updates the preview. + */ + void ClearPicks(); + + /** + * @brief Checks if any point exists in the either + * of the pointsets + * + * @return bool + */ + bool HasPicks() const; + + itkSetMacro(MitkTempDir, std::string); + itkGetConstMacro(MitkTempDir, std::string); + + itkSetMacro(PythonPath, std::string); + itkGetConstMacro(PythonPath, std::string); + + itkSetMacro(ModelType, std::string); + itkGetConstMacro(ModelType, std::string); + + itkSetMacro(CheckpointPath, std::string); + itkGetConstMacro(CheckpointPath, std::string); + + itkSetMacro(GpuId, int); + itkGetConstMacro(GpuId, int); + + itkSetMacro(TimeOutLimit, long); + itkGetConstMacro(TimeOutLimit, long); + + itkSetMacro(IsReady, bool); + itkGetConstMacro(IsReady, bool); + itkBooleanMacro(IsReady); + + /** + * @brief Initializes python service and + * starts async python daemon of SegmentAnything model. + * + */ + void InitSAMPythonProcess(); + + /** + * @brief Checks if Python daemon is ready to accept inputs. + * + * @return bool + */ + bool IsPythonReady() const; + + Message1 SAMStatusMessageEvent; + + protected: + SegmentAnythingTool(); + ~SegmentAnythingTool() = default; + + void ConnectActionsAndFunctions() override; + + /* + * @brief Add positive seed point action of StateMachine pattern + */ + virtual void OnAddPositivePoint(StateMachineAction*, InteractionEvent *interactionEvent); + + /* + * @brief Add negative seed point action of StateMachine pattern + */ + virtual void OnAddNegativePoint(StateMachineAction*, InteractionEvent *interactionEvent); + + /* + * @brief Delete action of StateMachine pattern. The function deletes positive or negative points in + the reverse order of creation. This is done by finding & deleting the Point having the highest + PointIdentifier value from either of the PointSets m_PointSetPositive & m_PointSetNegative. + */ + virtual void OnDelete(StateMachineAction*, InteractionEvent*); + + /* + * @brief Clear all seed points and call UpdatePreview to reset the segmentation Preview + */ + void ClearSeeds(); + + /** + * @brief Overriden method from the tool manager to execute the segmentation + * Implementation: + * 1. Creates Hash for input image from current plane geometry. + * 2. Transfers image pointer to python service along with the hash code. + * 3. Creates seed points as CSV string & transfers to python service + * 3. Retrieves resulting segmentation Image pointer from python service and sets to previewImage. + * + * @param inputAtTimeStep + * @param oldSegAtTimeStep + * @param previewImage + * @param timeStep + */ + void DoUpdatePreview(const Image *inputAtTimeStep, const Image *oldSegAtTimeStep, LabelSetImage *previewImage, TimeStepType timeStep) override; + + /** + * @brief Get the Points from positive and negative pointsets as std::vector. + * + * @param baseGeometry of Image + * @return std::vector> + */ + std::vector> GetPointsAsVector(const mitk::BaseGeometry*); + + /** + * @brief Get the Points from positive and negative pointsets as csv string. + * + * @param baseGeometry + * @return std::stringstream + */ + std::stringstream GetPointsAsCSVString(const mitk::BaseGeometry *baseGeometry); + + /** + * @brief Get the Hash For Current Plane from current working plane geometry. + * + * @return std::string + */ + std::string GetHashForCurrentPlane(const mitk::LevelWindow&); + + /** + * @brief Emits message to connected Listnerers. + * + */ + void EmitSAMStatusMessageEvent(const std::string&); + + /** + * @brief Cleans up segmentation preview and clears all seeds. + * + */ + void ConfirmCleanUp() override; + + /** + * @brief Applies ITK IntensityWindowing Filter to input image; + * + */ + template + void ITKWindowing(const itk::Image*, mitk::Image*, ScalarType, ScalarType); + + private: + /** + * @brief Convert 3D world coordinates to 2D indices. + * + * @param baseGeometry + * @param mitk::Point3D + * @return mitk::Point2D + */ + static mitk::Point2D Get2DIndicesfrom3DWorld(const mitk::BaseGeometry*, const mitk::Point3D&); + + /** + * @brief Checks if the image has valid size across each dimension. This function is + * critical for 2D images since 2D image are not valid in Saggital and Coronal views. + * + * @param inputAtTimeStep + * @return bool + */ + bool IsImageAtTimeStepValid(const Image *inputAtTimeStep); + + std::string m_MitkTempDir; + std::string m_PythonPath; + std::string m_ModelType; + std::string m_CheckpointPath; + int m_GpuId = 0; + PointSet::Pointer m_PointSetPositive; + PointSet::Pointer m_PointSetNegative; + DataNode::Pointer m_PointSetNodePositive; + DataNode::Pointer m_PointSetNodeNegative; + bool m_IsGenerateEmbeddings = true; + bool m_IsReady = false; + int m_PointSetCount = 0; + long m_TimeOutLimit = -1; + std::unique_ptr m_PythonService; + const Label::PixelType MASK_VALUE = 1; + }; +} // namespace + +#endif diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake index f9c467ab8b..c43ee4e133 100644 --- a/Modules/Segmentation/files.cmake +++ b/Modules/Segmentation/files.cmake @@ -1,120 +1,123 @@ set(CPP_FILES Algorithms/mitkCalculateSegmentationVolume.cpp Algorithms/mitkContourModelSetToImageFilter.cpp Algorithms/mitkContourSetToPointSetFilter.cpp Algorithms/mitkContourUtils.cpp Algorithms/mitkCorrectorAlgorithm.cpp Algorithms/mitkDiffImageApplier.cpp Algorithms/mitkDiffSliceOperation.cpp Algorithms/mitkDiffSliceOperationApplier.cpp Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp Algorithms/mitkGrowCutSegmentationFilter.cpp Algorithms/mitkImageLiveWireContourModelFilter.cpp Algorithms/mitkImageToContourFilter.cpp #Algorithms/mitkImageToContourModelFilter.cpp Algorithms/mitkImageToLiveWireContourFilter.cpp Algorithms/mitkManualSegmentationToSurfaceFilter.cpp Algorithms/mitkOtsuSegmentationFilter.cpp Algorithms/mitkSegmentationHelper.cpp Algorithms/mitkSegmentationObjectFactory.cpp Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp Algorithms/mitkShowSegmentationAsSurface.cpp Algorithms/mitkVtkImageOverwrite.cpp Controllers/mitkSegmentationInterpolationController.cpp Controllers/mitkToolManager.cpp Controllers/mitkSegmentationModuleActivator.cpp Controllers/mitkToolManagerProvider.cpp DataManagement/mitkContour.cpp DataManagement/mitkContourSet.cpp DataManagement/mitkExtrudedContour.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkSegWithPreviewTool.cpp Interactions/mitkBinaryThresholdBaseTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkCloseRegionTool.cpp Interactions/mitkContourModelInteractor.cpp Interactions/mitkContourModelLiveWireInteractor.cpp Interactions/mitkEditableContourTool.cpp Interactions/mitkLiveWireTool2D.cpp Interactions/mitkLassoTool.cpp Interactions/mitkContourTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkFillRegionBaseTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkGrowCutTool.cpp Interactions/mitkOtsuTool3D.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkRegionGrowingTool.cpp Interactions/mitkSegmentationsProcessingTool.cpp Interactions/mitkSegTool2D.cpp Interactions/mitkSubtractContourTool.cpp Interactions/mitkTool.cpp Interactions/mitkToolCommand.cpp Interactions/mitkPickingTool.cpp Interactions/mitknnUnetTool.cpp Interactions/mitkProcessExecutor.cpp + Interactions/mitkSegmentAnythingProcessExecutor.cpp Interactions/mitkMonaiLabelTool.cpp Interactions/mitkMonaiLabel2DTool.cpp Interactions/mitkMonaiLabel3DTool.cpp Interactions/mitkTotalSegmentatorTool.cpp + Interactions/mitkSegmentAnythingTool.cpp + Interactions/mitkSegmentAnythingPythonService.cpp Rendering/mitkContourMapper2D.cpp Rendering/mitkContourSetMapper2D.cpp Rendering/mitkContourSetVtkMapper3D.cpp Rendering/mitkContourVtkMapper3D.cpp SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp #Added from ML Controllers/mitkSliceBasedInterpolationController.cpp Algorithms/mitkSurfaceStampImageFilter.cpp ) set(RESOURCE_FILES Add.svg Add_Cursor.svg AI.svg AI_Cursor.svg Close.svg Close_Cursor.svg Erase.svg Erase_Cursor.svg Fill.svg Fill_Cursor.svg LiveWire.svg LiveWire_Cursor.svg Lasso.svg GrowCut.svg Lasso_Cursor.svg Otsu.svg Paint.svg Paint_Cursor.svg Picking.svg RegionGrowing.svg RegionGrowing_Cursor.svg Subtract.svg Subtract_Cursor.svg Threshold.svg ULThreshold.svg Wipe.svg Wipe_Cursor.svg Interactions/dummy.xml Interactions/EditableContourTool.xml Interactions/PickingTool.xml Interactions/MouseReleaseOnly.xml Interactions/PressMoveRelease.xml Interactions/PressMoveReleaseAndPointSetting.xml Interactions/PressMoveReleaseWithCTRLInversion.xml Interactions/PressMoveReleaseWithCTRLInversionAllMouseMoves.xml Interactions/SegmentationConfig.xml Interactions/SegmentationInteraction.xml Interactions/SegmentationToolsConfig.xml Interactions/ContourModelModificationConfig.xml Interactions/ContourModelModificationInteractor.xml ) diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui new file mode 100644 index 0000000000..6f1f495a00 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui @@ -0,0 +1,169 @@ + + + QmitkSegmentAnythingGUIControls + + + + 0 + 0 + 699 + 490 + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 100000 + 100000 + + + + QmitkSegmentAnythingToolWidget + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Welcome to Segment Anything Model (SAM) tool in MITK. [Experimental]</p><p>Please note that this is only an interface to SAM. MITK does not ship with SAM. Make sure to have a working internet connection to install Segment Anything Model via MITK. </p><p>Refer to <a href="https://segment-anything.com/"><span style=" text-decoration: underline; color:#0000ff;">https://segment-anything.com</span></a> to learn everything about the Segment Anything Model.</p></body></html> + + + Qt::RichText + + + true + + + + + + + + 0 + 0 + + + + +Press SHIFT+Left-click for positive seeds. +Press SHIFT+Right-click for negative seeds. +Press DEL to remove last seed. + + + + + + + + + + + 0 + 0 + + + + + 100000 + 16777215 + + + + Reset Picks + + + + + + + + 0 + 0 + + + + + 100000 + 16777215 + + + + Initialize Segment Anything + + + + + + + + 0 + 0 + + + + true + + + + + + + 1 + + + 0 + + + false + + + + + + + + + ctkComboBox + QComboBox +
ctkComboBox.h
+ 1 +
+ + ctkCollapsibleGroupBox + QWidget +
ctkCollapsibleGroupBox.h
+
+
+ + +
diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp new file mode 100644 index 0000000000..59bcbfab63 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp @@ -0,0 +1,300 @@ +/*============================================================================ + +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 "QmitkSegmentAnythingToolGUI.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MITK_TOOL_GUI_MACRO(MITKSEGMENTATIONUI_EXPORT, QmitkSegmentAnythingToolGUI, "") + +namespace +{ + mitk::IPreferences *GetPreferences() + { + auto *preferencesService = mitk::CoreServices::GetPreferencesService(); + return preferencesService->GetSystemPreferences()->Node("org.mitk.views.segmentation"); + } +} + +QmitkSegmentAnythingToolGUI::QmitkSegmentAnythingToolGUI() : QmitkSegWithPreviewToolGUIBase(true) +{ + m_EnableConfirmSegBtnFnc = [this](bool enabled) + { + bool result = false; + auto tool = this->GetConnectedToolAs(); + if (nullptr != tool) + { + result = enabled && tool->HasPicks(); + } + return result; + }; + m_Preferences = GetPreferences(); + m_Preferences->OnPropertyChanged += + mitk::MessageDelegate1( + this, &QmitkSegmentAnythingToolGUI::OnPreferenceChangedEvent); +} + +QmitkSegmentAnythingToolGUI::~QmitkSegmentAnythingToolGUI() +{ + auto tool = this->GetConnectedToolAs(); + if (nullptr != tool) + { + tool->SAMStatusMessageEvent -= mitk::MessageDelegate1( + this, &QmitkSegmentAnythingToolGUI::StatusMessageListener); + } +} + +void QmitkSegmentAnythingToolGUI::InitializeUI(QBoxLayout *mainLayout) +{ + m_Controls.setupUi(this); + m_Controls.statusLabel->setTextFormat(Qt::RichText); + + QString welcomeText; + if (m_GpuLoader.GetGPUCount() != 0) + { + welcomeText = "STATUS: Welcome to Segment Anything tool. You're in luck: " + + QString::number(m_GpuLoader.GetGPUCount()) + " GPU(s) were detected."; + } + else + { + welcomeText = "STATUS: Welcome to Segment Anything tool. Sorry, " + + QString::number(m_GpuLoader.GetGPUCount()) + " GPUs were detected."; + } + connect(m_Controls.activateButton, SIGNAL(clicked()), this, SLOT(OnActivateBtnClicked())); + connect(m_Controls.resetButton, SIGNAL(clicked()), this, SLOT(OnResetPicksClicked())); + + QIcon arrowIcon = QmitkStyleManager::ThemeIcon( + QStringLiteral(":/org_mitk_icons/icons/tango/scalable/actions/media-playback-start.svg")); + m_Controls.activateButton->setIcon(arrowIcon); + + bool isInstalled = this->ValidatePrefences(); + if (isInstalled) + { + QString modelType = QString::fromStdString(m_Preferences->Get("sam modeltype", "")); + welcomeText += " SAM is already found installed. Model type '" + modelType + "' selected in Preferences."; + } + else + { + welcomeText += " SAM tool is not configured correctly. Please go to Preferences (Cntl+P) > Segment Anything to configure and/or install SAM."; + } + this->EnableAll(isInstalled); + this->WriteStatusMessage(welcomeText); + this->ShowProgressBar(false); + m_Controls.samProgressBar->setMaximum(0); + mainLayout->addLayout(m_Controls.verticalLayout); + Superclass::InitializeUI(mainLayout); +} + +bool QmitkSegmentAnythingToolGUI::ValidatePrefences() +{ + const QString storageDir = QString::fromStdString(m_Preferences->Get("sam python path", "")); + bool isInstalled = QmitkSegmentAnythingToolGUI::IsSAMInstalled(storageDir); + std::string modelType = m_Preferences->Get("sam modeltype", ""); + std::string path = m_Preferences->Get("sam parent path", ""); + return (isInstalled && !modelType.empty() && !path.empty()); +} + +void QmitkSegmentAnythingToolGUI::EnableAll(bool isEnable) +{ + m_Controls.activateButton->setEnabled(isEnable); +} + +void QmitkSegmentAnythingToolGUI::WriteStatusMessage(const QString &message) +{ + m_Controls.statusLabel->setText(message); + m_Controls.statusLabel->setStyleSheet("font-weight: bold; color: white"); + qApp->processEvents(); +} + +void QmitkSegmentAnythingToolGUI::WriteErrorMessage(const QString &message) +{ + m_Controls.statusLabel->setText(message); + m_Controls.statusLabel->setStyleSheet("font-weight: bold; color: red"); + qApp->processEvents(); +} + +void QmitkSegmentAnythingToolGUI::ShowErrorMessage(const std::string &message, QMessageBox::Icon icon) +{ + this->setCursor(Qt::ArrowCursor); + QMessageBox *messageBox = new QMessageBox(icon, nullptr, message.c_str()); + messageBox->exec(); + delete messageBox; + MITK_WARN << message; +} + +void QmitkSegmentAnythingToolGUI::StatusMessageListener(const std::string &message) +{ + if (message.rfind("Error", 0) == 0) + { + this->EnableAll(true); + this->WriteErrorMessage(QString::fromStdString(message)); + } + else if (message == "TimeOut") + { // trying to re init the daemon + this->WriteErrorMessage(QString("STATUS: Sorry, operation timed out. Reactivating SAM tool...")); + if (this->ActivateSAMDaemon()) + { + this->WriteStatusMessage(QString("STATUS: Segment Anything tool re-initialized.")); + } + else + { + this->WriteErrorMessage(QString("STATUS: Couldn't init tool backend.")); + this->EnableAll(true); + } + } + else + { + this->WriteStatusMessage(QString::fromStdString(message)); + } +} + +void QmitkSegmentAnythingToolGUI::OnActivateBtnClicked() +{ + auto tool = this->GetConnectedToolAs(); + if (nullptr == tool) + { + return; + } + try + { + this->EnableAll(false); + qApp->processEvents(); + QString pythonPath = QString::fromStdString(m_Preferences->Get("sam python path", "")); + if (!QmitkSegmentAnythingToolGUI::IsSAMInstalled(pythonPath)) + { + throw std::runtime_error(WARNING_SAM_NOT_FOUND); + } + tool->SetPythonPath(pythonPath.toStdString()); + tool->SetGpuId(m_Preferences->GetInt("sam gpuid", -1)); + const QString modelType = QString::fromStdString(m_Preferences->Get("sam modeltype", "")); + tool->SetModelType(modelType.toStdString()); + tool->SetTimeOutLimit(m_Preferences->GetInt("sam timeout", 300)); + tool->SetCheckpointPath(m_Preferences->Get("sam parent path", "")); + this->WriteStatusMessage( + QString("STATUS: Initializing Segment Anything Model...")); + tool->SAMStatusMessageEvent += mitk::MessageDelegate1( + this, &QmitkSegmentAnythingToolGUI::StatusMessageListener); + if (this->ActivateSAMDaemon()) + { + this->WriteStatusMessage(QString("STATUS: Segment Anything tool initialized.")); + } + else + { + this->WriteErrorMessage(QString("STATUS: Couldn't init tool backend.")); + this->EnableAll(true); + } + } + catch (const std::exception &e) + { + std::stringstream errorMsg; + errorMsg << "STATUS: Error while processing parameters for Segment Anything segmentation. Reason: " << e.what(); + this->ShowErrorMessage(errorMsg.str()); + this->WriteErrorMessage(QString::fromStdString(errorMsg.str())); + this->EnableAll(true); + return; + } + catch (...) + { + std::string errorMsg = "Unkown error occured while generation Segment Anything segmentation."; + this->ShowErrorMessage(errorMsg); + this->EnableAll(true); + return; + } +} + +bool QmitkSegmentAnythingToolGUI::ActivateSAMDaemon() +{ + auto tool = this->GetConnectedToolAs(); + if (nullptr == tool) + { + return false; + } + this->ShowProgressBar(true); + qApp->processEvents(); + try + { + tool->InitSAMPythonProcess(); + while (!tool->IsPythonReady()) + { + qApp->processEvents(); + } + tool->IsReadyOn(); + } + catch (...) + { + tool->IsReadyOff(); + } + this->ShowProgressBar(false); + return tool->GetIsReady(); +} + +void QmitkSegmentAnythingToolGUI::ShowProgressBar(bool enabled) +{ + m_Controls.samProgressBar->setEnabled(enabled); + m_Controls.samProgressBar->setVisible(enabled); +} + +bool QmitkSegmentAnythingToolGUI::IsSAMInstalled(const QString &pythonPath) +{ + QString fullPath = pythonPath; + bool isPythonExists = false; + bool isSamExists = false; +#ifdef _WIN32 + isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python.exe")); + if (!(fullPath.endsWith("Scripts", Qt::CaseInsensitive) || fullPath.endsWith("Scripts/", Qt::CaseInsensitive))) + { + fullPath += QDir::separator() + QString("Scripts"); + isPythonExists = + (!isPythonExists) ? QFile::exists(fullPath + QDir::separator() + QString("python.exe")) : isPythonExists; + } +#else + isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python3")); + if (!(fullPath.endsWith("bin", Qt::CaseInsensitive) || fullPath.endsWith("bin/", Qt::CaseInsensitive))) + { + fullPath += QDir::separator() + QString("bin"); + isPythonExists = + (!isPythonExists) ? QFile::exists(fullPath + QDir::separator() + QString("python3")) : isPythonExists; + } +#endif + isSamExists = QFile::exists(fullPath + QDir::separator() + QString("run_inference_daemon.py")); + bool isExists = isSamExists && isPythonExists; + return isExists; +} + +void QmitkSegmentAnythingToolGUI::OnResetPicksClicked() +{ + auto tool = this->GetConnectedToolAs(); + if (nullptr != tool) + { + tool->ClearPicks(); + } +} + +void QmitkSegmentAnythingToolGUI::OnPreferenceChangedEvent(const mitk::IPreferences::ChangeEvent&) +{ + this->EnableAll(true); + this->WriteStatusMessage("A Preference change was detected. Please initialize the tool again."); + auto tool = this->GetConnectedToolAs(); + if (nullptr != tool) + { + tool->IsReadyOff(); + } +} diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h new file mode 100644 index 0000000000..7349f6a578 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h @@ -0,0 +1,121 @@ +/*============================================================================ + +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 QmitkSegmentAnythingToolGUI_h +#define QmitkSegmentAnythingToolGUI_h + +#include "QmitkSegWithPreviewToolGUIBase.h" +#include +#include "ui_QmitkSegmentAnythingGUIControls.h" +#include "QmitknnUNetGPU.h" +#include "QmitkSetupVirtualEnvUtil.h" +#include +#include +#include + +/** +\ingroup org_mitk_gui_qt_interactivesegmentation_internal +\brief GUI for mitk::SegmentAnythingTool. +*/ +class MITKSEGMENTATIONUI_EXPORT QmitkSegmentAnythingToolGUI : public QmitkSegWithPreviewToolGUIBase +{ + Q_OBJECT + +public: + mitkClassMacro(QmitkSegmentAnythingToolGUI, QmitkSegWithPreviewToolGUIBase); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + /** + * @brief Checks if SegmentAnything is found inside the selected python virtual environment. + * @return bool + */ + static bool IsSAMInstalled(const QString &); + +protected slots: + /** + * @brief Qt Slot + */ + void OnResetPicksClicked(); + + /** + * @brief Qt Slot + */ + void OnActivateBtnClicked(); + +protected: + QmitkSegmentAnythingToolGUI(); + ~QmitkSegmentAnythingToolGUI(); + + void InitializeUI(QBoxLayout *mainLayout) override; + + /** + * @brief Writes any message in white on the tool pane. + */ + void WriteStatusMessage(const QString&); + + /** + * @brief Writes any message in red on the tool pane. + */ + void WriteErrorMessage(const QString&); + + /** + * @brief Function to listen to tool class status emitters. + */ + void StatusMessageListener(const std::string&); + + /** + * @brief Function to listen to preference emitters. + */ + void OnPreferenceChangedEvent(const mitk::IPreferences::ChangeEvent&); + + /** + * @brief Creates a QMessage object and shows on screen. + */ + void ShowErrorMessage(const std::string&, QMessageBox::Icon = QMessageBox::Critical); + + /** + * @brief Enable (or Disable) GUI elements. Currently, on the activate button + * is affected. + */ + void EnableAll(bool); + + /** + * @brief Enable (or Disable) progressbar on GUI + * + */ + void ShowProgressBar(bool); + + /** + * @brief Requests the tool class to spawn the SAM python daemon + * process. Waits until the daemon is started. + * + * @return bool + */ + bool ActivateSAMDaemon(); + + /** + * @brief Checks if the preferences are correctly set by the user. + * + * @return bool + */ + bool ValidatePrefences(); + +private: + mitk::IPreferences* m_Preferences; + Ui_QmitkSegmentAnythingGUIControls m_Controls; + QmitkGPULoader m_GpuLoader; + bool m_FirstPreviewComputation = true; + const std::string WARNING_SAM_NOT_FOUND = + "SAM is not detected in the selected python environment. Please reinstall SAM."; +}; +#endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkSetupVirtualEnvUtil.cpp b/Modules/SegmentationUI/Qmitk/QmitkSetupVirtualEnvUtil.cpp index 50c6fe88f9..2cd4e90488 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkSetupVirtualEnvUtil.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkSetupVirtualEnvUtil.cpp @@ -1,182 +1,183 @@ /*============================================================================ 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.s ============================================================================*/ #include "QmitkSetupVirtualEnvUtil.h" #include "mitkLog.h" #include #include QmitkSetupVirtualEnvUtil::QmitkSetupVirtualEnvUtil() { m_BaseDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QDir::separator() + qApp->organizationName() + QDir::separator(); } QmitkSetupVirtualEnvUtil::QmitkSetupVirtualEnvUtil(const QString &baseDir) { m_BaseDir = baseDir; } QString& QmitkSetupVirtualEnvUtil::GetBaseDir() { return m_BaseDir; } QString QmitkSetupVirtualEnvUtil::GetVirtualEnvPath() { return m_venvPath; } QString& QmitkSetupVirtualEnvUtil::GetSystemPythonPath() { return m_SysPythonPath; } QString& QmitkSetupVirtualEnvUtil::GetPythonPath() { return m_PythonPath; } QString& QmitkSetupVirtualEnvUtil::GetPipPath() { return m_PipPath; } void QmitkSetupVirtualEnvUtil::SetVirtualEnvPath(const QString &path) { m_venvPath = path; } void QmitkSetupVirtualEnvUtil::SetPipPath(const QString &path) { m_PipPath = path; } void QmitkSetupVirtualEnvUtil::SetPythonPath(const QString &path) { if (this->IsPythonPath(path)) { m_PythonPath = path; } else { MITK_INFO << "Python was not detected in " + path.toStdString(); } } void QmitkSetupVirtualEnvUtil::SetSystemPythonPath(const QString &path) { if (this->IsPythonPath(path)) { m_SysPythonPath = path; } else { MITK_INFO << "Python was not detected in " + path.toStdString(); } } void QmitkSetupVirtualEnvUtil::PrintProcessEvent(itk::Object * /*pCaller*/, const itk::EventObject &e, void *) { std::string testCOUT; std::string testCERR; const auto *pEvent = dynamic_cast(&e); if (pEvent) { testCOUT = testCOUT + pEvent->GetOutput(); MITK_INFO << testCOUT; } const auto *pErrEvent = dynamic_cast(&e); if (pErrEvent) { testCERR = testCERR + pErrEvent->GetOutput(); MITK_ERROR << testCERR; } } void QmitkSetupVirtualEnvUtil::InstallPytorch(const std::string &workingDir, void (*callback)(itk::Object *, const itk::EventObject &, void *)) { mitk::ProcessExecutor::ArgumentListType args; auto spExec = mitk::ProcessExecutor::New(); auto spCommand = itk::CStyleCommand::New(); spCommand->SetCallback(callback); spExec->AddObserver(mitk::ExternalProcessOutputEvent(), spCommand); args.push_back("-m"); args.push_back("pip"); args.push_back("install"); args.push_back("light-the-torch"); spExec->Execute(workingDir, "python", args); - PipInstall("torch", workingDir, callback, "ltt"); + PipInstall("torch==2.0.0", workingDir, callback, "ltt"); + PipInstall("torchvision==0.15.0", workingDir, callback, "ltt"); } void QmitkSetupVirtualEnvUtil::InstallPytorch() { this->InstallPytorch(GetPythonPath().toStdString(), &PrintProcessEvent); } void QmitkSetupVirtualEnvUtil::PipInstall(const std::string &library, const std::string &workingDir, void (*callback)(itk::Object *, const itk::EventObject &, void *), const std::string &command) { mitk::ProcessExecutor::ArgumentListType args; auto spExec = mitk::ProcessExecutor::New(); auto spCommand = itk::CStyleCommand::New(); spCommand->SetCallback(callback); spExec->AddObserver(mitk::ExternalProcessOutputEvent(), spCommand); args.push_back("install"); args.push_back(library); spExec->Execute(workingDir, command, args); } void QmitkSetupVirtualEnvUtil::PipInstall(const std::string &library, void (*callback)(itk::Object*, const itk::EventObject&, void*), const std::string& command) { this->PipInstall(library, this->GetPipPath().toStdString(), callback, command); } void QmitkSetupVirtualEnvUtil::ExecutePython(const std::string &pythonCode, const std::string &workingDir, void (*callback)(itk::Object *, const itk::EventObject &, void *), const std::string &command) { mitk::ProcessExecutor::ArgumentListType args; auto spExec = mitk::ProcessExecutor::New(); auto spCommand = itk::CStyleCommand::New(); spCommand->SetCallback(callback); spExec->AddObserver(mitk::ExternalProcessOutputEvent(), spCommand); args.push_back("-c"); args.push_back(pythonCode); spExec->Execute(workingDir, command, args); } void QmitkSetupVirtualEnvUtil::ExecutePython(const std::string &args, void (*callback)(itk::Object *, const itk::EventObject &, void *), const std::string &command) { this->ExecutePython(args, this->GetPythonPath().toStdString(), callback, command); } bool QmitkSetupVirtualEnvUtil::IsPythonPath(const QString &pythonPath) { QString fullPath = pythonPath; bool isExists = #ifdef _WIN32 QFile::exists(fullPath + QDir::separator() + QString("python.exe")); #else QFile::exists(fullPath + QDir::separator() + QString("python3")); #endif return isExists; } diff --git a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.h b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.h index 5344f253a6..331990c3ed 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.h +++ b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.h @@ -1,428 +1,428 @@ /*============================================================================ 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 QmitkSlicesInterpolator_h #define QmitkSlicesInterpolator_h #include "mitkDataNode.h" #include "mitkDataStorage.h" #include "mitkSegmentationInterpolationController.h" #include "mitkSurfaceInterpolationController.h" #include "mitkToolManager.h" #include #include "mitkFeatureBasedEdgeDetectionFilter.h" #include "mitkPointCloudScoringFilter.h" #include #include #include #include #include #include #include #include "mitkVtkRepresentationProperty.h" #include "vtkProperty.h" // For running 3D interpolation in background #include #include #include #include namespace mitk { class PlaneGeometry; class SliceNavigationController; class TimeNavigationController; } class QPushButton; class QmitkRenderWindow; enum ModifyLabelActionTrigerred { Null, Erase, Merge }; /** \brief GUI for slices interpolation. \ingroup ToolManagerEtAl \ingroup Widgets \sa QmitkInteractiveSegmentation \sa mitk::SegmentationInterpolation While mitk::SegmentationInterpolation does the bookkeeping of interpolation (keeping track of which slices contain how much segmentation) and the algorithmic work, QmitkSlicesInterpolator is responsible to watch the GUI, to notice, which slice is currently visible. It triggers generation of interpolation suggestions and also triggers acception of suggestions. \todo show/hide feedback on demand Last contributor: $Author: maleike $ */ class MITKSEGMENTATIONUI_EXPORT QmitkSlicesInterpolator : public QWidget { Q_OBJECT public: QmitkSlicesInterpolator(QWidget *parent = nullptr, const char *name = nullptr); /** To be called once before real use. */ void Initialize(mitk::ToolManager *toolManager, const QList& windows); /** * @brief * */ void Uninitialize(); ~QmitkSlicesInterpolator() override; /** * @brief Set the Data Storage object * * @param storage */ void SetDataStorage(mitk::DataStorage::Pointer storage); /** * @brief Get the Data Storage object * * @return mitk::DataStorage* */ mitk::DataStorage *GetDataStorage(); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnToolManagerWorkingDataModified(); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnToolManagerReferenceDataModified(); /** * @brief Reacts to the time changed event. * * @param sender */ void OnTimeChanged(itk::Object *sender, const itk::EventObject &); /** * @brief Reacts to the slice changed event * * @param sender */ void OnSliceChanged(itk::Object *sender, const itk::EventObject &); void OnSliceNavigationControllerDeleted(const itk::Object *sender, const itk::EventObject &); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnInterpolationInfoChanged(const itk::EventObject &); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnInterpolationAborted(const itk::EventObject &); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnSurfaceInterpolationInfoChanged(const itk::EventObject &); private: /** * @brief Set the visibility of the 3d interpolation */ void Show3DInterpolationResult(bool); /** * @brief Function that reacts to a change in the activeLabel of the working segmentation image. * */ void OnActiveLabelChanged(mitk::Label::PixelType); /** * @brief Function that reacts to a change in the layer. * */ void OnLayerChanged(); /** * @brief Function that handles label removal from the segmentation image. * */ void OnRemoveLabel(mitk::Label::PixelType removedLabelValue); /** * @brief Function that to changes in the segmentation image. It handles the layer removal, addition, label erasure, * */ void OnModifyLabelChanged(const itk::Object *caller, const itk::EventObject & /*event*/); /** * @brief Add the necessary subscribers to the label set image, for UI responsiveness. * It deals with remove label, change active label, layer changes and change in the label. * */ void OnAddLabelSetConnection(); /** * @brief Add the necessary subscribers to the current LabelSetImage at the layer input, for UI responsiveness. * It deals with remove label, change active label, layer changes and change in the label. * * @param layerID */ void OnAddLabelSetConnection(unsigned int layerID); /** * @brief Remove the subscribers for the different events to the segmentation image. * */ void OnRemoveLabelSetConnection(); /** * @brief Merge contours for the current layerID and current timeStep. * * @param timeStep * @param layerID */ void MergeContours(unsigned int timeStep, unsigned int layerID); /** * @brief Prepare Inputs for 3D Interpolation. * */ void PrepareInputsFor3DInterpolation(); signals: void SignalRememberContourPositions(bool); void SignalShowMarkerNodes(bool); public slots: virtual void setEnabled(bool); /** Call this from the outside to enable/disable interpolation */ void EnableInterpolation(bool); void Enable3DInterpolation(bool); /** Call this from the outside to accept all interpolations */ void FinishInterpolation(mitk::SliceNavigationController *slicer = nullptr); protected slots: /** Reaction to button clicks. */ void OnAcceptInterpolationClicked(); /* Opens popup to ask about which orientation should be interpolated */ void OnAcceptAllInterpolationsClicked(); /* Reaction to button clicks */ void OnAccept3DInterpolationClicked(); /** * @brief Reaction to reinit 3D Interpolation. Re-reads the plane geometries of the image * that should have generated the * */ void OnReinit3DInterpolation(); /* * Will trigger interpolation for all slices in given orientation (called from popup menu of * OnAcceptAllInterpolationsClicked) */ void OnAcceptAllPopupActivated(QAction *action); /** Called on activation/deactivation */ void OnInterpolationActivated(bool); void On3DInterpolationActivated(bool); void OnInterpolationMethodChanged(int index); // Enhancement for 3D interpolation void On2DInterpolationEnabled(bool); void On3DInterpolationEnabled(bool); void OnInterpolationDisabled(bool); void OnShowMarkers(bool); void Run3DInterpolation(); /** * @brief Function triggers when the surface interpolation thread completes running. * It is responsible for retrieving the data, rendering it in the active color label, * storing the surface information in the feedback node. * */ void OnSurfaceInterpolationFinished(); void StartUpdateInterpolationTimer(); void StopUpdateInterpolationTimer(); void ChangeSurfaceColor(); /** * @brief Removes all observers to the labelSetImage at the layerID specified. * Is used when changing the segmentation image. * * @param labelSetImage * @param layerID */ void OnRemoveLabelSetConnection(mitk::LabelSetImage* labelSetImage, unsigned int layerID); protected: typedef std::map ActionToSliceDimensionMapType; const ActionToSliceDimensionMapType CreateActionToSlicer(const QList& windows); ActionToSliceDimensionMapType m_ActionToSlicerMap; void AcceptAllInterpolations(mitk::SliceNavigationController *slicer); /** Retrieves the currently selected PlaneGeometry from a SlicedGeometry3D that is generated by a SliceNavigationController and calls Interpolate to further process this PlaneGeometry into an interpolation. \param e is a actually a mitk::SliceNavigationController::GeometrySliceEvent, sent by a SliceNavigationController - \param slicer the SliceNavigationController + \param sliceNavigationController the SliceNavigationController */ bool TranslateAndInterpolateChangedSlice(const itk::EventObject &e, mitk::SliceNavigationController *sliceNavigationController); bool TranslateAndInterpolateChangedSlice(const mitk::TimeGeometry* timeGeometry); /** Given a PlaneGeometry, this method figures out which slice of the first working image (of the associated ToolManager) should be interpolated. The actual work is then done by our SegmentationInterpolation object. */ void Interpolate(mitk::PlaneGeometry *plane); /** Called internally to update the interpolation suggestion. Finds out about the focused render window and requests an interpolation. */ void UpdateVisibleSuggestion(); void SetCurrentContourListID(); private: void InitializeWindow(QmitkRenderWindow* window); void HideAllInterpolationControls(); void Show2DInterpolationControls(bool show); void Show3DInterpolationControls(bool show); void CheckSupportedImageDimension(); void WaitForFutures(); void NodeRemoved(const mitk::DataNode* node); void ClearSegmentationObservers(); mitk::SegmentationInterpolationController::Pointer m_Interpolator; mitk::SurfaceInterpolationController::Pointer m_SurfaceInterpolator; mitk::FeatureBasedEdgeDetectionFilter::Pointer m_EdgeDetector; mitk::PointCloudScoringFilter::Pointer m_PointScorer; mitk::ToolManager::Pointer m_ToolManager; bool m_Initialized; unsigned int m_ControllerToTimeObserverTag; QHash m_ControllerToSliceObserverTag; QHash m_ControllerToDeleteObserverTag; std::map m_SegmentationObserverTags; unsigned int InterpolationInfoChangedObserverTag; unsigned int SurfaceInterpolationInfoChangedObserverTag; unsigned int InterpolationAbortedObserverTag; QGroupBox *m_GroupBoxEnableExclusiveInterpolationMode; QComboBox *m_CmbInterpolation; QPushButton *m_BtnApply2D; QPushButton *m_BtnApplyForAllSlices2D; QPushButton *m_BtnApply3D; // T28261 // QPushButton *m_BtnSuggestPlane; QCheckBox *m_ChkShowPositionNodes; QPushButton *m_BtnReinit3DInterpolation; mitk::DataNode::Pointer m_FeedbackNode; mitk::DataNode::Pointer m_InterpolatedSurfaceNode; mitk::DataNode::Pointer m_3DContourNode; mitk::Image *m_Segmentation; mitk::SliceNavigationController *m_LastSNC; unsigned int m_LastSliceIndex; mitk::TimePointType m_TimePoint; bool m_2DInterpolationEnabled; bool m_3DInterpolationEnabled; unsigned int m_numTimesLabelSetConnectionAdded; mitk::DataStorage::Pointer m_DataStorage; QFuture m_Future; QFutureWatcher m_Watcher; QFuture m_ModifyFuture; QFutureWatcher m_ModifyWatcher; QTimer *m_Timer; QFuture m_PlaneFuture; QFutureWatcher m_PlaneWatcher; mitk::Label::PixelType m_PreviousActiveLabelValue; mitk::Label::PixelType m_CurrentActiveLabelValue; unsigned int m_PreviousLayerIndex; unsigned int m_CurrentLayerIndex; bool m_FirstRun; }; #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.cpp b/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.cpp index 00837b995c..68dfb6aa6b 100644 --- a/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.cpp @@ -1,55 +1,55 @@ /*============================================================================ 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.s ============================================================================*/ #include "QmitknnUNetGPU.h" #include QmitkGPULoader::QmitkGPULoader() { QProcess process; process.start("nvidia-smi --query-gpu=name,memory.total --format=csv"); process.waitForFinished(-1); QStringList infoStringList; while (process.canReadLine()) { QString line = process.readLine(); if (!line.startsWith("name")) { infoStringList << line; } } unsigned int count = 0; foreach (QString infoString, infoStringList) { QmitkGPUSpec spec; QStringList gpuDetails; gpuDetails = infoString.split(","); if(gpuDetails.count() == 2) { - spec.name = gpuDetails.at(0); + spec.name = gpuDetails.at(0).trimmed(); spec.id = count; - spec.memory = gpuDetails.at(1); + spec.memory = gpuDetails.at(1).trimmed(); this->m_Gpus.push_back(spec); ++count; } } } int QmitkGPULoader::GetGPUCount() const { return static_cast(m_Gpus.size()); } std::vector QmitkGPULoader::GetAllGPUSpecs() { return m_Gpus; } diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.cpp index 604206f78e..97327e8cab 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.cpp +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.cpp @@ -1,258 +1,258 @@ /*============================================================================ 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 "QmitkContourModelToImageWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include static const char* const HelpText = "Select a image and a contour(set)"; class QmitkContourModelToImageWidgetPrivate { public: QmitkContourModelToImageWidgetPrivate(); ~QmitkContourModelToImageWidgetPrivate(); /** @brief Check if selections is valid. */ void SelectionControl( unsigned int index, const mitk::DataNode* selection); - /** @brief Enable buttons if data selction is valid. */ + /** @brief Enable buttons if data selection is valid. */ void EnableButtons(bool enable = true); /** @brief Does the actual contour filling */ mitk::LabelSetImage::Pointer FillContourModelSetIntoImage(mitk::Image *image, mitk::ContourModelSet *contourSet, mitk::TimePointType timePoint); Ui::QmitkContourModelToImageWidgetControls m_Controls; QFutureWatcher m_Watcher; }; QmitkContourModelToImageWidgetPrivate::QmitkContourModelToImageWidgetPrivate() { } QmitkContourModelToImageWidgetPrivate::~QmitkContourModelToImageWidgetPrivate() { } void QmitkContourModelToImageWidgetPrivate::EnableButtons(bool enable) { m_Controls.btnProcess->setEnabled(enable); } void QmitkContourModelToImageWidgetPrivate::SelectionControl(unsigned int index, const mitk::DataNode* /*selection*/) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(index); dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } mitk::LabelSetImage::Pointer QmitkContourModelToImageWidgetPrivate::FillContourModelSetIntoImage(mitk::Image* image, mitk::ContourModelSet* contourSet, mitk::TimePointType timePoint) { // Use mitk::ContourModelSetToImageFilter to fill the ContourModelSet into the image mitk::ContourModelSetToImageFilter::Pointer contourFiller = mitk::ContourModelSetToImageFilter::New(); auto timeStep = image->GetTimeGeometry()->TimePointToTimeStep(timePoint); contourFiller->SetTimeStep(timeStep); contourFiller->SetImage(image); contourFiller->SetInput(contourSet); contourFiller->MakeOutputBinaryOn(); try { contourFiller->Update(); } catch (const std::exception & e) { MITK_ERROR << "Error while converting contour model. "<< e.what(); } catch (...) { MITK_ERROR << "Unknown error while converting contour model."; } if (nullptr == contourFiller->GetOutput()) { MITK_ERROR<<"Could not write the selected contours into the image!"; } auto result = mitk::LabelSetImage::New(); result->InitializeByLabeledImage(contourFiller->GetOutput()); return result; } void QmitkContourModelToImageWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode* selection) { Q_D(QmitkContourModelToImageWidget); QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); if (node0.IsNull() || node1.IsNull() ) { d->EnableButtons(false); dataSelectionWidget->SetHelpText(HelpText); } else { d->SelectionControl(index, selection); } } void QmitkContourModelToImageWidget::OnProcessingFinished() { // Called when processing finished // Adding the result to the data storage Q_D(QmitkContourModelToImageWidget); // Adding the result to the data storage auto result = d->m_Watcher.result(); if (result.IsNotNull()) { QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer contourNode = dataSelectionWidget->GetSelection(1); mitk::DataNode::Pointer filled = mitk::DataNode::New(); std::stringstream stream; stream << imageNode->GetName(); stream << "_"; stream << contourNode->GetName(); filled->SetName(stream.str()); filled->SetData(result); auto dataStorage = dataSelectionWidget->GetDataStorage(); if (dataStorage.IsNull()) { std::string exception = "Cannot add result to the data storage. Data storage invalid."; MITK_ERROR << "Error filling contours into an image: " << exception; QMessageBox::information(nullptr, "Error filling contours into an image", QString::fromStdString(exception)); } dataStorage->Add(filled, imageNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { MITK_ERROR<<"Error filling contours into an image!"; } d->EnableButtons(); } void QmitkContourModelToImageWidget::OnProcessPressed() { Q_D(QmitkContourModelToImageWidget); QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer contourNode = dataSelectionWidget->GetSelection(1); // Check if data nodes are valid if(imageNode.IsNull() || contourNode.IsNull() ) { MITK_ERROR << "Selection does not contain valid data"; QMessageBox::information( this, "Contour To Image", "Selection does not contain valid data, please select a binary image and a contour(set)", QMessageBox::Ok ); d->m_Controls.btnProcess->setEnabled(false); return; } mitk::Image::Pointer image = static_cast(imageNode->GetData()); // Check if the image is valid if (image.IsNull()) { MITK_ERROR<<"Error writing contours into image! Invalid image data selected!"; return; } const mitk::TimePointType timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); if (!image->GetTimeGeometry()->IsValidTimePoint(timePoint)) { MITK_ERROR << "Error writing contours into image! Currently selected time point is not supported by selected image data."; return; } // Check if the selected contours are valid mitk::ContourModelSet::Pointer contourSet; mitk::ContourModel::Pointer contour = dynamic_cast(contourNode->GetData()); if (contour.IsNotNull()) { contourSet = mitk::ContourModelSet::New(); contourSet->AddContourModel(contour); } else { contourSet = static_cast(contourNode->GetData()); if (contourSet.IsNull()) { MITK_ERROR<<"Error writing contours into binary image! Invalid contour data selected!"; return; } } //Disable Buttons during calculation and initialize Progressbar d->EnableButtons(false); // Start the computation in a background thread QFuture< mitk::LabelSetImage::Pointer > future = QtConcurrent::run(d, &QmitkContourModelToImageWidgetPrivate::FillContourModelSetIntoImage, image, contourSet, timePoint); d->m_Watcher.setFuture(future); } QmitkContourModelToImageWidget::QmitkContourModelToImageWidget(mitk::DataStorage* dataStorage, QWidget* parent) : QWidget(parent) , d_ptr(new QmitkContourModelToImageWidgetPrivate()) { Q_D(QmitkContourModelToImageWidget); // Set up UI d->m_Controls.setupUi(this); d->m_Controls.dataSelectionWidget->SetDataStorage(dataStorage); d->m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImageAndSegmentationPredicate); d->m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ContourModelPredicate); d->m_Controls.dataSelectionWidget->SetHelpText(HelpText); d->EnableButtons(false); // Create connections connect (d->m_Controls.btnProcess, SIGNAL(pressed()), this, SLOT(OnProcessPressed())); connect(d->m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); connect(&d->m_Watcher, SIGNAL(finished()), this, SLOT(OnProcessingFinished())); if( d->m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && d->m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) { OnSelectionChanged(0, d->m_Controls.dataSelectionWidget->GetSelection(0)); } } QmitkContourModelToImageWidget::~QmitkContourModelToImageWidget() { } diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.h index 797def3584..fb346b446d 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.h +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.h @@ -1,72 +1,72 @@ /*============================================================================ 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 QmitkContourModelToImageWidget_h #define QmitkContourModelToImageWidget_h #include #include #include class QmitkContourModelToImageWidgetPrivate; namespace mitk { class DataNode; class DataStorage; class Image; class ContourModelSet; class ContourModel; class Geometry3D; class PlaneGeometry; } /*! \brief QmitkContourModelToImageWidget Tool masks an image with a binary image or a surface. The Method requires an image and a binary image mask or a surface. The input image and the binary image mask must be of the same size. Masking with a surface creates first a binary image of the surface and then use this for the masking of the input image. */ class MITKSEGMENTATIONUI_EXPORT QmitkContourModelToImageWidget : public QWidget { Q_OBJECT public: /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ explicit QmitkContourModelToImageWidget(mitk::DataStorage* dataStorage, QWidget* parent = nullptr); - /** @brief Defaul destructor. */ + /** @brief Default destructor. */ ~QmitkContourModelToImageWidget() override; private slots: /** @brief This slot is called if the selection in the workbench is changed. */ void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); /** @brief This slot is called if user activates the button to mask an image. */ void OnProcessPressed(); /** @brief This slot is called after processing is finished */ void OnProcessingFinished(); private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(QmitkContourModelToImageWidget) Q_DISABLE_COPY(QmitkContourModelToImageWidget) }; #endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.h index 5769a75990..3f82fcd570 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.h +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.h @@ -1,85 +1,85 @@ /*============================================================================ 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 QmitkImageMaskingWidget_h #define QmitkImageMaskingWidget_h #include #include #include #include namespace Ui { class QmitkImageMaskingWidgetControls; } namespace mitk { class Image; } /*! \brief QmitkImageMaskingWidget Tool masks an image with a binary image or a surface. The Method requires an image and a binary image mask or a surface. The input image and the binary image mask must be of the same size. Masking with a surface creates first a binary image of the surface and then use this for the masking of the input image. */ class MITKSEGMENTATIONUI_EXPORT QmitkImageMaskingWidget : public QWidget { Q_OBJECT public: /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ explicit QmitkImageMaskingWidget(mitk::DataStorage* dataStorage, QWidget* parent = nullptr); - /** @brief Defaul destructor. */ + /** @brief Default destructor. */ ~QmitkImageMaskingWidget() override; private slots: /** @brief This slot is called if the selection in the workbench is changed. */ void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); /** @brief This slot is called if user activates the button to mask an image. */ void OnMaskImagePressed(); /** @brief This slot is called if the user toggles the "Custom" radio button. */ void OnCustomValueButtonToggled(bool checked); private: /** @brief Check if selections is valid. */ void SelectionControl( unsigned int index, const mitk::DataNode* selection); - /** @brief Enable buttons if data selction is valid. */ + /** @brief Enable buttons if data selection is valid. */ void EnableButtons(bool enable = true); /** @brief Mask an image with a given binary mask. Note that the input image and the mask image must be of the same size. */ itk::SmartPointer MaskImage(itk::SmartPointer referenceImage, itk::SmartPointer maskImage ); /** @brief Convert a surface into an binary image. */ itk::SmartPointer ConvertSurfaceToImage( itk::SmartPointer image, mitk::Surface::Pointer surface ); /** @brief Adds a new data object to the DataStorage.*/ void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, itk::SmartPointer segmentation, const std::string& name, mitk::DataNode::Pointer parent = nullptr); Ui::QmitkImageMaskingWidgetControls* m_Controls; }; #endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.h index b218cf76c9..030a8cb8a7 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.h +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.h @@ -1,75 +1,75 @@ /*============================================================================ 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 QmitkSurfaceToImageWidget_h #define QmitkSurfaceToImageWidget_h #include #include "itkSmartPointer.h" #include namespace Ui { class QmitkSurfaceToImageWidgetControls; } namespace mitk { class DataNode; class DataStorage; class Surface; class Image; class LabelSetImage; } /*! \brief QmitkSurfaceToImageWidget The Tool converts a surface to a binary image. The Method requires a surface and an image, which header information defines the output image. The resulting binary image has the same dimension, size, and Geometry3D as the input image. */ class MITKSEGMENTATIONUI_EXPORT QmitkSurfaceToImageWidget : public QWidget { Q_OBJECT public: /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ explicit QmitkSurfaceToImageWidget(mitk::DataStorage* dataStorage, QWidget* parent = nullptr); - /** @brief Defaul destructor. */ + /** @brief Default destructor. */ ~QmitkSurfaceToImageWidget() override; private slots: /** @brief This slot is called if the selection in the workbench is changed. */ void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); /** @brief This slot is called if user activates the button to convert a surface into a binary image. */ void OnSurface2ImagePressed(); private: - /** @brief Enable buttons if data selction is valid. */ + /** @brief Enable buttons if data selection is valid. */ void EnableButtons(bool enable = true); /** @brief Convert a surface into an binary image. */ itk::SmartPointer ConvertSurfaceToImage( itk::SmartPointer image, itk::SmartPointer surface ); Ui::QmitkSurfaceToImageWidgetControls* m_Controls; }; #endif diff --git a/Modules/SegmentationUI/files.cmake b/Modules/SegmentationUI/files.cmake index 4ed19de407..d2b5aeed4d 100644 --- a/Modules/SegmentationUI/files.cmake +++ b/Modules/SegmentationUI/files.cmake @@ -1,130 +1,133 @@ set(CPP_FILES Qmitk/QmitkSegWithPreviewToolGUIBase.cpp Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.cpp Qmitk/QmitkBinaryThresholdToolGUIBase.cpp Qmitk/QmitkBinaryThresholdToolGUI.cpp Qmitk/QmitkBinaryThresholdULToolGUI.cpp Qmitk/QmitkConfirmSegmentationDialog.cpp Qmitk/QmitkCopyToClipBoardDialog.cpp Qmitk/QmitkDrawPaintbrushToolGUI.cpp Qmitk/QmitkErasePaintbrushToolGUI.cpp Qmitk/QmitkEditableContourToolGUIBase.cpp Qmitk/QmitkGrowCutToolGUI.cpp Qmitk/QmitkLiveWireTool2DGUI.cpp Qmitk/QmitkLassoToolGUI.cpp Qmitk/QmitkOtsuTool3DGUI.cpp Qmitk/QmitkPaintbrushToolGUI.cpp Qmitk/QmitkPickingToolGUI.cpp Qmitk/QmitkSlicesInterpolator.cpp Qmitk/QmitkToolGUI.cpp Qmitk/QmitkToolGUIArea.cpp Qmitk/QmitkToolSelectionBox.cpp Qmitk/QmitknnUNetFolderParser.cpp Qmitk/QmitknnUNetToolGUI.cpp Qmitk/QmitknnUNetWorker.cpp Qmitk/QmitknnUNetGPU.cpp Qmitk/QmitkSurfaceStampWidget.cpp Qmitk/QmitkMaskStampWidget.cpp Qmitk/QmitkStaticDynamicSegmentationDialog.cpp Qmitk/QmitkSimpleLabelSetListWidget.cpp Qmitk/QmitkSegmentationTaskListWidget.cpp Qmitk/QmitkTotalSegmentatorToolGUI.cpp Qmitk/QmitkSetupVirtualEnvUtil.cpp Qmitk/QmitkMultiLabelInspector.cpp Qmitk/QmitkMultiLabelManager.cpp Qmitk/QmitkMultiLabelTreeModel.cpp Qmitk/QmitkMultiLabelTreeView.cpp Qmitk/QmitkMultiLabelPresetHelper.cpp Qmitk/QmitkLabelColorItemDelegate.cpp Qmitk/QmitkLabelToggleItemDelegate.cpp Qmitk/QmitkFindSegmentationTaskDialog.cpp + Qmitk/QmitkSegmentAnythingToolGUI.cpp Qmitk/QmitkMonaiLabelToolGUI.cpp Qmitk/QmitkMonaiLabel2DToolGUI.cpp Qmitk/QmitkMonaiLabel3DToolGUI.cpp SegmentationUtilities/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/QmitkContourModelToImageWidget.cpp SegmentationUtilities/QmitkImageMaskingWidget.cpp SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/QmitkSurfaceToImageWidget.cpp SegmentationUtilities/QmitkDataSelectionWidget.cpp ) set(H_FILES Qmitk/QmitkMultiLabelPresetHelper.h ) set(MOC_H_FILES Qmitk/QmitkSegWithPreviewToolGUIBase.h Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.h Qmitk/QmitkBinaryThresholdToolGUIBase.h Qmitk/QmitkBinaryThresholdToolGUI.h Qmitk/QmitkBinaryThresholdULToolGUI.h Qmitk/QmitkConfirmSegmentationDialog.h Qmitk/QmitkCopyToClipBoardDialog.h Qmitk/QmitkDrawPaintbrushToolGUI.h Qmitk/QmitkErasePaintbrushToolGUI.h Qmitk/QmitkEditableContourToolGUIBase.h Qmitk/QmitkGrowCutToolGUI.h Qmitk/QmitkLiveWireTool2DGUI.h Qmitk/QmitkLassoToolGUI.h Qmitk/QmitkOtsuTool3DGUI.h Qmitk/QmitkPaintbrushToolGUI.h Qmitk/QmitkPickingToolGUI.h Qmitk/QmitkSlicesInterpolator.h Qmitk/QmitkToolGUI.h Qmitk/QmitkToolGUIArea.h Qmitk/QmitkToolSelectionBox.h Qmitk/QmitknnUNetFolderParser.h Qmitk/QmitknnUNetToolGUI.h Qmitk/QmitknnUNetGPU.h Qmitk/QmitknnUNetWorker.h Qmitk/QmitknnUNetEnsembleLayout.h Qmitk/QmitkSurfaceStampWidget.h Qmitk/QmitkMaskStampWidget.h Qmitk/QmitkStaticDynamicSegmentationDialog.h Qmitk/QmitkSimpleLabelSetListWidget.h Qmitk/QmitkSegmentationTaskListWidget.h Qmitk/QmitkTotalSegmentatorToolGUI.h Qmitk/QmitkSetupVirtualEnvUtil.h Qmitk/QmitkMultiLabelInspector.h Qmitk/QmitkMultiLabelManager.h Qmitk/QmitkMultiLabelTreeModel.h Qmitk/QmitkMultiLabelTreeView.h Qmitk/QmitkLabelColorItemDelegate.h Qmitk/QmitkLabelToggleItemDelegate.h Qmitk/QmitkFindSegmentationTaskDialog.h + Qmitk/QmitkSegmentAnythingToolGUI.h Qmitk/QmitkMonaiLabelToolGUI.h Qmitk/QmitkMonaiLabel2DToolGUI.h Qmitk/QmitkMonaiLabel3DToolGUI.h SegmentationUtilities/QmitkBooleanOperationsWidget.h SegmentationUtilities/QmitkContourModelToImageWidget.h SegmentationUtilities/QmitkImageMaskingWidget.h SegmentationUtilities/QmitkMorphologicalOperationsWidget.h SegmentationUtilities/QmitkSurfaceToImageWidget.h SegmentationUtilities/QmitkDataSelectionWidget.h ) set(UI_FILES Qmitk/QmitkConfirmSegmentationDialog.ui Qmitk/QmitkGrowCutToolWidgetControls.ui Qmitk/QmitkOtsuToolWidgetControls.ui Qmitk/QmitkSurfaceStampWidgetGUIControls.ui Qmitk/QmitkMaskStampWidgetGUIControls.ui Qmitk/QmitknnUNetToolGUIControls.ui Qmitk/QmitkEditableContourToolGUIControls.ui Qmitk/QmitkSegmentationTaskListWidget.ui Qmitk/QmitkTotalSegmentatorGUIControls.ui Qmitk/QmitkMultiLabelInspectorControls.ui Qmitk/QmitkMultiLabelManagerControls.ui Qmitk/QmitkFindSegmentationTaskDialog.ui + Qmitk/QmitkSegmentAnythingGUIControls.ui Qmitk/QmitkMonaiLabelToolGUIControls.ui SegmentationUtilities/QmitkBooleanOperationsWidgetControls.ui SegmentationUtilities/QmitkContourModelToImageWidgetControls.ui SegmentationUtilities/QmitkImageMaskingWidgetControls.ui SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui SegmentationUtilities/QmitkSurfaceToImageWidgetControls.ui SegmentationUtilities/QmitkDataSelectionWidgetControls.ui ) set(QRC_FILES resources/SegmentationUI.qrc ) diff --git a/Plugins/org.blueberry.core.commands/src/berryCommandEvent.h b/Plugins/org.blueberry.core.commands/src/berryCommandEvent.h index 2fc3296faa..86348fa8ce 100755 --- a/Plugins/org.blueberry.core.commands/src/berryCommandEvent.h +++ b/Plugins/org.blueberry.core.commands/src/berryCommandEvent.h @@ -1,178 +1,178 @@ /*============================================================================ 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 BERRYCOMMANDEVENT_H_ #define BERRYCOMMANDEVENT_H_ #include "common/berryAbstractNamedHandleEvent.h" #include namespace berry { class Command; /** * An instance of this class describes changes to an instance of * Command. *

* This class is not intended to be extended by clients. *

* * @see ICommandListener#CommandChanged(CommandEvent::Pointer) */ class BERRY_COMMANDS CommandEvent : public AbstractNamedHandleEvent { public: berryObjectMacro(CommandEvent); /** * Creates a new instance of this class. * * @param command * the instance of the interface that changed. * @param categoryChanged * true, iff the category property changed. * @param definedChanged * true, iff the defined property changed. * @param descriptionChanged * true, iff the description property changed. * @param handledChanged * true, iff the handled property changed. * @param nameChanged * true, iff the name property changed. * @param parametersChanged * true if the parameters have changed; * false otherwise. * @param returnTypeChanged * true iff the return type property changed; * false otherwise. * @param helpContextIdChanged * true iff the help context identifier changed; * false otherwise. * @param enabledChanged - * true iff the comand enablement changed; + * true iff the command enablement changed; * false otherwise. * @since 3.3 */ CommandEvent(const SmartPointer command, bool categoryChanged, bool definedChanged, bool descriptionChanged, bool handledChanged, bool nameChanged, bool parametersChanged, bool returnTypeChanged = false, bool helpContextIdChanged = false, bool enabledChanged = false); /** * Returns the instance of the interface that changed. * * @return the instance of the interface that changed. Guaranteed not to be * null. */ SmartPointer GetCommand() const; /** * Returns whether or not the category property changed. * * @return true, iff the category property changed. */ bool IsCategoryChanged() const; /** * Returns whether or not the handled property changed. * * @return true, iff the handled property changed. */ bool IsHandledChanged() const; /** * Returns whether or not the help context identifier changed. * * @return true, iff the help context identifier changed. * @since 3.2 */ bool IsHelpContextIdChanged() const; /** * Returns whether or not the parameters have changed. * * @return true, iff the parameters property changed. */ bool IsParametersChanged() const; /** * Returns whether or not the return type property changed. * * @return true, iff the return type property changed. * @since 3.2 */ bool IsReturnTypeChanged() const; /** * Return whether the enable property changed. * - * @return true iff the comand enablement changed + * @return true iff the command enablement changed * @since 3.3 */ bool IsEnabledChanged() const; private: /** * The bit used to represent whether the command has changed its category. */ static int CHANGED_CATEGORY(); // = LAST_USED_BIT << 1; /** * The bit used to represent whether the command has changed its handler. */ static int CHANGED_HANDLED(); // = LAST_USED_BIT << 2; /** * The bit used to represent whether the command has changed its parameters. */ static int CHANGED_PARAMETERS(); // = LAST_USED_BIT << 3; /** * The bit used to represent whether the command has changed its return * type. * * @since 3.2 */ static int CHANGED_RETURN_TYPE(); // = LAST_USED_BIT << 4; /** * The bit used to represent whether the command has changed its help * context identifier. * * @since 3.2 */ static int CHANGED_HELP_CONTEXT_ID(); // = LAST_USED_BIT << 5; /** * The bit used to represent whether this commands active handler has * changed its enablement state. * * @since 3.3 */ static int CHANGED_ENABLED(); // = LAST_USED_BIT << 6; /** * The command that has changed; this value is never null. */ const SmartPointer command; }; } #endif /* BERRYCOMMANDEVENT_H_ */ diff --git a/Plugins/org.blueberry.core.commands/src/berryIParameterValueConverter.h b/Plugins/org.blueberry.core.commands/src/berryIParameterValueConverter.h index 487a0f66ee..f1139aeef0 100755 --- a/Plugins/org.blueberry.core.commands/src/berryIParameterValueConverter.h +++ b/Plugins/org.blueberry.core.commands/src/berryIParameterValueConverter.h @@ -1,89 +1,89 @@ /*============================================================================ 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 BERRYABSTRACTPARAMETERVALUECONVERTER_H_ #define BERRYABSTRACTPARAMETERVALUECONVERTER_H_ #include #include #include namespace berry { /** *

* Supports conversion between objects and strings for command parameter values. * Extenders must produce strings that identify objects (of a specific command * parameter type) as well as consume the strings to locate and return the * objects they identify. *

*

* This class offers multiple handlers of a command a consistent way of * converting string parameter values into the objects that the handlers would * prefer to deal with. This class also gives clients a way to serialize * object parameters as strings so that entire parameterized commands can be * serialized, stored and later deserialized and executed. *

*

* This class will typically be extended so the subclass can be referenced from * the converter attribute of the - * commandParameterType elemement of the + * commandParameterType element of the * org.blueberry.ui.commands extension-point. Objects implementing * this interface may also be passed directly to * {@link ParameterType#Define} by clients. *

* * @see ParameterType#Define(IParameterValueConverter::Pointer) * @see ParameterizedCommand#Serialize() */ struct BERRY_COMMANDS IParameterValueConverter { virtual ~IParameterValueConverter(); /** * Converts a string encoded command parameter value into the parameter * value object. * * @param parameterValue * a command parameter value string describing an object; may be * null * @return the object described by the command parameter value string; may * be null * @throws ParameterValueConversionException * if an object cannot be produced from the * parameterValue string */ virtual Object::Pointer ConvertToObject(const QString& parameterValue) = 0; /** * Converts a command parameter value object into a string that encodes a * reference to the object or serialization of the object. * * @param parameterValue * an object to convert into an identifying string; may be * null * @return a string describing the provided object; may be null * @throws ParameterValueConversionException * if a string reference or serialization cannot be provided for * the parameterValue */ virtual QString ConvertToString(const Object::Pointer& parameterValue) = 0; }; } Q_DECLARE_INTERFACE(berry::IParameterValueConverter, "org.blueberry.core.commands.IParameterValueConverter") #endif /* BERRYABSTRACTPARAMETERVALUECONVERTER_H_ */ diff --git a/Plugins/org.blueberry.core.commands/src/common/berryCommandExceptions.h b/Plugins/org.blueberry.core.commands/src/common/berryCommandExceptions.h index a0bbaf6124..e0523ac0b5 100644 --- a/Plugins/org.blueberry.core.commands/src/common/berryCommandExceptions.h +++ b/Plugins/org.blueberry.core.commands/src/common/berryCommandExceptions.h @@ -1,53 +1,53 @@ /*============================================================================ 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 BERRYCOMMANDEXCEPTIONS_H_ #define BERRYCOMMANDEXCEPTIONS_H_ #include #include namespace berry { CTK_DECLARE_EXCEPTION(BERRY_COMMANDS, CommandException, ctkRuntimeException) CTK_DECLARE_EXCEPTION(BERRY_COMMANDS, ExecutionException, CommandException) CTK_DECLARE_EXCEPTION(BERRY_COMMANDS, NotHandledException, CommandException) CTK_DECLARE_EXCEPTION(BERRY_COMMANDS, NotDefinedException, CommandException) CTK_DECLARE_EXCEPTION(BERRY_COMMANDS, NotEnabledException, CommandException) CTK_DECLARE_EXCEPTION(BERRY_COMMANDS, ParameterValueConversionException, CommandException) /** * Signals that a problem has occurred while trying to create an instance of * IParameterValues. In applications based on the registry * provided by core, this usually indicates a problem creating an * IExecutableExtension. For other applications, this exception * could be used to signify any general problem during initialization. * */ CTK_DECLARE_EXCEPTION(BERRY_COMMANDS, ParameterValuesException, CommandException) /** - * Signals that an exception occured while serializing a + * Signals that an exception occurred while serializing a * {@link ParameterizedCommand} to a string or deserializing a string to a * {@link ParameterizedCommand}. * * This class is not intended to be extended by clients. * */ CTK_DECLARE_EXCEPTION(BERRY_COMMANDS, SerializationException, CommandException) } #endif /*BERRYCOMMANDEXCEPTIONS_H_*/ diff --git a/Plugins/org.blueberry.core.expressions/plugin.xml b/Plugins/org.blueberry.core.expressions/plugin.xml index 3509a3e70b..ed9cf70941 100644 --- a/Plugins/org.blueberry.core.expressions/plugin.xml +++ b/Plugins/org.blueberry.core.expressions/plugin.xml @@ -1,18 +1,18 @@ - + diff --git a/Plugins/org.blueberry.core.expressions/src/berryPropertyTester.h b/Plugins/org.blueberry.core.expressions/src/berryPropertyTester.h index ca5b531d59..aef7eeadf8 100644 --- a/Plugins/org.blueberry.core.expressions/src/berryPropertyTester.h +++ b/Plugins/org.blueberry.core.expressions/src/berryPropertyTester.h @@ -1,121 +1,121 @@ /*============================================================================ 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 BERRYPROPERTYTESTER_H_ #define BERRYPROPERTYTESTER_H_ #include #include "internal/berryPropertyTesterDescriptor.h" #include namespace berry { /** * Abstract superclass of all property testers. Implementation classes of - * the extension point org.blueberry.core.expresssions.propertyTesters + * the extension point org.blueberry.core.expressions.propertyTesters * must extend PropertyTester. *

* A property tester implements the property tests enumerated in the property * tester extension point. For the following property test extension * \code{.unparsed} * * * \endcode * the corresponding implementation class looks like: * \code * public class MyPackageFragmentTester { * public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { * IPackageFragment fragement= (IPackageFragment)receiver; * if ("isDefaultPackage".equals(property)) { * return expectedValue == null * ? fragement.isDefaultPackage() * : fragement.isDefaultPackage() == ((Boolean)expectedValue).booleanValue(); * } * Assert.isTrue(false); * return false; * } * } * \endcode * The property can then be used in a test expression as follows: *

  *   <instanceof value="org.blueberry.core.IPackageFragment"/>
  *   <test property="org.blueberry.jdt.core.isDefaultPackage"/>
  * 
*

*

* There is no guarantee that the same instance of a property tester is used * to handle <test property="..."/> requests. So property testers * should always be implemented in a stateless fashion. *

*/ class BERRY_EXPRESSIONS PropertyTester : public QObject, public IPropertyTester { Q_OBJECT Q_INTERFACES(berry::IPropertyTester) private: IConfigurationElement::Pointer fConfigElement; QString fNamespace; QString fProperties; public: /** * Initialize the property tester with the given name space and property. *

* Note: this method is for internal use only. Clients must not call * this method. *

* @param descriptor the descriptor object for this tester */ void InternalInitialize(PropertyTesterDescriptor::Pointer descriptor); /** * Note: this method is for internal use only. Clients must not call * this method. * * @return the property tester descriptor */ PropertyTesterDescriptor::Pointer InternalCreateDescriptor(); /** * {@inheritDoc} */ bool Handles(const QString& namespaze, const QString& property) override; /** * {@inheritDoc} */ bool IsInstantiated() override; /** * {@inheritDoc} */ bool IsDeclaringPluginActive() override; /** * {@inheritDoc} */ IPropertyTester* Instantiate() override; }; } // namespace berry #endif /*BERRYPROPERTYTESTER_H_*/ diff --git a/Plugins/org.blueberry.core.expressions/src/internal/berryTypeExtensionManager.h b/Plugins/org.blueberry.core.expressions/src/internal/berryTypeExtensionManager.h index aeace05b79..580fdc1752 100644 --- a/Plugins/org.blueberry.core.expressions/src/internal/berryTypeExtensionManager.h +++ b/Plugins/org.blueberry.core.expressions/src/internal/berryTypeExtensionManager.h @@ -1,123 +1,123 @@ /*============================================================================ 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 BERRYTYPEEXTENSIONMANAGER_H_ #define BERRYTYPEEXTENSIONMANAGER_H_ #include "berryIPropertyTester.h" #include "berryTypeExtension.h" #include "berryPropertyCache.h" #include "berryProperty.h" #include #include #include #include namespace berry { class TypeExtensionManager : private IRegistryEventListener { private: QString fExtensionPoint; static const QString TYPE; class nullptr_PROPERTY_TESTER_ : public IPropertyTester { public: bool Handles(const QString& /*namespaze*/, const QString& /*property*/) override { return false; } bool IsInstantiated() override { return true; } bool IsDeclaringPluginActive() override { return true; } IPropertyTester* Instantiate() override { return this; } bool Test(Object::ConstPointer, const QString& /*property*/, const QList& /*args*/, Object::Pointer /*expectedValue*/) override { return false; } }; static const nullptr_PROPERTY_TESTER_ nullptr_PROPERTY_TESTER; /* * Map containing all already created type extension object. */ QHash fTypeExtensionMap; /* * Table containing mapping of class name to configuration element */ QHash > fConfigurationElementMap; /* * A cache to give fast access to the last 1000 method invocations. */ PropertyCache* fPropertyCache; public: static bool DEBUG; TypeExtensionManager(const QString& extensionPoint); ~TypeExtensionManager() override; Property::Pointer GetProperty(Object::ConstPointer receiver, const QString& namespaze, const QString& method); /*synchronized*/Property::Pointer GetProperty(Object::ConstPointer receiver, const QString& namespaze, const QString& method, bool forcePluginActivation); protected: friend class TypeExtension; /* * This method doesn't need to be synchronized since it is called - * from withing the getProperty method which is synchronized + * from within the getProperty method which is synchronized */ TypeExtension::Pointer Get(const Reflection::TypeInfo& typeInfo); /* * This method doesn't need to be synchronized since it is called - * from withing the getProperty method which is synchronized + * from within the getProperty method which is synchronized */ QList LoadTesters(const QString& typeName); private: /*synchronized*/void InitializeCaches(); void Added(const QList >& extensions) override; void Removed(const QList >& extensions) override; void Added(const QList >& extensionPoints) override; void Removed(const QList >& extensionPoints) override; }; } #endif /*BERRYTYPEEXTENSIONMANAGER_H_*/ diff --git a/Plugins/org.blueberry.core.jobs/src/berryIJobChangeListener.h b/Plugins/org.blueberry.core.jobs/src/berryIJobChangeListener.h index 1d8e41422f..bd400e9ba1 100644 --- a/Plugins/org.blueberry.core.jobs/src/berryIJobChangeListener.h +++ b/Plugins/org.blueberry.core.jobs/src/berryIJobChangeListener.h @@ -1,140 +1,140 @@ /*============================================================================ 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 BERRYIJOBCHANGELISTENER_H_ #define BERRYIJOBCHANGELISTENER_H_ #include "berryIJobChangeEvent.h" namespace berry { /** * Callback interface for clients interested in being notified when jobs change state. *

* A single job listener instance can be added either to the job manager, for notification * of all scheduled jobs, or to any set of individual jobs. A single listener instance should * not be added to both the job manager, and to individual jobs (such a listener may * receive duplicate notifications). *

* Clients should not rely on the result of the Job#GetState() * method on jobs for which notification is occurring. Listeners are notified of * all job state changes, but whether the state change occurs before, during, or * after listeners are notified is unspecified. *

* Clients may implement this interface. *

* @see IJobManager#AddJobChangeListener(IJobChangeListener::Pointer) * @see IJobManager#RemoveJobChangeListener(IJobChangeListener::Pointer) * @see Job#AddJobChangeListener(IJobChangeListener::Pointer) * @see Job#GetState() * @see Job#RemoveJobChangeListener(IJobChangeListener::Pointer) */ struct BERRY_JOBS IJobChangeListener { struct BERRY_JOBS Events { typedef Message1 JobChangeEventType; enum Type { NONE = 0x00000000, ABOUT_TO_RUN = 0x00000001, AWAKE = 0x00000002, DONE = 0x00000004, RUNNING = 0x00000008, SCHEDULED = 0x00000010, SLEEPING = 0x00000020, ALL = 0xffffffff }; Q_DECLARE_FLAGS(Types, Type) JobChangeEventType jobAboutToRun; JobChangeEventType jobAwake; JobChangeEventType jobDone; JobChangeEventType jobRunning; JobChangeEventType jobScheduled; JobChangeEventType jobSleeping; void AddListener(IJobChangeListener* listener); void RemoveListener(IJobChangeListener* listener); void SetExceptionHandler(const AbstractExceptionHandler& handler); typedef MessageDelegate1 Delegate; }; virtual Events::Types GetEventTypes() = 0; /** * Notification that a job is about to be run. Listeners are allowed to sleep, cancel, * or change the priority of the job before it is started (and as a result may prevent * the run from actually occurring). */ virtual void AboutToRun(const IJobChangeEvent::ConstPointer& /*event*/) { } /** * Notification that a job was previously sleeping and has now been rescheduled * to run. */ virtual void Awake(const IJobChangeEvent::ConstPointer& /*event*/) { } /** - * Notification that a job has completed execution, either due to cancelation, successful + * Notification that a job has completed execution, either due to cancellation, successful * completion, or failure. The event status object indicates how the job finished, * and the reason for failure, if applicable. */ virtual void Done(const IJobChangeEvent::ConstPointer& /*event*/) { } /** * Notification that a job has started running. */ virtual void Running(const IJobChangeEvent::ConstPointer& /*event*/) { } /** * Notification that a job is being added to the queue of scheduled jobs. * The event details includes the scheduling delay before the job should start * running. */ virtual void Scheduled(const IJobChangeEvent::ConstPointer& /*event*/) { } /** * Notification that a job was waiting to run and has now been put in the * sleeping state. */ virtual void Sleeping(const IJobChangeEvent::ConstPointer& /*event*/) { } }; } Q_DECLARE_OPERATORS_FOR_FLAGS(berry::IJobChangeListener::Events::Types) #endif /* BERRYIJOBCHANGELISTENER_H_ */ diff --git a/Plugins/org.blueberry.core.jobs/src/internal/berryJobManager.cpp b/Plugins/org.blueberry.core.jobs/src/internal/berryJobManager.cpp index 7bb26f7cfc..43fda5b558 100644 --- a/Plugins/org.blueberry.core.jobs/src/internal/berryJobManager.cpp +++ b/Plugins/org.blueberry.core.jobs/src/internal/berryJobManager.cpp @@ -1,1202 +1,1202 @@ /*============================================================================ 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. ============================================================================*/ #define NOMINMAX #include "berryJobManager.h" #include "berryIProgressMonitor.h" #include "berryNullProgressMonitor.h" #include "berryIStatus.h" #include "berryJobStatus.h" #include #include namespace berry { /** * test class implementing ISchedulingRule to validate client defined rules */ struct NullRule: public ISchedulingRule { bool Contains(ISchedulingRule::Pointer myRule) const override; bool IsConflicting(ISchedulingRule::Pointer myRule) const override; }; bool NullRule::IsConflicting(ISchedulingRule::Pointer dummyRule) const { return dummyRule == this; } bool NullRule::Contains(ISchedulingRule::Pointer dummyRule) const { return dummyRule == this; } JobManager::JobManager() : sptr_testRule(new NullRule()),m_active(true), m_Pool(new WorkerPool(this)), m_sptr_progressProvider(nullptr), m_JobQueueSleeping(true), m_JobQueueWaiting(false),m_suspended(false), m_waitQueueCounter(0) { m_JobListeners.global.SetExceptionHandler(MessageExceptionHandler< JobListeners> (&m_JobListeners, &JobListeners::HandleException)); } // DEBUG VARIABLES const QString& JobManager::PI_JOBS() { static const QString id("org.blueberry.core.jobs"); return id; } bool JobManager::DEBUG = false; bool JobManager::DEBUG_BEGIN_END = false; bool JobManager::DEBUG_DEADLOCK = false; bool JobManager::DEBUG_LOCKS = false; bool JobManager::DEBUG_TIMING = false; bool JobManager::DEBUG_SHUTDOWN = false; const int JobManager::PLUGIN_ERROR = 2; JobManager* JobManager::GetInstance() { // we don't need to lock the creation of "instance" because GetInstance() is // called when statically initializing InternalJob::ptr_manager (which happens // in single-threaded mode) static JobManager instance; return &instance; } std::string JobManager::PrintState(int state) { switch (state) { case Job::NONE: return "NONE"; case Job::WAITING: return "WAITING"; case Job::SLEEPING: return "SLEEPING"; case Job::RUNNING: return "RUNNING"; case InternalJob::BLOCKED: return "BLOCKED"; case InternalJob::ABOUT_TO_RUN: return "ABOUT_TO_RUN"; case InternalJob::ABOUT_TO_SCHEDULE: return "ABOUT_TO_SCHEDULE"; } return "UNKNOWN"; } void JobManager::Shutdown() { JobManager* ptr_instance(GetInstance()); if (ptr_instance != nullptr) { ptr_instance->DoShutdown(); // ptr_instance = 0; // need to call the destructor of the static object .. } } //void //JobManager //::Cancel(Object family) { // //don't synchronize because cancel calls listeners // for (Iterator it = select(family).iterator(); it.hasNext();) // cancel((Job) it.next()); // } IProgressMonitor::Pointer JobManager::CreateProgressGroup() { if (m_sptr_progressProvider != 0) return (m_sptr_progressProvider->CreateProgressGroup()); NullProgressMonitor::Pointer sptr_defaultProgressMonitor( new NullProgressMonitor); return sptr_defaultProgressMonitor; } Job* JobManager::CurrentJob() { //Poco::Thread* ptr_current = Poco::Thread::current(); //if (Worker* worker = dynamic_cast(ptr_current) ) // return ((Worker) ptr_current).currentJob(); // { // Poco::ScopedLock lockMe (m_mutex); // Poco::HashSet::Iterator it ; // for (it = m_running.begin(); it != m_running.end(); it ++) { // Job job* = dynamic_cast (it); // if (job->GetThread() == ptr_current) // return job; // } //} return nullptr; } //void //JobManager //::EndRule(ISchedulingRule rule) { //implicitJobs.end(rule, false); // } //Job[] //JobManager //::Find(Object family) { // List members = select(family); // return (Job[]) members.toArray(new Job[members.size()]); // } // // LockManager GetLockManager() { // return lockManager; // } // bool JobManager::IsIdle() { { Poco::ScopedLock m_managerLock(m_mutex); return m_running.empty() && m_JobQueueWaiting.IsEmpty(); } } bool JobManager::IsSuspended() { { Poco::ScopedLock m_managerLock(m_mutex); m_suspended = true; } return m_suspended; } // // /* // * @see IJobManager#join(String, IProgressMonitor) // */ //void //JobManager //::Join(final Object family, IProgressMonitor monitor) throws InterruptedException, OperationCanceledException { // monitor = monitorFor(monitor); // IJobChangeListener listener = null; // final Set jobs; // int jobCount; // Job blocking = null; // synchronized (lock) { // //don't join a waiting or sleeping job when suspended (deadlock risk) // int states = suspended ? Job.RUNNING : Job.RUNNING | Job.WAITING | Job.SLEEPING; // jobs = Collections.synchronizedSet(new HashSet(select(family, states))); // jobCount = jobs.size(); // if (jobCount > 0) { // //if there is only one blocking job, use it in the blockage callback below // if (jobCount == 1) // blocking = (Job) jobs.iterator().next(); // listener = new JobChangeAdapter() { // public void done(IJobChangeEvent event) { // //don't remove from list if job is being rescheduled // if (!((JobChangeEvent) event).reschedule) // jobs.remove(event.getJob()); // } // // //update the list of jobs if new ones are added during the join // public void scheduled(IJobChangeEvent event) { // //don't add to list if job is being rescheduled // if (((JobChangeEvent) event).reschedule) // return; // Job job = event.getJob(); // if (job.belongsTo(family)) // jobs.add(job); // } // }; // addJobChangeListener(listener); // } // } // if (jobCount == 0) { // //use up the monitor outside synchronized block because monitors call untrusted code // monitor.beginTask(JobMessages.jobs_blocked0, 1); // monitor.done(); // return; // } // //spin until all jobs are completed // try { // monitor.beginTask(JobMessages.jobs_blocked0, jobCount); // monitor.subTask(NLS.bind(JobMessages.jobs_waitFamSub, Integer.toString(jobCount))); // reportBlocked(monitor, blocking); // int jobsLeft; // int reportedWorkDone = 0; // while ((jobsLeft = jobs.size()) > 0) { // //don't let there be negative work done if new jobs have // //been added since the join began // int actualWorkDone = Math.max(0, jobCount - jobsLeft); // if (reportedWorkDone < actualWorkDone) { // monitor.worked(actualWorkDone - reportedWorkDone); // reportedWorkDone = actualWorkDone; // monitor.subTask(NLS.bind(JobMessages.jobs_waitFamSub, Integer.toString(jobsLeft))); // } // if (Thread.interrupted()) // throw new InterruptedException(); // if (monitor.isCanceled()) // throw new OperationCanceledException(); // //notify hook to service pending syncExecs before falling asleep // lockManager.aboutToWait(null); // Thread.sleep(100); // } // } finally { // lockManager.aboutToRelease(); // removeJobChangeListener(listener); // reportUnblocked(monitor); // monitor.done(); // } // } //JobManager //::NewLock() { // return lockManager.newLock(); // } void JobManager::RemoveJobChangeListener(IJobChangeListener* listener) { m_JobListeners.Remove(listener); } void JobManager::ReportBlocked(IProgressMonitor::Pointer sptr_monitor, InternalJob::Pointer sptr_blockingJob) const { if ( sptr_monitor.Cast() == 0 ) return ; if (sptr_blockingJob == 0 || sptr_blockingJob->IsSystem()) { Status::Pointer sptr_reason( new Status(IStatus::INFO_TYPE, JobManager::PI_JOBS(), 1, "the user operation is waiting for background work to complete", BERRY_STATUS_LOC)); } else { QString msg = "the user operation is waiting for : " + sptr_blockingJob->GetName() + " to complete. "; JobStatus::Pointer sptr_reason( new JobStatus(IStatus::INFO_TYPE, sptr_blockingJob.Cast(), msg, BERRY_STATUS_LOC)); } // ((IProgressmonitorWithBlocking) sptr_monitor)->SetBlocked(sptr_reason); } void JobManager::ReportUnblocked(IProgressMonitor::Pointer sptr_monitor) const { if ( IProgressMonitorWithBlocking::Pointer sptr_monitorWithBlocking = sptr_monitor.Cast() ) sptr_monitorWithBlocking->ClearBlocked(); } void JobManager::Resume() { { Poco::ScopedLock lockMe(m_mutex); m_suspended = false; //poke the job pool m_Pool->JobQueued(); } } //TODO implicit Jobs //void //JobManager //::Resume(ISchedulingRule rule)const { // implicitJobs.resume(rule); // } void JobManager::SetProgressProvider(ProgressProvider::Pointer provider) { m_sptr_progressProvider = provider; } void JobManager::SetRule(InternalJob::Pointer job, ISchedulingRule::Pointer sptr_rule) { Poco::ScopedLock m_managerLock(m_mutex); //cannot change the rule of a job that is already running ( GetRule is set to protected which should be // changed if this assert is needed // assert(job->GetState() == Job.NONE); ValidateRule(sptr_rule); job->InternalSetRule(sptr_rule); } //void //JobManager //::Sleep(Object family) { // //don't synchronize because sleep calls listeners // for (Iterator it = select(family).iterator(); it.hasNext();) { // sleep((InternalJob) it.next()); // } // } void JobManager::Suspend() { { Poco::ScopedLock lockMe(m_mutex); m_suspended = true; } } //void //JobManager //::Suspend(ISchedulingRule rule, IProgressMonitor monitor)const { // Assert.isNotNull(rule); // implicitJobs.suspend(rule, monitorFor(monitor)); // } //void //JobManager //::TransferRule(ISchedulingRule rule, Thread destinationThread) { // implicitJobs.transfer(rule, destinationThread); // } //void //JobManager //::SetLockListener(LockListener listener) { // lockManager.setLockListener(listener); // } //void //JobManager //::WakeUp(Object family) { // //don't synchronize because wakeUp calls listeners // for (Iterator it = select(family).iterator(); it.hasNext();) { // wakeUp((InternalJob) it.next(), 0L); // } // } void JobManager::AddJobChangeListener(IJobChangeListener* listener) { m_JobListeners.Add(listener); } //void //JobManager //::BeginRule(ISchedulingRule rule, IProgressMonitor monitor) { // validateRule(rule); // implicitJobs.begin(rule, monitorFor(monitor), false); // } // // /** // * For debugging purposes only // */ //std::String //JobManager //::PrintJobName(Job job) { // if (job instanceof ThreadJob) { // Job realJob = ((ThreadJob) job).realJob; // if (realJob != null) // return realJob.getClass().getName(); // return "ThreadJob on rule: " + job.getRule(); //$NON-NLS-1$ // } // return job.getClass().getName(); // } // // instance = this; // initDebugOptions(); // synchronized (lock) { // running = new HashSet(10); // } // pool.setDaemon(JobOSGiUtils.getDefault().useDaemonThreads()); //} void JobManager::ChangeState(InternalJob::Pointer sptr_job, int newState) { bool blockedJobs = false; { Poco::ScopedLock m_managerLock(m_mutex); int tmp_oldState = sptr_job->InternalGetState(); switch (tmp_oldState) { case Job::NONE: case InternalJob::ABOUT_TO_SCHEDULE: break; case InternalJob::BLOCKED: //remove this job from the linked list of blocked jobs sptr_job->Remove(); break; case Job::WAITING: m_JobQueueWaiting.Remove(sptr_job); // assert(false, "Tried to remove a job that wasn't in the queue"); break; case Job::SLEEPING: m_JobQueueSleeping.Remove(sptr_job); // assert(false, "Tried to remove a job that wasn't in the queue"); // this silences the warning but should be checked: // FALLTHRU case Job::RUNNING: case InternalJob::ABOUT_TO_RUN: m_running.remove(sptr_job); //add any blocked jobs back to the wait queue InternalJob::Pointer sptr_blocked(sptr_job->Previous()); sptr_job->Remove(); blockedJobs = sptr_blocked != 0; while (sptr_blocked != 0) { InternalJob::Pointer previous = sptr_blocked->Previous(); ChangeState(sptr_blocked, Job::WAITING); sptr_blocked = previous; } break; // default : // Assert.isLegal(false, "Invalid job state: " + job + ", state: " + oldState); } sptr_job->InternalSetState(newState); switch (newState) { case Job::NONE: sptr_job->SetStartTime(InternalJob::T_NONE); sptr_job->SetWaitQueueStamp(InternalJob::T_NONE); case InternalJob::BLOCKED: break; case Job::WAITING: m_JobQueueWaiting.Enqueue(sptr_job); break; case Job::SLEEPING: //try { m_JobQueueSleeping.Enqueue(sptr_job); //} catch (RuntimeException e) { // throw new RuntimeException("Error changing from state: " + oldState); //} break; case Job::RUNNING: case InternalJob::ABOUT_TO_RUN: sptr_job->SetStartTime(InternalJob::T_NONE); sptr_job->SetWaitQueueStamp(InternalJob::T_NONE); m_running.insert(sptr_job); break; case InternalJob::ABOUT_TO_SCHEDULE: break; // default : // Assert.isLegal(false, "Invalid job state: " + job + ", state: " + newState); } } //notify queue outside sync block if (blockedJobs) m_Pool->JobQueued(); } Poco::Timestamp::TimeDiff JobManager::DelayFor(int priority) { //these values may need to be tweaked based on machine speed switch (priority) { case Job::INTERACTIVE: return 0; case Job::SHORT: return 50; case Job::LONG: return 100; case Job::BUILD: return 500; case Job::DECORATE: return 1000; default: // Assert.isTrue(false, "Job has invalid priority: " + priority); //$NON-NLS-1$ return 0; } } void JobManager::DoSchedule(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay) { Poco::ScopedLock managerLock(m_mutex); //job may have been canceled already int state = job->InternalGetState(); if (state != InternalJob::ABOUT_TO_SCHEDULE && state != Job::SLEEPING) return; //if it's a decoration job with no rule, don't run it right now if the system is busy if (job->GetPriority() == Job::DECORATE && job->GetRule() == 0) { Poco::Timestamp::TimeDiff tmp_minDelay = m_running.size() * 100; delay = std::max(delay, tmp_minDelay); } if (delay > 0) { job->SetStartTime(Poco::Timestamp() + delay * 100); InternalJob::Pointer sptr_job(job); ChangeState(sptr_job, Job::SLEEPING); } else { job->SetStartTime(Poco::Timestamp() + DelayFor(job->GetPriority()) * 100); job->SetWaitQueueStamp(m_waitQueueCounter++); InternalJob::Pointer sptr_job(job); ChangeState(sptr_job, Job::WAITING); } } void JobManager::DoShutdown() { std::vector vec_ToCancel; { Poco::ScopedLock LockMe(m_mutex); if (m_active) { m_active = false; //cancel all running jobs vec_ToCancel.assign(m_running.begin(), m_running.end()); //clean up m_JobQueueSleeping.Clear(); m_JobQueueWaiting.Clear(); m_running.clear(); } } // Give running jobs a chance to finish. Wait 0.1 seconds for up to 3 times. if (!vec_ToCancel.empty()) { for (std::size_t i = 0; i < vec_ToCancel.size(); i++) { // cancel jobs outside sync block to avoid deadlock Cancel(vec_ToCancel[i]); } for (int waitAttempts = 0; waitAttempts < 3; waitAttempts++) { Poco::Thread::yield(); { Poco::ScopedLock LockMe(m_mutex); if (m_running.empty()) break; } if (DEBUG_SHUTDOWN) { // JobManager.debug("Shutdown - job wait cycle #" + (waitAttempts + 1)); std::vector vec_StillRunning; { Poco::ScopedLock LockMe(m_mutex); vec_StillRunning.assign(m_running.begin(), m_running.end()); // if (!vec_StillRunning.empty()) { //for (int j = 0; j < stillRunning.length; j++) { // JobManager.debug("\tJob: " + printJobName(stillRunning[j])); //$NON-NLS-1$ //} } } Poco::Thread::sleep(100); Poco::Thread::yield(); } // retrieve list of the jobs that are still running { Poco::ScopedLock LockMe(m_mutex); vec_ToCancel.assign(m_running.begin(), m_running.end()); } } if (!vec_ToCancel.empty()) { /*for (int i = 0; i < vec_ToCancel.size(); i++) {*/ // std::string tmp_jobName = PrintJobName(toCancel[i]); // //this doesn't need to be translated because it's just being logged // String msg = "Job found still running after platform shutdown. Jobs should be canceled by the plugin that // scheduled them during shutdown: " + jobName; // RuntimeLog.log(new Status(IStatus.WARNING, JobManager.PI_JOBS, JobManager.PLUGIN_ERROR, msg, null)); // // // TODO the RuntimeLog.log in its current implementation won't produce a log // // during this stage of shutdown. For now add a standard error output. // // One the logging story is improved, the System.err output below can be removed: // System.err.println(msg); // } } m_Pool->Shutdown(); } Job::Pointer JobManager::NextJob() { { Poco::ScopedLock managerLock(m_mutex); //do nothing if the job manager is suspended if (m_suspended) return Job::Pointer(nullptr); // tickle the sleep queue to see if anyone wakes up Poco::Timestamp now; InternalJob::Pointer ptr_job = m_JobQueueSleeping.Peek(); while (ptr_job != 0 && ptr_job->GetStartTime() < now) { // a job that slept to long is set a new start time and is put into the waiting queue ptr_job->SetStartTime(now + DelayFor(ptr_job->GetPriority())); ptr_job->SetWaitQueueStamp(m_waitQueueCounter++); InternalJob::Pointer sptr_job(ptr_job); ChangeState(sptr_job, Job::WAITING); ptr_job = m_JobQueueSleeping.Peek(); } //process the wait queue until we find a job whose rules are satisfied. while ((ptr_job = m_JobQueueWaiting.Peek()) != 0) { InternalJob::Pointer sptr_job(ptr_job); InternalJob::Pointer sptr_blocker = FindBlockingJob(sptr_job); if (sptr_blocker == 0) break; //queue this job after the job that's blocking it ChangeState(sptr_job, InternalJob::BLOCKED); //assert job does not already belong to some other data structure //Assert.isTrue(job.next() == null); //Assert.isTrue(job.previous() == null); sptr_blocker->AddLast(ptr_job); } // the job to run must be in the running list before we exit // the sync block, otherwise two jobs with conflicting rules could start at once if (ptr_job != 0) { InternalJob::Pointer sptr_job(ptr_job); ChangeState(sptr_job, InternalJob::ABOUT_TO_RUN); } return ptr_job.Cast (); } } //TODO Job families //void //JobManager //::Select(List members, Object family, InternalJob firstJob, int stateMask) { // if (firstJob == null) // return; // InternalJob job = firstJob; // do { // //note that job state cannot be NONE at this point // if ((family == null || job.belongsTo(family)) && ((job.getState() & stateMask) != 0)) // members.add(job); // job = job.previous(); // } while (job != null && job != firstJob); // } //List //JobManager //::Select(Object family) { // return select(family, Job.WAITING | Job.SLEEPING | Job.RUNNING); // } //List //JobManager //::Select(Object family, int stateMask) { // List members = new ArrayList(); // synchronized (lock) { // if ((stateMask & Job.RUNNING) != 0) { // for (Iterator it = running.iterator(); it.hasNext();) { // select(members, family, (InternalJob) it.next(), stateMask); // } // } // if ((stateMask & Job.WAITING) != 0) // select(members, family, waiting.peek(), stateMask); // if ((stateMask & Job.SLEEPING) != 0) // select(members, family, sleeping.peek(), stateMask); // } // return members; // } -// dummy validateRule implemenation +// dummy validateRule implementation void JobManager::ValidateRule(ISchedulingRule::Pointer sptr_rule) { //null rule always valid if (sptr_rule == 0) return; //contains method must be reflexive poco_assert(sptr_rule->Contains(sptr_rule)) ; //contains method must return false when given an unknown rule poco_assert(!sptr_rule->Contains(sptr_testRule)); //isConflicting method must be reflexive poco_assert(sptr_rule->IsConflicting(sptr_rule)); //isConflicting method must return false when given an unknown rule poco_assert(!sptr_rule->IsConflicting(sptr_testRule)); } bool JobManager::Cancel(InternalJob::Pointer sptr_job) { IProgressMonitor::Pointer sptr_progressMonitor(nullptr); bool runCanceling = false; { Poco::ScopedLock mangerMutex (m_mutex); switch (sptr_job->GetState()) { case Job::NONE : return true; case Job::RUNNING : //cannot cancel a job that has already started (as opposed to ABOUT_TO_RUN) if (sptr_job->InternalGetState() == Job::RUNNING) { sptr_progressMonitor = sptr_job->GetProgressMonitor(); runCanceling = sptr_job->IsRunCanceled(); if(runCanceling) sptr_job->SetRunCanceled(true); break ; } //signal that the job should be canceled before it gets a chance to run sptr_job->SetAboutToRunCanceled(true); return false; default : ChangeState(sptr_job, Job::NONE); } } //call monitor outside sync block if (sptr_progressMonitor != 0) { if(runCanceling) { if (!sptr_progressMonitor->IsCanceled()) sptr_progressMonitor->SetCanceled(true); sptr_job->Canceling(); } return false; } //only notify listeners if the job was waiting or sleeping m_JobListeners.Done(sptr_job.Cast(), Status::CANCEL_STATUS(BERRY_STATUS_LOC), false); return true; } IProgressMonitor::Pointer JobManager::CreateMonitor( Job::Pointer sptr_jobToMonitor) { IProgressMonitor::Pointer sptr_monitor(nullptr); if (m_sptr_progressProvider != 0) sptr_monitor = m_sptr_progressProvider->CreateMonitor(sptr_jobToMonitor); if (sptr_monitor == 0) { NullProgressMonitor::Pointer sptr_defaultMonitor(new NullProgressMonitor()); return sptr_defaultMonitor; } return sptr_monitor; } IProgressMonitor::Pointer JobManager::CreateMonitor(InternalJob::Pointer sptr_job, IProgressMonitor::Pointer group, int ticks) { { Poco::ScopedLock managerLock(m_mutex); //group must be set before the job is scheduled //this includes the ABOUT_TO_SCHEDULE state, during which it is still //valid to set the progress monitor if (sptr_job->GetState() != Job::NONE) { IProgressMonitor::Pointer dummy(nullptr); return dummy; } IProgressMonitor::Pointer sptr_monitor(nullptr); if (m_sptr_progressProvider != 0) sptr_monitor = m_sptr_progressProvider->CreateMonitor(sptr_job.Cast() , group, ticks); if (sptr_monitor == 0) { // return a default NullprogressMonitor NullProgressMonitor::Pointer sptr_defaultMonitor(new NullProgressMonitor() ); return sptr_defaultMonitor; } return sptr_monitor; } } void JobManager::EndJob(InternalJob::Pointer ptr_job, IStatus::Pointer result, bool notify) { Poco::Timestamp::TimeDiff rescheduleDelay(InternalJob::T_NONE); { Poco::ScopedLock lock ( m_mutex); // if the job is finishing asynchronously, there is nothing more to do for now if (result == Job::ASYNC_FINISH) return; //if job is not known then it cannot be done if (ptr_job->GetState() == Job::NONE) return; ptr_job->SetResult(result); ptr_job->SetProgressMonitor(IProgressMonitor::Pointer(nullptr)); ptr_job->SetThread(nullptr); rescheduleDelay = ptr_job->GetStartTime().epochMicroseconds(); InternalJob::Pointer sptr_job(ptr_job); ChangeState(sptr_job, Job::NONE); } //notify listeners outside sync block bool reschedule = m_active && rescheduleDelay > InternalJob::T_NONE && ptr_job->ShouldSchedule(); if (notify) m_JobListeners.Done(ptr_job.Cast(), result, reschedule); //reschedule the job if requested and we are still active if (reschedule) Schedule(ptr_job, rescheduleDelay, reschedule); } InternalJob::Pointer JobManager::FindBlockingJob(InternalJob::Pointer waitingJob) { if (waitingJob->GetRule() == 0) return InternalJob::Pointer(nullptr); { Poco::ScopedLock managerLock (m_mutex); if (m_running.empty() ) { InternalJob::Pointer dummy; return (dummy); } //check the running jobs bool hasBlockedJobs = false; QSet::Iterator it; for ( it = m_running.begin(); it != m_running.end(); it ++ ) { InternalJob::Pointer sptr_job = *it ++; if (waitingJob->IsConflicting(sptr_job)) return sptr_job; if (!hasBlockedJobs) hasBlockedJobs = sptr_job->Previous() != 0; } // there are no blocked jobs, so we are done if (!hasBlockedJobs) { InternalJob::Pointer dummy; return (dummy); } //check all jobs blocked by running jobs QSet::Iterator it_blocked; for( it_blocked = m_running.begin(); it_blocked != m_running.end(); it_blocked ++ ) { InternalJob::Pointer sptr_job = *it_blocked ++; while (true) { sptr_job = sptr_job->Previous(); if (sptr_job == 0) break; if (waitingJob->IsConflicting(sptr_job)) return sptr_job; } } } InternalJob::Pointer sptr_null; return (sptr_null); } bool JobManager::IsActive() { return m_active; } bool JobManager::IsBlocking(InternalJob::Pointer sptr_runningJob) { { Poco::ScopedLock lockMe (m_mutex); // if this job isn't running, it can't be blocking anyone if (sptr_runningJob->GetState() != Job::RUNNING) return false; // if any job is queued behind this one, it is blocked by it InternalJob::Pointer ptr_previous = sptr_runningJob->Previous(); while (ptr_previous != 0) { // ignore jobs of lower priority (higher priority value means lower priority) if (ptr_previous->GetPriority() < sptr_runningJob->GetPriority()) { if (!ptr_previous->IsSystem()) return true; // TODO Implicit Jobs // implicit jobs should interrupt unless they act on behalf of system jobs // if (previous instanceof ThreadJob && ((ThreadJob) previous).shouldInterrupt()) // return true; } ptr_previous = ptr_previous->previous; } // none found return false; } } //void //JobManager //::Join(InternalJob job) { // final IJobChangeListener listener; // final Semaphore barrier; // synchronized (lock) { // int state = job.getState(); // if (state == Job.NONE) // return; // //don't join a waiting or sleeping job when suspended (deadlock risk) // if (suspended && state != Job.RUNNING) // return; // //it's an error for a job to join itself // if (state == Job.RUNNING && job.getThread() == Thread.currentThread()) // throw new IllegalStateException("Job attempted to join itself"); //$NON-NLS-1$ // //the semaphore will be released when the job is done // barrier = new Semaphore(null); // listener = new JobChangeAdapter() { // public void done(IJobChangeEvent event) { // barrier.release(); // } // }; // job.addJobChangeListener(listener); // //compute set of all jobs that must run before this one // //add a listener that removes jobs from the blocking set when they finish // } // //wait until listener notifies this thread. // try { // while (true) { // //notify hook to service pending syncExecs before falling asleep // lockManager.aboutToWait(job.getThread()); // try { // if (barrier.acquire(Long.MAX_VALUE)) // break; // } catch (InterruptedException e) { // //loop and keep trying // } // } // } finally { // lockManager.aboutToRelease(); // job.removeJobChangeListener(listener); // } // } bool JobManager::RunNow(InternalJob::Pointer sptr_job) { { Poco::ScopedLock lockMe (m_mutex); //cannot start if there is a conflicting job if (FindBlockingJob(sptr_job) != 0) return false; ChangeState(sptr_job, Job::RUNNING); sptr_job->SetProgressMonitor(IProgressMonitor::Pointer(new NullProgressMonitor())); sptr_job->Run(IProgressMonitor::Pointer(nullptr)); } return true; } void JobManager::Schedule(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay, bool reschedule) { if (!m_active) throw Poco::IllegalStateException("Job manager has been shut down."); poco_assert(job); // "Job is null" poco_assert(delay >= 0); // "Scheduling delay is negative" { Poco::ScopedLock managerLock (m_mutex); //if the job is already running, set it to be rescheduled when done if (job->GetState() == Job::RUNNING) { job->SetStartTime(delay); return; } //can't schedule a job that is waiting or sleeping if (job->InternalGetState() != Job::NONE) return; //remember that we are about to schedule the job //to prevent multiple schedule attempts from succeeding (bug 68452) InternalJob::Pointer sptr_job(job); ChangeState(sptr_job, InternalJob::ABOUT_TO_SCHEDULE); } //notify listeners outside sync block m_JobListeners.Scheduled(job.Cast(), delay, reschedule); //schedule the job DoSchedule(job, delay); //call the pool outside sync block to avoid deadlock m_Pool->JobQueued(); } bool JobManager::Sleep(InternalJob::Pointer job) { { Poco::ScopedLock lockMe (m_mutex); InternalJob::Pointer sptr_job(job); switch (job->GetState()) { case Job::RUNNING : //cannot be paused if it is already running (as opposed to ABOUT_TO_RUN) if (job->InternalGetState() == Job::RUNNING) return false; //job hasn't started running yet (aboutToRun listener) break; case Job::SLEEPING : //update the job wake time job->SetStartTime(InternalJob::T_INFINITE); //change state again to re-shuffle the sleep queue ChangeState(sptr_job, Job::SLEEPING); return true; case Job::NONE : return true; case Job::WAITING : //put the job to sleep break; } job->SetStartTime(InternalJob::T_INFINITE); ChangeState(sptr_job, Job::SLEEPING); } m_JobListeners.Sleeping(job.Cast()); return true; } void JobManager::SetPriority(InternalJob::Pointer job, int newPriority) { { Poco::ScopedLock lockMe (m_mutex); InternalJob::Pointer sptr_job(job); int oldPriority = job->GetPriority(); if (oldPriority == newPriority) return; job->InternalSetPriority(newPriority); //if the job is waiting to run, re-shuffle the queue if (sptr_job->GetState() == Job::WAITING) { Poco::Timestamp oldStart = job->GetStartTime(); job->SetStartTime(oldStart += (DelayFor(newPriority) - DelayFor(oldPriority))); m_JobQueueWaiting.Resort(job); } } } Poco::Timespan::TimeDiff JobManager::SleepHint() { Poco::ScopedLock managerLock (m_mutex); // wait forever if job manager is suspended if (m_suspended) return InternalJob::T_INFINITE; if (!m_JobQueueWaiting.IsEmpty()) return 0; // return the anticipated time that the next sleeping job will wake InternalJob::Pointer ptr_next(nullptr); ptr_next = m_JobQueueSleeping.Peek(); if (ptr_next == 0) return InternalJob::T_INFINITE; Poco::Timestamp tmp_startTime = ptr_next->GetStartTime(); Poco::Timestamp tmp_currentTime; Poco::Timestamp::TimeDiff timeToStart = tmp_startTime - tmp_currentTime; return timeToStart; } Job::Pointer JobManager::StartJob() { Job::Pointer job(nullptr); while (true) { job = NextJob(); if (!job) return Job::Pointer(nullptr); //must perform this outside sync block because it is third party code bool shouldRun = job->ShouldRun(); //check for listener veto if (shouldRun) m_JobListeners.AboutToRun(job); //listeners may have canceled or put the job to sleep bool endJob = false; { Poco::ScopedLock lock(m_mutex); InternalJob::Pointer internal = job; if (internal->InternalGetState() == InternalJob::ABOUT_TO_RUN) { if (shouldRun && !internal->IsAboutToRunCanceled()) { internal->SetProgressMonitor(CreateMonitor(job)); //change from ABOUT_TO_RUN to RUNNING internal->InternalSetState(Job::RUNNING); break; } internal->SetAboutToRunCanceled(false); endJob = true; //fall through and end the job below } } if (endJob) { //job has been vetoed or canceled, so mark it as done EndJob(job,Status::CANCEL_STATUS(BERRY_STATUS_LOC), true); continue; } } m_JobListeners.Running(job); return job; } void JobManager::WakeUp(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay) { poco_assert(delay >= 0); // "Scheduling delay is negative" { Poco::ScopedLock m_managerLock (m_mutex); //cannot wake up if it is not sleeping if (job->GetState() != Job::SLEEPING) return; DoSchedule(job, delay); } //call the pool outside sync block to avoid deadlock m_Pool->JobQueued(); /// IListenerExtension only notify of wake up if immediate if (delay == 0) m_JobListeners.Awake(job.Cast()); } IProgressMonitor::Pointer JobManager::MonitorFor(IProgressMonitor::Pointer sptr_monitor) { if(sptr_monitor == 0 || sptr_monitor.Cast() ) { if(m_sptr_progressProvider != 0 ) sptr_monitor = m_sptr_progressProvider->GetDefaultMonitor(); } if(sptr_monitor == 0) { IProgressMonitor::Pointer sptr_nullProgressMonitor(new NullProgressMonitor()); return sptr_nullProgressMonitor; } return sptr_monitor; } } diff --git a/Plugins/org.blueberry.core.jobs/src/internal/berryJobManager.h b/Plugins/org.blueberry.core.jobs/src/internal/berryJobManager.h index dfc3597689..49f7e5d91b 100644 --- a/Plugins/org.blueberry.core.jobs/src/internal/berryJobManager.h +++ b/Plugins/org.blueberry.core.jobs/src/internal/berryJobManager.h @@ -1,431 +1,431 @@ /*============================================================================ 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 _BERRY_JOBMANAGER_H #define _BERRY_JOBMANAGER_H #include "berryInternalJob.h" #include "berryJobQueue.h" #include "berryWorkerPool.h" #include "berryJobListeners.h" #include "berryJob.h" #include "berryIProgressMonitorWithBlocking.h" #include "berryIJobManager.h" #include "berryISchedulingRule.h" #include #include #include #include #include #include #include #include #include namespace berry { /** * Implementation of API type IJobManager * * Implementation note: all the data structures of this class are protected * by a single lock object held as a private field in this class. The JobManager * instance itself is not used because this class is publicly reachable, and third * party clients may try to synchronize on it. * * The WorkerPool class uses its own monitor for synchronizing its data * structures. To avoid deadlock between the two classes, the JobManager * must NEVER call the worker pool while its own monitor is held. */ struct BERRY_JOBS JobManager: public IJobManager { public: friend class WorkerPool; friend struct InternalJob; friend struct NullRule; berryObjectMacro(JobManager); /** * The unique identifier constant of this plug-in. */ static const QString& PI_JOBS(); static bool DEBUG; static bool DEBUG_BEGIN_END; static bool DEBUG_DEADLOCK; static bool DEBUG_LOCKS; static bool DEBUG_TIMING; static bool DEBUG_SHUTDOWN; /** * Status code constant indicating an error occurred while running a plug-in. * For backward compatibility with Platform.PLUGIN_ERROR left at (value = 2). */ static const int PLUGIN_ERROR; /// const ImplicitJobs iImplicitJobs = new ImplicitJobs(this); /** * The singleton job manager instance. It must be a singleton because * all job instances maintain a reference (as an optimization) and have no way * of updating it. */ static JobManager* GetInstance(); /** * For debugging purposes only */ static std::string PrintState(int state); /** * Note that although this method is not API, clients have historically used * it to force jobs shutdown in cases where OSGi shutdown does not occur. * For this reason, this method should be considered near-API and should not * be changed if at all possible. */ static void Shutdown(); // void Cancel(Object family) ; IProgressMonitor::Pointer CreateProgressGroup() override; Job* CurrentJob(); // void EndRule(ISchedulingRule rule) ; // Job[] Find(Object family) ; // LockManager GetLockManager() { // return lockManager; // } bool IsIdle() override; bool IsSuspended() override; // void Join(final Object family, IProgressMonitor monitor) throws InterruptedException, OperationCanceledException ); // ILock NewLock() ; /** * @see IJobManager#RemoveChangeListener(IJobChangeListener*) */ void RemoveJobChangeListener(IJobChangeListener* listener) override; // /** //* report to the progress monitor that this thread is blocked, supplying //* an information message, and if possible the job that is causing the blockage. //* important: an invocation of this method must be followed eventually be //* an invocation of ReportUnblocked. //* @param monitor the monitor to report blocking to //* @param BlockingJob the job that is blocking this thread, or null //* @see #Reportunblocked //*/ void ReportBlocked( IProgressMonitor::Pointer monitor, InternalJob::Pointer blockingjob) const ; /** * Reports that this thread was blocked, but is no longer blocked and is able * to proceed. * @param monitor The monitor to report unblocking to. * @see #ReportBlocked */ void ReportUnblocked(IProgressMonitor::Pointer monitor) const ; /** * @have a look at IJobManager Resume */ void Resume(); // /** // * @have a look at IJobManager Resume // */ // void Resume(ISchedulingRule::Pointer rule)const ; /** * @have a look at IJobManager SetProgressProvider */ void SetProgressProvider(ProgressProvider::Pointer provider) override; void SetRule(InternalJob::Pointer job, ISchedulingRule::Pointer rule); // /* // * @see IJobManager#sleep(std::string) // */ // void Sleep(Object family) ; void Suspend(); /* * @see schedule(long) */ void Schedule(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay, bool reschedule); // void Suspend(ISchedulingRule::Pointer rule, IProgressMonitor::Pointer monitor)const ; // void TransferRule(ISchedulingRule rule, Thread destinationThread) ; // void SetLockListener(LockListener listener) ; // /** // * Puts a job to sleep. Returns true if the job was successfully put to sleep. // */ // void WakeUp(Object family) ; void AddJobChangeListener(IJobChangeListener* listener) override; // void beginRule(ISchedulingRule rule, IProgressMonitor monitor) ; protected: /** * Cancels a job */ bool Cancel(InternalJob::Pointer job); /** * Returns a new progress monitor for this job, belonging to the given * progress group. Returns null if it is not a valid time to set the job's group. */ IProgressMonitor::Pointer CreateMonitor(InternalJob::Pointer job, IProgressMonitor::Pointer group, int ticks); /** * Indicates that a job was running, and has now finished. Note that this method * can be called under OutOfMemoryError conditions and thus must be paranoid * about allocating objects. */ /// optional Extension IStatus for implementation help have a look at the Java JobAPI void EndJob(InternalJob::Pointer job,IStatus::Pointer result, bool notify); /** * Returns a running or blocked job whose scheduling rule conflicts with the * scheduling rule of the given waiting job. Returns null if there are no * conflicting jobs. A job can only run if there are no running jobs and no blocked * jobs whose scheduling rule conflicts with its rule. */ InternalJob::Pointer FindBlockingJob(InternalJob::Pointer waitingJob); /** * Returns whether the job manager is active (has not been shutdown). */ bool IsActive(); /** * Returns true if the given job is blocking the execution of a non-system * job. */ bool IsBlocking(InternalJob::Pointer runningJob); // void Join(InternalJob job) ; /** * Attempts to immediately start a given job. Returns true if the job was * successfully started, and false if it could not be started immediately * due to a currently running job with a conflicting rule. Listeners will never * be notified of jobs that are run in this way. */ bool RunNow(InternalJob::Pointer sptr_job); /** * Puts a job to sleep. Returns true if the job was successfully put to sleep. */ bool Sleep(InternalJob::Pointer job); /** * Changes a job priority. */ void SetPriority(InternalJob::Pointer job, int newPriority); /** * Returns the estimated time in milliseconds before the next job is scheduled * to wake up. The result may be negative. Returns InternalJob.T_INFINITE if * there are no sleeping or waiting jobs. */ Poco::Timespan::TimeDiff SleepHint(); /** * Returns the next job to be run, or null if no jobs are waiting to run. * The worker must call endJob when the job is finished running. */ Job::Pointer StartJob(); /* * @see Job#WakeUp(long) */ void WakeUp(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay); private: JobManager(); /* Poco Mutex for synchronizing purposes */ Poco::Mutex m_mutex; // Dummy Null rule to validate SchedulingRules implemented by clients SmartPointer sptr_testRule; // //ToDO static const ISchedulingRule nullRule = new ISchedulingRule() { // public bool Contains(ISchedulingRule rule) ; // public boolean IsConflicting(ISchedulingRule rule) ; /** * True if this manager is active, and false otherwise. A job manager * starts out active, and becomes inactive if it has been shutdown * and not restarted. */ volatile bool m_active; JobListeners m_JobListeners; // // /** // * The lock for synchronizing all activity in the job manager. To avoid deadlock, // * this lock must never be held for extended periods, and must never be // * held while third party code is being called. // */ // // private final Object lock = new Object(); // static const Object lock ; // // //private LockManager lockManager = new LockManager(); - // static const LockManger lockManager; + // static const LockManager lockManager; /** * The pool of worker threads. */ WorkerPool::Pointer m_Pool; ProgressProvider::Pointer m_sptr_progressProvider; /** * Jobs that are currently running. Should only be modified from changeState */ QSet m_running; /** * Jobs that are sleeping. Some sleeping jobs are scheduled to wake * up at a given start time, while others will sleep indefinitely until woken. * Should only be modified from changeState */ JobQueue m_JobQueueSleeping; /** * jobs that are waiting to be run. Should only be modified from changeState */ JobQueue m_JobQueueWaiting; /** * True if this manager has been suspended, and false otherwise. A job manager * starts out not suspended, and becomes suspended when suspend * is invoked. Once suspended, no jobs will start running until resume * is cancelled. */ bool m_suspended; /** * Counter to record wait queue insertion order. */ long long m_waitQueueCounter; // /** // * For debugging purposes only // */ // const std::string PrintJobName(Job job); /** * Atomically updates the state of a job, adding or removing from the * necessary queues or sets. */ void ChangeState(InternalJob::Pointer job, int newState); /** * Returns a new progress monitor for this job. Never returns null. */ IProgressMonitor::Pointer CreateMonitor(Job::Pointer sptr_jobToMonitor); /** * Returns the delay in milliseconds that a job with a given priority can * tolerate waiting. */ Poco::Timestamp::TimeDiff DelayFor(int priority); /** * Performs the scheduling of a job. Does not perform any notifications. */ void DoSchedule(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay); /** * Shuts down the job manager. Currently running jobs will be told * to stop, but worker threads may still continue processing. * (note: This implemented IJobManager.Shutdown which was removed * due to problems caused by premature shutdown) */ void DoShutdown(); // void InitDebugOptions() ; /** * Removes and returns the first waiting job in the queue. Returns null if there * are no items waiting in the queue. If an item is removed from the queue, * it is moved to the running jobs list. */ Job::Pointer NextJob(); /** * Returns a non-null progress monitor instance. If the monitor is null, * returns the default monitor supplied by the progress provider, or a * NullProgressMonitor if no default monitor is available. */ IProgressMonitor::Pointer MonitorFor(IProgressMonitor::Pointer monitor); // /** // * Adds all family members in the list of jobs to the collection // */ // void Select(List members, Object family, InternalJob firstJob, int stateMask) ; // // /** // * Returns a list of all jobs known to the job manager that belong to the given family. // */ // List Select(Object family) ; // // /** // * Returns a list of all jobs known to the job manager that belong to the given // * family and are in one of the provided states. // */ // List Select(Object family, int stateMask) ; /** * Validates that the given scheduling rule obeys the constraints of * scheduling rules as described in the ISchedulingRule */ void ValidateRule(ISchedulingRule::Pointer rule); }; } #endif /* _BERRY_TEMPLATE_H */ diff --git a/Plugins/org.blueberry.core.jobs/src/internal/berryJobQueue.cpp b/Plugins/org.blueberry.core.jobs/src/internal/berryJobQueue.cpp index 8818936f83..6d2dd57b5c 100644 --- a/Plugins/org.blueberry.core.jobs/src/internal/berryJobQueue.cpp +++ b/Plugins/org.blueberry.core.jobs/src/internal/berryJobQueue.cpp @@ -1,142 +1,142 @@ /*============================================================================ 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 "berryJobQueue.h" // changed Java JobQueue implementation .. // if only one element is in the queue than InternalJob->next and InternalJob->previous pointer are pointing to 0 and not to the Element itself // I think its better .. will see namespace berry { class DummyJob: public InternalJob { public: IStatus::Pointer Run(IProgressMonitor::Pointer) override { return Status::OK_STATUS(BERRY_STATUS_LOC); } DummyJob() : InternalJob("Queue-Head") { } }; JobQueue::JobQueue(bool allowConflictOvertaking) : dummy(new DummyJob()), m_allowConflictOvertaking(allowConflictOvertaking) { dummy->SetNext(dummy); dummy->SetPrevious(dummy); } -//TODO JobQueue Constructor IStatus Implementierung +//TODO JobQueue Constructor IStatus Implementation //TODO Constructor JobQueue IStatus .. implementation // public JobQueue(boolean allowConflictOvertaking) { // //compareTo on dummy is never called // dummy = new InternalJob("Queue-Head") {//$NON-NLS-1$ // public IStatus run(IProgressMonitor m) { // return Status.OK_STATUS; // } // }; // dummy.setNext(dummy); // dummy.setPrevious(dummy); // this.allowConflictOvertaking = allowConflictOvertaking; //} bool JobQueue::CanOvertake(InternalJob::Pointer newEntry, InternalJob::Pointer queueEntry) { //can never go past the end of the queue if (queueEntry == dummy.GetPointer()) return false; //if the new entry was already in the wait queue, ensure it is re-inserted in correct position (bug 211799) if (newEntry->GetWaitQueueStamp() > 0 && newEntry->GetWaitQueueStamp() < queueEntry->GetWaitQueueStamp()) return true; //if the new entry has lower priority, there is no need to overtake the existing entry if ((queueEntry == newEntry)) return false; // the new entry has higher priority, but only overtake the existing entry if the queue allows it InternalJob::Pointer sptr_queueEntry(queueEntry); return m_allowConflictOvertaking || !newEntry->IsConflicting(sptr_queueEntry); } void JobQueue::Clear() { dummy->SetNext(dummy); dummy->SetPrevious(dummy); } // notice: important that the first element in the queue is internally set as a dummy element InternalJob::Pointer JobQueue::Dequeue() { InternalJob::Pointer ptr_dummyPrevious = dummy->Previous(); // sets previous pointer to 0 if there is only 1 Element in the queue if (ptr_dummyPrevious == dummy) { dummy->previous = nullptr; return dummy; } return ptr_dummyPrevious->Remove(); } void JobQueue::Enqueue(InternalJob::Pointer newEntry) { InternalJob::Pointer tail = dummy->Next(); //overtake lower priority jobs. Only overtake conflicting jobs if allowed to while (CanOvertake(newEntry, tail)) tail = tail->Next(); InternalJob::Pointer tailPrevious = tail->Previous(); newEntry->SetNext(tail); newEntry->SetPrevious(tailPrevious); tailPrevious->SetNext(newEntry); tail->SetPrevious(newEntry); } void JobQueue::Remove(InternalJob::Pointer jobToRemove) { jobToRemove->Remove(); } void JobQueue::Resort(InternalJob::Pointer entry) { this->Remove(entry); this->Enqueue(entry); } bool JobQueue::IsEmpty() { return this->dummy->next == dummy; } InternalJob::Pointer JobQueue::Peek() { return dummy->Previous() == dummy ? InternalJob::Pointer(nullptr) : dummy->Previous(); } } diff --git a/Plugins/org.blueberry.core.jobs/src/internal/berryWorkerPool.cpp b/Plugins/org.blueberry.core.jobs/src/internal/berryWorkerPool.cpp index 9360e6ea59..41abb8fc98 100644 --- a/Plugins/org.blueberry.core.jobs/src/internal/berryWorkerPool.cpp +++ b/Plugins/org.blueberry.core.jobs/src/internal/berryWorkerPool.cpp @@ -1,215 +1,215 @@ /*============================================================================ 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. ============================================================================*/ #define NOMINMAX #include "berryWorkerPool.h" #include "berryJobManager.h" #include #include #include namespace berry { WorkerPool::WorkerPool(JobManager* myJobManager) : m_ptrManager(myJobManager), m_numThreads(0), m_sleepingThreads(0), m_threads( 10), m_busyThreads(0) // m_isDaemon(false), { } const long WorkerPool::BEST_BEFORE = 60000; const int WorkerPool::MIN_THREADS = 1; void WorkerPool::Shutdown() { Poco::ScopedLock LockMe(m_mutexOne); for(int i = 0; i<= m_numThreads; i++) { notify(); } } void WorkerPool::Add(Worker::Pointer worker) { Poco::Mutex::ScopedLock lock(m_mutexOne); m_threads.push_back(worker); } void WorkerPool::DecrementBusyThreads() { Poco::ScopedLock lockOne(m_mutexOne); //impossible to have less than zero busy threads if (--m_busyThreads < 0) { //TODO Decrementbusythreads if (jobmanager.debug) assert.istrue(false, integer.tostring(busythreads)); m_busyThreads = 0; } } void WorkerPool::IncrementBusyThreads() { Poco::ScopedLock lockOne(m_mutexOne); if (++m_busyThreads > m_numThreads) { m_busyThreads = m_numThreads; } } bool WorkerPool::Remove(Worker::Pointer worker) { Poco::ScopedLock lockOne(m_mutexOne); auto end = std::remove(m_threads.begin(), m_threads.end(), worker); bool removed = end != m_threads.end(); m_threads.erase(end); return removed; } void WorkerPool::EndWorker(Worker::Pointer sptr_worker) { Poco::ScopedLock lock(m_mutexOne); Remove(sptr_worker); } void WorkerPool::Sleep(long duration) { Poco::ScopedLock lock(m_mutexOne); m_sleepingThreads++; m_busyThreads--; try { wait(duration); throw FinallyThrowException(); } catch (FinallyThrowException&) { m_sleepingThreads--; m_busyThreads++; } catch (...) { m_sleepingThreads--; m_busyThreads++; } } InternalJob::Pointer WorkerPool::StartJob(Worker* worker) { // if we're above capacity, kill the thread { Poco::Mutex::ScopedLock lockOne(m_mutexOne); if (!m_ptrManager->IsActive()) { // must remove the worker immediately to prevent all threads from expiring Worker::Pointer sptr_worker(worker); EndWorker(sptr_worker); return InternalJob::Pointer(nullptr); } //set the thread to be busy now in case of reentrant scheduling IncrementBusyThreads(); } Job::Pointer ptr_job(nullptr); try { ptr_job = m_ptrManager->StartJob(); //spin until a job is found or until we have been idle for too long Poco::Timestamp idleStart; while (m_ptrManager->IsActive() && ptr_job == 0) { long tmpSleepTime = long(m_ptrManager->SleepHint()); if (tmpSleepTime > 0) Sleep(std::min(tmpSleepTime, BEST_BEFORE)); ptr_job = m_ptrManager->StartJob(); //if we were already idle, and there are still no new jobs, then the thread can expire { Poco::Mutex::ScopedLock lockOne(m_mutexOne); Poco::Timestamp tmpCurrentTime; long long tmpTime = tmpCurrentTime - idleStart; if (ptr_job == 0 && (tmpTime > BEST_BEFORE) && (m_numThreads - m_busyThreads) > MIN_THREADS) { //must remove the worker immediately to prevent all threads from expiring Worker::Pointer sptr_worker(worker); EndWorker(sptr_worker); return InternalJob::Pointer(nullptr); } } } if (ptr_job != 0) { //if this job has a rule, then we are essentially acquiring a lock //if ((job.getRule() != 0) && !(job instanceof ThreadJob)) { - // //don't need to re-aquire locks because it was not recorded in the graph + // //don't need to re-acquire locks because it was not recorded in the graph // //that this thread waited to get this rule // manager.getLockManager().addLockThread(Thread.currentThread(), job.getRule()); // } //see if we need to wake another worker if (m_ptrManager->SleepHint() <= 0) JobQueued(); } throw FinallyThrowException(); } catch (FinallyThrowException&) { //decrement busy thread count if we're not running a job if (ptr_job == 0) DecrementBusyThreads(); } catch (...) { DecrementBusyThreads(); } return ptr_job; } void WorkerPool::JobQueued() { Poco::ScopedLock lockOne(m_mutexOne); //if there is a sleeping thread, wake it up if (m_sleepingThreads > 0) { notify(); return; } //create a thread if all threads are busy if (m_busyThreads >= m_numThreads) { WorkerPool::WeakPtr wp_WorkerPool(WorkerPool::Pointer(this)); Worker::Pointer sptr_worker(new Worker(wp_WorkerPool)); Add(sptr_worker); sptr_worker->Start(); return; } } void WorkerPool::EndJob(InternalJob::Pointer job, IStatus::Pointer result) { DecrementBusyThreads(); //TODO LockManager // //need to end rule in graph before ending job so that 2 threads // //do not become the owners of the same rule in the graph // if ((job.getRule() != null) && !(job instanceof ThreadJob)) { // //remove any locks this thread may be owning on that rule // manager.getLockManager().removeLockCompletely(Thread.currentThread(), job.getRule()); // } m_ptrManager->EndJob(job, result, true); // //ensure this thread no longer owns any scheduling rules // manager.implicitJobs.endJob(job); } } diff --git a/Plugins/org.blueberry.core.runtime/src/berryIAdapterManager.h b/Plugins/org.blueberry.core.runtime/src/berryIAdapterManager.h index 96fa476b20..1c09fe9261 100644 --- a/Plugins/org.blueberry.core.runtime/src/berryIAdapterManager.h +++ b/Plugins/org.blueberry.core.runtime/src/berryIAdapterManager.h @@ -1,280 +1,280 @@ /*============================================================================ 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 BERRYIADAPTERMANAGER_H_ #define BERRYIADAPTERMANAGER_H_ #include #include #include "berryPlatformObject.h" #include "berryIAdapterFactory.h" #include #include namespace berry { /** * An adapter manager maintains a registry of adapter factories. Clients * directly invoke methods on an adapter manager to register and unregister * adapters. All adaptable objects (that is, objects that implement the IAdaptable * interface) tunnel IAdaptable.getAdapter invocations to their - * adapter manager's IAdapterManger.getAdapter method. The + * adapter manager's IAdapterManager.getAdapter method. The * adapter manager then forwards this request unmodified to the IAdapterFactory.getAdapter * method on one of the registered adapter factories. *

* Adapter factories can be registered programmatically using the registerAdapters * method. Alternatively, they can be registered declaratively using the * org.blueberry.core.runtime.adapters extension point. Factories registered * with this extension point will not be able to provide adapters until their * corresponding plugin has been activated. *

* The following code snippet shows how one might register an adapter of type * com.example.acme.Sticky on resources in the workspace. *

* * \code * IAdapterFactory pr = new IAdapterFactory() { * public Class[] getAdapterList() { * return new Class[] { com.example.acme.Sticky.class }; * } * public Object getAdapter(Object adaptableObject, Class adapterType) { * IResource res = (IResource) adaptableObject; * QualifiedName key = new QualifiedName("com.example.acme", "sticky-note"); * try { * com.example.acme.Sticky v = (com.example.acme.Sticky) res.getSessionProperty(key); * if (v == null) { * v = new com.example.acme.Sticky(); * res.setSessionProperty(key, v); * } * } catch (CoreException e) { * // unable to access session property - ignore * } * return v; * } * } * Platform.getAdapterManager().registerAdapters(pr, IResource.class); * \endcode * *

* This interface can be used without OSGi running. *

* This interface is not intended to be implemented by clients. *

* @see IAdaptable * @see IAdapterFactory */ struct org_blueberry_core_runtime_EXPORT IAdapterManager: public Object { berryObjectMacro(berry::IAdapterManager); /** * This value can be returned to indicate that no applicable adapter factory * was found. * @since org.blueberry.equinox.common 3.3 */ static const int NONE; /** * This value can be returned to indicate that an adapter factory was found, * but has not been loaded. * @since org.blueberry.equinox.common 3.3 */ static const int NOT_LOADED; /** * This value can be returned to indicate that an adapter factory is loaded. * @since org.blueberry.equinox.common 3.3 */ static const int LOADED; /** * Returns a Poco::Any object which contains an instance of the given name associated * with the given adaptable. Returns an empty Poco::Any if no such object can * be found. *

* Note that this method will never cause plug-ins to be loaded. If the * only suitable factory is not yet loaded, this method will return an empty Poco::Any. * If activation of the plug-in providing the factory is required, use the * LoadAdapter method instead. * * @param adaptable the adaptable object being queried (usually an instance * of IAdaptable) * @return a Poco::Any castable to the given adapter type, or empty * if the given adaptable object does not have an available adapter of the * given type */ template A* GetAdapter(const Object* adaptable) { const char* typeName = qobject_interface_iid(); if (typeName == nullptr) { BERRY_WARN << "Error getting adapter for '" << Reflection::GetClassName(adaptable) << "': " << "Cannot get the interface id for type '" << Reflection::GetClassName() << "'. It is probably missing a Q_DECLARE_INTERFACE macro in its header."; return nullptr; } return dynamic_cast(this->GetAdapter(adaptable, typeName, false)); } /** * Returns an object which is an instance of the given class name associated * with the given object. Returns null if no such object can * be found. *

* Note that this method will never cause plug-ins to be loaded. If the * only suitable factory is not yet loaded, this method will return null. * If activation of the plug-in providing the factory is required, use the * loadAdapter method instead. * * @param adaptable the adaptable object being queried (usually an instance * of IAdaptable) * @param adapterTypeName the fully qualified name of the type of adapter to look up * @return an object castable to the given adapter type, or null * if the given adaptable object does not have an available adapter of the * given type */ virtual Object* GetAdapter(const Object* adaptable, const QString& adapterTypeName) = 0; /** * Returns whether there is an adapter factory registered that may be able * to convert adaptable to an object of type adapterTypeName. *

* Note that a return value of true does not guarantee that * a subsequent call to GetAdapter with the same arguments * will return a non-empty result. If the factory's plug-in has not yet been * loaded, or if the factory itself returns nothing, then * GetAdapter will still return an empty Poco::Any. * * @param adaptableType the adaptable object being queried (usually an instance * of IAdaptable) * @param adapterType the fully qualified class name of an adapter to * look up * @return true if there is an adapter factory that claims * it can convert adaptable to an object of type adapterType, * and false otherwise. */ virtual bool HasAdapter(const Object* adaptableType, const QString& adapterType) = 0; template int QueryAdapter(const Object* adaptable) { const char* typeName = qobject_interface_iid(); if (typeName == nullptr) { BERRY_WARN << "Error querying adapter manager for '" << Reflection::GetClassName(adaptable) << "': " << "Cannot get the interface id for type '" << Reflection::GetClassName() << "'. It is probably missing a Q_DECLARE_INTERFACE macro in its header."; return NONE; } return this->QueryAdapter(adaptable, typeName); } /** * Returns a status of an adapter factory registered that may be able * to convert adaptable to an object of type adapterTypeName. *

* One of the following values can be returned:

* @param adaptableType the adaptable object being queried (usually an instance * of IAdaptable) * @param adapterType the fully qualified class name of an adapter to * look up * @return a status of the adapter */ virtual int QueryAdapter(const Object* adaptableType, const QString& adapterType) = 0; /** * Returns an object that is an instance of the given class name associated * with the given object. Returns an empty Poco::Any if no such object can * be found. *

* Note that unlike the GetAdapter methods, this method * will cause the plug-in that contributes the adapter factory to be loaded * if necessary. As such, this method should be used judiciously, in order * to avoid unnecessary plug-in activations. Most clients should avoid * activation by using GetAdapter instead. * * @param adaptable the adaptable object being queried (usually an instance * of IAdaptable) * @return a Poco::Any castable to the given adapter type, or empty * if the given adaptable object does not have an available adapter of the * given type */ template A* LoadAdapter(const Object* adaptable) { const char* typeName = qobject_interface_iid(); if (typeName == nullptr) { BERRY_WARN << "Error getting adapter for '" << Reflection::GetClassName(adaptable) << "': " << "Cannot get the interface id for type '" << Reflection::GetClassName() << "'. It is probably missing a Q_DECLARE_INTERFACE macro in its header."; return nullptr; } return dynamic_cast(this->GetAdapter(adaptable, typeName, true)); } /** * Registers the given adapter factory as extending objects of the given * type. * * @param factory the adapter factory * @param adaptableTypeName the fully qualified typename being extended * @see #UnregisterAdapters */ virtual void RegisterAdapters(IAdapterFactory* factory, const QString& adaptableTypeName) = 0; /** * Removes the given adapter factory completely from the list of registered * factories. Equivalent to calling UnregisterAdapters(IAdapterFactory*, const std::string&) * on all classes against which it had been explicitly registered. Does * nothing if the given factory is not currently registered. * * @param factory the adapter factory to remove * @see #RegisterAdapters */ virtual void UnregisterAdapters(IAdapterFactory* factory) = 0; /** * Removes the given adapter factory from the list of factories registered * as extending the given class. Does nothing if the given factory and type * combination is not registered. * * @param factory the adapter factory to remove * @param adaptableTypeName one of the type names against which the given factory is * registered * @see #RegisterAdapters */ virtual void UnregisterAdapters(IAdapterFactory* factory, const QString& adaptableTypeName) = 0; private: virtual Object* GetAdapter(const Object* adaptable, const QString& adapterType, bool force) = 0; }; } // namespace berry Q_DECLARE_INTERFACE(berry::IAdapterManager, "org.blueberry.service.IAdapterManager") #endif /*BERRYIADAPTERMANAGER_H_*/ diff --git a/Plugins/org.blueberry.core.runtime/src/berryIStatus.h b/Plugins/org.blueberry.core.runtime/src/berryIStatus.h index cad224941c..c5fa114bf4 100644 --- a/Plugins/org.blueberry.core.runtime/src/berryIStatus.h +++ b/Plugins/org.blueberry.core.runtime/src/berryIStatus.h @@ -1,199 +1,199 @@ /*============================================================================ 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 BERRYISTATUS_H_ #define BERRYISTATUS_H_ #include #include #include namespace berry { /** * A status object represents the outcome of an operation. * All CoreExceptions carry a status object to indicate * what went wrong. Status objects are also returned by methods needing * to provide details of failures (e.g., validation methods). *

* A status carries the following information: *

* Some status objects, known as multi-statuses, have other status objects * as children. *

*

* The class Status is the standard public implementation * of status objects; the subclass MultiStatus is the * implements multi-status objects. *

* This interface can be used without OSGi running. *

* @see MultiStatus * @see Status */ struct org_blueberry_core_runtime_EXPORT IStatus: public Object { berryObjectMacro(berry::IStatus); enum Severity { /** Status severity constant (value 0) indicating this status represents the nominal case. * This constant is also used as the status code representing the nominal case. */ OK_TYPE = 0x00, /** Status type severity (bit mask, value 1) indicating this status is informational only. */ INFO_TYPE = 0x01, /** Status type severity (bit mask, value 2) indicating this status represents a warning. */ WARNING_TYPE = 0x02, /** Status type severity (bit mask, value 4) indicating this status represents an error. */ ERROR_TYPE = 0x04, - /** Status type severity (bit mask, value 8) indicating this status represents a cancelation. */ + /** Status type severity (bit mask, value 8) indicating this status represents a cancellation. */ CANCEL_TYPE = 0x08 }; Q_DECLARE_FLAGS(Severities, Severity) /** * Returns a list of status object immediately contained in this * multi-status, or an empty list if this is not a multi-status. * * @return an array of status objects * @see #IsMultiStatus() */ virtual QList GetChildren() const = 0; /** * Returns the plug-in-specific status code describing the outcome. * * @return plug-in-specific status code */ virtual int GetCode() const = 0; /** * Returns the relevant low-level exception, or null if none. * For example, when an operation fails because of a network communications * failure, this might return the java.io.IOException * describing the exact nature of that failure. * * @return the relevant low-level exception, or null if none */ virtual const ctkException* GetException() const = 0; /** * Returns the message describing the outcome. * The message is localized to the current locale. * * @return a localized message */ virtual QString GetMessage() const = 0; /** * Returns the unique identifier of the plug-in associated with this status * (this is the plug-in that defines the meaning of the status code). * * @return the unique identifier of the relevant plug-in */ virtual QString GetPlugin() const = 0; /** * Returns the severity. The severities are as follows (in * descending order): *
    - *
  • CANCEL_TYPE - cancelation occurred
  • + *
  • CANCEL_TYPE - cancellation occurred
  • *
  • ERROR_TYPE - a serious error (most severe)
  • *
  • WARNING_TYPE - a warning (less severe)
  • *
  • INFO_TYPE - an informational ("fyi") message (least severe)
  • *
  • OK_TYPE - everything is just fine
  • *
*

* The severity of a multi-status is defined to be the maximum * severity of any of its children, or OK if it has * no children. *

* * @return the severity: one of OK_TYPE, ERROR_TYPE, * INFO_TYPE, WARNING_TYPE, or CANCEL_TYPE */ virtual Severity GetSeverity() const = 0; /** * Returns whether this status is a multi-status. * A multi-status describes the outcome of an operation * involving multiple operands. *

* The severity of a multi-status is derived from the severities * of its children; a multi-status with no children is * OK_TYPE by definition. * A multi-status carries a plug-in identifier, a status code, * a message, and an optional exception. Clients may treat * multi-status objects in a multi-status unaware way. *

* * @return true for a multi-status, * false otherwise * @see #GetChildren() */ virtual bool IsMultiStatus() const = 0; /** * Returns whether this status indicates everything is okay * (neither info, warning, nor error). * * @return true if this status has severity * OK, and false otherwise */ virtual bool IsOK() const = 0; /** * Returns whether the severity of this status matches the given * severity mask. Note that a status with severity OK_TYPE * will never match; use isOK instead to detect * a status with a severity of OK. * * @param severityMask a mask formed by bitwise or'ing severity mask * constants (ERROR_TYPE, WARNING_TYPE, * INFO_TYPE, CANCEL_TYPE) * @return true if there is at least one match, * false if there are no matches * @see #GetSeverity() * @see #CANCEL_TYPE * @see #ERROR_TYPE * @see #WARNING_TYPE * @see #INFO_TYPE */ virtual bool Matches(const Severities& severityMask) const = 0; virtual QString GetFileName() const = 0; virtual QString GetMethodName() const = 0; virtual int GetLineNumber() const = 0; }; } Q_DECLARE_OPERATORS_FOR_FLAGS(berry::IStatus::Severities) #endif /* BERRYISTATUS_H_ */ diff --git a/Plugins/org.blueberry.core.runtime/src/berryObject.h b/Plugins/org.blueberry.core.runtime/src/berryObject.h index 325abc974d..513786dcd5 100644 --- a/Plugins/org.blueberry.core.runtime/src/berryObject.h +++ b/Plugins/org.blueberry.core.runtime/src/berryObject.h @@ -1,241 +1,241 @@ /*============================================================================ 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 BERRYOBJECT_H_ #define BERRYOBJECT_H_ #include #include "berryMacros.h" #include "berryMessage.h" #include #include #include #include #include #ifdef _MSC_VER // disable inheritance by dominance warnings #pragma warning( disable : 4250 4275 ) #endif class QDebug; class QTextStream; namespace berry { class org_blueberry_core_runtime_EXPORT Indent { public: /** Standard class typedefs. */ typedef Indent Self; /** Construct the object with an initial Indentation level. */ Indent(int ind = 0) { m_Indent=ind; } /** * Determine the next Indentation level. Keep Indenting by two until the * a maximum of forty spaces is reached. */ Indent GetNextIndent(); /** Print out the Indentation. Basically output a bunch of spaces. */ friend org_blueberry_core_runtime_EXPORT QDebug operator<<(QDebug os, const Indent& o); private: int m_Indent; }; /** \class Object * \brief Light weight base class for most BlueBerry classes. * * Object is copied from itk::LightObject and is the highest * level base class for most BlueBerry objects. It * implements reference counting and the API for object printing. * */ class org_blueberry_core_runtime_EXPORT Object { private: mutable Message<> m_DestroyMessage; public: typedef Object Self; typedef berry::SmartPointer Pointer; typedef berry::SmartPointer ConstPointer; typedef berry::WeakPointer WeakPtr; typedef berry::WeakPointer ConstWeakPtr; static const char* GetStaticClassName(); virtual QString GetClassName() const; static Reflection::TypeInfo GetStaticTypeInfo(); virtual Reflection::TypeInfo GetTypeInfo() const; static QList GetStaticSuperclasses(); virtual QList GetSuperclasses() const; /** Delete an BlueBerry object. This method should always be used to delete an * object when the new operator was used to create it. Using the C * delete method will not work with reference counting. */ virtual void Delete(); #ifdef _WIN32 /** Used to avoid dll boundary problems. */ void* operator new(size_t); void* operator new[](size_t); void operator delete(void*); void operator delete[](void*, size_t); #endif /** * Cause the object to print itself out. This is usually used to provide * detailed information about the object's state. It just calls the - * header/self/trailer virtual print methods, which can be overriden by + * header/self/trailer virtual print methods, which can be overridden by * subclasses. */ QDebug Print(QDebug os, Indent Indent=0) const; /** * Returns a string representation of this object. The default * implementation returns an empty string. */ virtual QString ToString() const; /** * Returns a hash code value for the object. */ virtual uint HashCode() const; /** * Override this method to implement a specific "less than" operator * for associative STL containers. */ virtual bool operator<(const Object*) const; /** Increase the reference count (mark as used by another object). */ void Register() const; /** Decrease the reference count (release by another object). * Set del to false if you do not want the object to be deleted if * the reference count is zero (use with care!) */ void UnRegister(bool del = true) const; /** Gets the reference count on this object. */ int GetReferenceCount() const { return m_ReferenceCount.load(); } /** Sets the reference count on this object. This is a dangerous * method, use it with care. */ void SetReferenceCount(int); inline void AddDestroyListener(const MessageAbstractDelegate<>& delegate) const { m_DestroyMessage += delegate; } inline void RemoveDestroyListener(const MessageAbstractDelegate<>& delegate) const { m_DestroyMessage -= delegate; } /** * A generic comparison method. Override this method in subclasses and * cast to your derived class to provide a more detailed comparison. */ virtual bool operator==(const Object*) const; #ifdef BLUEBERRY_DEBUG_SMARTPOINTER unsigned int GetTraceId() const; private: unsigned int m_TraceId; unsigned int& GetTraceIdCounter() const; public: #endif protected: friend struct QScopedPointerObjectDeleter; Object(); virtual ~Object(); /** * Methods invoked by Print() to print information about the object * including superclasses. Typically not called by the user (use Print() * instead) but used in the hierarchical print process to combine the * output of several classes. */ virtual QDebug PrintSelf(QDebug os, Indent indent) const; virtual QDebug PrintHeader(QDebug os, Indent indent) const; virtual QDebug PrintTrailer(QDebug os, Indent indent) const; /** Number of uses of this object by other objects. */ mutable QAtomicInt m_ReferenceCount; /** Mutex lock to protect modification to the reference count */ mutable QMutex m_ReferenceCountLock; private: Object(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; // A custom deleter for QScopedPointer // berry::Object instances in a QScopedPointer should have reference count one, // such that they are not accidentally deleted when a temporary smart pointer // pointing to it goes out of scope. This deleter fixes the reference count and // always deletes the instance. Use a berry::SmartPointer if the lifetime should // exceed the one of the pointer. struct QScopedPointerObjectDeleter { static inline void cleanup(Object* obj) { if (obj == nullptr) return; obj->UnRegister(false); delete obj; } }; org_blueberry_core_runtime_EXPORT QDebug operator<<(QDebug os, const berry::Indent& o); } /** * This operator allows all subclasses of Object to be printed via QDebug <<. * It in turn invokes the Print method, which in turn will invoke the * PrintSelf method that all objects should define, if they have anything * interesting to print out. */ org_blueberry_core_runtime_EXPORT QDebug operator<<(QDebug os, const berry::Object& o); org_blueberry_core_runtime_EXPORT QDebug operator<<(QDebug os, const berry::SmartPointer& o); org_blueberry_core_runtime_EXPORT QDebug operator<<(QDebug os, const berry::SmartPointer& o); org_blueberry_core_runtime_EXPORT QTextStream& operator<<(QTextStream& os, const berry::Object& o); org_blueberry_core_runtime_EXPORT QTextStream& operator<<(QTextStream& os, const berry::SmartPointer& o); //org_blueberry_core_runtime_EXPORT QTextStream& operator<<(QTextStream& os, const berry::SmartPointer& o); Q_DECLARE_METATYPE(berry::Object::Pointer) org_blueberry_core_runtime_EXPORT uint qHash(const berry::Object& o); #endif /*BERRYOBJECT_H_*/ diff --git a/Plugins/org.blueberry.core.runtime/src/berryPlatformObject.h b/Plugins/org.blueberry.core.runtime/src/berryPlatformObject.h index c36c7381eb..e89a1ace00 100755 --- a/Plugins/org.blueberry.core.runtime/src/berryPlatformObject.h +++ b/Plugins/org.blueberry.core.runtime/src/berryPlatformObject.h @@ -1,81 +1,81 @@ /*============================================================================ 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 BERRYPLATFORMOBJECT_H_ #define BERRYPLATFORMOBJECT_H_ #include #include #include "berryIAdaptable.h" namespace berry { /** * An abstract superclass implementing the IAdaptable * interface. getAdapter invocations are directed * to the platform's adapter manager. *

* Note: In situations where it would be awkward to subclass this * class, the same affect can be achieved simply by implementing * the IAdaptable interface and explicitly forwarding * the getAdapter request to the platform's - * adapater manager. The method would look like: + * adapter manager. The method would look like: *

  *     public Object getAdapter(Class adapter) {
  *         return Platform.getAdapterManager().getAdapter(this, adapter);
  *     }
  * 
*

*

* Clients may subclass. *

* * @see Platform#getAdapterManager */ class org_blueberry_core_runtime_EXPORT PlatformObject : public virtual Object, public virtual IAdaptable { public: berryObjectMacro(berry::PlatformObject); /** * Constructs a new platform object. */ PlatformObject(); /** * Returns an object which is an instance of the given class * associated with this object. Returns null if * no such object can be found. *

* This implementation of the method declared by IAdaptable * passes the request along to the platform's adapter manager; roughly * Platform.getAdapterManager().getAdapter(this, adapter). * Subclasses may override this method (however, if they do so, they * should invoke the method on their superclass to ensure that the * Platform's adapter manager is consulted). *

* * @see IAdaptable#getAdapter * @see Platform#getAdapterManager */ Object* GetAdapter(const QString& adapter) const override; }; } #endif /* BERRYPLATFORMOBJECT_H_ */ diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationContainer.h b/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationContainer.h index 45c092537d..778bce9295 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationContainer.h +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationContainer.h @@ -1,180 +1,180 @@ /*============================================================================ 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 BERRYAPPLICATIONCONTAINER_H #define BERRYAPPLICATIONCONTAINER_H #include #include #include #include #include struct ctkApplicationLauncher; struct ctkApplicationRunnable; namespace berry { struct IBranding; struct IExtensionRegistry; class ApplicationDescriptor; class ApplicationHandle; class MainApplicationLauncher; /* * This container will discover installed BlueBerry applications and register the * appropriate ctkApplicationDescriptor service with the service registry. */ class ApplicationContainer : public QObject, public QMutex, private IRegistryEventListener, private ctkServiceTrackerCustomizer { Q_OBJECT private: static const QString PI_RUNTIME; // = "org.blueberry.core.runtime"; static const QString PT_APPLICATIONS; // = "applications"; static const QString PT_APP_VISIBLE; // = "visible"; static const QString PT_APP_THREAD; // = "thread"; static const QString PT_APP_THREAD_ANY; // = "any"; static const QString PT_APP_CARDINALITY; // = "cardinality"; static const QString PT_APP_CARDINALITY_SINGLETON_GLOBAL; // = "singleton-global"; static const QString PT_APP_CARDINALITY_SINGLETON_SCOPED; // = "singleton-scoped"; static const QString PT_APP_CARDINALITY_UNLIMITED; // = "*"; static const QString PT_APP_ICON; // = "icon"; static const QString PT_PRODUCTS; // = "products"; static const QString EXT_ERROR_APP; // = "org.blueberry.core.runtime.app.error"; static const QString PROP_PRODUCT; // = "blueberry.product"; static const QString PROP_BLUEBERRY_APPLICATION; // = "blueberry.application"; static const QString PROP_BLUEBERRY_APPLICATION_LAUNCH_DEFAULT; // = "blueberry.application.launchDefault"; static const int NOT_LOCKED; // = 0; static const int LOCKED_SINGLETON_GLOBAL_RUNNING; // = 1; static const int LOCKED_SINGLETON_GLOBAL_APPS_RUNNING; // = 2; static const int LOCKED_SINGLETON_SCOPED_RUNNING; // = 3; static const int LOCKED_SINGLETON_LIMITED_RUNNING; // = 4; static const int LOCKED_MAIN_THREAD_RUNNING; // = 5; ctkPluginContext* context; QMutex lock; // A map of ApplicationDescriptors keyed by application ID /* @GuardedBy(lock) */ QHash apps; IExtensionRegistry* extensionRegistry; QScopedPointer> launcherTracker; mutable QScopedPointer branding; mutable bool missingProductReported; /* @GuardedBy(lock) */ QList activeHandles; // the currently active application handles /* @GuardedBy(lock) */ ApplicationHandle* activeMain; // the handle currently running on the main thread /* @GuardedBy(lock) */ ApplicationHandle* activeGlobalSingleton; // the current global singleton handle /* @GuardedBy(lock) */ ApplicationHandle* activeScopedSingleton; // the current scoped singleton handle /* @GuardedBy(lock) */ QHash > activeLimited; // Map of handles that have cardinality limits mutable QString defaultAppId; //DefaultApplicationListener defaultAppListener; ctkApplicationRunnable* defaultMainThreadAppHandle; // holds the default app handle to be run on the main thread volatile bool missingApp; QScopedPointer missingAppLauncher; public: ApplicationContainer(ctkPluginContext* context, IExtensionRegistry* extensionRegistry); ~ApplicationContainer() override; void Start(); void Stop(); IBranding* GetBranding() const; ctkPluginContext* GetContext() const; void Launch(ApplicationHandle* appHandle); void Lock(ApplicationHandle* appHandle); void Unlock(ApplicationHandle* appHandle); int IsLocked(const ApplicationDescriptor* eclipseApp) const; void StartDefaultApp(bool delayError); private: Q_DISABLE_COPY(ApplicationContainer) friend class ApplicationHandle; /* * Only used to find the default application */ ApplicationDescriptor* GetAppDescriptor(const QString& applicationId); ApplicationDescriptor* CreateAppDescriptor(const SmartPointer& appExtension); ApplicationDescriptor* RemoveAppDescriptor(const QString& applicationId); /* * Registers an ApplicationDescriptor service for each eclipse application * available in the extension registry. */ void RegisterAppDescriptors(); void RegisterAppDescriptor(const QString& applicationId); /* * Returns a list of all the available application IDs which are available * in the extension registry. */ QList > GetAvailableAppExtensions() const; QString GetAvailableAppsMsg() const; /* - * Returns the application extension for the specified applicaiton ID. + * Returns the application extension for the specified application ID. * A RuntimeException is thrown if the extension does not exist for the * given application ID. */ SmartPointer GetAppExtension(const QString& applicationId) const; Q_SLOT void PluginChanged(const ctkPluginEvent& event); void StopAllApps(); QString GetDefaultAppId() const; ctkApplicationLauncher* addingService(const ctkServiceReference& reference) override; void modifiedService(const ctkServiceReference& reference, ctkApplicationLauncher* service) override; void removedService(const ctkServiceReference& reference, ctkApplicationLauncher* service) override; void Added(const QList >& extensions) override; void Added(const QList >& extensionPoints) override; void Removed(const QList >& extensions) override; void Removed(const QList >& extensionPoints) override; void RefreshAppDescriptors(); }; } #endif // BERRYAPPLICATIONCONTAINER_H diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.cpp index d83da9b8cc..bd600d2bcc 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.cpp @@ -1,1340 +1,1340 @@ /*============================================================================ 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 "berryExtensionRegistry.h" #include "berryCombinedEventDelta.h" #include "berryConfigurationElement.h" #include "berryConfigurationElementAttribute.h" #include "berryConfigurationElementDescription.h" #include "berryExtension.h" #include "berryExtensionHandle.h" #include "berryExtensionPoint.h" #include "berryExtensionPointHandle.h" #include "berryExtensionsParser.h" #include "berryIConfigurationElement.h" #include "berryIExtension.h" #include "berryIExtensionPoint.h" #include "berrySimpleExtensionPointFilter.h" #include "berryMultiStatus.h" #include "berryRegistryConstants.h" #include "berryRegistryContribution.h" #include "berryRegistryContributor.h" #include "berryRegistryMessages.h" #include "berryRegistryObjectFactory.h" #include "berryRegistryObjectManager.h" #include "berryRegistryProperties.h" #include "berryRegistryStrategy.h" #include "berryStatus.h" #include #include namespace berry { struct ExtensionRegistry::ListenerInfo { IExtensionPointFilter filter; IRegistryEventListener* listener; ListenerInfo(IRegistryEventListener* listener, const IExtensionPointFilter& filter) : filter(filter), listener(listener) { } /** * Used by ListenerList to ensure uniqueness. */ bool operator==(const ListenerInfo& another) const { return another.listener == this->listener; } }; void ExtensionRegistry::Add(const SmartPointer &element) { QWriteLocker l(&access); eventDelta = CombinedEventDelta::RecordAddition(); BasicAdd(element, true); FireRegistryChangeEvent(); eventDelta.Reset(); } QString ExtensionRegistry::AddExtension(int extension) { Extension::Pointer addedExtension = registryObjects->GetObject(extension, RegistryObjectManager::EXTENSION).Cast(); QString extensionPointToAddTo = addedExtension->GetExtensionPointIdentifier(); ExtensionPoint::Pointer extPoint = registryObjects->GetExtensionPointObject(extensionPointToAddTo); //orphan extension if (extPoint.IsNull()) { registryObjects->AddOrphan(extensionPointToAddTo, extension); return QString(); } // otherwise, link them QList newExtensions = extPoint->GetRawChildren(); newExtensions.push_back(extension); Link(extPoint, newExtensions); if (!eventDelta.IsNull()) eventDelta.RememberExtension(extPoint, extension); return extPoint->GetNamespace(); //return RecordChange(extPoint, extension, ExtensionDelta::ADDED); } QString ExtensionRegistry::AddExtensionPoint(int extPoint) { ExtensionPoint::Pointer extensionPoint = registryObjects->GetObject(extPoint, RegistryObjectManager::EXTENSION_POINT).Cast(); if (!eventDelta.IsNull()) eventDelta.RememberExtensionPoint(extensionPoint); QList orphans = registryObjects->RemoveOrphans(extensionPoint->GetUniqueIdentifier()); if (orphans.empty()) return QString(); Link(extensionPoint, orphans); if (!eventDelta.IsNull()) eventDelta.RememberExtensions(extensionPoint, orphans); return extensionPoint->GetNamespace(); //return RecordChange(extensionPoint, orphans, ExtensionDelta::ADDED); } QSet ExtensionRegistry::AddExtensionsAndExtensionPoints(const SmartPointer& element) { // now add and resolve extensions and extension points QSet affectedNamespaces; QList extPoints = element->GetExtensionPoints(); for (int i = 0; i < extPoints.size(); i++) { QString namespaze = this->AddExtensionPoint(extPoints[i]); if (!namespaze.isEmpty()) affectedNamespaces.insert(namespaze); } QList extensions = element->GetExtensions(); for (int i = 0; i < extensions.size(); i++) { QString namespaze = this->AddExtension(extensions[i]); if (!namespaze.isEmpty()) affectedNamespaces.insert(namespaze); } return affectedNamespaces; } void ExtensionRegistry::AddListenerInternal(IRegistryEventListener* listener, const IExtensionPointFilter& filter) { listeners.Add(ListenerInfo(listener, filter)); } void ExtensionRegistry::BasicAdd(const SmartPointer& element, bool link) { registryObjects->AddContribution(element); if (!link) return; AddExtensionsAndExtensionPoints(element); SetObjectManagers(registryObjects->CreateDelegatingObjectManager( registryObjects->GetAssociatedObjects(element->GetContributorId()))); } void ExtensionRegistry::SetObjectManagers(const SmartPointer& manager) { if (!eventDelta.IsNull()) eventDelta.SetObjectManager(manager); } void ExtensionRegistry::BasicRemove(const QString& contributorId) { // ignore anonymous namespaces RemoveExtensionsAndExtensionPoints(contributorId); QHash associatedObjects = registryObjects->GetAssociatedObjects(contributorId); registryObjects->RemoveObjects(associatedObjects); registryObjects->AddNavigableObjects(associatedObjects); // put the complete set of navigable objects SetObjectManagers(registryObjects->CreateDelegatingObjectManager(associatedObjects)); registryObjects->RemoveContribution(contributorId); registryObjects->RemoveContributor(contributorId); } void ExtensionRegistry::FireRegistryChangeEvent() { // if there is nothing to say, just bail out if (listeners.IsEmpty()) { return; } // for thread safety, create tmp collections QList tmpListeners = listeners.GetListeners(); // do the notification asynchronously //strategy->ScheduleChangeEvent(tmpListeners, tmpDeltas, this); this->ScheduleChangeEvent(tmpListeners, eventDelta); } //RegistryDelta ExtensionRegistry::GetDelta(const QString& namespaze) const //{ // // is there a delta for the plug-in? // RegistryDelta existingDelta = deltas.value(namespaze); // if (existingDelta != null) // return existingDelta; // //if not, create one // RegistryDelta delta = new RegistryDelta(); // deltas.put(namespace, delta); // return delta; //} void ExtensionRegistry::Link(const SmartPointer& extPoint, const QList& extensions) { extPoint->SetRawChildren(extensions); registryObjects->Add(extPoint, true); } //QString ExtensionRegistry::RecordChange(const SmartPointer& extPoint, int extension, int kind) //{ // // avoid computing deltas when there are no listeners // if (listeners.isEmpty()) // return QString(); // ExtensionDelta extensionDelta = new ExtensionDelta(); // extensionDelta.setExtension(extension); // extensionDelta.setExtensionPoint(extPoint.getObjectId()); // extensionDelta.setKind(kind); // getDelta(extPoint.getNamespace()).addExtensionDelta(extensionDelta); // return extPoint.getNamespace(); //} //QString ExtensionRegistry::RecordChange(const SmartPointer& extPoint, const QList& extensions, int kind) //{ // if (listeners.isEmpty()) // return null; // QString namespace = extPoint.getNamespace(); // if (extensions == null || extensions.length == 0) // return namespace; // RegistryDelta pluginDelta = getDelta(extPoint.getNamespace()); // for (int i = 0; i < extensions.length; i++) { // ExtensionDelta extensionDelta = new ExtensionDelta(); // extensionDelta.setExtension(extensions[i]); // extensionDelta.setExtensionPoint(extPoint.getObjectId()); // extensionDelta.setKind(kind); // pluginDelta.addExtensionDelta(extensionDelta); // } // return namespace; //} QString ExtensionRegistry::RemoveExtension(int extensionId) { Extension::Pointer extension = registryObjects->GetObject(extensionId, RegistryObjectManager::EXTENSION).Cast(); registryObjects->RemoveExtensionFromNamespaceIndex(extensionId, extension->GetNamespaceIdentifier()); QString xptName = extension->GetExtensionPointIdentifier(); ExtensionPoint::Pointer extPoint = registryObjects->GetExtensionPointObject(xptName); if (extPoint.IsNull()) { registryObjects->RemoveOrphan(xptName, extensionId); return QString(); } // otherwise, unlink the extension from the extension point QList existingExtensions = extPoint->GetRawChildren(); QList newExtensions; if (existingExtensions.size() > 1) { for (int i = 0; i < existingExtensions.size(); ++i) if (existingExtensions[i] != extension->GetObjectId()) newExtensions.push_back(existingExtensions[i]); } Link(extPoint, newExtensions); if (!eventDelta.IsNull()) eventDelta.RememberExtension(extPoint, extensionId); return extPoint->GetNamespace(); //return recordChange(extPoint, extension.getObjectId(), IExtensionDelta.REMOVED); } QString ExtensionRegistry::RemoveExtensionPoint(int extPoint) { ExtensionPoint::Pointer extensionPoint = registryObjects->GetObject( extPoint, RegistryObjectManager::EXTENSION_POINT).Cast(); registryObjects->RemoveExtensionPointFromNamespaceIndex(extPoint, extensionPoint->GetNamespace()); QList existingExtensions = extensionPoint->GetRawChildren(); if (!existingExtensions.empty()) { registryObjects->AddOrphans(extensionPoint->GetUniqueIdentifier(), existingExtensions); Link(extensionPoint, QList()); } if (!eventDelta.IsNull()) { eventDelta.RememberExtensionPoint(extensionPoint); eventDelta.RememberExtensions(extensionPoint, existingExtensions); } return extensionPoint->GetNamespace(); //return recordChange(extensionPoint, existingExtensions, IExtensionDelta.REMOVED); } QSet ExtensionRegistry::RemoveExtensionsAndExtensionPoints(const QString& contributorId) { QSet affectedNamespaces; QList extensions = registryObjects->GetExtensionsFrom(contributorId); for (int i = 0; i < extensions.size(); i++) { QString namespaze = this->RemoveExtension(extensions[i]); if (!namespaze.isEmpty()) affectedNamespaces.insert(namespaze); } // remove extension points QList extPoints = registryObjects->GetExtensionPointsFrom(contributorId); for (int i = 0; i < extPoints.size(); i++) { QString namespaze = this->RemoveExtensionPoint(extPoints[i]); if (!namespaze.isEmpty()) affectedNamespaces.insert(namespaze); } return affectedNamespaces; } struct ExtensionRegistry::QueueElement { QList listenerInfos; CombinedEventDelta scheduledDelta; QueueElement() { } QueueElement(const QList& infos, const CombinedEventDelta& delta) : listenerInfos(infos), scheduledDelta(delta) { } }; class ExtensionRegistry::RegistryEventThread : public QThread { private: QAtomicInt stop; ExtensionRegistry* registry; Queue& queue; public: RegistryEventThread(ExtensionRegistry* registry, Queue& queue) : stop(0), registry(registry), queue(queue) { this->setObjectName("Extension Registry Event Dispatcher"); } void interrupt() { stop.fetchAndStoreOrdered(1); } void run() override { while (!stop.fetchAndAddOrdered(0)) { QueueElement element; { Queue::Locker l(&queue); while (queue.empty()) queue.wait(); element = queue.takeFirst(); } registry->ProcessChangeEvent(element.listenerInfos, element.scheduledDelta); } } }; bool ExtensionRegistry::CheckReadWriteAccess(QObject* key, bool persist) const { if (masterToken == key) return true; if (userToken == key && !persist) return true; return false; } void ExtensionRegistry::LogError(const QString& owner, const QString& contributionName, const ctkException& e) { QString message = QString("Could not parse XML contribution for \"%1\". Any contributed extensions " "and extension points will be ignored.").arg(QString(owner) + "/" + contributionName); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, message, e, BERRY_STATUS_LOC)); Log(status); } void ExtensionRegistry::CreateExtensionData(const QString& contributorId, const ConfigurationElementDescription& description, const SmartPointer& parent, bool persist) { ConfigurationElement::Pointer currentConfigurationElement = GetElementFactory()->CreateConfigurationElement(persist); currentConfigurationElement->SetContributorId(contributorId); currentConfigurationElement->SetName(description.GetName()); QList descriptionProperties = description.GetAttributes(); QList properties; if (!descriptionProperties.empty()) { for (int i = 0; i < descriptionProperties.size(); i++) { properties.push_back(descriptionProperties[i].GetName()); properties.push_back(Translate(descriptionProperties[i].GetValue(), nullptr)); } } currentConfigurationElement->SetProperties(properties); QString value = description.GetValue(); if (!value.isEmpty()) currentConfigurationElement->SetValue(value); GetObjectManager()->Add(currentConfigurationElement, true); // process children QList children = description.GetChildren(); if (!children.empty()) { for (int i = 0; i < children.size(); i++) { CreateExtensionData(contributorId, children[i], currentConfigurationElement, persist); } } QList newValues = parent->GetRawChildren(); newValues.push_back(currentConfigurationElement->GetObjectId()); parent->SetRawChildren(newValues); currentConfigurationElement->SetParentId(parent->GetObjectId()); currentConfigurationElement->SetParentType(parent.Cast() ? RegistryObjectManager::CONFIGURATION_ELEMENT : RegistryObjectManager::EXTENSION); } bool ExtensionRegistry::RemoveObject(const SmartPointer& registryObject, bool isExtensionPoint, QObject* token) { if (!CheckReadWriteAccess(token, registryObject->ShouldPersist())) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry.removeExtension() method. Check if proper access token is supplied."); int id = registryObject->GetObjectId(); QWriteLocker l(&access); eventDelta = CombinedEventDelta::RecordRemoval(); if (isExtensionPoint) { RemoveExtensionPoint(id); } else { RemoveExtension(id); } QHash removed; removed.insert(id, registryObject); // There is some asymmetry between extension and extension point removal. Removing extension point makes // extensions "orphans" but does not remove them. As a result, only extensions needs to be processed. if (!isExtensionPoint) { registryObjects->AddAssociatedObjects(removed, registryObject); } registryObjects->RemoveObjects(removed); registryObjects->AddNavigableObjects(removed); IObjectManager::Pointer manager = registryObjects->CreateDelegatingObjectManager(removed); //GetDelta(namespaze)->SetObjectManager(manager); //eventDelta->SetObjectManager(manager); registryObjects->UnlinkChildFromContributions(id); FireRegistryChangeEvent(); eventDelta.Reset(); return true; } void ExtensionRegistry::SetFileManager(const QString& /*cacheBase*/, bool /*isCacheReadOnly*/) { // if (cacheStorageManager != nullptr) // cacheStorageManager->Close(); // close existing file manager first // if (cacheBase != null) { // cacheStorageManager = new StorageManager(cacheBase, isCacheReadOnly ? "none" : null, isCacheReadOnly); //$NON-NLS-1$ // try { // cacheStorageManager.open(!isCacheReadOnly); // } catch (IOException e) { // // Ignore the exception. The registry will be rebuilt from source. // } // } } void ExtensionRegistry::EnterRead() { access.lockForRead(); } void ExtensionRegistry::ExitRead() { access.unlock(); } void ExtensionRegistry::SetElementFactory() { if (isMultiLanguage) { throw ctkRuntimeException("Multi-language registry not supported yet."); //theRegistryObjectFactory = new RegistryObjectFactoryMulti(this); } else { theRegistryObjectFactory.reset(new RegistryObjectFactory(this)); } } //TableReader ExtensionRegistry::getTableReader() const //{ // return theTableReader; //} bool ExtensionRegistry::CheckCache() { // for (int index = 0; index < strategy.getLocationsLength(); index++) { // File possibleCacheLocation = strategy.getStorage(index); // if (possibleCacheLocation == null) // break; // bail out on the first null // setFileManager(possibleCacheLocation, strategy.isCacheReadOnly(index)); // if (cacheStorageManager != null) { // // check this new location: // File cacheFile = null; // try { // cacheFile = cacheStorageManager.lookup(TableReader.getTestFileName(), false); // } catch (IOException e) { // //Ignore the exception. The registry will be rebuilt from the xml files. // } // if (cacheFile != null && cacheFile.isFile()) // return true; // found the appropriate location // } // } return false; } void ExtensionRegistry::StopChangeEventScheduler() { if (!eventThread.isNull()) { Queue::Locker l(&queue); eventThread->interrupt(); eventThread->wait(); eventThread.reset(); } } SmartPointer ExtensionRegistry::GetObjectManager() const { return registryObjects; } void ExtensionRegistry::AddListener(IRegistryEventListener* listener, const QString& extensionPointId) { AddListenerInternal(listener, extensionPointId.isEmpty() ? IExtensionPointFilter(nullptr) : IExtensionPointFilter(new SimpleExtensionPointFilter(extensionPointId))); } void ExtensionRegistry::AddListener(IRegistryEventListener* listener, const IExtensionPointFilter& filter) { this->AddListenerInternal(listener, filter); } QList > ExtensionRegistry::GetConfigurationElementsFor(const QString& extensionPointId) const { // this is just a convenience API - no need to do any sync'ing here int lastdot = extensionPointId.lastIndexOf('.'); if (lastdot == -1) { QList(); } return GetConfigurationElementsFor(extensionPointId.left(lastdot), extensionPointId.mid(lastdot + 1)); } QList > ExtensionRegistry::GetConfigurationElementsFor(const QString& pluginId, const QString& extensionPointSimpleId) const { // this is just a convenience API - no need to do any sync'ing here IExtensionPoint::Pointer extPoint = this->GetExtensionPoint(pluginId, extensionPointSimpleId); if (extPoint.IsNull()) return QList(); return extPoint->GetConfigurationElements(); } QList > ExtensionRegistry::GetConfigurationElementsFor(const QString& pluginId, const QString& extensionPointName, const QString& extensionId) const { // this is just a convenience API - no need to do any sync'ing here IExtension::Pointer extension = this->GetExtension(pluginId, extensionPointName, extensionId); if (extension.IsNull()) return QList(); return extension->GetConfigurationElements(); } SmartPointer ExtensionRegistry::GetExtension(const QString& extensionId) const { if (extensionId.isEmpty()) return IExtension::Pointer(); int lastdot = extensionId.lastIndexOf('.'); if (lastdot == -1) return IExtension::Pointer(); QString namespaze = extensionId.left(lastdot); QList extensions; { QReadLocker l(&access); extensions = registryObjects->GetExtensionsFromNamespace(namespaze); } for (int i = 0; i < extensions.size(); i++) { ExtensionHandle::Pointer suspect = extensions[i]; if (extensionId == suspect->GetUniqueIdentifier()) return suspect; } return IExtension::Pointer(); } SmartPointer ExtensionRegistry::GetExtension(const QString& extensionPointId, const QString& extensionId) const { // this is just a convenience API - no need to do any sync'ing here int lastdot = extensionPointId.lastIndexOf('.'); if (lastdot == -1) return IExtension::Pointer(); return GetExtension(extensionPointId.left(lastdot), extensionPointId.mid(lastdot + 1), extensionId); } SmartPointer ExtensionRegistry::GetExtension(const QString& pluginId, const QString& extensionPointName, const QString& extensionId) const { // this is just a convenience API - no need to do any sync'ing here IExtensionPoint::Pointer extPoint = GetExtensionPoint(pluginId, extensionPointName); if (extPoint.IsNotNull()) return extPoint->GetExtension(extensionId); return IExtension::Pointer(); } SmartPointer ExtensionRegistry::GetExtensionPoint(const QString& xptUniqueId) const { QReadLocker l(&access); return registryObjects->GetExtensionPointHandle(xptUniqueId); } SmartPointer ExtensionRegistry::GetExtensionPoint(const QString& elementName, const QString& xpt) const { QReadLocker l(&access); return registryObjects->GetExtensionPointHandle(elementName + '.' + xpt); } QList > ExtensionRegistry::GetExtensionPoints() const { QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionPointsHandles(); } QList result; foreach(ExtensionPointHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList > ExtensionRegistry::GetExtensionPoints(const QString& namespaceName) const { QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionPointsFromNamespace(namespaceName); } QList result; foreach(ExtensionPointHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList > ExtensionRegistry::GetExtensions(const QString& namespaceName) const { QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionsFromNamespace(namespaceName); } QList result; foreach (ExtensionHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList > ExtensionRegistry::GetExtensions(const SmartPointer& contributor) const { RegistryContributor::Pointer regContributor = contributor.Cast(); if (regContributor.IsNull()) throw ctkInvalidArgumentException("Contributor must be a RegistryContributor."); // should never happen QString contributorId = regContributor->GetActualId(); QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionsFromContributor(contributorId); } QList result; foreach (ExtensionHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList > ExtensionRegistry::GetExtensionPoints(const SmartPointer& contributor) const { RegistryContributor::Pointer regContributor = contributor.Cast(); if (regContributor.IsNull()) throw ctkInvalidArgumentException("Contributor must be a RegistryContributor."); // should never happen QString contributorId = regContributor->GetActualId(); QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionPointsFromContributor(contributorId); } QList result; foreach (ExtensionPointHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList ExtensionRegistry::GetNamespaces() const { QReadLocker l(&access); QList namespaceElements = registryObjects->GetNamespacesIndex().Elements(); QList namespaceNames; for (int i = 0; i < namespaceElements.size(); i++) { namespaceNames.push_back(namespaceElements[i]->GetKey()); } return namespaceNames; } bool ExtensionRegistry::HasContributor(const SmartPointer& contributor) const { RegistryContributor::Pointer regContributor = contributor.Cast(); if (regContributor.IsNull()) throw ctkInvalidArgumentException("Contributor must be a RegistryContributor."); // should never happen QString contributorId = regContributor->GetActualId(); return HasContributor(contributorId); } bool ExtensionRegistry::HasContributor(const QString& contributorId) const { QReadLocker l(&access); return registryObjects->HasContribution(contributorId); } void ExtensionRegistry::Remove(const QString& removedContributorId, long timestamp) { Remove(removedContributorId); if (timestamp != 0) aggregatedTimestamp.Remove(timestamp); } void ExtensionRegistry::RemoveContributor(const SmartPointer& contributor, QObject* key) { RegistryContributor::Pointer regContributor = contributor.Cast(); if (regContributor.IsNull()) throw ctkInvalidArgumentException("Contributor must be a RegistryContributor."); // should never happen if (!CheckReadWriteAccess(key, true)) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry.removeContributor() method. Check if proper access token is supplied."); QString contributorId = regContributor->GetActualId(); Remove(contributorId); } void ExtensionRegistry::Remove(const QString& removedContributorId) { QWriteLocker l(&access); eventDelta = CombinedEventDelta::RecordRemoval(); BasicRemove(removedContributorId); FireRegistryChangeEvent(); eventDelta.Reset(); } void ExtensionRegistry::RemoveListener(IRegistryEventListener* listener) { listeners.Remove(ListenerInfo(listener, IExtensionPointFilter(nullptr))); } ExtensionRegistry::ExtensionRegistry(RegistryStrategy* registryStrategy, QObject* masterToken, QObject* userToken) : registryObjects(nullptr), isMultiLanguage(false), mlErrorLogged(false), eventThread(nullptr) { isMultiLanguage = RegistryProperties::GetProperty(RegistryConstants::PROP_REGISTRY_MULTI_LANGUAGE) == "true"; if (registryStrategy != nullptr) strategy.reset(registryStrategy); else strategy.reset(new RegistryStrategy(QList(), QList(), nullptr)); this->masterToken = masterToken; this->userToken = userToken; registryObjects = new RegistryObjectManager(this); bool isRegistryFilledFromCache = false; // indicates if registry was able to use cache to populate it's content if (strategy->CacheUse()) { // Try to read the registry from the cache first. If that fails, create a new registry QTime timer; if (Debug()) timer.start(); //The cache is made of several files, find the real names of these other files. If all files are found, try to initialize the objectManager if (CheckCache()) { // TODO Registry Cache // try { // theTableReader.setTableFile(cacheStorageManager.lookup(TableReader.TABLE, false)); // theTableReader.setExtraDataFile(cacheStorageManager.lookup(TableReader.EXTRA, false)); // theTableReader.setMainDataFile(cacheStorageManager.lookup(TableReader.MAIN, false)); // theTableReader.setContributionsFile(cacheStorageManager.lookup(TableReader.CONTRIBUTIONS, false)); // theTableReader.setContributorsFile(cacheStorageManager.lookup(TableReader.CONTRIBUTORS, false)); // theTableReader.setNamespacesFile(cacheStorageManager.lookup(TableReader.NAMESPACES, false)); // theTableReader.setOrphansFile(cacheStorageManager.lookup(TableReader.ORPHANS, false)); // long timestamp = strategy.getContributionsTimestamp(); // isRegistryFilledFromCache = registryObjects.init(timestamp); // if (isRegistryFilledFromCache) // aggregatedTimestamp.set(timestamp); // } catch (IOException e) { // // The registry will be rebuilt from the xml files. Make sure to clear anything filled // // from cache so that we won't have partially filled items. // isRegistryFilledFromCache = false; // clearRegistryCache(); // log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, RegistryMessages.registry_bad_cache, e)); // } } // if (!isRegistryFilledFromCache) // { // // set cache storage manager to a first writable location // for (int index = 0; index < strategy.getLocationsLength(); index++) { // if (!strategy.isCacheReadOnly(index)) { // setFileManager(strategy.getStorage(index), false); // break; // } // } // } if (Debug() && isRegistryFilledFromCache) BERRY_INFO << "Reading registry cache: " << timer.elapsed() << "ms"; if (Debug()) { if (!isRegistryFilledFromCache) BERRY_INFO << "Reloading registry from manifest files..."; else BERRY_INFO << "Using registry cache..."; } } if (DebugEvents()) { struct DebugRegistryListener : public IRegistryEventListener { void Added(const QList& extensions) override { BERRY_INFO << "Registry extensions ADDED:"; foreach(IExtension::Pointer extension, extensions) { BERRY_INFO << "\t" << extension->GetExtensionPointUniqueIdentifier() << " - " << extension->GetNamespaceIdentifier() << "." << extension->GetSimpleIdentifier(); } } void Removed(const QList& extensions) override { BERRY_INFO << "Registry extensions REMOVED:"; foreach(IExtension::Pointer extension, extensions) { BERRY_INFO << "\t" << extension->GetExtensionPointUniqueIdentifier() << " - " << extension->GetNamespaceIdentifier() << "." << extension->GetSimpleIdentifier(); } } void Added(const QList& extensionPoints) override { BERRY_INFO << "Registry extension-points ADDED:"; foreach(IExtensionPoint::Pointer extensionPoint, extensionPoints) { BERRY_INFO << "\t" << extensionPoint->GetUniqueIdentifier(); } } void Removed(const QList& extensionPoints) override { BERRY_INFO << "Registry extension-points REMOVED:"; foreach(IExtensionPoint::Pointer extensionPoint, extensionPoints) { BERRY_INFO << "\t" << extensionPoint->GetUniqueIdentifier(); } } }; debugRegistryListener.reset(new DebugRegistryListener()); AddListener(debugRegistryListener.data()); } // Do extra start processing if specified in the registry strategy strategy->OnStart(this, isRegistryFilledFromCache); } ExtensionRegistry::~ExtensionRegistry() { } void ExtensionRegistry::Stop(QObject* /*key*/) { // If the registry creator specified a key token, check that the key mathches it - // (it is assumed that registry owner keeps the key to prevent unautorized accesss). + // (it is assumed that registry owner keeps the key to prevent unautorized access). if (masterToken != nullptr && masterToken != nullptr) { throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry.stop() method. Check if proper access token is supplied."); //$NON-NLS-1$ } // Do extra stop processing if specified in the registry strategy strategy->OnStop(this); StopChangeEventScheduler(); // if (cacheStorageManager == nullptr) // return; // if (!registryObjects.isDirty() || cacheStorageManager.isReadOnly()) { // cacheStorageManager.close(); // theTableReader.close(); // return; // } // File tableFile = null; // File mainFile = null; // File extraFile = null; // File contributionsFile = null; // File contributorsFile = null; // File namespacesFile = null; // File orphansFile = null; // TableWriter theTableWriter = new TableWriter(this); // try { // cacheStorageManager.lookup(TableReader.TABLE, true); // cacheStorageManager.lookup(TableReader.MAIN, true); // cacheStorageManager.lookup(TableReader.EXTRA, true); // cacheStorageManager.lookup(TableReader.CONTRIBUTIONS, true); // cacheStorageManager.lookup(TableReader.CONTRIBUTORS, true); // cacheStorageManager.lookup(TableReader.NAMESPACES, true); // cacheStorageManager.lookup(TableReader.ORPHANS, true); // tableFile = File.createTempFile(TableReader.TABLE, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // mainFile = File.createTempFile(TableReader.MAIN, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // extraFile = File.createTempFile(TableReader.EXTRA, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // contributionsFile = File.createTempFile(TableReader.CONTRIBUTIONS, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // contributorsFile = File.createTempFile(TableReader.CONTRIBUTORS, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // namespacesFile = File.createTempFile(TableReader.NAMESPACES, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // orphansFile = File.createTempFile(TableReader.ORPHANS, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // theTableWriter.setTableFile(tableFile); // theTableWriter.setExtraDataFile(extraFile); // theTableWriter.setMainDataFile(mainFile); // theTableWriter.setContributionsFile(contributionsFile); // theTableWriter.setContributorsFile(contributorsFile); // theTableWriter.setNamespacesFile(namespacesFile); // theTableWriter.setOrphansFile(orphansFile); // } catch (IOException e) { // cacheStorageManager.close(); // return; //Ignore the exception since we can recompute the cache // } // try { // long timestamp; // // A bit of backward compatibility: if registry was modified, but timestamp was not, // // it means that the new timestamp tracking mechanism was not used. In this case // // explicitly obtain timestamps for all contributions. Note that this logic // // maintains a problem described in the bug 104267 for contributions that // // don't use the timestamp tracking mechanism. // if (aggregatedTimestamp.isModifed()) // timestamp = aggregatedTimestamp.getContentsTimestamp(); // use timestamp tracking // else // timestamp = strategy.getContributionsTimestamp(); // use legacy approach // if (theTableWriter.saveCache(registryObjects, timestamp)) // cacheStorageManager.update(new QString[] {TableReader.TABLE, TableReader.MAIN, TableReader.EXTRA, TableReader.CONTRIBUTIONS, TableReader.CONTRIBUTORS, TableReader.NAMESPACES, TableReader.ORPHANS}, new QString[] {tableFile.getName(), mainFile.getName(), extraFile.getName(), contributionsFile.getName(), contributorsFile.getName(), namespacesFile.getName(), orphansFile.getName()}); // } catch (IOException e) { // //Ignore the exception since we can recompute the cache // } // theTableReader.close(); // cacheStorageManager.close(); } void ExtensionRegistry::ClearRegistryCache() { // QString[] keys = new QString[] {TableReader.TABLE, TableReader.MAIN, TableReader.EXTRA, TableReader.CONTRIBUTIONS, TableReader.ORPHANS}; // for (int i = 0; i < keys.length; i++) // try { // cacheStorageManager.remove(keys[i]); // } catch (IOException e) { // log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, IStatus.ERROR, RegistryMessages.meta_registryCacheReadProblems, e)); // } aggregatedTimestamp.Reset(); } RegistryObjectFactory* ExtensionRegistry::GetElementFactory() { if (theRegistryObjectFactory.isNull()) SetElementFactory(); return theRegistryObjectFactory.data(); } void ExtensionRegistry::Log(const SmartPointer& status) const { strategy->Log(status); } QString ExtensionRegistry::Translate(const QString& key, QTranslator* resources) const { if (isMultiLanguage) return key; return strategy->Translate(key, resources); } bool ExtensionRegistry::Debug() const { return strategy->Debug(); } bool ExtensionRegistry::DebugEvents() const { return strategy->DebugRegistryEvents(); } bool ExtensionRegistry::UseLazyCacheLoading() const { return strategy->CacheLazyLoading(); } long ExtensionRegistry::ComputeState() const { return strategy->GetContainerTimestamp(); } QObject* ExtensionRegistry::CreateExecutableExtension(const SmartPointer& defaultContributor, const QString& className, const QString& requestedContributorName) { return strategy->CreateExecutableExtension(defaultContributor, className, requestedContributorName); } void ExtensionRegistry::ProcessChangeEvent( const QList& listenerInfos, const CombinedEventDelta& scheduledDelta) { for (int i = 0; i < listenerInfos.size(); i++) { const ListenerInfo& listenerInfo = listenerInfos[i]; IRegistryEventListener* extensionListener = listenerInfo.listener; QList extensions = scheduledDelta.GetExtensions(listenerInfo.filter); QList extensionPoints = scheduledDelta.GetExtensionPoints(listenerInfo.filter); // notification order - on addition: extension points; then extensions if (scheduledDelta.IsAddition()) { if (!extensionPoints.empty()) extensionListener->Added(extensionPoints); if (!extensions.empty()) extensionListener->Added(extensions); } else { // on removal: extensions; then extension points if (!extensions.empty()) extensionListener->Removed(extensions); if (!extensionPoints.empty()) extensionListener->Removed(extensionPoints); } } IObjectManager::Pointer manager = scheduledDelta.GetObjectManager(); if (manager.IsNotNull()) manager->Close(); } void ExtensionRegistry::ScheduleChangeEvent(const QList& listenerInfos, const CombinedEventDelta& scheduledDelta) { QueueElement newElement(listenerInfos, scheduledDelta); if (eventThread.isNull()) { eventThread.reset(new RegistryEventThread(this, queue)); eventThread->start(); } { Queue::Locker l(&queue); queue.push_back(newElement); queue.notify(); } } bool ExtensionRegistry::AddContribution(QIODevice* is, const SmartPointer& contributor, bool persist, const QString& contributionName, QTranslator* translationBundle, QObject* key, long timestamp) { bool result = AddContribution(is, contributor, persist, contributionName, translationBundle, key); if (timestamp != 0) aggregatedTimestamp.Add(timestamp); return result; } bool ExtensionRegistry::AddContribution(QIODevice* is, const SmartPointer& contributor, bool persist, const QString& contributionName, QTranslator* translationBundle, QObject* key) { if (!CheckReadWriteAccess(key, persist)) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry::AddContribution() method. Check if proper access token is supplied."); RegistryContributor::Pointer internalContributor = contributor.Cast(); registryObjects->AddContributor(internalContributor); // only adds a contributor if it is not already present QString ownerName = internalContributor->GetActualName(); QString message = QString("Problems parsing plug-in manifest for: \"%1\".").arg(ownerName); MultiStatus::Pointer problems(new MultiStatus(RegistryMessages::OWNER_NAME, ExtensionsParser::PARSE_PROBLEM, message, BERRY_STATUS_LOC)); ExtensionsParser parser(problems, this); RegistryContribution::Pointer contribution = GetElementFactory()->CreateContribution(internalContributor->GetActualId(), persist); try { QXmlInputSource xmlInput(is); bool success = parser.parseManifest(strategy->GetXMLParser(), &xmlInput, contributionName, GetObjectManager().GetPointer(), contribution, translationBundle); int status = problems->GetSeverity(); if (status != IStatus::OK_TYPE || !success) { Log(problems); if (status == IStatus::ERROR_TYPE || status == IStatus::CANCEL_TYPE || !success) return false; } } catch (const ctkException& e) { LogError(ownerName, contributionName, e); return false; } Add(contribution); // the add() method does synchronization return true; } bool ExtensionRegistry::AddExtensionPoint(const QString& identifier, const SmartPointer& contributor, bool persist, const QString& label, const QString& schemaReference, QObject* token) { if (!CheckReadWriteAccess(token, persist)) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry::AddExtensionPoint() method. Check if proper access token is supplied."); RegistryContributor::Pointer internalContributor = contributor.Cast(); registryObjects->AddContributor(internalContributor); // only adds a contributor if it is not already present QString contributorId = internalContributor->GetActualId(); // Extension point Id might not be null if (identifier.isEmpty()) { QString message = QString("Missing ID for the extension point \"%1\". Element ignored.").arg(label); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, message, BERRY_STATUS_LOC)); Log(status); } // addition wraps in a contribution RegistryContribution::Pointer contribution = GetElementFactory()->CreateContribution(contributorId, persist); ExtensionPoint::Pointer currentExtPoint = GetElementFactory()->CreateExtensionPoint(persist); QString uniqueId; QString namespaceName; int simpleIdStart = identifier.lastIndexOf('.'); if (simpleIdStart == -1) { namespaceName = contribution->GetDefaultNamespace(); uniqueId = namespaceName + '.' + identifier; } else { namespaceName = identifier.left(simpleIdStart); uniqueId = identifier; } currentExtPoint->SetUniqueIdentifier(uniqueId); currentExtPoint->SetNamespace(namespaceName); QString labelNLS = Translate(label, nullptr); currentExtPoint->SetLabel(labelNLS); currentExtPoint->SetSchema(schemaReference); if (!GetObjectManager()->AddExtensionPoint(currentExtPoint, true)) { if (Debug()) { QString msg = QString("Ignored duplicate extension point \"%1\" supplied by \"%2\".").arg(uniqueId).arg(contribution->GetDefaultNamespace()); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, msg, BERRY_STATUS_LOC)); Log(status); } return false; } currentExtPoint->SetContributorId(contributorId); // array format: {Number of extension points, Number of extensions, Extension Id} QList contributionChildren; // Put the extension points into this namespace contributionChildren.push_back(1); contributionChildren.push_back(0); contributionChildren.push_back(currentExtPoint->GetObjectId()); contribution->SetRawChildren(contributionChildren); Add(contribution); return true; } bool ExtensionRegistry::AddExtension(const QString& identifier, const SmartPointer& contributor, bool persist, const QString& label, const QString& extensionPointId, const ConfigurationElementDescription& configurationElements, QObject* token) { if (!CheckReadWriteAccess(token, persist)) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry::AddExtensionPoint() method. Check if proper access token is supplied."); // prepare namespace information RegistryContributor::Pointer internalContributor = contributor.Cast(); registryObjects->AddContributor(internalContributor); // only adds a contributor if it is not already present QString contributorId = internalContributor->GetActualId(); // addition wraps in a contribution RegistryContribution::Pointer contribution = GetElementFactory()->CreateContribution(contributorId, persist); Extension::Pointer currentExtension = GetElementFactory()->CreateExtension(persist); QString simpleId; QString namespaceName; int simpleIdStart = identifier.lastIndexOf('.'); if (simpleIdStart != -1) { simpleId = identifier.mid(simpleIdStart + 1); namespaceName = identifier.left(simpleIdStart); } else { simpleId = identifier; namespaceName = contribution->GetDefaultNamespace(); } currentExtension->SetSimpleIdentifier(simpleId); currentExtension->SetNamespaceIdentifier(namespaceName); QString extensionLabelNLS = Translate(label, nullptr); currentExtension->SetLabel(extensionLabelNLS); QString targetExtensionPointId; if (extensionPointId.indexOf('.') == -1) // No dots -> namespace name added at the start targetExtensionPointId = contribution->GetDefaultNamespace() + '.' + extensionPointId; else targetExtensionPointId = extensionPointId; currentExtension->SetExtensionPointIdentifier(targetExtensionPointId); // if we have an Id specified, check for duplicates. Only issue warning if duplicate found // as it might still work fine - depending on the access pattern. if (!simpleId.isNull() && Debug()) { QString uniqueId = namespaceName + '.' + simpleId; IExtension::Pointer existingExtension = GetExtension(uniqueId); if (existingExtension.IsNotNull()) { QString currentSupplier = contribution->GetDefaultNamespace(); QString existingSupplier = existingExtension->GetContributor()->GetName(); QString msg = QString("Extensions supplied by \"%1\" and \"%2\" have the same Id: \"%3\".") .arg(currentSupplier).arg(existingSupplier).arg(uniqueId); IStatus::Pointer status(new Status(IStatus::WARNING_TYPE, RegistryMessages::OWNER_NAME, 0, msg, BERRY_STATUS_LOC)); Log(status); return false; } } GetObjectManager()->Add(currentExtension, true); CreateExtensionData(contributorId, configurationElements, currentExtension, persist); currentExtension->SetContributorId(contributorId); QList contributionChildren; contributionChildren.push_back(0); contributionChildren.push_back(1); contributionChildren.push_back(currentExtension->GetObjectId()); contribution->SetRawChildren(contributionChildren); Add(contribution); return true; } bool ExtensionRegistry::RemoveExtension(const SmartPointer& extension, QObject* token) { ExtensionHandle::Pointer handle = extension.Cast(); if (handle.IsNull()) return false; return RemoveObject(handle->GetObject(), false, token); } bool ExtensionRegistry::RemoveExtensionPoint(const SmartPointer& extensionPoint, QObject* token) { ExtensionPointHandle::Pointer handle = extensionPoint.Cast(); if (handle.IsNull()) return false; return RemoveObject(handle->GetObject(), true, token); } QList > ExtensionRegistry::GetAllContributors() const { QList result; QReadLocker l(&access); foreach(RegistryContributor::Pointer contributor, registryObjects->GetContributors().values()) { result.push_back(contributor); } return result; } bool ExtensionRegistry::IsMultiLanguage() const { return isMultiLanguage; } QList ExtensionRegistry::Translate(const QList& nonTranslated, const SmartPointer& contributor, const QLocale& locale) const { return strategy->Translate(nonTranslated, contributor, locale); } QLocale ExtensionRegistry::GetLocale() const { return strategy->GetLocale(); } void ExtensionRegistry::LogMultiLangError() const { if (mlErrorLogged) // only log this error ones return; IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, QString("The requested multi-language operation is not enabled. See runtime option \"") + RegistryConstants::PROP_REGISTRY_MULTI_LANGUAGE + "\".", ctkInvalidArgumentException(""), BERRY_STATUS_LOC)); Log(status); mlErrorLogged = true; } } diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryContributor.h b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryContributor.h index 2e27c93a20..2ffe88e19b 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryContributor.h +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryContributor.h @@ -1,139 +1,139 @@ /*============================================================================ 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 BERRYREGISTRYCONTRIBUTOR_H #define BERRYREGISTRYCONTRIBUTOR_H #include "berryIContributor.h" namespace berry { /** * This class describes a registry contributor which is an entity that supplies information * to the extension registry. Depending on the registry strategy, contributor might delegate * some of its functionality to a "host" contributor. For instance, OSGi registry strategy * uses "host" contributor to delegate some functionality from fragments to plug-ins. *

* This class can be instantiated by the registry Service Providers. *

* This class is not intended to be extended. *

* Note: This class/interface is part of an interim API that is still under * development and expected to change significantly before reaching stability. * It is being made available at this early stage to solicit feedback from pioneering * adopters on the understanding that any code that uses this API will almost certainly * be broken (repeatedly) as the API evolves. *

* @noextend This class is not intended to be subclassed by clients. */ class RegistryContributor : public IContributor { private: /** * Actual ID of the contributor (e.g., "12"). IDs are expected to be unique in the workspace. */ QString actualContributorId; /** * Actual name of the contributor (e.g., "org.eclipse.core.runtime.fragment"). */ QString actualContributorName; /** * ID associated with the entity "in charge" of the contributor (e.g., "1"). IDs are expected * to be unique in the workspace. If contributor does not rely on a host, this value should be * the same as the actual contributor ID. */ QString hostId; /** * Name of the entity "in charge" of the contributor (e.g. "org.eclipse.core.runtime"). * If contributor does not rely on a host, this value should be the same as the actual * contributor name. */ QString hostName; public: berryObjectMacro(berry::RegistryContributor); /** * Constructor for the registry contributor. *

* The actual ID is a string identifier for the contributor (e.g., "12") and is expected * to be unique within the workspace. The actual ID of the contributor must not * be null. *

* The actual name is the name associated with the contributor * (e.g., "org.eclipse.core.runtime.fragment"). The actual name of the contributor must * not be null. *

* The host ID is the identifier associated with the entity "in charge" of the contributor * (e.g., "1"). IDs are expected to be unique in the workspace. If contributor does not * rely on a host, then null should be used as the host ID. *

* The host name is the name of the entity "in charge" of the contributor * (e.g., "org.eclipse.core.runtime"). If contributor does not rely on a host, then * null should be used as the host name. *

- * There should be 1-to-1 mapping between the contributor and the contibutor ID. + * There should be 1-to-1 mapping between the contributor and the contributor ID. * The IDs (either actual or host) can not be re-used in the same registry. * For example, if ID of 12 was used to identify contributorA, the ID of 12 can not * be used to identify contributorB or a host for the contributorC. *

* @param actualId contributor identifier * @param actualName name of the contributor * @param hostId id associated with the host, or null * @param hostName name of the host, or null */ RegistryContributor(const QString& actualId, const QString& actualName, const QString& hostId, const QString& hostName); /** * Provides actual ID associated with the registry contributor (e.g., "12"). IDs are expected * to be unique in the workspace. * * @return actual ID of the registry contributor */ QString GetActualId() const; /** * Provides actual name of the registry contributor (e.g., "org.eclipe.core.runtime.fragment"). * * @return actual name of the registry contributor */ QString GetActualName() const; /** * Provides ID associated with the entity "in charge" of the contributor (e.g., "1"). IDs are expected * to be unique in the workspace. If contributor does not rely on a host, this value should be * the same as the actual contributor ID. * * @return id of the registry contributor */ QString GetId() const; /** * Provides name of the entity "in charge" of the contributor (e.g., "org.eclipse.core.runtime"). * If contributor does not rely on a host, this value should be the same as the actual contributor name. * * @return name of the registry contributor */ QString GetName() const override; }; } #endif // BERRYREGISTRYCONTRIBUTOR_H diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.cpp index 3a5f23ef26..402bf7a6ed 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.cpp @@ -1,119 +1,119 @@ /*============================================================================ 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 "berryRegistryObject.h" #include "berryExtensionRegistry.h" #include "berryRegistryObjectManager.h" namespace berry { // it is assumed that int has 32 bits (bits #0 to #31); // bits #0 - #29 are the offset (limited to about 1Gb) -// bit #30 - persistance flag +// bit #30 - persistence flag // bit #31 - registry object has no extra data offset // the bit#31 is a sign bit; bit#30 is the highest mantissa bit const int RegistryObject::EMPTY_MASK = 0x80000000; // only taking bit #31 const int RegistryObject::PERSIST_MASK = 0x40000000; // only taking bit #30 const int RegistryObject::OFFSET_MASK = 0x3FFFFFFF; // all bits but #30, #31 RegistryObject::RegistryObject() : registry(nullptr), objectId(RegistryObjectManager::UNKNOWN), extraDataOffset(EMPTY_MASK) { objectKey = QString::number(objectId); } QString RegistryObject::GetKey() const { return objectKey; } bool RegistryObject::IsEqual(const KeyedElement& other) const { return objectId == static_cast(other).objectId; } RegistryObject::RegistryObject(ExtensionRegistry* registry, bool persist) : registry(registry), objectId(RegistryObjectManager::UNKNOWN), extraDataOffset(EMPTY_MASK) { objectKey = QString::number(objectId); SetPersist(persist); } void RegistryObject::SetRawChildren(const QList& values) { children = values; } QList RegistryObject::GetRawChildren() const { return children; } void RegistryObject::SetObjectId(int value) { objectId = value; objectKey = QString::number(value); } int RegistryObject::GetObjectId() const { return objectId; } bool RegistryObject::ShouldPersist() const { return (extraDataOffset & PERSIST_MASK) == PERSIST_MASK; } bool RegistryObject::NoExtraData() const { return (extraDataOffset & EMPTY_MASK) == EMPTY_MASK; } int RegistryObject::GetExtraDataOffset() const { if (NoExtraData()) return -1; return extraDataOffset & OFFSET_MASK; } void RegistryObject::SetExtraDataOffset(int offset) { if (offset == -1) { extraDataOffset &= ~OFFSET_MASK; // clear all offset bits extraDataOffset |= EMPTY_MASK; return; } if ((offset & OFFSET_MASK) != offset) throw ctkInvalidArgumentException("Registry object: extra data offset is out of range"); extraDataOffset &= ~(OFFSET_MASK | EMPTY_MASK); // clear all offset bits; mark as non-empty extraDataOffset |= (offset & OFFSET_MASK); // set all offset bits } QLocale RegistryObject::GetLocale() const { return registry->GetLocale(); } void RegistryObject::SetPersist(bool persist) { if (persist) extraDataOffset |= PERSIST_MASK; else extraDataOffset &= ~PERSIST_MASK; } } diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.h b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.h index 2158df3d03..aecc42ad76 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.h +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.h @@ -1,98 +1,98 @@ /*============================================================================ 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 BERRYREGISTRYOBJECT_H #define BERRYREGISTRYOBJECT_H #include "berryKeyedElement.h" namespace berry { class ExtensionRegistry; /** * An object which has the general characteristics of all the nestable elements * in a plug-in manifest. */ class RegistryObject : public KeyedElement { public: berryObjectMacro(berry::RegistryObject); RegistryObject(); //Implementation of the KeyedElement interface QString GetKey() const override; int GetObjectId() const; //This can not return null. It returns the singleton empty array or an array QList GetRawChildren() const; bool NoExtraData() const; protected: friend class RegistryObjectManager; friend class ExtensionRegistry; friend class ExtensionsParser; QList children; // it is assumed that int has 32 bits (bits #0 to #31); // bits #0 - #29 are the offset (limited to about 1Gb) - // bit #30 - persistance flag + // bit #30 - persistence flag // bit #31 - registry object has no extra data offset // the bit#31 is a sign bit; bit#30 is the highest mantissa bit static const int EMPTY_MASK; // = 0x80000000; // only taking bit #31 static const int PERSIST_MASK; // = 0x40000000; // only taking bit #30 static const int OFFSET_MASK; // = 0x3FFFFFFF; // all bits but #30, #31 //The registry that owns this object ExtensionRegistry* registry; RegistryObject(ExtensionRegistry* registry, bool persist); void SetRawChildren(const QList& values); void SetObjectId(int value); bool ShouldPersist() const; // Convert no extra data to -1 on output int GetExtraDataOffset() const; // Accept -1 as "no extra data" on input void SetExtraDataOffset(int offset); QLocale GetLocale() const; private: //Object identifier uint objectId; // = RegistryObjectManager::UNKNOWN; // The key QString objectKey; // The field combines offset, persistence flag, and no offset flag int extraDataOffset; // = EMPTY_MASK; void SetPersist(bool persist); bool IsEqual(const KeyedElement& other) const override; }; } #endif // BERRYREGISTRYOBJECT_H diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObjectManager.h b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObjectManager.h index f962c2496f..566231a86a 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObjectManager.h +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObjectManager.h @@ -1,281 +1,281 @@ /*============================================================================ 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 BERRYREGISTRYOBJECTMANAGER_H #define BERRYREGISTRYOBJECTMANAGER_H #include "berryIObjectManager.h" #include "berryHashtableOfStringAndInt.h" #include "berryKeyedHashSet.h" #include namespace berry { class ExtensionHandle; class ExtensionPoint; class ExtensionPointHandle; class ExtensionRegistry; class RegistryContribution; class RegistryContributor; class RegistryIndexElement; class RegistryObject; class RegistryObjectReferenceMap; /** * This class manage all the object from the registry but does not deal with their dependencies. * It serves the objects which are either directly obtained from memory or read from a cache. * It also returns handles for objects. */ class RegistryObjectManager : public IObjectManager { public: berryObjectMacro(berry::RegistryObjectManager); //Constants used to get the objects and their handles enum Type { CONFIGURATION_ELEMENT = 1, EXTENSION, EXTENSION_POINT, THIRDLEVEL_CONFIGURATION_ELEMENT }; RegistryObjectManager(ExtensionRegistry* registry); ~RegistryObjectManager() override; void Add(const SmartPointer& registryObject, bool hold); SmartPointer GetObject(int id, short type) const override; - // The current impementation of this method assumes that we don't cache dynamic + // The current implementation of this method assumes that we don't cache dynamic // extension. In this case all extensions not yet loaded (i.e. not in the memory cache) // are "not dynamic" and we actually check memory objects to see if they are dynamic. // // If we decide to allow caching of dynamic objects, the implementation // of this method would have to retrieved the object from disk and check // its "dynamic" status. The problem is that id alone is not enough to get the object // from the disk; object type is needed as well. bool ShouldPersist(int id) const; QList > GetObjects(const QList& values, short type) const override; SmartPointer GetHandle(int id, short type) const override; QList > GetHandles(const QList& ids, short type) const override; bool IsDirty() const; void MarkDirty(); void Close() override; ExtensionRegistry* GetRegistry() const; QList > GetExtensionsFromContributor(const QString& contributorId) const; QList > GetExtensionPointsFromContributor(const QString& contributorId) const; QList > GetExtensionPointsFromNamespace(const QString& namespaceName) const; // This method filters out extensions with no extension point QList > GetExtensionsFromNamespace(const QString& namespaceName) const; SmartPointer GetContributor(const QString& id) const; protected: friend class Extension; friend class ExtensionPoint; friend class ExtensionRegistry; friend class ExtensionsParser; friend class RegistryContribution; friend class RegistryObject; mutable QMutex mutex; static const int CACHE_INITIAL_SIZE; // = 512; static int UNKNOWN; typedef QHash > OrphansMapType; typedef QHash > ContributorsMapType; /** * Initialize the object manager. Return true if the initialization succeeded, false otherwise */ bool Init(long timeStamp); void AddContribution(const SmartPointer& contribution); QList GetExtensionPointsFrom(const QString& id) const; QList GetExtensionPointsFrom_unlocked(const QString& id) const; bool HasContribution(const QString& id) const; void Remove(int id, bool release); void Remove_unlocked(int id, bool release); QList > GetObjects_unlocked(const QList& values, short type) const; SmartPointer GetExtensionPointObject(const QString& xptUniqueId) const; SmartPointer GetExtensionPointObject_unlocked(const QString& xptUniqueId) const; QList > GetExtensionPointsHandles() const; SmartPointer GetExtensionPointHandle(const QString& xptUniqueId); QList GetExtensionsFrom(const QString& contributorId) const; QList GetExtensionsFrom_unlocked(const QString& contributorId) const; bool AddExtensionPoint(const SmartPointer& currentExtPoint, bool hold); void RemoveExtensionPoint(const QString& extensionPointId); void RemoveContribution(const QString &contributorId); void AddOrphans(const QString& extensionPoint, const QList& extensions); void AddOrphan(const QString& extensionPoint, int extension); QList RemoveOrphans(const QString& extensionPoint); void RemoveOrphan(const QString& extensionPoint, int extension); //This method is only used by the writer to reach in QHash > GetOrphanExtensions() const; // This method is only used by the writer to reach in int GetNextId() const; // This method is only used by the writer to reach in HashtableOfStringAndInt GetExtensionPoints() const; // This method is only used by the writer to reach in QList GetContributions() const; // This method is used internally and by the writer to reach in. Notice that it doesn't // return contributors marked as removed. ContributorsMapType& GetContributors() const; // only adds a contributor if it is not already present in the table void AddContributor(const SmartPointer& newContributor); void RemoveContributor(const QString& id); KeyedHashSet& GetNamespacesIndex() const; /** * Collect all the objects that are removed by this operation and store * them in a IObjectManager so that they can be accessed from the appropriate * deltas but not from the registry. */ QHash > GetAssociatedObjects(const QString& contributionId) const; /** * Adds elements to be removed along with the registry object. */ void AddAssociatedObjects(QHash >& map, const SmartPointer& registryObject); /** * Add to the set of the objects all extensions and extension points that * could be navigated to from the objects in the set. */ void AddNavigableObjects(QHash >& associatedObjects); void RemoveObjects(const QHash >& associatedObjects); SmartPointer CreateDelegatingObjectManager(const QHash >& object); bool UnlinkChildFromContributions(int id); private: // key: extensionPointName, value: object id HashtableOfStringAndInt extensionPoints; //This is loaded on startup. Then entries can be added when loading a new plugin from the xml. // key: object id, value: an object RegistryObjectReferenceMap* cache; //Entries are added by getter. The structure is not thread safe. //key: int, value: int //OffsetTable fileOffsets = null; //This is read once on startup when loading from the cache. Entries are never added here. They are only removed to prevent "removed" objects to be reloaded. int nextId; //This is only used to get the next number available. mutable bool orphanExtensionsLoaded; //Those two data structures are only used when the addition or the removal of a plugin occurs. //They are used to keep track on a contributor basis of the extension being added or removed - KeyedHashSet newContributions; //represents the contributers added during this session. - mutable KeyedHashSet formerContributions; //represents the contributers encountered in previous sessions. This is loaded lazily. + KeyedHashSet newContributions; //represents the contributors added during this session. + mutable KeyedHashSet formerContributions; //represents the contributors encountered in previous sessions. This is loaded lazily. mutable bool formerContributionsLoaded; mutable QHash > contributors; // key: contributor ID; value: contributor name mutable bool contributorsLoaded; QHash > removedContributors; // key: contributor ID; value: contributor name mutable KeyedHashSet namespacesIndex; // registry elements (extension & extensionpoints) indexed by namespaces mutable bool namespacesIndexLoaded; // Map key: extensionPointFullyQualifiedName, value int[] of orphan extensions. // The orphan access does not need to be synchronized because the it is protected by the lock in extension registry. mutable QHash > orphanExtensions; KeyedHashSet heldObjects; //strong reference to the objects that must be hold on to //Indicate if objects have been removed or added from the table. This only needs to be set in a couple of places (addNamespace and removeNamespace) bool isDirty; bool fromCache; ExtensionRegistry* registry; // TODO make ExtensionPoint, Extension provide namespace in a same way (move it to the RegistryObject?) // See if all the registryObjects have the same namespace. If not, return null. // Also can return null if empty array is passed in or objects are of an unexpected type QString FindCommonNamespaceIdentifier(const QList >& registryObjects) const; void RemoveExtensionPointFromNamespaceIndex(int extensionPoint, const QString& namespaceName); void RemoveExtensionFromNamespaceIndex(int extensions, const QString& namespaceName); // Called from a synchronized method void UpdateNamespaceIndex(const SmartPointer& contribution, bool added); KeyedHashSet& GetFormerContributions() const; void Remove(const SmartPointer& registryObject, bool release); void Hold(const SmartPointer& toHold); void Release(const SmartPointer& toRelease); SmartPointer BasicGetObject(int id, short type) const; SmartPointer Load(int id, short type) const; OrphansMapType& GetOrphans() const; // Find or create required index element SmartPointer GetNamespaceIndex(const QString& namespaceName) const; void CollectChildren(const SmartPointer& ce, int level, QHash >& collector) const; // Called from a synchronized method only bool UnlinkChildFromContributions(const QList >& contributions, int id); }; } #endif // BERRYREGISTRYOBJECTMANAGER_H diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObjectReferenceMap.h b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObjectReferenceMap.h index 85e6f1ba51..398fe6d6b1 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObjectReferenceMap.h +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObjectReferenceMap.h @@ -1,140 +1,140 @@ /*============================================================================ 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 BERRYREGISTRYOBJECTREFERENCEMAP_H #define BERRYREGISTRYOBJECTREFERENCEMAP_H #include #include namespace berry { class RegistryObject; class RegistryObjectReferenceMap { public: enum ReferenceType { /** * Constant indicating that hard references should be used. */ HARD = 0, /** - * Constant indiciating that soft references should be used. + * Constant indicating that soft references should be used. */ SOFT = 1 }; /** * Constructs a new ReferenceMap with the * specified reference type, load factor and initial * capacity. * * @param referenceType the type of reference to use for values; * must be {@link #HARD} or {@link #SOFT} * @param capacity the initial capacity for the map */ RegistryObjectReferenceMap(ReferenceType referenceType, int capacity); ~RegistryObjectReferenceMap(); /** * Returns the value associated with the given key, if any. * * @return the value associated with the given key, or null * if the key maps to no value */ SmartPointer Get(int key) const; /** * Associates the given key with the given value.

* The value may be null. * * @param key the key of the mapping * @param value the value of the mapping * @throws ctkInvalidArgumentException if either the key or value * is null */ void Put(int key, const SmartPointer& value); /** * Removes the key and its associated value from this map. * * @param key the key to remove * @return the value associated with that key, or null if * the key was not in the map */ SmartPointer Remove(int key); private: /** * The common interface for all elements in the map. Both * smart and weak pointer map values conform to this interface. */ struct IEntry; /** * IEntry implementation that acts as a hard reference. * The value of a hard reference entry is never garbage * collected until it is explicitly removed from the map. */ class SmartRef; /** * IEntry implementation that acts as a weak reference. */ class WeakRef; typedef QHash ReferenceMapType; mutable ReferenceMapType references; ReferenceType valueType; /** * Constructs a new table entry for the given data * * @param key The entry key * @param value The entry value * @param next The next value in the entry's collision chain * @return The new table entry */ IEntry* NewEntry(const SmartPointer& value) const; /** * Purges stale mappings from this map.

* * Ordinarily, stale mappings are only removed during * a write operation; typically a write operation will * occur often enough that you'll never need to manually * invoke this method.

* * Note that this method is not synchronized! Special * care must be taken if, for instance, you want stale * mappings to be removed on a periodic basis by some * background thread. */ void Purge() const; /** * @param key The key to remove * @param cleanup true if doing map maintenance; false if it is a real request to remove * @return The removed map value */ SmartPointer DoRemove(int key, bool cleanup); }; } #endif // BERRYREGISTRYOBJECTREFERENCEMAP_H diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryTimestamp.h b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryTimestamp.h index 91093af976..16be398138 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryTimestamp.h +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryTimestamp.h @@ -1,83 +1,83 @@ /*============================================================================ 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 BERRYREGISTRYTIMESTAMP_H #define BERRYREGISTRYTIMESTAMP_H namespace berry { /** * Aggregated registry timestamp. Corresponds to the current contents of the registry. *

* This class may be instantiated. *

- * This class is not indended to be subclassed. + * This class is not intended to be subclassed. */ class RegistryTimestamp { private: /** * Current aggregated timestamp */ long aggregateTimestamp; bool modified; public: /** * Public constructor. */ RegistryTimestamp(); /** * Returns value of the aggregated timestamp. * @return value of the aggregated timestamp */ long GetContentsTimestamp() const; /** * Set value of the aggregated timestamp. * @param timestamp the aggregated timestamp of the current registry contents */ void Set(long timestamp); /** * Sets aggregated timestamp to the value corresponding to an empty registry. */ void Reset(); /** * Determines if the aggregate timestamp was modified using add() or remove() * methods. * @return true: the timestamp was modified after the last set/reset */ bool IsModifed() const; /** * Add individual contribution timestamp to the aggregated timestamp. * @param timestamp the time stamp of the contribution being added to the registry */ void Add(long timestamp); /** * Remove individual contribution timestamp from the aggregated timestamp. * @param timestamp the time stamp of the contribution being removed from the registry */ void Remove(long timestamp); }; } #endif // BERRYREGISTRYTIMESTAMP_H diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h index e2819f5db0..cb4c05330b 100644 --- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h +++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h @@ -1,118 +1,118 @@ /*============================================================================ 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 BERRYHELPINDEXVIEW_H_ #define BERRYHELPINDEXVIEW_H_ #include #include #include class ctkSearchBox; class QHelpIndexWidget; namespace berry { class HelpIndexWidget : public QListView { Q_OBJECT Q_SIGNALS: /** * This signal is emitted when an item is activated and its * associated \a link should be shown. To know where the link - * belongs to, the \a keyword is given as a second paremeter. + * belongs to, the \a keyword is given as a second parameter. */ void linkActivated(const QUrl &link, const QString &keyword); /** * This signal is emitted when the item representing the \a keyword * is activated and the item has more than one link associated. * The \a links consist of the document title and their URL. */ void linksActivated(const QMap &links, const QString &keyword); public: HelpIndexWidget(); public Q_SLOTS: /** * Filters the indices according to \a filter or \a wildcard. * The item with the best match is set as current item. */ void filterIndices(const QString &filter, const QString &wildcard = QString()); /** * Activates the current item which will result eventually in * the emitting of a linkActivated() or linksActivated() * signal. */ void activateCurrentItem(); private Q_SLOTS: void showLink(const QModelIndex &index); }; class HelpIndexView : public QtViewPart { Q_OBJECT public: HelpIndexView(); ~HelpIndexView() override; void SetFocus() override; protected: void CreateQtPartControl(QWidget* parent) override; void setSearchLineEditText(const QString &text); QString searchLineEditText() const; protected Q_SLOTS: void linkActivated(const QUrl& link); void linksActivated(const QMap &links, const QString &keyword); private Q_SLOTS: void filterIndices(const QString &filter); void enableSearchLineEdit(); void disableSearchLineEdit(); void setIndexWidgetBusy(); void unsetIndexWidgetBusy(); private: bool eventFilter(QObject *obj, QEvent *e) override; void focusInEvent(QFocusEvent *e); void open(HelpIndexWidget *indexWidget, const QModelIndex &index); Q_DISABLE_COPY(HelpIndexView) ctkSearchBox* m_SearchLineEdit; HelpIndexWidget* m_IndexWidget; }; } // namespace berry #endif /*BERRYHELPINDEXVIEW_H_*/ diff --git a/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox index f4a0815bae..1dee9db8bc 100644 --- a/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox +++ b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox @@ -1,16 +1,16 @@ /** \page org_blueberry_views_logview The Logging Plugin \imageMacro{logview-dox.svg,"Icon of the Logging Plugin",2.00} This plug-in records all logging output of events and progress as specified in the source code with time of occurrence, level of importance (Info, Warning, Error, Fatal, Debug), the message given and the origin of the message (source code section). \imageMacro{LogView.png,"Screenshot of the Logging Plugin",16.00} There are different features available in the view. The 'Filter' text field provides the possibility to search for all log events containing a certain substring. The 'Copy to clipboard' button allows you to copy the current content of the logging view to your clipboard. This enables you to insert the logging information to any text processing application. In the simple logging view, you'll see logging messages and logging levels. A brief description of the logging levels can be found in the \ref LoggingPage "logging concept documentation". With two checkboxes more information on every logging message can be activated. The checkbox 'categories' adds a column for the category. The checkbox 'advanced fields' additionally displays the time from application start to the log message entry and the function, filename and line number of the logging message origin. -\imageMacro{LogViewExplain.png,"Details on the Vizualized Logging Information",16.00} +\imageMacro{LogViewExplain.png,"Details on the Visualized Logging Information",16.00} */ diff --git a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp index 6dd5f99784..3e506e8aea 100644 --- a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp +++ b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp @@ -1,332 +1,332 @@ /*============================================================================ 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 "berryQtPlatformLogModel.h" #include "berryQtLogPlugin.h" #include #include #include #include #include #include #include #include #include namespace berry { const QString QtPlatformLogModel::Error = QString("Error"); const QString QtPlatformLogModel::Warn = QString("Warning"); const QString QtPlatformLogModel::Fatal = QString("Fatal"); const QString QtPlatformLogModel::Info = QString("Info"); const QString QtPlatformLogModel::Debug = QString("Debug"); void QtPlatformLogModel::slotFlushLogEntries() { m_Mutex.lock(); QList *tmp=m_Active; m_Active=m_Pending; m_Pending=tmp; m_Mutex.unlock(); int num = static_cast(m_Pending->size()); if (num > 0) { int row = static_cast(m_Entries.size()); this->beginInsertRows(QModelIndex(), row, row+num-1); do { m_Entries.push_back(m_Pending->front()); m_Pending->pop_front(); } while(--num); this->endInsertRows(); } } void QtPlatformLogModel::addLogEntry(const mitk::LogMessage &msg) { m_Mutex.lock(); //mitk::LogBackendCout::FormatSmart(msg); FormatSmart is not static any more. So commented out this statement. Todo: fix m_Active->push_back(ExtendedLogMessage(msg)); m_Mutex.unlock(); emit signalFlushLogEntries(); } void QtPlatformLogModel::SetShowAdvancedFiels( bool showAdvancedFiels ) { if( m_ShowAdvancedFiels != showAdvancedFiels ) { m_ShowAdvancedFiels = showAdvancedFiels; this->beginResetModel(); this->endResetModel(); } } void QtPlatformLogModel::SetShowCategory( bool showCategory ) { if( m_ShowCategory != showCategory ) { m_ShowCategory = showCategory; this->beginResetModel(); this->endResetModel(); } } void QtPlatformLogModel::addLogEntry(const ctkPluginFrameworkEvent& event) { auto level = mitk::LogLevel::Info; if (event.getType() == ctkPluginFrameworkEvent::PLUGIN_ERROR) { level = mitk::LogLevel::Error; } else if (event.getType() == ctkPluginFrameworkEvent::FRAMEWORK_WAIT_TIMEDOUT || event.getType() == ctkPluginFrameworkEvent::PLUGIN_WARNING) { level = mitk::LogLevel::Warn; } mitk::LogMessage msg(level,"n/a",-1,"n/a"); QString str; QDebug dbg(&str); dbg << event; msg.Message = str.toStdString(); //msg.moduleName = event.getPlugin()->getSymbolicName().toStdString(); addLogEntry(msg); } QtPlatformLogModel::QtPlatformLogModel(QObject* parent) : QAbstractTableModel(parent), m_ShowAdvancedFiels(false), m_ShowCategory(true) { m_Active=new QList; m_Pending=new QList; connect(this, SIGNAL(signalFlushLogEntries()), this, SLOT( slotFlushLogEntries() ), Qt::QueuedConnection ); QtLogPlugin::GetInstance()->GetContext()->connectFrameworkListener(this, SLOT(addLogEntry(ctkPluginFrameworkEvent))); myBackend = new QtLogBackend(this); } QtPlatformLogModel::~QtPlatformLogModel() { disconnect(this, SIGNAL(signalFlushLogEntries()), this, SLOT( slotFlushLogEntries() )); QtLogPlugin::GetInstance()->GetContext()->disconnectFrameworkListener(this); - // dont delete and unregister backend, only deactivate it to avoid thread syncronization issues cause mitk::UnregisterBackend is not threadsafe + // dont delete and unregister backend, only deactivate it to avoid thread synchronization issues cause mitk::UnregisterBackend is not threadsafe // will be fixed. // delete myBackend; // delete m_Active; // delete m_Pending; m_Mutex.lock(); myBackend->Deactivate(); m_Mutex.unlock(); } // QT Binding int QtPlatformLogModel::rowCount(const QModelIndex&) const { return static_cast(m_Entries.size()); } int QtPlatformLogModel::columnCount(const QModelIndex&) const { int returnValue = 2; if( m_ShowAdvancedFiels ) returnValue += 7; if( m_ShowCategory ) returnValue += 1; return returnValue; } /* struct LogEntry { LogEntry(const std::string& msg, const std::string& src, std::time_t t) : message(msg.c_str()), moduleName(src.c_str()),time(std::clock()) { } QString message; clock_t time; QString level; QString filePath; QString lineNumber; QString moduleName; QString category; QString function; LogEntry(const mitk::LogMessage &msg) { message = msg.Message.c_str(); filePath = msg.filePath; std::stringstream out; out << msg.LineNumber; lineNumber = out.str().c_str(); moduleName = msg.ModuleName; category = msg.Category.c_str(); function = msg.FunctionName; time=std::clock(); } }; */ QVariant QtPlatformLogModel::data(const QModelIndex& index, int role) const { const ExtendedLogMessage *msg = &m_Entries[index.row()]; if (role == Qt::DisplayRole) { switch (index.column()) { case 0: if (m_ShowAdvancedFiels) return msg->getTime(); else return msg->getLevel(); case 1: if (m_ShowAdvancedFiels) return msg->getLevel(); else return msg->getMessage(); case 2: if (m_ShowAdvancedFiels) return msg->getMessage(); else return msg->getCategory(); case 3: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getCategory(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getModuleName(); else break; case 4: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getModuleName(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getFunctionName(); else break; case 5: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getFunctionName(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getPath(); else break; case 6: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getPath(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getLine(); else break; case 7: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getLine(); else break; } } else if( role == Qt::DecorationRole ) { if ( (m_ShowAdvancedFiels && index.column()==1) || (!m_ShowAdvancedFiels && index.column()==0) ) { QString file ( ":/org_blueberry_ui_qt_log/information.png" ); if( msg->message.Level == mitk::LogLevel::Error ) file = ":/org_blueberry_ui_qt_log/error.png"; else if( msg->message.Level == mitk::LogLevel::Warn ) file = ":/org_blueberry_ui_qt_log/warning.png"; else if( msg->message.Level == mitk::LogLevel::Debug ) file = ":/org_blueberry_ui_qt_log/debug.png"; else if( msg->message.Level == mitk::LogLevel::Fatal ) file = ":/org_blueberry_ui_qt_log/fatal.png"; QIcon icon(file); return QVariant(icon); } } return QVariant(); } QVariant QtPlatformLogModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { if( m_ShowAdvancedFiels && m_ShowCategory ) { switch (section) { case 0: return QVariant(" Time "); case 1: return QVariant(" Level "); case 2: return QVariant(" Message "); case 3: return QVariant(" Category "); case 4: return QVariant(" Module "); case 5: return QVariant(" Function "); case 6: return QVariant(" File "); case 7: return QVariant(" Line "); } } else if (m_ShowAdvancedFiels && !m_ShowCategory) { switch (section) { case 0: return QVariant(" Time "); case 1: return QVariant(" Level "); case 2: return QVariant(" Message "); case 3: return QVariant(" Module "); case 4: return QVariant(" Function "); case 5: return QVariant(" File "); case 6: return QVariant(" Line "); } } - else //!m_ShowAdvancedFiels, m_ShowCategory is not handled seperately because it only activates case 2 + else //!m_ShowAdvancedFiels, m_ShowCategory is not handled separately because it only activates case 2 { switch (section) { case 0: return QVariant(" Level "); case 1: return QVariant(" Message "); case 2: return QVariant(" Category "); } } } return QVariant(); } QVariant QtPlatformLogModel::ExtendedLogMessage::getTime() const { std::stringstream ss; std::locale C("C"); ss.imbue(C); ss << std::setw(7) << std::setprecision(3) << std::fixed << ((double)this->time)/CLOCKS_PER_SEC; return QVariant(QString(ss.str().c_str())); } QString QtPlatformLogModel::GetDataAsString() { QString returnValue(""); for (int message=0; messagerowCount(QModelIndex()); message++) { for (int column=0; columncolumnCount(QModelIndex()); column++) { returnValue += " " + this->data(this->index(message,column),Qt::DisplayRole).toString(); } returnValue += "\n"; } return returnValue; } } diff --git a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.h b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.h index bd6b7f567e..561b148d9b 100644 --- a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.h +++ b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.h @@ -1,211 +1,211 @@ /*============================================================================ 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 BERRYQTPLATFORMLOGMODEL_H_ #define BERRYQTPLATFORMLOGMODEL_H_ #include "berryLog.h" #include "ctkPluginFrameworkEvent.h" #include #include #include #include #include "berryLog.h" #include namespace berry { /** Documentation * @brief An object of this class represents a table of logging data. * The table presentation can be modified by the methods * SetShowAdvancedFiels() and SetShowCategory(). */ class QtPlatformLogModel : public QAbstractTableModel { Q_OBJECT public: QtPlatformLogModel(QObject* parent = nullptr); ~QtPlatformLogModel() override; void SetShowAdvancedFiels( bool showAdvancedFiels ); void SetShowCategory( bool showCategory ); int rowCount(const QModelIndex&) const override; int columnCount(const QModelIndex&) const override; QVariant data(const QModelIndex& index, int) const override; /** Documentation - * @return Retruns the complete table data as string representation. + * @return Returns the complete table data as string representation. */ QString GetDataAsString(); QVariant headerData(int section, Qt::Orientation orientation, int) const override; void addLogEntry(const mitk::LogMessage &msg); Q_SLOT void addLogEntry(const ctkPluginFrameworkEvent& event); private: bool m_ShowAdvancedFiels; bool m_ShowCategory; /** Documentation * @brief An object of this struct internally represents a logging message. * It offers methods to convert the logging data into QVaraint objects * and also adds time and threadid as logging data. The struct is * internally used to store logging data in the table data model. */ struct ExtendedLogMessage { mitk::LogMessage message; clock_t time; int threadid; ExtendedLogMessage(const ExtendedLogMessage &src):message(src.message),time(src.time),threadid(src.threadid) { } ExtendedLogMessage(const mitk::LogMessage &msg):message(msg),time(std::clock()),threadid(0) { } ExtendedLogMessage operator = (const ExtendedLogMessage& src) { return ExtendedLogMessage(src); } QVariant getLevel() const { switch(this->message.Level) { default: case mitk::LogLevel::Info: return QVariant(Info); case mitk::LogLevel::Warn: return QVariant(Warn); case mitk::LogLevel::Error: return QVariant(Error); case mitk::LogLevel::Fatal: return QVariant(Fatal); case mitk::LogLevel::Debug: return QVariant(Debug); } } QVariant getMessage() const { return QVariant(QString::fromStdString(this->message.Message)); } QVariant getCategory() const { return QVariant(QString::fromStdString(this->message.Category)); } QVariant getModuleName() const { return QVariant(QString::fromStdString(this->message.ModuleName)); } QVariant getFunctionName() const { return QVariant(QString::fromStdString(this->message.FunctionName)); } QVariant getPath() const { return QVariant(QString::fromStdString(this->message.FilePath)); } QVariant getLine() const { return QVariant(QString::number(this->message.LineNumber)); } /** This method is implemented in the cpp file to save includes. */ QVariant getTime() const; }; class QtLogBackend : public mitk::LogBackendBase { public: QtLogBackend(QtPlatformLogModel *_myModel) { myModel=_myModel; deactivated = false; mitk::RegisterBackend(this); BERRY_INFO << "BlueBerry log backend registered"; } ~QtLogBackend() override { mitk::UnregisterBackend(this); } void ProcessMessage(const mitk::LogMessage &l ) override { if(!deactivated) myModel->addLogEntry(l); } mitk::LogBackendBase::OutputType GetOutputType() const override { return mitk::LogBackendBase::OutputType::Other; } void Deactivate() { deactivated=true; } private: QtPlatformLogModel *myModel; bool deactivated; } *myBackend; QList m_Entries; QList *m_Active,*m_Pending; static const QString Error; static const QString Warn; static const QString Fatal; static const QString Info; static const QString Debug; QMutex m_Mutex; signals: void signalFlushLogEntries(); protected slots: void slotFlushLogEntries(); }; } #endif /*BERRYQTPLATFORMLOGMODEL_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryCommandContributionItemParameter.h b/Plugins/org.blueberry.ui.qt/src/actions/berryCommandContributionItemParameter.h index 52cb8ea7ff..b847146713 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryCommandContributionItemParameter.h +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryCommandContributionItemParameter.h @@ -1,193 +1,193 @@ /*============================================================================ 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 BERRYCOMMANDCONTRIBUTIONITEMPARAMETER_H #define BERRYCOMMANDCONTRIBUTIONITEMPARAMETER_H #include #include #include #include "berryCommandContributionItem.h" namespace berry { struct IServiceLocator; /** * A help class for the various parameters that can be used with command * contributions. Mandatory parameters are in the constructor, and public fields * can be set to fill in other parameters. */ class BERRY_UI_QT CommandContributionItemParameter : public virtual Object { public: berryObjectMacro(CommandContributionItemParameter); /** * a service locator that is most appropriate for this contribution. * Typically the local {@link IWorkbenchWindow} or * {@link IWorkbenchPartSite} will be sufficient. Must not be * null. */ IServiceLocator* serviceLocator; /** * The id for this item. May be null. Items without an id * cannot be referenced later. */ QString id; /** * A command id for a defined command. Must not be null. */ QString commandId; /** * A map of strings to strings which represent parameter names to values. * The parameter names must match those in the command definition. May be * null */ QHash parameters; /** * An icon for this item. May be null. */ QIcon icon; /** * A label for this item. May be null. */ QString label; /** * A mnemonic for this item to be applied to the label. May be * null. */ QChar mnemonic; /** * A shortcut key sequence. This is a workaround and will be * removed when key binding support is fully implemented */ QKeySequence shortcut; /** * A tooltip for this item. May be null. Tooltips are * currently only valid for toolbar contributions. */ QString tooltip; /** * The style of this menu contribution. See the CommandContributionItem - * STYLE_* contants. + * STYLE_* constants. */ CommandContributionItem::Style style; /** * The help context id to be applied to this contribution. May be * null */ QString helpContextId; /** * The icon style to use. */ QString iconStyle; /** * The visibility tracking for a menu contribution. */ bool visibleEnabled; /** * Any number of mode bits, like * {@link CommandContributionItem#MODE_FORCE_TEXT}. */ CommandContributionItem::Modes mode; /** * Create the parameter object. Nullable attributes can be set directly. * * @param serviceLocator * a service locator that is most appropriate for this * contribution. Typically the local {@link IWorkbenchWindow} or * {@link IWorkbenchPartSite} will be sufficient. Must not be * null. * @param id * The id for this item. May be null. Items * without an id cannot be referenced later. * @param commandId * A command id for a defined command. Must not be * null. * @param style - * The style of this menu contribution. See the STYLE_* contants. + * The style of this menu contribution. See the STYLE_* constants. */ CommandContributionItemParameter(IServiceLocator* serviceLocator, const QString& id, const QString& commandId, CommandContributionItem::Style style); /** * Build the parameter object. *

* Note: This constructor should not be called outside the framework. *

* * @param serviceLocator * a service locator that is most appropriate for this * contribution. Typically the local {@link IWorkbenchWindow} or * {@link IWorkbenchPartSite} will be sufficient. Must not be * null. * @param id * The id for this item. May be null. Items * without an id cannot be referenced later. * @param commandId * A command id for a defined command. Must not be * null. * @param parameters * A map of strings to strings which represent parameter names to * values. The parameter names must match those in the command * definition. May be null * @param icon * An icon for this item. May be null. * @param label * A label for this item. May be null. * @param mnemonic * A mnemonic for this item to be applied to the label. May be * null. * @param tooltip * A tooltip for this item. May be null. Tooltips * are currently only valid for toolbar contributions. * @param style - * The style of this menu contribution. See the STYLE_* contants. + * The style of this menu contribution. See the STYLE_* constants. * @param helpContextId * the help context id to be applied to this contribution. May be * null * @param visibleEnabled * Visibility tracking for the menu contribution. * @note This constructor is not intended to be referenced by clients. */ CommandContributionItemParameter(IServiceLocator* serviceLocator, const QString& id, const QString& commandId, const QHash ¶meters, const QIcon& icon, const QString label, const QChar &mnemonic, const QString& tooltip, CommandContributionItem::Style style, const QString& helpContextId, bool visibleEnabled); }; } #endif // BERRYCOMMANDCONTRIBUTIONITEM_H diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryContributionItemFactory.h b/Plugins/org.blueberry.ui.qt/src/actions/berryContributionItemFactory.h index ade6420acf..2dda3b6f0c 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryContributionItemFactory.h +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryContributionItemFactory.h @@ -1,132 +1,132 @@ /*============================================================================ 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 BERRYCONTRIBUTIONITEMFACTORY_H #define BERRYCONTRIBUTIONITEMFACTORY_H #include #include #include namespace berry { struct IContributionItem; struct IWorkbenchWindow; /** * Access to standard contribution items provided by the workbench. *

* Most of the functionality of this class is provided by * static methods and fields. * Example usage: *

  * MenuManager menu = ...;
  * IContributionItem::Pointer reEdit
  *     = ContributionItemFactory::REOPEN_EDITORS->Create(window);
  * menu->Add(reEdit);
  * 
*

*

* Clients may declare subclasses that provide additional application-specific * contribution item factories. *

*/ class BERRY_UI_QT ContributionItemFactory { private: /** * Id of contribution items created by this factory. */ const QString contributionItemId; protected: /** * Creates a new workbench contribution item factory with the given id. * * @param contributionItemId the id of contribution items created by this factory */ ContributionItemFactory(const QString& contributionItemId); public: /** * Creates a new standard contribution item for the given workbench window. *

* A typical contribution item automatically registers listeners against the * workbench window so that it can keep its enablement state up to date. * Ordinarily, the window's references to these listeners will be dropped * automatically when the window closes. However, if the client needs to get * rid of a contribution item while the window is still open, the client must * call IContributionItem#dispose to give the item an * opportunity to deregister its listeners and to perform any other cleanup. *

* * @param window the workbench window * @return the workbench contribution item */ virtual SmartPointer Create(IWorkbenchWindow* window) = 0; /** * Returns the id of this contribution item factory. * * @return the id of contribution items created by this factory */ QString GetId() const; /** * Workbench contribution item (id "openWindows"): A list of windows * currently open in the workbench. Selecting one of the items makes the * corresponding window the active window. * This action dynamically maintains the list of windows. */ static const QScopedPointer OPEN_WINDOWS; /** * Workbench contribution item (id "viewsShortlist"): A list of views * available to be opened in the window, arranged as a shortlist of * promising views and an "Other" subitem. Selecting * one of the items opens the corresponding view in the active window. * This action dynamically maintains the view shortlist. */ static const QScopedPointer VIEWS_SHORTLIST; /** * Workbench contribution item (id "reopenEditors"): A list of recent * editors (with inputs) available to be reopened in the window. Selecting * one of the items reopens the corresponding editor on its input in the * active window. This action dynamically maintains the list of editors. */ static const QScopedPointer REOPEN_EDITORS; /** * Workbench contribution item (id "perspectivesShortlist"): A list of * perspectives available to be opened, arranged as a shortlist of * promising perspectives and an "Other" subitem. Selecting * one of the items makes the corresponding perspective active. Should a * new perspective need to be opened, a workbench user preference controls - * whether the prespective is opened in the active window or a new window. + * whether the perspective is opened in the active window or a new window. * This action dynamically maintains the perspectives shortlist. */ static const QScopedPointer PERSPECTIVES_SHORTLIST; virtual ~ContributionItemFactory() = default; }; } #endif // BERRYCONTRIBUTIONITEMFACTORY_H diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryIContributionItem.h b/Plugins/org.blueberry.ui.qt/src/actions/berryIContributionItem.h index 7c2600b8bf..33b39e7e9e 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryIContributionItem.h +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryIContributionItem.h @@ -1,194 +1,194 @@ /*============================================================================ 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 BERRYICONTRIBUTIONITEM_H #define BERRYICONTRIBUTIONITEM_H #include #include class QStatusBar; class QMenu; class QMenuBar; class QToolBar; class QAction; namespace berry { struct IContributionManager; /** * A contribution item represents a contribution to a shared UI resource such as a * menu or tool bar. More generally, contribution items are managed by a contribution * manager. * For instance, in a tool bar a contribution item is a tool bar button or a separator. * In a menu bar a contribution item is a menu, and in a menu a contribution item * is a menu item or separator. *

* A contribution item can realize itself in different Qt widgets, using the different * fill methods. The same type of contribution item can be used with a * MenuBarManager, ToolBarManager, * or a StatusLineManager. *

*

* This interface is internal to the framework; it should not be implemented outside * the framework. *

* * @see IContributionManager */ struct IContributionItem : public virtual Object { berryObjectMacro(berry::IContributionItem); /** * Fills the given status bar control with controls representing this * contribution item. Used by StatusLineManager. * * @param parent the parent control */ virtual void Fill(QStatusBar* parent) = 0; /** * Fills the given menu bar with controls representing this contribution item. * Used by MenuBarManager. * * @param parent the parent menu * @param before */ virtual void Fill(QMenuBar* parent, QAction* before) = 0; /** * Fills the given menu with controls representing this contribution item. * Used by MenuManager. * * @param parent the parent menu * @param before */ virtual void Fill(QMenu* parent, QAction* before) = 0; /** * Fills the given tool bar with controls representing this contribution item. * Used by ToolBarManager. * * @param parent the parent tool bar * @param before */ virtual void Fill(QToolBar* parent, QAction* before) = 0; /** * Returns the identifier of this contribution item. * The id is used for retrieving an item from its manager. * * @return the contribution item identifier, or null * if none */ virtual QString GetId() const = 0; /** * Returns whether this contribution item is enabled. * * @return true if this item is enabled */ virtual bool IsEnabled() const = 0; /** * Returns whether this contribution item is dirty. A dirty item will be * recreated when the action bar is updated. * * @return true if this item is dirty */ virtual bool IsDirty() const = 0; /** * Returns whether this contribution item is dynamic. A dynamic contribution * item contributes items conditionally, dependent on some internal state. * * @return true if this item is dynamic, and * false for normal items */ virtual bool IsDynamic() const = 0; /** * Returns whether this contribution item is a group marker. * This information is used when adding items to a group. * * @return true if this item is a group marker, and * false for normal items * * @see GroupMarker * @see IContributionManager#appendToGroup(String, IContributionItem) * @see IContributionManager#prependToGroup(String, IContributionItem) */ virtual bool IsGroupMarker() const = 0; /** * Returns whether this contribution item is a separator. * This information is used to enable hiding of unnecessary separators. * * @return true if this item is a separator, and * false for normal items * @see Separator */ virtual bool IsSeparator() const = 0; /** - * Returns whether this contribution item is visibile within its manager. + * Returns whether this contribution item is visible within its manager. * * @return true if this item is visible, and * false otherwise */ virtual bool IsVisible() const = 0; /** * Saves any state information of the control(s) owned by this contribution item. * The contribution manager calls this method before disposing of the controls. */ virtual void SaveWidgetState() = 0; /** * Sets the parent manager of this item * * @param parent the parent contribution manager */ virtual void SetParent(IContributionManager* parent) = 0; /** - * Sets whether this contribution item is visibile within its manager. + * Sets whether this contribution item is visible within its manager. * * @param visible true if this item should be visible, and * false otherwise */ virtual void SetVisible(bool visible) = 0; /** * Updates any controls cached by this contribution item with any * changes which have been made to this contribution item since the last update. * Called by contribution manager update methods. */ virtual void Update() = 0; /** * Updates any controls cached by this contribution item with changes * for the the given property. * * @param id the id of the changed property */ virtual void Update(const QString& id) = 0; }; } #endif // BERRYICONTRIBUTIONITEM_H diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryIContributionManagerOverrides.h b/Plugins/org.blueberry.ui.qt/src/actions/berryIContributionManagerOverrides.h index 8fdb67e9a7..e80564f5a8 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryIContributionManagerOverrides.h +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryIContributionManagerOverrides.h @@ -1,72 +1,72 @@ /*============================================================================ 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 BERRYICONTRIBUTIONMANAGEROVERRIDES_H #define BERRYICONTRIBUTIONMANAGEROVERRIDES_H #include #include #include namespace berry { struct IContributionItem; /** * This interface is used by instances of IContributionItem - * to determine if the values for certain properties have been overriden + * to determine if the values for certain properties have been overridden * by their manager. *

* This interface is internal to the framework; it should not be implemented outside * the framework. *

*/ struct BERRY_UI_QT IContributionManagerOverrides : virtual Object { berryObjectMacro(berry::IContributionManagerOverrides); /** * Id for the enabled property. Value is "enabled". */ static const QString P_ENABLED; /** * Find out the enablement of the item * @param item the contribution item for which the enable override value is * determined * @return
    *
  • 1 if the given contribution item should be enabled
  • *
  • 0 if the item should not be enabled
  • *
  • -1 if the item may determine its own enablement
  • *
*/ virtual int GetEnabled(const IContributionItem* item) const = 0; /** - * Visiblity override. + * Visibility override. * * @param item the contribution item in question * @return
    *
  • 1 if the given contribution item should be visible
  • *
  • 0 if the item should not be visible
  • *
  • -1 if the item may determine its own visibility
  • *
*/ virtual int GetVisible(const IContributionItem* item) const = 0; }; } #endif // BERRYICONTRIBUTIONMANAGEROVERRIDES_H diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.cpp b/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.cpp index c3bc449562..1a3064882e 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.cpp +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.cpp @@ -1,675 +1,675 @@ /*============================================================================ 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 "berryMenuManager.h" #include "berryIContributionManagerOverrides.h" #include "berryQActionProperties.h" #include "berrySubContributionItem.h" #include #include class QMenuProxy { public: QMenu* menu; QMenuBar* menuBar; enum Type { MenuBar, Menu }; QMenuProxy(Type type, QWidget* parent = nullptr) : menu(nullptr), menuBar(nullptr) { switch (type) { case MenuBar: menuBar = new QMenuBar(parent); break; case Menu: menu = new QMenu(parent); break; } } bool isMenuBar() const { return menuBar != nullptr; } void setTitle(const QString& title) { if (menu) menu->setTitle(title); } void setIcon(const QIcon& icon) { if (menu) menu->setIcon(icon); } QList actions() const { return menu ? menu->actions() : menuBar->actions(); } void removeAction(QAction* action) { menu ? menu->removeAction(action) : menuBar->removeAction(action); } bool isEnabled() const { return menu ? menu->isEnabled() : menuBar->isEnabled(); } void setEnabled(bool enabled) { menu ? menu->setEnabled(enabled) : menuBar->setEnabled(enabled); } QAction* getParentItem() const { return menu ? menu->menuAction() : nullptr; } }; namespace berry { struct NullOverrides: public IContributionManagerOverrides { public: int GetEnabled(const IContributionItem* /*item*/) const override { return -1; } int GetVisible(const IContributionItem* /*item*/) const override { return -1; } }; void MenuManager::HandleAboutToShow() { if (this->removeAllWhenShown) { this->RemoveAll(); } emit AboutToShow(this); this->Update(false, false); } void MenuManager::HandleAboutToHide() { emit AboutToHide(this); } MenuManager::MenuManager(const QString& text, const QString& id) : id(id), menu(nullptr), menuItem(nullptr) , menuText(text), parent(nullptr) , removeAllWhenShown(false), visible(true) { } MenuManager::MenuManager(const QString& text, const QIcon& image, const QString& id) : id(id), menu(nullptr), menuItem(nullptr) , menuText(text), image(image) , parent(nullptr), removeAllWhenShown(false), visible(true) { } bool MenuManager::IsDirty() const { return ContributionManager::IsDirty(); } MenuManager::~MenuManager() { delete menu; } QMenu* MenuManager::CreateContextMenu(QWidget* parent) { if (!menu) { menu = new QMenuProxy(QMenuProxy::Menu, parent); this->InitializeMenu(); } return menu->menu; } QMenuBar* MenuManager::CreateMenuBar(QWidget* parent) { if (!menu) { menu = new QMenuProxy(QMenuProxy::MenuBar, parent); this->Update(false); } return menu->menuBar; } void MenuManager::AddMenuListener(QObject* listener) { this->connect(this, SIGNAL(AboutToShow(IMenuManager*)), listener, SLOT(MenuAboutToShow(IMenuManager*))); this->connect(this, SIGNAL(AboutToHide(IMenuManager*)), listener, SLOT(MenuAboutToHide(IMenuManager*))); } void MenuManager::RemoveMenuListener(QObject* listener) { this->disconnect(listener); } void MenuManager::Fill(QStatusBar* /*parent*/) { } void MenuManager::Fill(QToolBar* /*parent*/, QAction* /*before*/) { } void MenuManager::Fill(QMenu* parent, QAction* before) { this->FillMenu(parent, before); } void MenuManager::Fill(QMenuBar* parent, QAction* before) { this->FillMenu(parent, before); } void MenuManager::FillMenu(QWidget* parent, QAction* before) { if (!menuItem) { menuItem = new QAction(parent); if (parent) { parent->insertAction(before, menuItem); } menuItem->setText(GetMenuText()); menuItem->setIcon(image); if(!menu) { menu = new QMenuProxy(QMenuProxy::Menu, parent); } if (!menu->isMenuBar()) menuItem->setMenu(menu->menu); this->InitializeMenu(); this->SetDirty(true); } } IMenuManager::Pointer MenuManager::FindMenuUsingPath(const QString& path) const { IContributionItem::Pointer item(this->FindUsingPath(path)); if (IMenuManager::Pointer manager = item.Cast()) { return manager; } return IMenuManager::Pointer(nullptr); } IContributionItem::Pointer MenuManager::FindUsingPath(const QString& path) const { QString id(path); QString rest; int separator = path.indexOf('/'); if (separator != -1) { id = path.left(separator); rest = path.mid(separator + 1); } else { return ContributionManager::Find(path); } IContributionItem::Pointer item(ContributionManager::Find(id)); if (IMenuManager::Pointer manager = item.Cast()) { return manager->FindUsingPath(rest); } return IContributionItem::Pointer(nullptr); } QString MenuManager::GetId() const { return id; } QMenu* MenuManager::GetMenu() const { return menu->menu; } QString MenuManager::GetMenuText() const { if (definitionId == "") { return menuText; } // ExternalActionManager::ICallback callback = ExternalActionManager // .getInstance().getCallback(); // if (callback != null) // { // String shortCut = callback.getAcceleratorText(definitionId); // if (shortCut == null) // { // return menuText; // } // return menuText + "\t" + shortCut; //$NON-NLS-1$ // } return menuText; } QIcon MenuManager::GetImage() const { return image; } SmartPointer MenuManager::GetOverrides() { if (!overrides) { if (!parent) { overrides = new NullOverrides(); } else { overrides = parent->GetOverrides(); } ContributionManager::SetOverrides(overrides); } return overrides; } IContributionManager* MenuManager::GetParent() const { return parent; } bool MenuManager::GetRemoveAllWhenShown() const { return removeAllWhenShown; } bool MenuManager::IsDynamic() const { return false; } bool MenuManager::IsEnabled() const { return true; } bool MenuManager::IsGroupMarker() const { return false; } bool MenuManager::IsSeparator() const { return false; } bool MenuManager::IsVisible() const { if (!visible) { return false; // short circuit calculations in this case } if (removeAllWhenShown) { // we have no way of knowing if the menu has children return true; } // menus aren't visible if all of its children are invisible (or only contains visible separators). bool visibleChildren = false; foreach(IContributionItem::Pointer item, this->GetItems()) { if (item->IsVisible() && !item->IsSeparator()) { visibleChildren = true; break; } } return visibleChildren; } void MenuManager::MarkDirty() { ContributionManager::MarkDirty(); // Can't optimize by short-circuiting when the first dirty manager is encountered, // since non-visible children are not even processed. // That is, it's possible to have a dirty sub-menu under a non-dirty parent menu // even after the parent menu has been updated. // If items are added/removed in the sub-menu, we still need to propagate the dirty flag up, // even if the sub-menu is already dirty, since the result of isVisible() may change // due to the added/removed items. IContributionManager* p = this->GetParent(); if (p) { p->MarkDirty(); } } void MenuManager::SaveWidgetState() { } void MenuManager::SetOverrides(SmartPointer newOverrides) { overrides = newOverrides; ContributionManager::SetOverrides(overrides); } void MenuManager::SetParent(IContributionManager* manager) { parent = manager; } void MenuManager::SetRemoveAllWhenShown(bool removeAll) { this->removeAllWhenShown = removeAll; } void MenuManager::SetVisible(bool visible) { this->visible = visible; } void MenuManager::SetCommandId(const QString& definitionId) { this->definitionId = definitionId; } void MenuManager::Update() { this->UpdateMenuItem(); } void MenuManager::Update(const QString& property) { QList items = GetItems(); for (int i = 0; i < items.size(); i++) { items[i]->Update(property); } if (menu != nullptr && menu->getParentItem() != nullptr) { if (QActionProperties::TEXT == property) { QString text = GetMenuText(); if (!text.isNull()) { menu->getParentItem()->setText(text); } } else if (QActionProperties::IMAGE == property && !image.isNull()) { menu->getParentItem()->setIcon(image); } } } void MenuManager::Update(bool force) { this->Update(force, false); } void MenuManager::UpdateAll(bool force) { this->Update(force, true); } void MenuManager::InitializeMenu() { menu->setTitle(GetMenuText()); menu->setIcon(GetImage()); if (!menu->isMenuBar()) { this->connect(menu->menu, SIGNAL(aboutToShow()), SLOT(HandleAboutToShow())); this->connect(menu->menu, SIGNAL(aboutToHide()), SLOT(HandleAboutToHide())); } // Don't do an update(true) here, in case menu is never opened. // Always do it lazily in handleAboutToShow(). } void MenuManager::UpdateMenuItem() { if (menuItem && menu) { bool enabled = removeAllWhenShown || menu->actions().size() > 0; if (menu->isEnabled() != enabled) { menuItem->setEnabled(enabled); } } } void MenuManager::DoItemFill(IContributionItem::Pointer ci, QAction* before) { if (menu->isMenuBar()) { ci->Fill(menu->menuBar, before); } else { ci->Fill(menu->menu, before); } } void MenuManager::Update(bool force, bool recursive) { if (ContributionManager::IsDirty() || force) { if (menu) { // clean contains all active items without double separators QList items = this->GetItems(); QList clean; IContributionItem::Pointer separator; foreach (IContributionItem::Pointer ci, items) { if (!ci->IsVisible()) { continue; } if (ci->IsSeparator()) { // delay creation until necessary // (handles both adjacent separators, and separator at end) separator = ci; } else { if (separator) { if (clean.size() > 0) { clean.push_back(separator); } separator = nullptr; } clean.push_back(ci); } } // remove obsolete (removed or non active) QList mi = menu->actions(); for (int i = 0; i < mi.size(); i++) { Object::Pointer data = mi[i]->data().value(); if (!data || !clean.contains(data.Cast())) { menu->removeAction(mi[i]); } else if (IContributionItem::Pointer ci = data.Cast()) { if(ci->IsDynamic() && ci->IsDirty()) { menu->removeAction(mi[i]); delete mi[i]; } } } // add new mi = menu->actions(); int srcIx = 0; int destIx = 0; for (QList::Iterator e = clean.begin(); e != clean.end(); ++e) { IContributionItem::Pointer src(*e); IContributionItem::Pointer dest; // get corresponding item in widget if (srcIx < mi.size()) { dest = mi[srcIx]->data().value().Cast(); } else { dest = nullptr; } if (dest && src == dest) { srcIx++; destIx++; } else if (dest && dest->IsSeparator() && src->IsSeparator()) { mi[srcIx]->setData(QVariant::fromValue(src)); srcIx++; destIx++; } else { int start = menu->actions().size(); //qDebug() << "***** Filling item destIx = " << destIx << " (size: " << start << ")"; this->DoItemFill(src, destIx >= start ? nullptr : menu->actions().at(destIx)); int newItems = menu->actions().size() - start; //qDebug() << "***** New items: " << newItems; for (int i = 0; i < newItems; ++i) { menu->actions().at(destIx++)->setData(QVariant::fromValue(src)); } } // May be we can optimize this call. If the menu has just // been created via the call src.fill(fMenuBar, destIx) then // the menu has already been updated with update(true) // (see MenuManager). So if force is true we do it again. But // we can't set force to false since then information for the // sub sub menus is lost. if (recursive) { IContributionItem::Pointer item(src); if (SubContributionItem::Pointer subItem = item.Cast()) { item = subItem->GetInnerItem(); } if (IMenuManager::Pointer mm = item.Cast()) { mm->UpdateAll(force); } } } // remove any old menu items not accounted for for (; srcIx < mi.size(); srcIx++) { menu->removeAction(mi[srcIx]); delete mi[srcIx]; } this->SetDirty(false); } } else { - // I am not dirty. Check if I must recursivly walk down the hierarchy. + // I am not dirty. Check if I must recursively walk down the hierarchy. if (recursive) { foreach (IContributionItem::Pointer ci, this->GetItems()) { if (IMenuManager::Pointer mm = ci.Cast()) { if (mm->IsVisible()) { mm->UpdateAll(force); } } } } } this->UpdateMenuItem(); } void MenuManager::DumpActionInfo(QMenuProxy* menu) { if (menu->isMenuBar()) { //qDebug() << "QMenuBar [" << menu->menuBar << "]"; DumpActionInfo(menu->menuBar, 1); } else { //qDebug() << "QMenu [" << menu->menu << "]" << menu->menu; DumpActionInfo(menu->menu, 1); } } void MenuManager::DumpActionInfo(QWidget* widget, int level) { QString indent = " |"; for (int i = 0; i < level; ++i) indent += "--"; foreach(QAction* action, widget->actions()) { qDebug() << qPrintable(indent) << action->text() << "[" << action << "]"; if (action->menu()) { DumpActionInfo(action->menu(), level+1); } } } } diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.h b/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.h index 21b4b66e54..4e84952186 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.h +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.h @@ -1,403 +1,403 @@ /*============================================================================ 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 BERRYMENUMANAGER_H_ #define BERRYMENUMANAGER_H_ #include "berryIMenuManager.h" #include "berryContributionManager.h" #include #include class QMenu; class QMenuProxy; class QAction; namespace berry { /** * A menu manager is a contribution manager which realizes itself and its items * in a menu control; either as a menu bar, a sub-menu, or a context menu. *

* This class may be instantiated; it may also be subclassed. *

*/ class BERRY_UI_QT MenuManager: public QObject, public ContributionManager, public IMenuManager { Q_OBJECT public: berryObjectMacro(MenuManager); private: /** * The menu id. */ QString id; /** * The menu control; null before * creation and after disposal. */ QMenuProxy* menu; QAction* menuItem; /** * The menu item widget; null before * creation and after disposal. This field is used * when this menu manager is a sub-menu. */ //SmartPointer menuItem; /** * The text for a sub-menu. */ QString menuText; /** * The image for a sub-menu. */ QIcon image; /** * The overrides for items of this manager */ SmartPointer overrides; /** * The parent contribution manager. */ IContributionManager* parent; /** * Indicates whether removeAll should be * called just before the menu is displayed. */ bool removeAllWhenShown; /** * allows a submenu to display a shortcut key. This is often used with the * QuickMenu command or action which can pop up a menu using the shortcut. */ QString definitionId; private: Q_SLOT void HandleAboutToShow(); Q_SLOT void HandleAboutToHide(); protected: /** * Indicates this item is visible in its manager; true * by default. */ bool visible; public: Q_SIGNAL void AboutToShow(IMenuManager* mm); Q_SIGNAL void AboutToHide(IMenuManager* mm); /** * Creates a menu manager with the given text and id. * Typically no text is given when creating a context menu. * Supply a text and id for creating a sub-menu, where it needs to be referred to by the id. * * @param text the text for the menu, or "" if none * @param id the menu id, or "" if it is to have no id */ MenuManager(const QString& text = QString(), const QString& id = QString()); ~MenuManager() override; /** * Creates a menu manager with the given text, image, and id. * Typically used for creating a sub-menu, where it needs to be referred to by id. * * @param text the text for the menu, or "" if none * @param image the image for the menu, or ImageDescriptor::Pointer(0) if none * @param id the menu id, or "" if it is to have no id */ MenuManager(const QString& text, const QIcon& image, const QString& id); bool IsDirty() const override; /** * Creates and returns a Qt menu control for this menu, * and installs all registered contributions. * Does not create a new control if one already exists. *

* Note that the menu is not expected to be dynamic. *

* * @param parent the parent control * @return the menu control */ QMenu* CreateContextMenu(QWidget* parent); /** * Creates and returns a Qt menu bar control for this menu, * for use in the given QWidget, and installs all registered * contributions. Does not create a new control if one already exists. * * @param parent the parent decorations * @return the menu control * @since 2.1 */ QMenuBar* CreateMenuBar(QWidget* parent); void AddMenuListener(QObject* listener) override; void RemoveMenuListener(QObject *listener) override; /* * @see IContributionItem#Fill(QStatusBar*) */ void Fill(QStatusBar* parent) override; /* * @see IContributionItem#Fill(QToolBar*, int) */ void Fill(QToolBar* parent, QAction *index) override; /* * @see IContributionItem#Fill(QMenu*, int) */ void Fill(QMenu* parent, QAction *before) override; /* * @see IContributionItem#Fill(QMenuBar*, int) */ void Fill(QMenuBar* parent, QAction *before) override; /* * @see IMenuManager#FindMenuUsingPath(const QString&) */ IMenuManager::Pointer FindMenuUsingPath(const QString& path) const override; /* * @see IMenuManager#FindUsingPath(const QString&) */ IContributionItem::Pointer FindUsingPath(const QString& path) const override; /** * Returns the menu id. The menu id is used when creating a contribution * item for adding this menu as a sub menu of another. * * @return the menu id */ QString GetId() const override; /** * Returns the SWT menu control for this menu manager. * * @return the menu control */ QMenu* GetMenu() const; /** * Returns the text shown in the menu, potentially with a shortcut * appended. * * @return the menu text */ QString GetMenuText() const; /** * Returns the image for this menu as an image descriptor. * * @return the image, or null if this menu has no image */ QIcon GetImage() const; /* * @see IContributionManager#GetOverrides() */ SmartPointer GetOverrides() override; /** - * Returns the parent contribution manager of this manger. + * Returns the parent contribution manager of this manager. * * @return the parent contribution manager */ IContributionManager* GetParent() const; /* * @see IMenuManager#GetRemoveAllWhenShown() */ bool GetRemoveAllWhenShown() const override; /* * @see IContributionItem#IsDynamic() */ bool IsDynamic() const override; /** * Returns whether this menu should be enabled or not. * Used to enable the menu item containing this menu when it is realized as a sub-menu. *

* The default implementation of this framework method * returns true. Subclasses may reimplement. *

* * @return true if enabled, and * false if disabled */ bool IsEnabled() const override; /* * @see IContributionItem#IsGroupMarker() */ bool IsGroupMarker() const override; /* * @see IContributionItem#IsSeparator() */ bool IsSeparator() const override; /* * @see IContributionItem#IsVisible() */ bool IsVisible() const override; /** * The MenuManager implementation of this ContributionManager method * also propagates the dirty flag up the parent chain. */ void MarkDirty() override; /* * @see IMenuManager#removeMenuListener(IMenuListener) */ //void RemoveMenuListener(SmartPointer listener); /* * @IContributionItem#SaveWidgetState() */ void SaveWidgetState() override; /** * Sets the overrides for this contribution manager * * @param newOverrides the overrides for the items of this manager */ void SetOverrides(SmartPointer newOverrides); /* * @see IContributionItem#SetParent(IContributionManager) */ void SetParent(IContributionManager* manager) override; /* * @see IMenuManager#SetRemoveAllWhenShown(boolean) */ void SetRemoveAllWhenShown(bool removeAll) override; /* * @see IContributionItem#SetVisible(bool) */ void SetVisible(bool visible) override; /** * Sets the command id of this action. This simply allows the menu * item text to include a short cut if available. It can be used to * notify a user of a key combination that will open a quick menu. * * @param definitionId * the command definition id */ void SetCommandId(const QString& definitionId); /* * @see IContributionItem#Update() */ void Update() override; void Update(const QString& property) override; /** * The MenuManager implementation of this IContributionManager * updates this menu, but not any of its submenus. * * @see #UpdateAll */ void Update(bool force) override; /* * @see IMenuManager#UpdateAll(bool) */ void UpdateAll(bool force) override; private: /** * Initializes the menu control. */ void InitializeMenu(); /** * Dispose any images allocated for this menu */ // void DisposeOldImages(); /** * Updates the menu item for this sub menu. * The menu item is disabled if this sub menu is empty. * Does nothing if this menu is not a submenu. */ void UpdateMenuItem(); void FillMenu(QWidget* parent, QAction* before); void DumpActionInfo(QMenuProxy* menu); void DumpActionInfo(QWidget* widget, int level); protected: /** * Call an IContributionItem's fill method with the * implementation's widget. The default is to use the Menu * widget.
* fill(Menu menu, int index) * * @param ci * An IContributionItem whose fill() * method should be called. * @param before * The position the fill() method should start * inserting at. */ void DoItemFill(IContributionItem::Pointer ci, QAction *before); /** * Incrementally builds the menu from the contribution items. * This method leaves out double separators and separators in the first * or last position. * * @param force true means update even if not dirty, * and false for normal incremental updating * @param recursive true means recursively update * all submenus, and false means just this menu */ void Update(bool force, bool recursive); }; } #endif /* BERRYMENUMANAGER_H_ */ diff --git a/Plugins/org.blueberry.ui.qt/src/application/berryWorkbenchWindowAdvisor.h b/Plugins/org.blueberry.ui.qt/src/application/berryWorkbenchWindowAdvisor.h index 18f15f4ddb..7135b29cf2 100644 --- a/Plugins/org.blueberry.ui.qt/src/application/berryWorkbenchWindowAdvisor.h +++ b/Plugins/org.blueberry.ui.qt/src/application/berryWorkbenchWindowAdvisor.h @@ -1,262 +1,262 @@ /*============================================================================ 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 BERRYWORKBENCHWINDOWADVISOR_H_ #define BERRYWORKBENCHWINDOWADVISOR_H_ #include #include namespace berry { struct IActionBarConfigurer; struct IMemento; struct IWorkbenchWindowConfigurer; class ActionBarAdvisor; class Shell; /** * Public base class for configuring a workbench window. *

* The workbench window advisor object is created in response to a workbench * window being created (one per window), and is used to configure the window. *

*

* An application should declare a subclass of WorkbenchWindowAdvisor * and override methods to configure workbench windows to suit the needs of the * particular application. *

*

* The following advisor methods are called at strategic points in the * workbench window's lifecycle (as with the workbench advisor, all occur * within the dynamic scope of the call to * PlatformUI#CreateAndRunWorkbench()): *

    *
  • PreWindowOpen() - called as the window is being opened; * use to configure aspects of the window other than actions bars
  • *
  • PostWindowRestore() - called after the window has been * recreated from a previously saved state; use to adjust the restored * window
  • *
  • PostWindowCreate() - called after the window has been created, * either from an initial state or from a restored state; used to adjust the * window
  • *
  • OpenIntro() - called immediately before the window is opened in * order to create the introduction component, if any.
  • *
  • PostWindowOpen() - called after the window has been * opened; use to hook window listeners, etc.
  • *
  • PreWindowShellClose() - called when the window's shell * is closed by the user; use to pre-screen window closings
  • *
*

* */ class BERRY_UI_QT WorkbenchWindowAdvisor { private: SmartPointer windowConfigurer; protected: /** * Returns the workbench window configurer. * * @return the workbench window configurer */ SmartPointer GetWindowConfigurer(); public: /** * Creates a new workbench window advisor for configuring a workbench * window via the given workbench window configurer. * * @param configurer an object for configuring the workbench window */ WorkbenchWindowAdvisor(const SmartPointer& configurer); virtual ~WorkbenchWindowAdvisor(); /** * Performs arbitrary actions before the window is opened. *

* This method is called before the window's controls have been created. * Clients must not call this method directly (although super calls are okay). * The default implementation does nothing. Subclasses may override. * Typical clients will use the window configurer to tweak the * workbench window in an application-specific way; however, filling the * window's menu bar, tool bar, and status line must be done in * ActionBarAdvisor#FillActionBars(), which is called immediately * after this method is called. *

*/ virtual void PreWindowOpen(); /** * Creates a new action bar advisor to configure the action bars of the window * via the given action bar configurer. * The default implementation returns a new instance of ActionBarAdvisor. * * @param configurer the action bar configurer for the window * @return the action bar advisor for the window */ virtual SmartPointer CreateActionBarAdvisor( SmartPointer configurer); /** * Performs arbitrary actions after the window has been restored, * but before it is opened. *

* This method is called after a previously-saved window has been * recreated. This method is not called when a new window is created from * scratch. This method is never called when a workbench is started for the * very first time, or when workbench state is not saved or restored. * Clients must not call this method directly (although super calls are okay). * The default implementation does nothing. Subclasses may override. * It is okay to call IWorkbench#Close() from this method. *

* * @exception WorkbenchException thrown if there are any errors to report * from post-restoration of the window */ virtual void PostWindowRestore(); /** - * Opens the introduction componenet. + * Opens the introduction component. *

* Clients must not call this method directly (although super calls are okay). * The default implementation opens the intro in the first window provided * if the preference WorkbenchPreferenceConstants#SHOW_INTRO is true. If * an intro is shown then this preference will be set to false. * Subsequently, and intro will be shown only if * WorkbenchConfigurer#GetSaveAndRestore() returns * true and the introduction was visible on last shutdown. * Subclasses may override. *

*/ virtual void OpenIntro(); /** * Performs arbitrary actions after the window has been created (possibly * after being restored), but has not yet been opened. *

* This method is called after the window has been created from scratch, * or when it has been restored from a previously-saved window. In the latter case, * this method is called after PostWindowRestore(). * Clients must not call this method directly (although super calls are okay). * The default implementation does nothing. Subclasses may override. *

*/ virtual void PostWindowCreate(); /** * Performs arbitrary actions after the window has been opened (possibly * after being restored). *

* This method is called after the window has been opened. This method is * called after the window has been created from scratch, or when * it has been restored from a previously-saved window. * Clients must not call this method directly (although super calls are okay). * The default implementation does nothing. Subclasses may override. *

*/ virtual void PostWindowOpen(); /** * Performs arbitrary actions as the window's shell is being closed * directly, and possibly veto the close. *

* This method is called from a IShellListener associated with the window, * for example when the user clicks the window's close button. It is not * called when the window is being closed for other reasons, such as if the * user exits the workbench via the ActionFactory#QUIT action. * Clients must not call this method directly (although super calls are * okay). If this method returns false, then the user's * request to close the shell is ignored. This gives the workbench advisor * an opportunity to query the user and/or veto the closing of a window * under some circumstances. *

* * @return true to allow the window to close, and * false to prevent the window from closing * @see IWorkbenchWindow#Close() * @see WorkbenchAdvisor#PreShutdown() */ virtual bool PreWindowShellClose(); /** * Performs arbitrary actions after the window is closed. *

* This method is called after the window's controls have been disposed. * Clients must not call this method directly (although super calls are * okay). The default implementation does nothing. Subclasses may override. *

*/ virtual void PostWindowClose(); /** * Creates the contents of the window. *

* The default implementation adds a menu bar, a cool bar, a status line, * a perspective bar, and a fast view bar. The visibility of these controls * can be configured using the SetShow* methods on * IWorkbenchWindowConfigurer. *

*

* Subclasses may override to define custom window contents and layout, * but must call IWorkbenchWindowConfigurer#CreatePageComposite(). *

* * @param shell the window's shell * @see IWorkbenchWindowConfigurer#CreateMenuBar() * @see IWorkbenchWindowConfigurer#CreateCoolBarControl() * @see IWorkbenchWindowConfigurer#CreateStatusLineControl() * @see IWorkbenchWindowConfigurer#CreatePageComposite() */ virtual void CreateWindowContents(SmartPointer shell); /** * Creates and returns the control to be shown when the window has no open pages. * If null is returned, the default window background is shown. *

* The default implementation returns null. * Subclasses may override. *

* * @param parent the parent composite * @return the control or null */ virtual QWidget* CreateEmptyWindowContents(QWidget* parent); /** * Saves arbitrary application specific state information. * * @param memento the storage area for object's state * @return a status object indicating whether the save was successful */ virtual bool SaveState(SmartPointer memento); /** * Restores arbitrary application specific state information. * * @param memento the storage area for object's state * @return a status object indicating whether the restore was successful */ virtual bool RestoreState(SmartPointer memento); }; } #endif /*BERRYWORKBENCHWINDOWADVISOR_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryIContributionRoot.h b/Plugins/org.blueberry.ui.qt/src/berryIContributionRoot.h index 5b3074227d..91a1a898d2 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIContributionRoot.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIContributionRoot.h @@ -1,67 +1,67 @@ /*============================================================================ 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 BERRYICONTRIBUTIONROOT_H #define BERRYICONTRIBUTIONROOT_H #include namespace berry { struct IContributionItem; class Expression; /** * Instances of this interface represent a position in the contribution * hierarchy into which {@link AbstractContributionFactory} instances may insert * elements. Instances of this interface are provided by the platform and this * interface should NOT be implemented by clients. */ struct IContributionRoot : public Object { berryObjectMacro(berry::IContributionRoot); /** * Adds a given contribution item with provided visibility expression and * kill-switch filtering as a direct child of this container. This should be * called for all top-level elements created in * berry::AbstractContributionFactory::CreateContributionItems(). * * @param item * the item to add * @param visibleWhen * the visibility expression. May be null. */ virtual void AddContributionItem(const SmartPointer& item, const SmartPointer& visibleWhen) = 0; /** - * Registers visibilty for arbitrary {@link IContributionItem} instances + * Registers visibility for arbitrary {@link IContributionItem} instances * that are NOT direct children of this container. Ie: children of a * {@link IContributionManager} that has been previously registered with a * call to AddContributionItem(). * * @param item * the item for which to register a visibility clause * @param visibleWhen * the visibility expression. May be null in which * case this method is a no-op. */ virtual void RegisterVisibilityForChild(const SmartPointer& item, const SmartPointer& visibleWhen) = 0; }; } #endif // BERRYICONTRIBUTIONROOT_H diff --git a/Plugins/org.blueberry.ui.qt/src/berryIEditorReference.h b/Plugins/org.blueberry.ui.qt/src/berryIEditorReference.h index aa6908b2c8..8dba8713c0 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIEditorReference.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIEditorReference.h @@ -1,79 +1,79 @@ /*============================================================================ 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 BERRYIEDITORREFERENCE_H_ #define BERRYIEDITORREFERENCE_H_ #include "berryIWorkbenchPartReference.h" #include "berryIEditorPart.h" #include "berryIEditorInput.h" namespace berry { /** * \ingroup org_blueberry_ui_qt * * Implements a reference to a editor. - * The IEditorPart will not be instanciated until + * The IEditorPart will not be instantiated until * the editor becomes visible or the API getEditor * is sent with true; *

* This interface is not intended to be implemented by clients. *

*/ struct BERRY_UI_QT IEditorReference : public virtual IWorkbenchPartReference { berryObjectMacro(berry::IEditorReference); ~IEditorReference() override; /** * Returns the factory id of the factory used to * restore this editor. Returns null if the editor * is not persistable. */ virtual QString GetFactoryId() = 0; /** * Returns the editor input name. May return null is the * name is not available or if the editor failed to be * restored. */ virtual QString GetName() = 0; /** * Returns the editor referenced by this object. * Returns null if the editor was not instantiated or * it failed to be restored. Tries to restore the editor * if restore is true. */ virtual IEditorPart::Pointer GetEditor(bool restore) = 0; /** * Returns the editor input for the editor referenced by this object. *

* Unlike most of the other methods on this type, this method * can trigger plug-in activation. *

* * @return the editor input for the editor referenced by this object * @throws PartInitException if there was an error restoring the editor input * @since 3.1 */ virtual IEditorInput::Pointer GetEditorInput() = 0; }; } // namespace berry #endif /*BERRYIEDITORREFERENCE_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryIEditorRegistry.h b/Plugins/org.blueberry.ui.qt/src/berryIEditorRegistry.h index ac26a03df3..c1e1006973 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIEditorRegistry.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIEditorRegistry.h @@ -1,275 +1,275 @@ /*============================================================================ 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 MITKIEDITORREGISTRY_H_ #define MITKIEDITORREGISTRY_H_ #include "berryIEditorDescriptor.h" #include "berryIFileEditorMapping.h" namespace berry { /** * \ingroup org_blueberry_ui_qt * * Registry of editors known to the workbench. *

* An editor can be created in one of two ways: *

    *
  • An editor can be defined by an extension to the workbench.
  • *
  • The user manually associates an editor with a given resource extension * type. This will override any default workbench or platform association. *
  • *
*

*

* The registry does not keep track of editors that are "implicitly" determined. * For example a bitmap (.bmp) file will typically not have a * registered editor. Instead, when no registered editor is found, the * underlying OS is consulted. *

*

* This interface is not intended to be implemented by clients. *

* * @see org.blueberry.ui.IWorkbench#getEditorRegistry() */ struct BERRY_UI_QT IEditorRegistry { /** * The property identifier for the contents of this registry. */ static const int PROP_CONTENTS; // = 0x01; /** * The identifier for the system external editor descriptor. This descriptor * is always present in the registry on all platforms. * Use {@link #FindEditor} to access the editor descriptor for this identifier. * * @since 3.0 */ static const QString SYSTEM_EXTERNAL_EDITOR_ID; // = "org.blueberry.ui.systemExternalEditor"; /** * The identifier for the system in-place editor descriptor. This descriptor * is only present in the registry on platforms that support in-place editing * (for example Win32). Use {@link #FindEditor} to access the editor * descriptor for this identifier. * * @since 3.0 */ static const QString SYSTEM_INPLACE_EDITOR_ID; // = "org.blueberry.ui.systemInPlaceEditor"; /* * Adds a listener for changes to properties of this registry. * Has no effect if an identical listener is already registered. *

* The properties ids are as follows: *

    *
  • PROP_CONTENTS: Triggered when the file editor mappings in * the editor registry change.
  • *
*

* * @param listener a property listener */ // virtual void AddPropertyListener(IPropertyListener listener) = 0; virtual ~IEditorRegistry(); /** * Finds and returns the descriptor of the editor with the given editor id. * * @param editorId the editor id * @return the editor descriptor with the given id, or null if not * found */ virtual IEditorDescriptor::Pointer FindEditor(const QString& editorId) = 0; /** * Returns the default editor. The default editor always exist. * * @return the descriptor of the default editor * @deprecated The system external editor is the default editor. * Use findEditor(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID) * instead. */ virtual IEditorDescriptor::Pointer GetDefaultEditor() = 0; /** * Returns the default editor for a given file name. This method assumes an * unknown content type for the given file. *

* The default editor is determined by taking the file extension for the * file and obtaining the default editor for that extension. *

* * @param fileName * the file name in the system * @return the descriptor of the default editor, or null if * not found */ virtual IEditorDescriptor::Pointer GetDefaultEditor(const QString& fileName) = 0; /* * Returns the default editor for a given file name and with the given content type. *

* The default editor is determined by taking the file extension for the * file and obtaining the default editor for that extension. *

* * @param fileName the file name in the system * @param contentType the content type or null for the unknown content type * @return the descriptor of the default editor, or null if not * found * @since 3.1 */ //virtual IEditorDescriptor::Pointer GetDefaultEditor(const QString& fileName, IContentType contentType) = 0; /** * Returns the list of file editors registered to work against the file with * the given file name. This method assumes an unknown content type for the * given file. *

* Note: Use getDefaultEditor(String) if you only the need * the default editor rather than all candidate editors. *

* * @param fileName * the file name in the system * @return a list of editor descriptors */ virtual QList GetEditors(const QString& fileName) = 0; /* * Returns the list of file editors registered to work against the file with * the given file name and with the given content type. *

* Note: Use getDefaultEditor(String) if you only the need * the default editor rather than all candidate editors. *

* * @param fileName * the file name in the system * @param contentType * the content type or null for the unknown * content type * @return a list of editor descriptors * @since 3.1 */ //virtual QList GetEditors(const QString& fileName, IContentType contentType) = 0; /** * Returns a list of mappings from file type to editor. The resulting list * is sorted in ascending order by file extension. *

* Each mapping defines an extension and the set of editors that are * available for that type. The set of editors includes those registered * via plug-ins and those explicitly associated with a type by the user * in the workbench preference pages. *

* * @return a list of mappings sorted alphabetically by extension */ virtual QList GetFileEditorMappings() = 0; /* * Returns the image descriptor associated with a given file. This image is * usually displayed next to the given file. This method assumes an unknown * content type for the given file. *

* The image is determined by taking the file extension of the file and * obtaining the image for the default editor associated with that * extension. A default image is returned if no default editor is available. *

* * @param filename * the file name in the system * @return the descriptor of the image to display next to the file */ // virtual ImageDescriptor* GetImageDescriptor(const QString& filename) = 0; /* * Returns the image descriptor associated with a given file. This image is * usually displayed next to the given file. *

* The image is determined by taking the file extension of the file and * obtaining the image for the default editor associated with that * extension. A default image is returned if no default editor is available. *

* * @param filename * the file name in the system * @param contentType * the content type of the file or null for the * unknown content type * @return the descriptor of the image to display next to the file * @since 3.1 */ - // virtual ImageDescriptor* GetImageDescriptor(const std::tring& filename, IContentType contentType) = 0; + // virtual ImageDescriptor* GetImageDescriptor(const std::string& filename, IContentType contentType) = 0; /* * Removes the given property listener from this registry. * Has no affect if an identical listener is not registered. * * @param listener a property listener */ // virtual void RemovePropertyListener(IPropertyListener listener) = 0; /** * Sets the default editor id for the files that match that * specified file name or extension. The specified editor must be * defined as an editor for that file name or extension. * * @param fileNameOrExtension the file name or extension pattern (e.g. "*.xml"); * @param editorId the editor id or null for no default */ virtual void SetDefaultEditor(const QString& fileNameOrExtension, const QString& editorId) = 0; /** * Returns whether there is an in-place editor that could handle a file * with the given name. * * @param filename the file name * @return true if an in-place editor is available, and * false otherwise * @since 3.0 */ virtual bool IsSystemInPlaceEditorAvailable(const QString& filename) = 0; /** * Returns whether the system has an editor that could handle a file * with the given name. * * @param filename the file name * @return true if an external editor available, and * false otherwise * @since 3.0 */ virtual bool IsSystemExternalEditorAvailable(const QString& filename) = 0; /* * Returns the image descriptor associated with the system editor that * would be used to edit this file externally. * * @param filename the file name * @return the descriptor of the external editor image, or null * if none * @since 3.0 */ // virtual ImageDescriptor GetSystemExternalEditorImageDescriptor(const QString& filename) = 0; }; } #endif /*MITKIEDITORREGISTRY_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryIEditorSite.h b/Plugins/org.blueberry.ui.qt/src/berryIEditorSite.h index f04095c4df..5d9e33a7e4 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIEditorSite.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIEditorSite.h @@ -1,128 +1,128 @@ /*============================================================================ 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 BERRYIEDITORSITE_H_ #define BERRYIEDITORSITE_H_ #include "berryIWorkbenchPartSite.h" namespace berry { /** * \ingroup org_blueberry_ui_qt * * The primary interface between an editor part and the workbench. *

- * The workbench exposes its implemention of editor part sites via this + * The workbench exposes its implementation of editor part sites via this * interface, which is not intended to be implemented or extended by clients. *

*/ struct BERRY_UI_QT IEditorSite : public virtual IWorkbenchPartSite { berryObjectMacro(berry::IEditorSite); ~IEditorSite() override; /** * Returns the action bar contributor for this editor. *

- * An action contributor is responsable for the creation of actions. + * An action contributor is responsible for the creation of actions. * By design, this contributor is used for one or more editors of the same type. * Thus, the contributor returned by this method is not owned completely * by the editor - it is shared. *

* * @return the editor action bar contributor, or null if none exists */ //virtual IEditorActionBarContributor getActionBarContributor(); /** * Returns the action bars for this part site. Editors of the same type (and * in the same window) share the same action bars. Contributions to the * action bars are done by the IEditorActionBarContributor. * * @return the action bars * @since 2.1 */ //virtual IActionBars getActionBars(); /** *

* Registers a pop-up menu with the default id for extension. The default id * is defined as the part id. *

*

* By default, context menus include object contributions based on the * editor input for the current editor. It is possible to override this * behaviour by calling this method with includeEditorInput * as false. This might be desirable for editors that * present a localized view of an editor input (e.g., a node in a model * editor). *

*

* For a detailed description of context menu registration see * {@link IWorkbenchPartSite#registerContextMenu(MenuManager, ISelectionProvider)} *

* * @param menuManager * the menu manager; must not be null. * @param selectionProvider * the selection provider; must not be null. * @param includeEditorInput * Whether the editor input should be included when adding object * contributions to this context menu. * @see IWorkbenchPartSite#registerContextMenu(MenuManager, * ISelectionProvider) * @since 3.1 */ // virtual void registerContextMenu(MenuManager menuManager, // ISelectionProvider selectionProvider, boolean includeEditorInput); /** *

* Registers a pop-up menu with a particular id for extension. This method * should only be called if the target part has more than one context menu * to register. *

*

* By default, context menus include object contributions based on the * editor input for the current editor. It is possible to override this * behaviour by calling this method with includeEditorInput * as false. This might be desirable for editors that * present a localized view of an editor input (e.g., a node in a model * editor). *

*

* For a detailed description of context menu registration see * {@link IWorkbenchPartSite#registerContextMenu(MenuManager, ISelectionProvider)} *

* * @param menuId * the menu id; must not be null. * @param menuManager * the menu manager; must not be null. * @param selectionProvider * the selection provider; must not be null. * @param includeEditorInput * Whether the editor input should be included when adding object * contributions to this context menu. * @see IWorkbenchPartSite#registerContextMenu(MenuManager, * ISelectionProvider) * @since 3.1 */ // virtual void registerContextMenu(String menuId, MenuManager menuManager, // ISelectionProvider selectionProvider, boolean includeEditorInput); }; } #endif /*BERRYIEDITORSITE_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryIPersistableElement.h b/Plugins/org.blueberry.ui.qt/src/berryIPersistableElement.h index 35989b56ab..368394fb91 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIPersistableElement.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIPersistableElement.h @@ -1,63 +1,63 @@ /*============================================================================ 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 BERRYIPERSISTABLEELEMENT_H #define BERRYIPERSISTABLEELEMENT_H #include namespace berry { /** * Interface for asking an object to store its state in a memento. *

* This interface is typically included in interfaces where - * persistance is required. + * persistence is required. *

* When the workbench is shutdown objects which implement this interface * will be persisted. At this time the GetFactoryId method * is invoked to discover the id of the element factory that will be used * to re-create the object from a memento. Then the SaveState * method is invoked to store the element data into a newly created memento. * The resulting mementos are collected up and written out to a single file. *

*

* During workbench startup these mementos are read from the file. The * factory Id for each is retrieved and mapped to an IElementFactory * which has been registered in the element factory extension point. If a * factory exists for the Id it will be engaged to re-create the original * object. *

* * @see IAdaptable * @see IMemento * @see IElementFactory */ struct IPersistableElement : public IPersistable { /** * Returns the id of the element factory which should be used to re-create this * object. *

* Factory ids are declared in extensions to the standard extension point * "org.eclipse.ui.elementFactories". *

* * @return the element factory id * @see IElementFactory */ virtual QString GetFactoryId() const = 0; }; } #endif // BERRYIPERSISTABLEELEMENT_H diff --git a/Plugins/org.blueberry.ui.qt/src/berryIStructuredSelection.h b/Plugins/org.blueberry.ui.qt/src/berryIStructuredSelection.h index 726dfa4325..4395446aab 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIStructuredSelection.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIStructuredSelection.h @@ -1,84 +1,84 @@ /*============================================================================ 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 BERRYISTRUCTUREDSELECTION_H_ #define BERRYISTRUCTUREDSELECTION_H_ #include "berryISelection.h" #include #include namespace berry { /** * A selection containing elements. */ struct BERRY_UI_QT IStructuredSelection : public ISelection { typedef ObjectList ContainerType; typedef ContainerType::const_iterator iterator; berryObjectMacro(berry::IStructuredSelection); /** * Returns the first element in this selection, or null * if the selection is empty. * * @return an element, or null if none */ virtual Object::Pointer GetFirstElement() const = 0; /** * Returns an iterator to the beginning of the elements of this selection. * * @return an iterator over the selected elements */ virtual iterator Begin() const = 0; /** * Returns an iterator to the end of the elements of this selection. * * @return an iterator over the selected elements */ virtual iterator End() const = 0; /** * Returns the number of elements selected in this selection. * * @return the number of elements selected */ virtual int Size() const = 0; /** * Returns the elements in this selection as a vector. * * @return the selected elements as a vector */ virtual ContainerType::Pointer ToVector() const = 0; /* * We need to define at least the destructor in this compilation unit * because of the export macro above. Otherwise Windows throws - * a linker error in dependent librraies. The export macro is needed + * a linker error in dependent libraries. The export macro is needed * for gcc < 4.5 to correctly mark the type_info object of this class * as visible (we have default visibility 'hidden') so that dynamic_cast calls work. */ ~IStructuredSelection() override; }; } #endif /* BERRYISTRUCTUREDSELECTION_H_ */ diff --git a/Plugins/org.blueberry.ui.qt/src/berryIViewSite.h b/Plugins/org.blueberry.ui.qt/src/berryIViewSite.h index 70f052e120..ed4a144795 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIViewSite.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIViewSite.h @@ -1,57 +1,57 @@ /*============================================================================ 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 BERRYIVIEWSITE_H_ #define BERRYIVIEWSITE_H_ #include "berryIWorkbenchPartSite.h" #include namespace berry { /** * \ingroup org_blueberry_ui_qt * * The primary interface between a view part and the workbench. *

- * The workbench exposes its implemention of view part sites via this interface, + * The workbench exposes its implementation of view part sites via this interface, * which is not intended to be implemented or extended by clients. *

*/ struct BERRY_UI_QT IViewSite : public virtual IWorkbenchPartSite { berryObjectMacro(berry::IViewSite); ~IViewSite() override; /** * Returns the action bars for this part site. * Views have exclusive use of their site's action bars. * * @return the action bars */ //IActionBars getActionBars(); /** * Returns the secondary id for this part site's part, * or null if it has none. * * @see IWorkbenchPage#showView(String, String, int) */ virtual QString GetSecondaryId() = 0; }; } #endif /*BERRYIVIEWSITE_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryIWorkbench.h b/Plugins/org.blueberry.ui.qt/src/berryIWorkbench.h index 905f58a87f..2d9321e54b 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIWorkbench.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIWorkbench.h @@ -1,421 +1,421 @@ /*============================================================================ 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 BERRYIWORKBENCH_H_ #define BERRYIWORKBENCH_H_ #include #include "services/berryIServiceLocator.h" #include "berryIViewRegistry.h" #include "berryIEditorRegistry.h" #include "intro/berryIIntroManager.h" #include "berryIPerspectiveRegistry.h" #include "berryIWorkbenchWindow.h" #include "berryIWorkbenchListener.h" #include "berryIWindowListener.h" #include "berryDisplay.h" namespace berry { struct IElementFactory; struct IExtensionTracker; struct IWorkbenchPage; /** * \ingroup org_blueberry_ui_qt * * A workbench is the root object for the BlueBerry Platform user interface. *

* A workbench has one or more main windows which present to the end * user information based on some underlying model, typically on resources in an * underlying workspace. A workbench usually starts with a single open window, * and automatically closes when its last window closes. *

*

* Each workbench window has a collection of pages; the active * page is the one that is being presented to the end user; at most one page is * active in a window at a time. *

*

* Each workbench page has a collection of workbench parts, of which * there are two kinds: views and editors. A page's parts are arranged (tiled or * stacked) for presentation on the screen. The arrangement is not fixed; the * user can arrange the parts as they see fit. A perspective is a * template for a page, capturing a collection of parts and their arrangement. *

*

* The platform creates a workbench when the workbench plug-in is activated; * since this happens at most once during the life of the running platform, * there is only one workbench instance. Due to its singular nature, it is * commonly referred to as the workbench. *

*

* The workbench supports a few {@link IServiceLocator services} by default. If * these services are used to allocate resources, it is important to remember to * clean up those resources after you are done with them. Otherwise, the * resources will exist until the workbench shuts down. The supported services * are: *

*
    *
  • {@link ICommandService}
  • *
  • {@link IContextService}
  • *
  • {@link IHandlerService}
  • *
*

* This interface is not intended to be implemented by clients. *

* * @see PlatformUI#GetWorkbench */ struct BERRY_UI_QT IWorkbench : public IServiceLocator { berryObjectMacro(berry::IWorkbench); ~IWorkbench() override; /** * Returns the display for this workbench. *

* Code should always ask the workbench for the display rather than rely on * {@link Display#GetDefault Display.getDefault()}. *

* * @return the display to be used for all UI interactions with this * workbench */ virtual Display* GetDisplay() const = 0; /** * Adds a workbench listener. * * @param listener * the workbench listener to add * @since 3.2 */ virtual void AddWorkbenchListener(IWorkbenchListener* listener) = 0; /** * Removes a workbench listener. * * @param listener * the workbench listener to remove * @since 3.2 */ virtual void RemoveWorkbenchListener(IWorkbenchListener* listener) = 0; /** * Returns the workbench events object */ virtual IWorkbenchListener::Events& GetWorkbenchEvents() = 0; /** * Adds a window listener. * * @param listener * the window listener to add * @since 2.0 */ virtual void AddWindowListener(IWindowListener* listener) = 0; /** * Removes a window listener. * * @param listener * the window listener to remove * @since 2.0 */ virtual void RemoveWindowListener(IWindowListener* listener) = 0; /** * Returns the window events object * */ virtual IWindowListener::Events& GetWindowEvents() = 0; /** * Closes this workbench and all its open windows. *

* If the workbench has an open editor with unsaved content, the user will * be given the opportunity to save it. *

* * @return true if the workbench was successfully closed, and * false if it is still open */ virtual bool Close() = 0; /** * Returns the currently active window for this workbench (if any). Returns * null if there is no active workbench window. Returns * null if called from a non-UI thread. * * @return the active workbench window, or null if there is * no active workbench window or if called from a non-UI thread */ virtual IWorkbenchWindow::Pointer GetActiveWorkbenchWindow() const = 0; /** * Return the extension tracker for the workbench. This tracker may be used * by plug-ins to ensure responsiveness to changes to the plug-in registry. *

* The tracker at this level of the workbench is typically used to track * elements that persist for the life of the workbench. For example, * IEditorDescriptor objects fall into this category. *

* * @return the extension tracker * @see IWorkbenchWindow#GetExtensionTracker() * @see IWorkbenchPage#GetExtensionTracker() */ virtual IExtensionTracker* GetExtensionTracker() const = 0; /** * Returns the perspective registry for the workbench. * * @return the workbench perspective registry */ virtual IPerspectiveRegistry* GetPerspectiveRegistry() const = 0; /** * Returns the view registry for the workbench. * * @return the workbench view registry * @since 3.1 */ virtual IViewRegistry* GetViewRegistry() const = 0; /** * Returns the editor registry for the workbench. * * @return the workbench editor registry */ virtual IEditorRegistry* GetEditorRegistry() const = 0; /** * Returns the number of open main windows associated with this workbench. * Note that wizards and dialogs are not included in this list since they * are not considered main windows. * * @return the number of open windows * @since 3.0 */ virtual std::size_t GetWorkbenchWindowCount() const = 0; /** * Returns a list of the open main windows associated with this workbench. * Note that wizards and dialogs are not included in this list since they * are not considered main windows. * * @return a list of open windows */ virtual QList GetWorkbenchWindows() const = 0; /** * Creates and opens a new workbench window with one page. The perspective * of the new page is defined by the specified perspective ID. The new * window and new page become active. *

* Note: The caller is responsible to ensure the action using this * method will explicitly inform the user a new window will be opened. * Otherwise, callers are strongly recommended to use the * openPerspective APIs to programmatically show a * perspective to avoid confusing the user. *

*

* In most cases where this method is used the caller is tightly coupled to * a particular perspective. They define it in the registry and contribute * some user interface action to open or activate it. In situations like * this a static variable is often used to identify the perspective ID. *

* * @param perspectiveId * the perspective id for the window's initial page, or * null for no initial page * @param input * the page input, or null if there is no current * input. This is used to seed the input for the new page's * views. * @return the new workbench window * @exception WorkbenchException * if a new window and page could not be opened * * @see IWorkbench#showPerspective(String, IWorkbenchWindow, IAdaptable) */ virtual IWorkbenchWindow::Pointer OpenWorkbenchWindow(const QString& perspectiveId, IAdaptable* input) = 0; /** * Creates and opens a new workbench window with one page. The perspective * of the new page is defined by the default perspective ID. The new window * and new page become active. *

* Note: The caller is responsible to ensure the action using this * method will explicitly inform the user a new window will be opened. * Otherwise, callers are strongly recommended to use the * openPerspective APIs to programmatically show a * perspective to avoid confusing the user. *

* * @param input * the page input, or null if there is no current * input. This is used to seed the input for the new page's * views. * @return the new workbench window * @exception WorkbenchException * if a new window and page could not be opened * * @see IWorkbench#showPerspective(String, IWorkbenchWindow, IAdaptable) */ virtual IWorkbenchWindow::Pointer OpenWorkbenchWindow(IAdaptable* input) = 0; /** * Shows the specified perspective to the user. The caller should use this * method when the perspective to be shown is not dependent on the page's * input. That is, the perspective can open in any page depending on user * preferences. *

* The perspective may be shown in the specified window, in another existing * window, or in a new window depending on user preferences. The exact * policy is controlled by the workbench to ensure consistency to the user. * The policy is subject to change. The current policy is as follows: *

    *
  • If the specified window has the requested perspective open, then the * window is given focus and the perspective is shown. The page's input is * ignored.
  • *
  • If another window that has the workspace root as input and the * requested perspective open and active, then the window is given focus. *
  • *
  • Otherwise the requested perspective is opened and shown in the * specified window or in a new window depending on the current user * preference for opening perspectives, and that window is given focus. *
  • *
*

*

* The workbench also defines a number of menu items to activate or open * each registered perspective. A complete list of these perspectives is * available from the perspective registry found on IWorkbench. *

* * @param perspectiveId * the perspective ID to show * @param window * the workbench window of the action calling this method. * @return the workbench page that the perspective was shown * @exception WorkbenchException * if the perspective could not be shown * * @since 2.0 */ virtual SmartPointer ShowPerspective(const QString& perspectiveId, IWorkbenchWindow::Pointer window) = 0; /** * Shows the specified perspective to the user. The caller should use this * method when the perspective to be shown is dependent on the page's input. * That is, the perspective can only open in any page with the specified * input. *

* The perspective may be shown in the specified window, in another existing * window, or in a new window depending on user preferences. The exact * policy is controlled by the workbench to ensure consistency to the user. * The policy is subject to change. The current policy is as follows: *

    *
  • If the specified window has the requested perspective open and the * same requested input, then the window is given focus and the perspective * is shown.
  • *
  • If another window has the requested input and the requested * perspective open and active, then that window is given focus.
  • *
  • If the specified window has the same requested input but not the * requested perspective, then the window is given focus and the perspective * is opened and shown on condition that the user preference is not to open * perspectives in a new window.
  • *
  • Otherwise the requested perspective is opened and shown in a new * window, and the window is given focus.
  • *
*

*

* The workbench also defines a number of menu items to activate or open * each registered perspective. A complete list of these perspectives is * available from the perspective registry found on IWorkbench. *

* * @param perspectiveId * the perspective ID to show * @param window * the workbench window of the action calling this method. * @param input * the page input, or null if there is no current * input. This is used to seed the input for the page's views * @return the workbench page that the perspective was shown * @exception WorkbenchException * if the perspective could not be shown * * @since 2.0 */ virtual SmartPointer ShowPerspective(const QString& perspectiveId, IWorkbenchWindow::Pointer window, IAdaptable* input) = 0; /** * Save all dirty editors in the workbench. Opens a dialog to prompt the * user if confirm is true. Return true if successful. Return * false if the user has canceled the command. * * @param confirm true to ask the user before saving unsaved * changes (recommended), and false to save * unsaved changes without asking * @return true if the command succeeded, and * false if the operation was canceled by the user or * an error occurred while saving */ virtual bool SaveAllEditors(bool confirm) = 0; /** - * Returns the element factory with the given id. The calles takes + * Returns the element factory with the given id. The caller takes * ownership of the returned pointer. * * @param factoryId * the id of the element factory * @return the element factory, or null if none * @see IElementFactory */ virtual IElementFactory* GetElementFactory(const QString& factoryId) const = 0; /** * Return the intro manager for this workbench. * * @return the intro manager for this workbench. Guaranteed not to be * null. */ virtual IIntroManager* GetIntroManager() const = 0; /** * Returns a boolean indicating whether the workbench is in the process of * closing. * * @return true if the workbench is in the process of * closing, false otherwise * @since 3.1 */ virtual bool IsClosing() const = 0; /** * Applies changes of the current theme to the user interface. */ virtual void UpdateTheme() = 0; }; } #endif /*BERRYIWORKBENCH_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryIWorkbenchPartReference.h b/Plugins/org.blueberry.ui.qt/src/berryIWorkbenchPartReference.h index cc5c390f3b..d205ac78c2 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIWorkbenchPartReference.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIWorkbenchPartReference.h @@ -1,138 +1,138 @@ /*============================================================================ 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 BERRYIWORKBENCHPARTREFERENCE_H_ #define BERRYIWORKBENCHPARTREFERENCE_H_ #include #include #include "berryIPropertyChangeListener.h" namespace berry { struct IWorkbenchPart; struct IWorkbenchPage; /** * \ingroup org_blueberry_ui_qt * * Implements a reference to a IWorkbenchPart. - * The IWorkbenchPart will not be instanciated until the part + * The IWorkbenchPart will not be instantiated until the part * becomes visible or the API getPart is sent with true; *

* This interface is not intended to be implemented by clients. *

*/ struct BERRY_UI_QT IWorkbenchPartReference : public Object { berryObjectMacro(berry::IWorkbenchPartReference); ~IWorkbenchPartReference() override; /** * Returns the IWorkbenchPart referenced by this object. * Returns null if the editors was not instantiated or * it failed to be restored. Tries to restore the editor * if restore is true. */ virtual SmartPointer GetPart(bool restore) = 0; /** * @see IWorkbenchPart#getTitleImage */ virtual QIcon GetTitleImage() const = 0; /** * @see IWorkbenchPart#getTitleToolTip */ virtual QString GetTitleToolTip() const = 0; /** * @see IWorkbenchPartSite#getId */ virtual QString GetId() const = 0; /** * @see IWorkbenchPart#addPropertyListener */ virtual void AddPropertyListener(IPropertyChangeListener* listener) = 0; /** * @see IWorkbenchPart#removePropertyListener */ virtual void RemovePropertyListener(IPropertyChangeListener* listener) = 0; /** * Returns the workbench page that contains this part */ virtual SmartPointer GetPage() const = 0; /** * Returns the name of the part, as it should be shown in tabs. * * @return the part name */ virtual QString GetPartName() const = 0; /** * Returns the content description for the part (or the empty string if none) * * @return the content description for the part */ virtual QString GetContentDescription() const = 0; /** * Returns true if the part is pinned otherwise returns false. */ virtual bool IsPinned() const = 0; /** * Returns whether the part is dirty (i.e. has unsaved changes). * * @return true if the part is dirty, false otherwise */ virtual bool IsDirty() const = 0; /** * Return an arbitrary property from the reference. If the part has been * instantiated, it just delegates to the part. If not, then it looks in its * own cache of properties. If the property is not available or the part has * never been instantiated, it can return null. * * @param key * The property to return. Must not be null. * @return The String property, or null. */ virtual QString GetPartProperty(const QString& key) const = 0; /** * Add a listener for changes in the arbitrary properties set. * * @param listener * Must not be null. */ //virtual void addPartPropertyListener(IPropertyChangeListener listener) = 0; /** * Remove a listener for changes in the arbitrary properties set. * * @param listener * Must not be null. */ //virtual void removePartPropertyListener(IPropertyChangeListener listener) = 0; }; } // namespace berry #endif /*BERRYIWORKBENCHPARTREFERENCE_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryMenuUtil.h b/Plugins/org.blueberry.ui.qt/src/berryMenuUtil.h index 12332c5974..ee61eb4867 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryMenuUtil.h +++ b/Plugins/org.blueberry.ui.qt/src/berryMenuUtil.h @@ -1,134 +1,134 @@ /*============================================================================ 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 BERRYMENUUTIL_H #define BERRYMENUUTIL_H #include namespace berry { /** * Provides utilities and constants for use with the new menus API. * * @note This class is not intended to be subclassed by clients. * @note This class is not intended to be instantiated by clients. */ class BERRY_UI_QT MenuUtil { public: /** * * Workbench Menu. On supported platforms, this menu is shown when no * workbench windows are active */ static QString WORKBENCH_MENU; // = "menu:org.blueberry.ui.workbench.menu"; /** Main Menu */ static QString MAIN_MENU; // = "menu:org.blueberry.ui.main.menu"; /** Main ToolBar */ static QString MAIN_TOOLBAR; // = "toolbar:org.blueberry.ui.main.toolbar"; /** -Any- Popup Menu */ static QString ANY_POPUP; // = "popup:org.blueberry.ui.popup.any"; /** * Valid query attribute. Usage menu:menu.id?before=contribution.id. */ static QString QUERY_BEFORE; // = "before"; /** * Valid query attribute. Usage menu:menu.id?after=contribution.id. */ static QString QUERY_AFTER; // = "after"; /** * Valid query attribute. Usage menu:menu.id?endof=contribution.id. *

* This menu contribution will be placed at the end of the group defined by * contribution.id (usually right in front of the next group marker * or separator). Further contribution processing can still place other * contributions after this one. *

*/ static QString QUERY_ENDOF; // = "endof"; /** * Contributions of targets to this location will be included with the show * in menu. */ static QString SHOW_IN_MENU_ID; // = "popup:org.blueberry.ui.menus.showInMenu"; /** * @param id * The menu's id * @return The locator URI for a menu with the given id */ static QString MenuUri(const QString& id); /** * @param id * The id of the menu * @param location * The relative location specifier * @param refId * The id of the menu element to be relative to * @return A location URI formatted with the given parameters */ static QString MenuAddition(const QString& id, const QString& location, const QString& refId); /** * Convenience method to create a standard menu addition The resulting * string has the format: "menu:[id]?after=additions" * * @param id * The id of the root element to contribute to * @return The formatted string */ static QString MenuAddition(const QString& id); /** * @param id * The toolbar's id - * @return The lcoation URI for a toolbar with the given id + * @return The location URI for a toolbar with the given id */ static QString ToolbarUri(const QString& id); /** * @param id * The id of the toolbar * @param location * The relative location specifier * @param refId * The id of the toolbar element to be relative to * @return A location URI formatted with the given parameters */ static QString ToolbarAddition(const QString& id, const QString& location, const QString& refId); /** * Convenience method to create a standard toolbar addition The resulting * string has the format: "toolbar:[id]?after=additions" * * @param id * The id of the root element to contribute to * @return The formatted string */ static QString ToolbarAddition(const QString& id); }; } #endif // BERRYMENUUTIL_H diff --git a/Plugins/org.blueberry.ui.qt/src/berryPropertyChangeEvent.h b/Plugins/org.blueberry.ui.qt/src/berryPropertyChangeEvent.h index 740bb995cc..e54c0d7a3b 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryPropertyChangeEvent.h +++ b/Plugins/org.blueberry.ui.qt/src/berryPropertyChangeEvent.h @@ -1,125 +1,125 @@ /*============================================================================ 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 BERRYPROPERTYCHANGEEVENT_H_ #define BERRYPROPERTYCHANGEEVENT_H_ #include #include #include namespace berry { /** * An event object describing a change to a named property. *

* This concrete class was designed to be instantiated, but may * also be subclassed if required. *

*

* The JFace frameworks contain classes that report property * change events for internal state changes that may be of interest * to external parties. A special listener interface * (IPropertyChangeListener) is defined for this purpose, * and a typical class allow listeners to be registered via * an addPropertyChangeListener method. *

* * @see IPropertyChangeListener */ class BERRY_UI_QT PropertyChangeEvent : public Object { public: berryObjectMacro(PropertyChangeEvent); private: /** * The name of the changed property. */ QString propertyName; /** * The old value of the changed property, or null if * not known or not relevant. */ Object::Pointer oldValue; /** * The new value of the changed property, or null if * not known or not relevant. */ Object::Pointer newValue; /** - * The object on which the property change occured + * The object on which the property change occurred */ Object::Pointer source; public: /** * Creates a new property change event. * * @param source the object whose property has changed * @param property the property that has changed (must not be null) * @param oldValue the old value of the property, or null if none * @param newValue the new value of the property, or null if none */ PropertyChangeEvent(Object::Pointer source, const QString& property, Object::Pointer oldValue, Object::Pointer newValue); /** * Returns the new value of the property. * * @return the new value, or null if not known * or not relevant (for instance if the property was removed). */ Object::Pointer GetNewValue(); /** * Returns the old value of the property. * * @return the old value, or null if not known * or not relevant (for instance if the property was just * added and there was no old value). */ Object::Pointer GetOldValue(); /** * Returns the name of the property that changed. *

* Warning: there is no guarantee that the property name returned * is a constant string. Callers must compare property names using * equals, not ==. *

* * @return the name of the property that changed */ QString GetProperty(); /** * Returns the object whose property has changed * * @return the object whose property has changed */ Object::Pointer GetSource(); }; } #endif /* BERRYPROPERTYCHANGEEVENT_H_ */ diff --git a/Plugins/org.blueberry.ui.qt/src/berrySameShellProvider.h b/Plugins/org.blueberry.ui.qt/src/berrySameShellProvider.h index e94e1595cd..c14ad3970b 100644 --- a/Plugins/org.blueberry.ui.qt/src/berrySameShellProvider.h +++ b/Plugins/org.blueberry.ui.qt/src/berrySameShellProvider.h @@ -1,70 +1,70 @@ /*============================================================================ 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 BERRYSAMESHELLPROVIDER_H_ #define BERRYSAMESHELLPROVIDER_H_ #include #include "berryShell.h" #include #include "berryIShellProvider.h" namespace berry { /** * Standard shell provider that always returns the shell containing the given * control. This will always return the correct shell for the control, even if * the control is reparented. * * @since 3.1 */ class BERRY_UI_QT SameShellProvider : public IShellProvider { private: QWidget* targetControl; Shell::Pointer shell; public: berryObjectMacro(SameShellProvider); /** * Returns a shell provider that always returns the current * shell for the given control. * * @param targetControl control whose shell will be tracked, or null if getShell() should always * return null */ SameShellProvider(QWidget* targetControl); /** * Returns a shell provider that always returns the given shell. * * @param shell the shell which should always be returned, - * or null if GetShell() should alway return null + * or null if GetShell() should always return null */ SameShellProvider(Shell::Pointer shell); /* (non-javadoc) * @see IShellProvider#getShell() */ Shell::Pointer GetShell() const override; }; } #endif /* BERRYSAMESHELLPROVIDER_H_ */ diff --git a/Plugins/org.blueberry.ui.qt/src/berryWindow.h b/Plugins/org.blueberry.ui.qt/src/berryWindow.h index beab88ed1a..56ea246b1c 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryWindow.h +++ b/Plugins/org.blueberry.ui.qt/src/berryWindow.h @@ -1,675 +1,675 @@ /*============================================================================ 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 BERRYWINDOW_H_ #define BERRYWINDOW_H_ #include #include "berryIShellProvider.h" #include "berryIShellListener.h" #include "internal/berryWindowManager.h" #include "tweaklets/berryGuiWidgetsTweaklet.h" #include #include namespace berry { //struct IToolBarManager; class MenuManager; //class StatusLineManager; /** * A JFace window is an object that has no visual representation (no widgets) * until it is told to open. *

* Creating a window involves the following steps: *

    *
  • creating an instance of a concrete subclass of Window *
  • *
  • creating the window's shell and widget tree by calling * create (optional)
  • *
  • assigning the window to a window manager using * WindowManager.add (optional)
  • *
  • opening the window by calling open
  • *
* Opening the window will create its shell and widget tree if they have not * already been created. When the window is closed, the shell and widget tree * are disposed of and are no longer referenced, and the window is automatically * removed from its window manager. A window may be reopened. *

*

* The JFace window framework (this package) consists of this class, * Window, the abstract base of all windows, and one concrete * window classes (ApplicationWindow) which may also be * subclassed. Clients may define additional window subclasses as required. *

*

* The Window class provides methods that subclasses may * override to configure the window, including: *

    *
  • close- extend to free other SWT resources
  • *
  • configureShell- extend or reimplement to set shell * properties before window opens
  • *
  • createContents- extend or reimplement to create controls * before window opens
  • *
  • getInitialSize- reimplement to give the initial size for * the shell
  • *
  • getInitialLocation- reimplement to give the initial * location for the shell
  • *
  • getShellListener- extend or reimplement to receive shell * events
  • *
  • handleFontChange- reimplement to respond to font changes *
  • *
  • handleShellCloseEvent- extend or reimplement to handle * shell closings
  • *
*

*/ class BERRY_UI_QT Window: public IShellProvider { public: berryObjectMacro(Window, IShellProvider); /** * Standard return code constant (value 0) indicating that the window was * opened. * * @see #Open */ static const int OK; // = 0; /** * Standard return code constant (value 1) indicating that the window was * canceled. * * @see #Open */ static const int CANCEL; // = 1; /** * An array of images to be used for the window. It is expected that the * array will contain the same icon rendered at different resolutions. */ static QList defaultImages; /** * This interface defines a Exception Handler which can be set as a global * handler and will be called if an exception happens in the event loop. */ struct IExceptionHandler: public Object { berryObjectMacro(IExceptionHandler); /** * Handle the exception. * * @param t - * The exception that occured. + * The exception that occurred. */ virtual void HandleException(const std::exception& t) = 0; }; private: struct WindowShellListener : public IShellListener { WindowShellListener(Window* wnd); void ShellClosed(const ShellEvent::Pointer& event) override; private: Window* window; }; QScopedPointer windowShellListener; /** * Defines a default exception handler. */ struct DefaultExceptionHandler: public IExceptionHandler { /* * (non-Javadoc) * * @see org.blueberry.jface.window.Window.IExceptionHandler#handleException(java.lang.Throwable) */ void HandleException(const std::exception& t) override; }; /** * Menu bar manager, or null if none (default). * * @see #AddMenuBar */ SmartPointer menuBarManager; /** * The exception handler for this application. */ static IExceptionHandler::Pointer exceptionHandler; /** * Object used to locate the default parent for modal shells */ struct DefaultModalParent: public IShellProvider { Shell::Pointer GetShell() const override; }; friend struct DefaultModalParent; static IShellProvider::Pointer defaultModalParent; /** * Object that returns the parent shell. */ IShellProvider::Pointer parentShell; /** * Shell style bits. * * @see #setShellStyle */ int shellStyle; // = Constants::SHELL_TRIM; /** * Window manager, or null if none. * * @see #setWindowManager */ WindowManager* windowManager; /** * Window shell, or null if none. */ Shell::Pointer shell; /** * Top level SWT control, or null if none */ QWidget* contents; /** * Window return code; initially OK. * * @see #setReturnCode */ int returnCode; // = OK; /** * true if the open method should not return * until the window closes, and false if the * open method should return immediately; initially * false (non-blocking). * * @see #setBlockOnOpen */ bool block; // = false; /** * Returns the most specific modal child from the given list of Shells. * * @param toSearch shells to search for modal children * @return the most specific modal child, or null if none * * @since 3.1 */ static Shell::Pointer GetModalChild( const QList& toSearch); protected: /** * Creates a window instance, whose shell will be created under the given * parent shell. Note that the window will have no visual representation * until it is told to open. By default, open does not block. * * @param parentShell * the parent shell, or null to create a top-level * shell. Try passing "(Shell)null" to this method instead of "null" * if your compiler complains about an ambiguity error. * @see #SetBlockOnOpen */ Window(Shell::Pointer parentShell); /** * Creates a new window which will create its shell as a child of whatever * the given shellProvider returns. * * @param shellProvider object that will return the current parent shell. Not null. * */ Window(IShellProvider::Pointer shellProvider); ~Window() override; /** * Given the desired position of the window, this method returns an adjusted * position such that the window is no larger than its monitor, and does not * extend beyond the edge of the monitor. This is used for computing the * initial window position, and subclasses can use this as a utility method * if they want to limit the region in which the window may be moved. * * @param preferredSize * the preferred position of the window * @return a rectangle as close as possible to preferredSize that does not * extend outside the monitor * */ QRect GetConstrainedShellBounds(const QRect& preferredSize); /** * Initializes this windows variables */ virtual void Init(); /** * Determines if the window should handle the close event or do nothing. *

* The default implementation of this framework method returns * true, which will allow the * handleShellCloseEvent method to be called. Subclasses may * extend or reimplement. *

* * @return whether the window should handle the close event. */ virtual bool CanHandleShellCloseEvent(); /** * Configures the given shell in preparation for opening this window in it. *

* The default implementation of this framework method sets the shell's * image and gives it a grid layout. Subclasses may extend or reimplement. *

* * @param newShell * the shell */ virtual void ConfigureShell(Shell::Pointer newShell); /** * Creates and returns this window's contents. Subclasses may attach any * number of children to the parent. As a convenience, the return value of * this method will be remembered and returned by subsequent calls to * getContents(). Subclasses may modify the parent's layout if they overload * getLayout() to return null. * *

- * It is common practise to create and return a single composite that + * It is common practice to create and return a single composite that * contains the entire window contents. *

* *

* The default implementation of this framework method creates an instance * of Composite. Subclasses may override. *

* * @param parent * the parent composite for the controls in this window. The type * of layout used is determined by getLayout() * * @return the control that will be returned by subsequent calls to * getContents() */ virtual QWidget* CreateContents(Shell::Pointer parent); /** * Creates and returns this window's shell. *

* The default implementation of this framework method creates a new shell * and configures it using configureShell. Rather than * override this method, subclasses should instead override * configureShell. *

* * @return the shell */ virtual Shell::Pointer CreateShell(); /** * Returns the top level control for this window. The parent of this control * is the shell. * * @return the top level control, or null if this window's * control has not been created yet */ virtual QWidget* GetContents(); /** * Returns the initial location to use for the shell. The default * implementation centers the shell horizontally (1/2 of the difference to * the left and 1/2 to the right) and vertically (1/3 above and 2/3 below) * relative to the parent shell, or display bounds if there is no parent * shell. * * @param initialSize * the initial size of the shell, as returned by * getInitialSize. * @return the initial location of the shell */ virtual QPoint GetInitialLocation(const QPoint& initialSize); /** * Returns the initial size to use for the shell. The default implementation * returns the preferred size of the shell, using * Shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true). * * @return the initial size of the shell */ virtual QPoint GetInitialSize(); /** * Returns parent shell, under which this window's shell is created. * * @return the parent shell, or null if there is no parent * shell */ Shell::Pointer GetParentShell(); /** * Returns a shell listener. This shell listener gets registered with this * window's shell. *

* The default implementation of this framework method returns a new * listener that makes this window the active window for its window manager * (if it has one) when the shell is activated, and calls the framework * method handleShellCloseEvent when the shell is closed. * Subclasses may extend or reimplement. *

* * @return a shell listener */ virtual IShellListener* GetShellListener(); /** * Returns the shell style bits. *

* The default value is SWT.CLOSE|SWT.MIN|SWT.MAX|SWT.RESIZE. * Subclassers should call setShellStyle to change this * value, rather than overriding this method. *

* * @return the shell style bits */ int GetShellStyle(); /** * Notifies that the window's close button was pressed, the close menu was * selected, or the ESCAPE key pressed. *

* The default implementation of this framework method sets the window's * return code to CANCEL and closes the window using * close. Subclasses may extend or reimplement. *

*/ virtual void HandleShellCloseEvent(); /** * Initializes the location and size of this window's SWT shell after it has * been created. *

* This framework method is called by the create framework * method. The default implementation calls getInitialSize * and getInitialLocation and passes the results to * Shell.setBounds. This is only done if the bounds of the * shell have not already been modified. Subclasses may extend or * reimplement. *

*/ virtual void InitializeBounds(); /** * Changes the parent shell. This is only safe to use when the shell is not * yet realized (i.e., created). Once the shell is created, it must be * disposed (i.e., closed) before this method can be called. * * @param newParentShell * The new parent shell; this value may be null if * there is to be no parent. * @since 3.1 */ void SetParentShell(Shell::Pointer newParentShell); /** * Sets this window's return code. The return code is automatically returned * by open if block on open is enabled. For non-blocking * opens, the return code needs to be retrieved manually using * getReturnCode. * * @param code * the return code */ void SetReturnCode(int code); /** * Sets the shell style bits. This method has no effect after the shell is * created. *

* The shell style bits are used by the framework method * createShell when creating this window's shell. *

* * @param newShellStyle * the new shell style bits */ void SetShellStyle(int newShellStyle); /** * Configures this window to have a menu bar. * Does nothing if it already has one. * This method must be called before this window's shell is created. */ void AddMenuBar(); /** * Returns a new menu manager for the window. *

* Subclasses may override this method to customize the menu manager. *

* @return a menu manager */ virtual SmartPointer CreateMenuManager(); /** * Creates the trim widgets around the content area. * * @param shell the shell */ virtual void CreateTrimWidgets(SmartPointer shell); public: /** * Closes this window, disposes its shell, and removes this window from its * window manager (if it has one). *

* This framework method may be extended (super.close must * be called). *

*

* Note that in order to prevent recursive calls to this method * it does not call Shell#close(). As a result ShellListeners * will not receive a shellClosed event. *

* * @return true if the window is (or was already) closed, and * false if it is still open */ virtual bool Close(); /** * Creates this window's widgetry in a new top-level shell. *

* The default implementation of this framework method creates this window's * shell (by calling createShell), and its controls (by * calling createContents), then initializes this window's * shell bounds (by calling initializeBounds). *

*/ virtual void Create(); /** * Returns the default image. This is the image that will be used for * windows that have no shell image at the time they are opened. There is no * default image unless one is installed via setDefaultImage. * * @return the default image, or null if none * @see #SetDefaultImage */ static QIcon GetDefaultImage(); /** * Returns the array of default images to use for newly opened windows. It * is expected that the array will contain the same icon rendered at * different resolutions. * * @see org.blueberry.swt.widgets.Decorations#setImages(org.blueberry.swt.graphics.Image[]) * * @return the array of images to be used when a new window is opened * @see #SetDefaultImages * @since 3.0 */ static QList GetDefaultImages(); /** * Returns this window's return code. A window's return codes are * window-specific, although two standard return codes are predefined: * OK and CANCEL. * * @return the return code */ int GetReturnCode(); /** * Returns this window's shell. * * @return this window's shell, or null if this window's * shell has not been created yet */ Shell::Pointer GetShell() const override; /** * Returns the window manager of this window. * * @return the WindowManager, or null if none */ WindowManager* GetWindowManager(); /** * Returns the menu bar manager for this window (if it has one). * * @return the menu bar manager, or null if * this window does not have a menu bar * @see #AddMenuBar() */ MenuManager* GetMenuBarManager() const; /** * Opens this window, creating it first if it has not yet been created. *

* If this window has been configured to block on open ( * setBlockOnOpen), this method waits until the window is * closed by the end user, and then it returns the window's return code; * otherwise, this method returns immediately. A window's return codes are * window-specific, although two standard return codes are predefined: * OK and CANCEL. *

* * @return the return code * * @see #Create() */ int Open(); /** * Sets whether the open method should block until the window * closes. * * @param shouldBlock * true if the open method should * not return until the window closes, and false * if the open method should return immediately */ void SetBlockOnOpen(bool shouldBlock); /** * Sets the default image. This is the image that will be used for windows * that have no shell image at the time they are opened. There is no default * image unless one is installed via this method. * * @param image * the default image, or null if none */ static void SetDefaultImage(const QIcon& image); /** * Sets the array of default images to use for newly opened windows. It is * expected that the array will contain the same icon rendered at different * resolutions. * * @see org.blueberry.swt.widgets.Decorations#setImages(org.blueberry.swt.graphics.Image[]) * * @param images * the array of images to be used when this window is opened * @since 3.0 */ static void SetDefaultImages(const QList& images); /** * Sets the window manager of this window. *

* Note that this method is used by WindowManager to maintain * a backpointer. Clients must not call the method directly. *

* * @param manager * the window manager, or null if none */ void SetWindowManager(WindowManager* manager); /** * Sets the exception handler for this application. *

* Note that the handler may only be set once. Subsequent calls to this method will be * ignored. *

* * @param handler * the exception handler for the application. */ static void SetExceptionHandler(IExceptionHandler::Pointer handler); /** * Sets the default parent for modal Windows. This will be used to locate * the parent for any modal Window constructed with a null parent. * * @param provider shell provider that will be used to locate the parent shell * whenever a Window is created with a null parent * @since 3.1 */ static void SetDefaultModalParent(IShellProvider::Pointer provider); }; } #endif /* BERRYWINDOW_H_ */ diff --git a/Plugins/org.blueberry.ui.qt/src/berryWorkbenchPart.h b/Plugins/org.blueberry.ui.qt/src/berryWorkbenchPart.h index 69cf519f19..2427402bc7 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryWorkbenchPart.h +++ b/Plugins/org.blueberry.ui.qt/src/berryWorkbenchPart.h @@ -1,241 +1,241 @@ /*============================================================================ 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 __BERRY_WORKBENCH_PART_H__ #define __BERRY_WORKBENCH_PART_H__ #include "berryIWorkbenchPart.h" #include "berryIWorkbenchPartSite.h" #include #include #include namespace berry { /** * \ingroup org_blueberry_ui_qt * * Abstract base implementation of all workbench parts. *

* This class is not intended to be subclassed by clients outside this * package; clients should instead subclass ViewPart or * EditorPart. *

* * @see org.blueberry.ui.part.ViewPart * @see org.blueberry.ui.part.EditorPart */ class BERRY_UI_QT WorkbenchPart : public QObject, public virtual IWorkbenchPart, public IExecutableExtension { Q_OBJECT Q_INTERFACES(berry::IExecutableExtension); public: berryObjectMacro(WorkbenchPart, QObject, IWorkbenchPart, IExecutableExtension); ~WorkbenchPart() override; private: QString m_Title; QIcon m_TitleImage; QString m_ToolTip; IConfigurationElement::Pointer m_ConfigElement; IWorkbenchPartSite::Pointer m_PartSite; QString m_PartName; QString m_ContentDescription; QHash partProperties; IPropertyChangeListener::Events partChangeEvents; void InternalSetContentDescription(const QString& description); void InternalSetPartName(const QString& partName); protected: WorkbenchPart(); /** * Returns the configuration element for this part. The configuration element * comes from the plug-in registry entry for the extension defining this part. * * @return the configuration element for this part */ IConfigurationElement::Pointer GetConfigurationElement() const { return m_ConfigElement; } /** * Sets the part site. * * Subclasses must invoke this method from IEditorPart.init * and IViewPart.init. * * @param site the workbench part site */ void SetSite(IWorkbenchPartSite::Pointer site); /** * Checks that the given site is valid for this type of part. * The default implementation does nothing. * * @param site the site to check */ virtual void CheckSite(IWorkbenchPartSite::Pointer site); /** * Sets or clears the title image of this part. * * @param titleImage the title image, or null to clear */ virtual void SetTitleImage(const QIcon& titleImage); /** * Sets or clears the title tool tip text of this part. Clients should * call this method instead of overriding getTitleToolTip * * @param toolTip the new tool tip text, or null to clear */ virtual void SetTitleToolTip(const QString& toolTip); /** * Sets the name of this part. The name will be shown in the tab area for * the part. Clients should call this method instead of overriding getPartName. * Setting this to the empty string will cause a default part name to be used. * * @param partName the part name, as it should be displayed in tabs. */ virtual void SetPartName(const QString& partName); /** * Sets the content description for this part. The content description is typically * a short string describing the current contents of the part. Setting this to the * empty string will cause a default content description to be used. Clients should * call this method instead of overriding getContentDescription(). For views, the * content description is shown (by default) in a line near the top of the view. For * editors, the content description is shown beside the part name when showing a * list of editors. If the editor is open on a file, this typically contains the path * to the input file, without the filename or trailing slash. * * @param description the content description */ virtual void SetContentDescription(const QString& description); void FirePropertyChanged(const QString& key, const QString& oldValue, const QString& newValue); void FirePropertyChange(int propertyId); public: /* (non-Javadoc) * Method declared on IWorkbenchPart. */ void AddPropertyListener(IPropertyChangeListener* l) override; void RemovePropertyListener(IPropertyChangeListener* l) override; void SetPartProperty(const QString& key, const QString& value) override; /* (non-Javadoc) * @see org.blueberry.ui.IWorkbenchPart3#getPartProperty(java.lang.String) */ QString GetPartProperty(const QString& key) const override; /* (non-Javadoc) * @see org.blueberry.ui.IWorkbenchPart3#getPartProperties() */ const QHash& GetPartProperties() const override; /** * {@inheritDoc} * The WorkbenchPart implementation of this * IExecutableExtension records the configuration element in * and internal state variable (accessible via getConfigElement). * It also loads the title image, if one is specified in the configuration element. * Subclasses may extend. * * Should not be called by clients. It is called by the core plugin when creating * this executable extension. */ void SetInitializationData(const IConfigurationElement::Pointer& cfig, const QString& propertyName, const Object::Pointer& data) override; /* * Creates the controls for this workbench part. *

* Subclasses must implement this method. For a detailed description of the * requirements see IWorkbenchPart *

* * @param parent the parent control * @see IWorkbenchPart */ void CreatePartControl(QWidget* parent) override = 0; /* (non-Javadoc) * Asks this part to take focus within the workbench. *

* Subclasses must implement this method. For a detailed description of the * requirements see IWorkbenchPart *

* * @see IWorkbenchPart */ void SetFocus() override = 0; /* * Method declared on IWorkbenchPart. */ IWorkbenchPartSite::Pointer GetSite() const override; /** * {@inheritDoc} *

- * It is considered bad practise to overload or extend this method. + * It is considered bad practice to overload or extend this method. * Parts should call setPartName to change their part name. *

*/ QString GetPartName() const override; /** * {@inheritDoc} *

- * It is considered bad practise to overload or extend this method. + * It is considered bad practice to overload or extend this method. * Parts should call setContentDescription to change their content description. *

*/ QString GetContentDescription() const override; /* (non-Javadoc) * Method declared on IWorkbenchPart. */ QIcon GetTitleImage() const override; /* (non-Javadoc) * Gets the title tool tip text of this part. * * @return the tool tip text */ QString GetTitleToolTip() const override; }; } // namespace berry #endif // __BERRY_WORKBENCH_PART_H__ diff --git a/Plugins/org.blueberry.ui.qt/src/handlers/berryHandlerUtil.h b/Plugins/org.blueberry.ui.qt/src/handlers/berryHandlerUtil.h index d526f0ac1f..78e2e375d6 100644 --- a/Plugins/org.blueberry.ui.qt/src/handlers/berryHandlerUtil.h +++ b/Plugins/org.blueberry.ui.qt/src/handlers/berryHandlerUtil.h @@ -1,382 +1,382 @@ /*============================================================================ 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 BERRYHANDLERUTIL_H_ #define BERRYHANDLERUTIL_H_ #include #include #include #include #include "berryIWorkbenchPart.h" #include "berryIWorkbenchPartSite.h" #include "berryISelection.h" #include "berryIWorkbenchWindow.h" #include "berryISources.h" namespace berry { /** * \ingroup org_blueberry_ui_qt * * Some common utilities for working with handlers in Platform UI. *

* Note: this class should not be instantiated or extended by clients. *

* * @since 3.3 */ class BERRY_UI_QT HandlerUtil { private: static void NoVariableFound(const ExecutionEvent::ConstPointer& event, const QString& name); static void IncorrectTypeFound(const ExecutionEvent::ConstPointer& event, const QString& name, const QString& expectedType, const QString& wrongType); public: typedef ObjectList StringVectorType; /** * Extract the variable. * * @param event * The execution event that contains the application context * @param name * The variable name to extract. * @return The object from the application context, or null * if it could not be found. */ static Object::ConstPointer GetVariable(const ExecutionEvent::ConstPointer& event, const QString& name); /** * Extract the variable. * * @param event * The execution event that contains the application context * @param name * The variable name to extract. * @return The object from the application context. Will not return * null. * @throws ExecutionException * if the variable is not found. */ static Object::ConstPointer GetVariableChecked(const ExecutionEvent::ConstPointer& event, const QString& name); /** * Extract the variable. * * @param context * The IEvaluationContext or null * @param name * The variable name to extract. * @return The object from the application context, or null * if it could not be found. */ static Object::ConstPointer GetVariable(Object::Pointer context, const QString& name); /** * Return the active contexts. * * @param event * The execution event that contains the application context * @return a collection of String contextIds, or null. */ static StringVectorType::ConstPointer GetActiveContexts(const ExecutionEvent::ConstPointer& event); /** * Return the active contexts. * * @param event * The execution event that contains the application context * @return a collection of String contextIds. Will not return * null. * @throws ExecutionException * If the context variable is not found. */ static StringVectorType::ConstPointer GetActiveContextsChecked(const ExecutionEvent::ConstPointer& event); /** * Return the active workbench window. * * @param event * The execution event that contains the application context * @return the active workbench window, or null. */ static IWorkbenchWindow::Pointer GetActiveWorkbenchWindow(const ExecutionEvent::ConstPointer& event); /** * Return the active workbench window. * * @param event * The execution event that contains the application context * @return the active workbench window. Will not return null. * @throws ExecutionException * If the active workbench window variable is not found. */ static IWorkbenchWindow::Pointer GetActiveWorkbenchWindowChecked( const ExecutionEvent::ConstPointer& event); /** * Return the part id of the active editor. * * @param event * The execution event that contains the application context * @return the part id of the active editor, or null. */ static ObjectString::ConstPointer GetActiveEditorId(const ExecutionEvent::ConstPointer& event); /** * Return the part id of the active editor. * * @param event * The execution event that contains the application context * @return the part id of the active editor. Will not return * null. * @throws ExecutionException * If the active editor id variable is not found. */ static ObjectString::ConstPointer GetActiveEditorIdChecked(const ExecutionEvent::ConstPointer& event); /** * Return the active part. * * @param event * The execution event that contains the application context * @return the active part, or null. */ static IWorkbenchPart::Pointer GetActivePart(const ExecutionEvent::ConstPointer& event); /** * Return the active part. * * @param event * The execution event that contains the application context * @return the active part. Will not return null. * @throws ExecutionException * If the active part variable is not found. */ static IWorkbenchPart::Pointer GetActivePartChecked(const ExecutionEvent::ConstPointer& event); /** * Return the part id of the active part. * * @param event * The execution event that contains the application context * @return the part id of the active part, or null. */ static ObjectString::ConstPointer GetActivePartId(const ExecutionEvent::ConstPointer& event); /** * Return the part id of the active part. * * @param event * The execution event that contains the application context * @return the part id of the active part. Will not return null. * @throws ExecutionException * If the active part id variable is not found. */ static ObjectString::ConstPointer GetActivePartIdChecked(const ExecutionEvent::ConstPointer& event); /** * Return the active part site. * * @param event * The execution event that contains the application context * @return the active part site, or null. */ static IWorkbenchPartSite::Pointer GetActiveSite(const ExecutionEvent::ConstPointer& event); /** * Return the active part site. * * @param event * The execution event that contains the application context * @return the active part site. Will not return null. * @throws ExecutionException * If the active part site variable is not found. */ static IWorkbenchPartSite::Pointer GetActiveSiteChecked(const ExecutionEvent::ConstPointer& event); /** * Return the current selection. * * @param event * The execution event that contains the application context * @return the current selection, or null. */ static ISelection::ConstPointer GetCurrentSelection(const ExecutionEvent::ConstPointer& event); /** * Return the current selection. * * @param event * The execution event that contains the application context * @return the current selection. Will not return null. * @throws ExecutionException * If the current selection variable is not found. */ static ISelection::ConstPointer GetCurrentSelectionChecked(const ExecutionEvent::ConstPointer& event); /** * Return the menu IDs that were applied to the registered context menu. * * @param event * The execution event that contains the application context * @return the menu IDs, or null. */ static StringVectorType::ConstPointer GetActiveMenus(const ExecutionEvent::ConstPointer& event); /** * Return the menu IDs that were applied to the registered context menu. * * @param event * The execution event that contains the application context * @return the menu IDs. Will not return null. * @throws ExecutionException * If the active menus variable is not found. */ static StringVectorType::ConstPointer GetActiveMenusChecked(const ExecutionEvent::ConstPointer& event); /** * Return the active menu selection. The active menu is a registered context * menu. * * @param event * The execution event that contains the application context * @return the active menu selection, or null. */ static ISelection::ConstPointer GetActiveMenuSelection(const ExecutionEvent::ConstPointer& event); /** * Return the active menu selection. The active menu is a registered context * menu. * * @param event * The execution event that contains the application context * @return the active menu selection. Will not return null. * @throws ExecutionException * If the active menu selection variable is not found. */ static ISelection::ConstPointer GetActiveMenuSelectionChecked(const ExecutionEvent::ConstPointer& event); /** * Return the active menu editor input, if available. The active menu is a * registered context menu. * * @param event * The execution event that contains the application context * @return the active menu editor, or null. */ static ISelection::ConstPointer GetActiveMenuEditorInput(const ExecutionEvent::ConstPointer& event); /** * Return the active menu editor input. The active menu is a registered * context menu. Some context menus do not include the editor input which * will throw an exception. * * @param event * The execution event that contains the application context * @return the active menu editor input. Will not return null. * @throws ExecutionException * If the active menu editor input variable is not found. */ static ISelection::ConstPointer GetActiveMenuEditorInputChecked( const ExecutionEvent::ConstPointer& event); /** * Return the ShowInContext selection. * * @param event * The execution event that contains the application context * @return the show in selection, or null. */ static ISelection::ConstPointer GetShowInSelection(const ExecutionEvent::ConstPointer& event); /** * Return the ShowInContext selection. Will not return null. * * @param event * The execution event that contains the application context * @return the show in selection, or null. * @throws ExecutionException * If the show in selection variable is not found. */ static ISelection::ConstPointer GetShowInSelectionChecked(const ExecutionEvent::ConstPointer& event); /** * Return the ShowInContext input. * * @param event * The execution event that contains the application context * @return the show in input, or null. */ static Object::ConstPointer GetShowInInput(const ExecutionEvent::ConstPointer& event); /** * Return the ShowInContext input. Will not return null. * * @param event * The execution event that contains the application context * @return the show in input, or null. * @throws ExecutionException * If the show in input variable is not found. */ static Object::ConstPointer GetShowInInputChecked(const ExecutionEvent::ConstPointer& event); /** * Toggles the command's state. * * @param command The command whose state needs to be toggled * @return the original value before toggling * * @throws ExecutionException * When the command doesn't contain the toggle state or when the state doesn't contain a boolean value */ static bool ToggleCommandState(const SmartPointer& command); /** * Checks whether the radio state of the command is same as the radio state * parameter's value * * @param event * The execution event that contains the application context - * @return true whe the values are same, false + * @return true when the values are same, false * otherwise * * @throws ExecutionException * When the command doesn't have the radio state or the event * doesn't have the radio state parameter */ static bool MatchesRadioState(const SmartPointer& event); /** * Updates the radio state of the command to the given value * * @param command * the command whose state should be updated * @param newState * the new state * * @throws ExecutionException * When the command doesn't have a radio state */ static void UpdateRadioState(const SmartPointer& command, const QString& newState); }; } #endif /*BERRYHANDLERUTIL_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryCommandParameter.h b/Plugins/org.blueberry.ui.qt/src/internal/berryCommandParameter.h index 0ff245e569..84bae63608 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryCommandParameter.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryCommandParameter.h @@ -1,187 +1,187 @@ /*============================================================================ 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 BERRYCOMMANDPARAMETER_H #define BERRYCOMMANDPARAMETER_H #include "berryIParameter.h" #include "berryITypedParameter.h" namespace berry { struct IConfigurationElement; /** *

* A parameter for a command. A parameter identifies a type of information that * the command might accept. For example, a "Show View" command might accept the * id of a view for display. This parameter also identifies possible values, for * display in the user interface. *

*

* Parameters are mutable, and can change as the command changes. Notifications * will not be sent if the parameter itself changes. Listeners can be attached * to the command. *

*/ class CommandParameter : public IParameter, public ITypedParameter { public: berryObjectMacro(berry::CommandParameter); private: /** * The name of the configuration element attribute contain the values. This * is used to retrieve the executable extension * IParameterValues. */ static const QString ATTRIBUTE_VALUES; // = "values"; /** * The constant integer hash code value meaning the hash code has not yet * been computed. */ static const int HASH_CODE_NOT_COMPUTED; // = 0; /** * A factor for computing the hash code for all schemes. */ static const int HASH_FACTOR; // = 89; /** * The seed for the hash code for all schemes. */ static const int HASH_INITIAL; /** * The hash code for this object. This value is computed lazily, and marked * as invalid when one of the values on which it is based changes. */ mutable int hashCode; // = HASH_CODE_NOT_COMPUTED; /** * The non-externalized name of this parameter. The name is used as the in a * name-value parameter map. This value will never be null. */ const QString name; /** * Whether the parameter is optional (as opposed to required). */ const bool optional; /** * The type for this parameter. This value may be null if the * parameter is not typed. */ const SmartPointer parameterType; /** * The actual IParameterValues implementation. This is lazily * loaded from the valuesConfigurationElement, to avoid * unnecessary class-loading. */ mutable QScopedPointer values; /** * The configuration element providing the executable extension that will * implement IParameterValues. This value will not be * null. */ const SmartPointer valuesConfigurationElement; protected: /** * The identifier for this object. This identifier should be unique across * all objects of the same type and should never change. This value will * never be null. */ const QString id; /** * The string representation of this object. This string is for debugging * purposes only, and is not meant to be displayed to the user. This value * is computed lazily, and is cleared if one of its dependent values * changes. */ mutable QString str; public: /** * Constructs a new instance of Parameter with all of its * values pre-defined. * * @param id * The identifier for this parameter; must not be * null. * @param name * The name for this parameter; must not be null. * @param values * The values for this parameter; must not be null. * @param parameterType * the type for this parameter; may be null if the - * parmeter doesn't declare type. + * parameter doesn't declare type. * @param optional * Whether this parameter is optional (as opposed to required). * @param commandService * The command service from which parameter types can be * retrieved; must not be null. */ CommandParameter(const QString& id, const QString& name, const SmartPointer& values, const SmartPointer& parameterType, const bool optional); /** * Tests whether this object is equal to another object. A parameter is only * equal to another parameter with the same properties. * * @param object * The object with which to compare; may be null. * @return true if the objects are equal; false * otherwise. */ bool operator==(const Object* object) const override; QString GetId() const override; QString GetName() const override; SmartPointer GetParameterType() const override; IParameterValues* GetValues() const override; uint HashCode() const override { if (hashCode == HASH_CODE_NOT_COMPUTED) { hashCode = HASH_INITIAL * HASH_FACTOR + qHash(id); if (hashCode == HASH_CODE_NOT_COMPUTED) { hashCode++; } } return hashCode; } bool IsOptional() const override; QString ToString() const override; }; } #endif // BERRYCOMMANDPARAMETER_H diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryCommandService.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryCommandService.cpp index f37b522b35..889118ab0a 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryCommandService.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryCommandService.cpp @@ -1,313 +1,313 @@ /*============================================================================ 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 "berryCommandService.h" #include #include #include #include #include #include "berryPersistentState.h" #include "berryWorkbenchPlugin.h" #include "berryElementReference.h" #include #include #include #include #include #include #include namespace berry { const std::string CommandService::PREFERENCE_KEY_PREFIX = "org.blueberry.ui.commands/state"; std::string CommandService::CreatePreferenceKey(const SmartPointer& command, const QString& stateId) { return PREFERENCE_KEY_PREFIX + '/' + command->GetId().toStdString() + '/' + stateId.toStdString(); } CommandService::CommandService( CommandManager* commandManager) : commandManager(commandManager) , commandPersistence(this) { if (commandManager == nullptr) { throw std::invalid_argument("Cannot create a command service with a null manager"); } } CommandService::~CommandService() { this->Dispose(); } void CommandService::AddExecutionListener(IExecutionListener* listener) { commandManager->AddExecutionListener(listener); } void CommandService::DefineUncategorizedCategory(const QString& name, const QString& description) { commandManager->DefineUncategorizedCategory(name, description); } SmartPointer CommandService::Deserialize(const QString& serializedParameterizedCommand) const { return commandManager->Deserialize(serializedParameterizedCommand); } void CommandService::Dispose() { /* - * All state on all commands neeeds to be disposed. This is so that the + * All state on all commands needs to be disposed. This is so that the * state has a chance to persist any changes. */ const QList commands = commandManager->GetAllCommands(); foreach (const Command::Pointer& command, commands) { const QList stateIds = command->GetStateIds(); foreach(const QString& stateId, stateIds) { const State::Pointer state = command->GetState(stateId); if (PersistentState::Pointer persistentState = state.Cast()) { if (persistentState->ShouldPersist()) { persistentState->Save(WorkbenchPlugin::GetDefault()->GetPreferences(), CreatePreferenceKey(command, stateId)); } } } } commandCallbacks.clear(); } SmartPointer CommandService::GetCategory(const QString& categoryId) const { return commandManager->GetCategory(categoryId); } SmartPointer CommandService::GetCommand(const QString& commandId) const { return commandManager->GetCommand(commandId); } QList > CommandService::GetDefinedCategories() const { return commandManager->GetDefinedCategories(); } QStringList CommandService::GetDefinedCategoryIds() const { return commandManager->GetDefinedCategoryIds().toList(); } QStringList CommandService::GetDefinedCommandIds() const { return commandManager->GetDefinedCommandIds().toList(); } QList > CommandService::GetDefinedCommands() const { return commandManager->GetDefinedCommands(); } QStringList CommandService::GetDefinedParameterTypeIds() const { return commandManager->GetDefinedParameterTypeIds().toList(); } QList > CommandService::GetDefinedParameterTypes() const { return commandManager->GetDefinedParameterTypes(); } QString CommandService::GetHelpContextId(const SmartPointer& command) const { return commandManager->GetHelpContextId(command); } QString CommandService::GetHelpContextId(const QString& commandId) const { Command::Pointer command = GetCommand(commandId); return commandManager->GetHelpContextId(command); } SmartPointer CommandService::GetParameterType(const QString& parameterTypeId) const { return commandManager->GetParameterType(parameterTypeId); } void CommandService::ReadRegistry() { commandPersistence.Read(); } void CommandService::RemoveExecutionListener(IExecutionListener* listener) { commandManager->RemoveExecutionListener(listener); } void CommandService::SetHelpContextId(const SmartPointer& handler, const QString& helpContextId) { commandManager->SetHelpContextId(handler, helpContextId); } void CommandService::RefreshElements(const QString& commandId, const QHash& filter) { Command::Pointer cmd = GetCommand(commandId); if (!cmd->IsDefined() || !(cmd->GetHandler().Cast())) { return; } IElementUpdater::Pointer updater = cmd->GetHandler().Cast(); if (commandCallbacks.isEmpty()) { return; } if(!commandCallbacks.contains(commandId)) { return; } foreach (IElementReference::Pointer callbackRef, commandCallbacks[commandId]) { struct _SafeRunnable : public ISafeRunnable { IElementUpdater* updater; IElementReference* callbackRef; _SafeRunnable(IElementUpdater* updater, IElementReference* callbackRef) : updater(updater), callbackRef(callbackRef) {} void HandleException(const ctkException& exc) override { WorkbenchPlugin::Log(QString("Failed to update callback: ") + callbackRef->GetCommandId() + exc.what()); } void Run() override { updater->UpdateElement(callbackRef->GetElement().GetPointer(), callbackRef->GetParameters()); } }; QHash parms = callbackRef->GetParameters(); ISafeRunnable::Pointer run(new _SafeRunnable(updater.GetPointer(), callbackRef.GetPointer())); if (filter.isEmpty()) { SafeRunner::Run(run); } else { bool match = true; QHashIterator i(filter); while (i.hasNext()) { i.next(); Object::Pointer value = parms[i.key()]; if (i.value() != value) { match = false; break; } } if (match) { SafeRunner::Run(run); } } } } SmartPointer CommandService::RegisterElementForCommand( const SmartPointer& command, const SmartPointer& element) { if (!command->GetCommand()->IsDefined()) { throw NotDefinedException( "Cannot define a callback for undefined command " + command->GetCommand()->GetId()); } if (element.IsNull()) { throw NotDefinedException("No callback defined for command " + command->GetCommand()->GetId()); } QHash paramMap = command->GetParameterMap(); QHash parms; for (QHash::const_iterator i = paramMap.begin(); i != paramMap.end(); ++i) { Object::Pointer value(new ObjectString(i.value())); parms.insert(i.key(), value); } IElementReference::Pointer ref(new ElementReference(command->GetId(), element, parms)); RegisterElement(ref); return ref; } void CommandService::RegisterElement(const SmartPointer& elementReference) { QList& parameterizedCommands = commandCallbacks[elementReference->GetCommandId()]; parameterizedCommands.push_back(elementReference); // If the active handler wants to update the callback, it can do // so now Command::Pointer command = GetCommand(elementReference->GetCommandId()); if (command->IsDefined()) { if (IElementUpdater::Pointer updater = command->GetHandler().Cast()) { updater->UpdateElement(elementReference->GetElement().GetPointer(), elementReference->GetParameters()); } } } void CommandService::UnregisterElement(const SmartPointer& elementReference) { if (commandCallbacks.contains(elementReference->GetCommandId())) { QList& parameterizedCommands = commandCallbacks[elementReference->GetCommandId()]; parameterizedCommands.removeAll(elementReference); if (parameterizedCommands.isEmpty()) { commandCallbacks.remove(elementReference->GetCommandId()); } } } const CommandPersistence* CommandService::GetCommandPersistence() const { return &commandPersistence; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryDragUtil.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryDragUtil.cpp index 3cac5f379e..039cdb2950 100755 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryDragUtil.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryDragUtil.cpp @@ -1,289 +1,289 @@ /*============================================================================ 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 "tweaklets/berryGuiWidgetsTweaklet.h" #include "berryDragUtil.h" #include "berryGeometry.h" #include "berryQtTracker.h" namespace berry { const QString DragUtil::DROP_TARGET_ID = "org.blueberry.ui.internal.dropTarget"; TestDropLocation::Pointer DragUtil::forcedDropTarget(nullptr); QList DragUtil::defaultTargets = QList(); DragUtil::TargetListType::Pointer DragUtil::GetTargetList(QWidget* control) { Object::Pointer data = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetData( control, DROP_TARGET_ID); TargetListType::Pointer list = data.Cast (); return list; } IDropTarget::Pointer DragUtil::GetDropTarget(const QList& toSearch, QWidget* mostSpecificControl, Object::Pointer draggedObject, const QPoint& position, const QRect& dragRectangle) { for (QList::const_iterator iter = toSearch.begin(); iter != toSearch.end(); ++iter) { IDragOverListener* next = *iter; IDropTarget::Pointer dropTarget = next->Drag(mostSpecificControl, draggedObject, position, dragRectangle); if (dropTarget != 0) { return dropTarget; } } return IDropTarget::Pointer(nullptr); } void DragUtil::AddDragTarget(QWidget* control, IDragOverListener* target) { if (control == nullptr) { defaultTargets.push_back(target); } else { TargetListType::Pointer targetList = GetTargetList(control); if (targetList == 0) { targetList = new TargetListType(); Tweaklets::Get(GuiWidgetsTweaklet::KEY)->SetData(control, DROP_TARGET_ID, targetList); } targetList->push_back(target); } } void DragUtil::RemoveDragTarget(QWidget* control, IDragOverListener* target) { if (control == nullptr) { defaultTargets.removeAll(target); } else { TargetListType::Pointer targetList = GetTargetList(control); if (targetList != 0) { targetList->removeAll(target); if (targetList->empty()) { Tweaklets::Get(GuiWidgetsTweaklet::KEY)->SetData(control, DROP_TARGET_ID, Object::Pointer(nullptr)); } } } } QRect DragUtil::GetDisplayBounds(QWidget* boundsControl) { QWidget* parent = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetParent( boundsControl); if (parent == nullptr) { return Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetBounds(boundsControl); } QRect rect = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetBounds( boundsControl); return Geometry::ToDisplay(parent, rect); } bool DragUtil::PerformDrag(Object::Pointer draggedItem, const QRect& sourceBounds, const QPoint& initialLocation, bool allowSnapping) { IDropTarget::Pointer target = DragToTarget(draggedItem, sourceBounds, initialLocation, allowSnapping); if (target == 0) { return false; } target->Drop(); target->DragFinished(true); return true; } void DragUtil::ForceDropLocation(TestDropLocation::Pointer forcedLocation) { forcedDropTarget = forcedLocation; } IDropTarget::Pointer DragUtil::DragToTarget(Object::Pointer draggedItem, const QRect& sourceBounds, const QPoint& initialLocation, bool allowSnapping) { //final Display display = Display.getCurrent(); // Testing...immediately 'drop' onto the test target if (forcedDropTarget != 0) { QPoint location = forcedDropTarget->GetLocation(); QWidget* currentControl = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->FindControl( forcedDropTarget->GetShells(), location); return GetDropTarget(currentControl, draggedItem, location, sourceBounds); } // Create a tracker. This is just an XOR rect on the screen. // As it moves we notify the drag listeners. QtTracker tracker; //tracker.setStippled(true); QtTrackerMoveListener trackerListener(draggedItem, sourceBounds, initialLocation, allowSnapping); trackerListener.connect(&tracker, SIGNAL(Moved(QtTracker*,QPoint)), SLOT(Moved(QtTracker*,QPoint))); // Setup...when the drag starts we might already be over a valid target, check this... // If there is a 'global' target then skip the check IDropTarget::Pointer target; QWidget* startControl = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetCursorControl(); if (startControl != nullptr && allowSnapping) { target = GetDropTarget(startControl, draggedItem, initialLocation, sourceBounds); } // Set up an initial tracker rectangle QRect startRect = sourceBounds; if (target != 0) { QRect rect = target->GetSnapRectangle(); if (rect.width() != 0 && rect.height() != 0) { startRect = rect; } tracker.SetCursor(target->GetCursor()); } if (startRect.width() != 0 && startRect.height() != 0) { tracker.SetRectangle(startRect); } - // Tracking Loop...tracking is preformed on the 'SWT.Move' listener registered + // Tracking Loop...tracking is performed on the 'SWT.Move' listener registered // against the tracker. // // HACK: // // Some control needs to capture the mouse during the drag or other // // controls will interfere with the cursor // Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); // if (shell != null) // { // shell.setCapture(true); // } // Run tracker until mouse up occurs or escape key pressed. bool trackingOk = tracker.Open(); // // HACK: // // Release the mouse now // if (shell != null) // { // shell.setCapture(false); // } // Done tracking... // Get the current drop target IDropTarget::Pointer dropTarget; QPoint finalLocation = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetCursorLocation(); QWidget* targetControl = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetCursorControl(); dropTarget = GetDropTarget(targetControl, draggedItem, finalLocation, tracker.GetRectangle()); // Cleanup... //delete tracker; // if we're going to perform a 'drop' then delay the issuing of the 'finished' // callback until after it's done... if (trackingOk) { return dropTarget; } else if (dropTarget != 0) { // If the target can handle a 'finished' notification then send one dropTarget->DragFinished(false); } return IDropTarget::Pointer(nullptr); } IDropTarget::Pointer DragUtil::GetDropTarget(QWidget* toSearch, Object::Pointer draggedObject, const QPoint& position, const QRect& dragRectangle) { // Search for a listener by walking the control's parent hierarchy for (QWidget* current = toSearch; current != nullptr; current = Tweaklets::Get( GuiWidgetsTweaklet::KEY)->GetParent(current)) { TargetListType::Pointer targetList = GetTargetList(current); QList targets; if (targetList != 0) targets = *targetList; IDropTarget::Pointer dropTarget = GetDropTarget(targets, toSearch, draggedObject, position, dragRectangle); if (dropTarget != 0) { return dropTarget; } // // Don't look to parent shells for drop targets // if (current instanceof Shell) { // break; // } } // No controls could handle this event -- check for default targets return GetDropTarget(defaultTargets, toSearch, draggedObject, position, dragRectangle); } //QPoint DragUtil::GetEventLoc(GuiTk::ControlEvent::Pointer event) //{ // Control ctrl = (Control) event.widget; // return ctrl.toDisplay(new QPoint(event.x, event.y)); //} } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorDescriptor.h b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorDescriptor.h index 53a6158445..f4649e1df2 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorDescriptor.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorDescriptor.h @@ -1,388 +1,388 @@ /*============================================================================ 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 BERRYEDITORDESCRIPTOR_H_ #define BERRYEDITORDESCRIPTOR_H_ #include "berryIEditorDescriptor.h" #include "berryIMemento.h" #include #include namespace berry { struct IEditorPart; /** * \ingroup org_blueberry_ui_internal * * @see IEditorDescriptor */ class BERRY_UI_QT EditorDescriptor : public IEditorDescriptor { //, Serializable, IPluginContribution { public: berryObjectMacro(EditorDescriptor); // @issue the following constants need not be public; see bug 47600 /** * Open internal constant. Value 0x01. */ static const int OPEN_INTERNAL; // = 0x01; /** * Open in place constant. Value 0x02. */ static const int OPEN_INPLACE; // = 0x02; /** * Open external constant. Value 0x04. */ static const int OPEN_EXTERNAL; // = 0x04; private: QString editorName; QString imageFilename; mutable QIcon imageDesc; mutable bool testImage; QString className; QString launcherName; QString fileName; QString id; bool matchingStrategyChecked; IEditorMatchingStrategy::Pointer matchingStrategy; //Program program; //The id of the plugin which contributed this editor, null for external editors QString pluginIdentifier; int openMode; IConfigurationElement::Pointer configurationElement; /** * Create a new instance of an editor descriptor. Limited * to internal framework calls. * @param element * @param id2 */ /* package */ public: EditorDescriptor(const QString& id2, IConfigurationElement::Pointer element); /** * Create a new instance of an editor descriptor. Limited * to internal framework calls. */ /* package */ public: EditorDescriptor(); /** * Creates a descriptor for an external program. * * @param filename the external editor full path and filename * @return the editor descriptor */ //public: static EditorDescriptor::Pointer CreateForProgram(const QString& filename) { // if (filename == null) { // throw new IllegalArgumentException(); // } // EditorDescriptor editor = new EditorDescriptor(); // // editor.setFileName(filename); // editor.setID(filename); // editor.setOpenMode(OPEN_EXTERNAL); // // //Isolate the program name (no directory or extension) // int start = filename.lastIndexOf(File.separator); // String name; // if (start != -1) { // name = filename.substring(start + 1); // } else { // name = filename; // } // int end = name.lastIndexOf('.'); // if (end != -1) { // name = name.substring(0, end); // } // editor.setName(name); // // // get the program icon without storing it in the registry // ImageDescriptor imageDescriptor = new ProgramImageDescriptor(filename, // 0); // editor.setImageDescriptor(imageDescriptor); // // return editor; // } /** * Return the program called programName. Return null if it is not found. * @return org.blueberry.swt.program.Program */ //private: static Program FindProgram(const QString& programName) { // // Program[] programs = Program.getPrograms(); // for (int i = 0; i < programs.length; i++) { // if (programs[i].getName().equals(programName)) { // return programs[i]; // } // } // // return null; // } /** * Create the editor action bar contributor for editors of this type. * * @return the action bar contributor, or null */ //public: IEditorActionBarContributor::Pointer CreateActionBarContributor(); /** * Return the editor class name. * * @return the class name */ public: QString GetEditorClassName() const; /** * Return the configuration element used to define this editor, or null. * * @return the element or null */ public: IConfigurationElement::Pointer GetConfigurationElement() const; /** * Create an editor part based on this descriptor. * * @return the editor part * @throws CoreException thrown if there is an issue creating the editor */ public: SmartPointer CreateEditor(); /** * Return the file name of the command to execute for this editor. * * @return the file name to execute */ public: QString GetFileName() const; /** * Return the id for this editor. * * @return the id */ public: QString GetId() const override; /** * Return the image descriptor describing this editor. * * @return the image descriptor */ public: QIcon GetImageDescriptor() const override; /** * Verifies that the image descriptor generates an image. If not, the * descriptor is replaced with the default image. * * @since 3.1 */ private: void VerifyImage() const; /** * The name of the image describing this editor. * * @return the image file name */ public: QString GetImageFilename() const; /** * Return the user printable label for this editor. * * @return the label */ public: QString GetLabel() const override; /** * Returns the class name of the launcher. * * @return the launcher class name */ public: QString GetLauncher() const; /** * Return the contributing plugin id. * * @return the contributing plugin id */ public: QString GetPluginID() const; /** * Get the program for the receiver if there is one. * @return Program */ //public: Program GetProgram() { // return this.program; // } /* (non-Javadoc) * @see org.blueberry.ui.IEditorDescriptor#isInternal */ public: bool IsInternal() const override; /* (non-Javadoc) * @see org.blueberry.ui.IEditorDescriptor#isOpenInPlace */ public: bool IsOpenInPlace() const override; /* (non-Javadoc) * @see org.blueberry.ui.IEditorDescriptor#isOpenExternal */ public: bool IsOpenExternal() const override; /** * Load the object properties from a memento. * * @return true if the values are valid, false otherwise */ protected: bool LoadValues(IMemento::Pointer memento); /** * Save the object values in a IMemento */ protected: void SaveValues(IMemento::Pointer memento); /** * Return the open mode of this editor. * * @return the open mode of this editor * @since 3.1 */ private: int GetOpenMode() const; /** * Set the class name of an internal editor. */ /* package */public: void SetClassName(const QString& newClassName); /** * Set the configuration element which contributed this editor. */ /* package */public: void SetConfigurationElement( IConfigurationElement::Pointer newConfigurationElement); /** * Set the filename of an external editor. */ /* package */public: void SetFileName(const QString& aFileName); /** * Set the id of the editor. * For internal editors this is the id as provided in the extension point * For external editors it is path and filename of the editor */ /* package */public: void SetID(const QString& anID); /** - * The Image to use to repesent this editor + * The Image to use to represent this editor */ /* package */ // public : void SetImageDescriptor(ImageDescriptor desc) { // imageDesc = desc; // testImage = true; // } /** * The name of the image to use for this editor. */ /* package */ // public: void SetImageFilename(const QString& aFileName) { // imageFilename = aFileName; // } /** * Sets the new launcher class name * * @param newLauncher the new launcher */ /* package */public: void SetLauncher(const QString& newLauncher); /** * The label to show for this editor. */ /* package */public: void SetName(const QString& newName); /** * Sets the open mode of this editor descriptor. * * @param mode the open mode * * @issue this method is public as a temporary fix for bug 47600 */ public: void SetOpenMode(int mode); /** * The id of the plugin which contributed this editor, null for external editors. */ /* package */public: void SetPluginIdentifier(const QString& anID); /** * Set the receivers program. * @param newProgram */ /* package */ // public: void SetProgram(Program newProgram) { // // this.program = newProgram; // if (editorName == null) { // setName(newProgram.getName()); // } // } /** * For debugging purposes only. */ public: QString ToString() const override; /* (non-Javadoc) * @see org.blueberry.ui.activities.support.IPluginContribution#getLocalId() */ public: QString GetLocalId() const; /* (non-Javadoc) * @see org.blueberry.ui.activities.support.IPluginContribution#getPluginId() */ public: QString GetPluginId() const; /* (non-Javadoc) * @see org.blueberry.ui.IEditorDescriptor#getEditorManagementPolicy() */ public: IEditorMatchingStrategy::Pointer GetEditorMatchingStrategy() override; }; } #endif /*BERRYEDITORDESCRIPTOR_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorReference.h b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorReference.h index 25cf8c269c..01052cfaf2 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorReference.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorReference.h @@ -1,232 +1,232 @@ /*============================================================================ 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 BERRYEDITORREFERENCE_H_ #define BERRYEDITORREFERENCE_H_ #include "berryWorkbenchPartReference.h" #include "berryIEditorReference.h" #include "berryIEditorInput.h" #include "berryIMemento.h" #include "berryIWorkbenchPart.h" #include "berryIEditorPart.h" namespace berry { class EditorManager; class EditorDescriptor; class PartPane; struct IWorkbenchPage; /** * \ingroup org_blueberry_ui_internal * */ class EditorReference : public WorkbenchPartReference, public IEditorReference { private: const EditorManager* manager; private: IMemento::Pointer editorMemento; private: IMemento::Pointer editorState; /** * Flag that lets us detect malfunctioning editors that don't fire PROP_INPUT events. * It is never needed for a correctly-functioning */ private: bool expectingInputChange; /** * Flag that determines whether we've already reported that this editor is malfunctioning. * This prevents us from spamming the event log if we repeatedly detect the same error in * a particular editor. If we ever detect an editor is violating its public contract in * a way we can recover from (such as a missing property change event), we report the error * once and then silently ignore errors from the same editor. */ private: bool reportedMalfunctioningEditor; /** * User-readable name of the editor's input */ QString name; QString factoryId; IEditorInput::Pointer restoredInput; /** * @param manager * The editor manager for this reference * @param input * our input * @param desc * the descriptor from the declaration * @param editorState - * propogate state from another editor. Can be null. + * propagate state from another editor. Can be null. */ public: berryObjectMacro(EditorReference); EditorReference(EditorManager* manager, IEditorInput::Pointer input, SmartPointer desc, IMemento::Pointer editorState = IMemento::Pointer(nullptr)); /** * Constructs a new editor reference for use by editors being restored from * a memento. */ EditorReference(EditorManager* manager, IMemento::Pointer memento); public: SmartPointer GetDescriptor(); /** * @param id the id * @return the editor descriptor */ private: SmartPointer GetDescriptor(const QString& id); /** * Initializes the necessary editor listeners and handlers */ private: void InitListenersAndHandlers(); protected: SmartPointer CreatePane() override; /** * This method is called when there should be a change in the editor pin * status (added or removed) so that it will ask its presentable part * to fire a PROP_TITLE event in order for the presentation to request * the new icon for this editor */ public: void PinStatusUpdated(); public: QString GetFactoryId() override; protected: QString ComputePartName() const override; public: QString GetName() override; public: IEditorPart::Pointer GetEditor(bool restore) override; public: void SetName(const QString& name); public: IMemento::Pointer GetMemento(); public: SmartPointer GetPage() const override; public: IEditorInput::Pointer GetEditorInput() override; private: IEditorInput::Pointer GetRestoredInput(); /* (non-Javadoc) * @see org.blueberry.ui.IWorkbenchPartReference#getTitleImage() * This method will append a pin to the icon of the editor * if the "automatically close editors" option in the * preferences is enabled and the editor has been pinned. */ //public: ImageDescriptor computeImageDescriptor() { // ImageDescriptor descriptor = super.computeImageDescriptor(); // if (!isPinned()) { // return descriptor; // } // // // Check if the pinned preference is set // IPreferenceStore prefStore = WorkbenchPlugin.getDefault() // .getPreferenceStore(); // boolean bUsePin = prefStore // .getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN) // || ((TabBehaviour)Tweaklets.get(TabBehaviour.KEY)).alwaysShowPinAction(); // // if (!bUsePin) { // return descriptor; // } // // ImageDescriptor pinDesc = this.manager.getEditorPinImageDesc(); // if (pinDesc == null) { // return descriptor; // } // // return new OverlayIcon(descriptor, pinDesc, new Point(16, 16)); // } protected: /** * Wrapper for restoring the editor. First, this delegates to busyRestoreEditorHelper * to do the real work of restoring the view. If unable to restore the editor, this * method tries to substitute an error part and return success. * * @return the created part */ IWorkbenchPart::Pointer CreatePart() override; using WorkbenchPartReference::PropertyChanged; void PropertyChanged(Object::Pointer source, int propId); /** * Attempts to set the input of the editor to the given input. Note that the input * can't always be changed for an editor. Editors that don't implement IReusableEditor * can't have their input changed once they've been materialized. * * @param input new input * @return true iff the input was actually changed */ public: bool SetInput(IEditorInput::Pointer input); /** * Reports a recoverable malfunction in the system log. A recoverable malfunction would be * something like failure to fire an expected property change. Only the first malfunction is * * @param string */ private: void ReportMalfunction(const QString& string); private: IEditorPart::Pointer CreatePartHelper(); /** * Creates and returns an empty editor (ErrorEditorPart). * * @param descr the editor descriptor * @return the empty editor part or null in case of an exception */ public: IEditorPart::Pointer GetEmptyEditor(SmartPointer descr); }; } // namespace berry #endif /*BERRYEDITORREFERENCE_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorRegistry.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorRegistry.cpp index 0f994146b2..c4c35cbdda 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorRegistry.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorRegistry.cpp @@ -1,1295 +1,1295 @@ /*============================================================================ 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 "berryEditorRegistry.h" #include "berryWorkbenchPlugin.h" #include "berryEditorRegistryReader.h" #include "berryWorkbenchRegistryConstants.h" namespace berry { const QString EditorRegistry::EMPTY_EDITOR_ID = "org.blueberry.ui.internal.emptyEditorTab"; QHash EditorRegistry::EditorMap::defaultMap; QHash EditorRegistry::EditorMap::map; EditorRegistry::RelatedRegistry::RelatedRegistry(EditorRegistry* reg) : editorRegistry(reg) { } QList EditorRegistry::RelatedRegistry::GetRelatedObjects( const QString& fileName) { IFileEditorMapping::Pointer mapping = editorRegistry->GetMappingFor(fileName); if (mapping.IsNull()) { return QList(); } return mapping->GetEditors(); } EditorRegistry::EditorRegistry() : relatedRegistry(this) { this->InitialIdToEditorMap(mapIDtoEditor); this->InitializeFromStorage(); //IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker(); //tracker.registerHandler(this, // ExtensionTracker.createExtensionPointFilter(getExtensionPointFilter())); } void EditorRegistry::AddEditorFromPlugin(EditorDescriptor::Pointer editor, const QList& extensions, const QList& filenames, const QList& /*contentTypeVector*/, bool bDefault) { //PlatformUI.getWorkbench().getExtensionTracker().registerObject(editor.getConfigurationElement().getDeclaringExtension(), editor, IExtensionTracker.REF_WEAK); // record it in our quick reference list sortedEditorsFromPlugins.push_back(editor); // add it to the table of mappings for (QList::const_iterator itr = extensions.begin(); itr != extensions.end(); ++itr) { QString fileExtension = *itr; if (!fileExtension.isEmpty()) { FileEditorMapping::Pointer mapping = this->GetMappingFor("*." + fileExtension); if (mapping.IsNull()) { // no mapping for that extension mapping = new FileEditorMapping(fileExtension); typeEditorMappings.PutDefault(this->MappingKeyFor(mapping), mapping); } mapping->AddEditor(editor); if (bDefault) { mapping->SetDefaultEditor(editor); } } } // add it to the table of mappings for (QList::const_iterator itr = filenames.begin(); itr != filenames.end(); ++itr) { QString filename = *itr; if (!filename.isEmpty()) { FileEditorMapping::Pointer mapping = this->GetMappingFor(filename); if (mapping.IsNull()) { // no mapping for that extension QString name; QString extension; int index = filename.indexOf('.'); if (index == -1) { name = filename; extension = ""; } else { name = filename.left(index); extension = filename.mid(index + 1); } mapping = new FileEditorMapping(name, extension); typeEditorMappings.PutDefault(this->MappingKeyFor(mapping), mapping); } mapping->AddEditor(editor); if (bDefault) { mapping->SetDefaultEditor(editor); } } } // for (QList::const_iterator itr = contentTypeVector.begin(); // itr != contentTypeVector.end(); ++itr) // { // QString contentTypeId = *itr; // if (!contentTypeId.empty()) // { // IContentType contentType = Platform.getContentTypeManager().getContentType(contentTypeId); // if (contentType != null) // { // IEditorDescriptor [] editorArray = (IEditorDescriptor[]) contentTypeToEditorMappings.get(contentType); // if (editorArray == null) // { // editorArray = new IEditorDescriptor[] // { editor}; // contentTypeToEditorMappings.put(contentType, editorArray); // } // else // { // IEditorDescriptor [] newArray = new IEditorDescriptor[editorArray.length + 1]; // if (bDefault) // { // default editors go to the front of the line // newArray[0] = editor; // System.arraycopy(editorArray, 0, newArray, 1, editorArray.length); // } // else // { // newArray[editorArray.length] = editor; // System.arraycopy(editorArray, 0, newArray, 0, editorArray.length); // } // contentTypeToEditorMappings.put(contentType, newArray); // } // } // } // } // Update editor map. mapIDtoEditor[editor->GetId()] = editor; } void EditorRegistry::AddExternalEditorsToEditorMap() { // Add registered editors (may include external editors). QList maps = typeEditorMappings.AllMappings(); for (int i = 0; i < maps.size(); ++i) { FileEditorMapping::Pointer map = maps[i]; QList descArray = map->GetEditors(); for (QList::iterator itr = descArray.begin(); itr != descArray.end(); ++itr) { mapIDtoEditor[(*itr)->GetId()] = itr->Cast (); } } } IEditorDescriptor::Pointer EditorRegistry::FindEditor(const QString& id) { return mapIDtoEditor[id]; } IEditorDescriptor::Pointer EditorRegistry::GetDefaultEditor() { // the default editor will always be the system external editor // this should never return null return this->FindEditor(IEditorRegistry::SYSTEM_EXTERNAL_EDITOR_ID); } IEditorDescriptor::Pointer EditorRegistry::GetDefaultEditor( const QString& fileName) { //return this->GetDefaultEditor(filename, guessAtContentType(filename)); return this->GetEditorForContentType(fileName /*, contentType*/); } IEditorDescriptor::Pointer EditorRegistry::GetEditorForContentType( const QString& filename /*IContentType contentType*/) { IEditorDescriptor::Pointer desc; ; QList contentTypeResults = this->FindRelatedObjects(/*contentType,*/filename, relatedRegistry); if (contentTypeResults.size() > 0) { desc = contentTypeResults.front(); } return desc; } QList EditorRegistry::FindRelatedObjects( /*IContentType type,*/const QString& fileName, RelatedRegistry& /*registry*/) { QList allRelated; QList nonDefaultFileEditors; QList related; if (!fileName.isEmpty()) { FileEditorMapping::Pointer mapping = this->GetMappingFor(fileName); if (!mapping.IsNull()) { // backwards compatibility - add editors flagged as "default" related = mapping->GetDeclaredDefaultEditors(); for (QList::iterator itr = related.begin(); itr != related.end(); ++itr) { // we don't want to return duplicates if (std::find(allRelated.begin(), allRelated.end(), *itr) == allRelated.end()) { allRelated.push_back(*itr); } } // add all filename editors to the nonDefaultList // we'll later try to add them all after content types are resolved // duplicates (ie: default editors) will be ignored QList tmpList = mapping->GetEditors(); nonDefaultFileEditors.append(tmpList); } int index = fileName.indexOf('.'); if (index != -1) { QString extension = "*" + fileName.mid(index); mapping = this->GetMappingFor(extension); if (!mapping.IsNull()) { related = mapping->GetDeclaredDefaultEditors(); for (QList::iterator itr = related.begin(); itr != related.end(); ++itr) { // we don't want to return duplicates if (std::find(allRelated.begin(), allRelated.end(), *itr) == allRelated.end()) { allRelated.push_back(*itr); } } QList tmpList = mapping->GetEditors(); nonDefaultFileEditors.append(tmpList); } } } // if (type != null) { // // now add any objects directly related to the content type // related = registry.getRelatedObjects(type); // for (int i = 0; i < related.length; i++) { // // we don't want to return duplicates // if (!allRelated.contains(related[i])) { // // if it's not filtered, add it to the list // if (!WorkbenchActivityHelper.filterItem(related[i])) { // allRelated.add(related[i]); // } // } // } // // } // if (type != null) { // // now add any indirectly related objects, walking up the content type hierarchy // while ((type = type.getBaseType()) != null) { // related = registry.getRelatedObjects(type); // for (int i = 0; i < related.length; i++) { // // we don't want to return duplicates // if (!allRelated.contains(related[i])) { // // if it's not filtered, add it to the list // if (!WorkbenchActivityHelper.filterItem(related[i])) { // allRelated.add(related[i]); // } // } // } // } // } // add all non-default editors to the list for (QList::iterator i = nonDefaultFileEditors.begin(); i != nonDefaultFileEditors.end(); ++i) { IEditorDescriptor::Pointer editor = *i; if (std::find(allRelated.begin(), allRelated.end(), editor) == allRelated.end()) { allRelated.push_back(editor); } } return allRelated; } QList EditorRegistry::GetEditors( const QString& filename) { //return getEditors(filename, guessAtContentType(filename)); return this->FindRelatedObjects(/*contentType,*/filename, relatedRegistry); } QList EditorRegistry::GetFileEditorMappings() { QList array(typeEditorMappings.AllMappings()); std::sort(array.begin(), array.end(), CmpFileEditorMapping()); QList result; for (QList::iterator itr = array.begin(); itr != array.end(); ++itr) { result.push_back(itr->Cast ()); } return result; } FileEditorMapping::Pointer EditorRegistry::GetMappingFor(const QString& ext) { QString key = this->MappingKeyFor(ext); return typeEditorMappings.Get(key); } QList EditorRegistry::GetMappingForFilename( const QString& filename) { QList mapping; // Lookup on entire filename mapping[0] = this->GetMappingFor(filename); // Lookup on filename's extension int index = filename.indexOf('.'); if (index != -1) { QString extension = filename.mid(index); mapping[1] = this->GetMappingFor("*" + extension); } return mapping; } // QList EditorRegistry::GetSortedEditorsFromOS() // { // List externalEditors = new ArrayList(); // Program[] programs = Program.getPrograms(); // // for (int i = 0; i < programs.length; i++) // { // //1FPLRL2: ITPUI:WINNT - NOTEPAD editor cannot be launched // //Some entries start with %SystemRoot% // //For such cases just use the file name as they are generally // //in directories which are on the path // /* // * if (fileName.charAt(0) == '%') { fileName = name + ".exe"; } // */ // // EditorDescriptor editor = new EditorDescriptor(); // editor.setOpenMode(EditorDescriptor.OPEN_EXTERNAL); // editor.setProgram(programs[i]); // // // determine the program icon this editor would need (do not let it // // be cached in the workbench registry) // ImageDescriptor desc = new ExternalProgramImageDescriptor( // programs[i]); // editor.setImageDescriptor(desc); // externalEditors.add(editor); // } // // Object[] tempArray = sortEditors(externalEditors); // IEditorDescriptor[] array = new IEditorDescriptor[externalEditors // .size()]; // for (int i = 0; i < tempArray.length; i++) // { // array[i] = (IEditorDescriptor) tempArray[i]; // } // return array; // } QList EditorRegistry::GetSortedEditorsFromPlugins() { QList result; for (QList::iterator itr = sortedEditorsFromPlugins.begin(); itr != sortedEditorsFromPlugins.end(); ++itr) { result.push_back((*itr).Cast ()); } return result; } void EditorRegistry::InitialIdToEditorMap( QHash& map) { this->AddSystemEditors(map); } void EditorRegistry::AddSystemEditors( QHash& map) { // there will always be a system external editor descriptor EditorDescriptor::Pointer editor(new EditorDescriptor()); editor->SetID(IEditorRegistry::SYSTEM_EXTERNAL_EDITOR_ID); editor->SetName("System Editor"); editor->SetOpenMode(EditorDescriptor::OPEN_EXTERNAL); // @issue we need a real icon for this editor? map[IEditorRegistry::SYSTEM_EXTERNAL_EDITOR_ID] = editor; // there may be a system in-place editor if supported by platform // if (ComponentSupport.inPlaceEditorSupported()) // { // editor = new EditorDescriptor(); // editor.setID(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID); // editor.setName(WorkbenchMessages.SystemInPlaceDescription_name); // editor.setOpenMode(EditorDescriptor.OPEN_INPLACE); // // @issue we need a real icon for this editor? // map.put(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID, editor); // } EditorDescriptor::Pointer emptyEditorDescriptor(new EditorDescriptor()); emptyEditorDescriptor->SetID(EMPTY_EDITOR_ID); emptyEditorDescriptor->SetName("(Empty)"); //$NON-NLS-1$ //emptyEditorDescriptor.setImageDescriptor(WorkbenchImages //.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_ELEMENT)); map[EMPTY_EDITOR_ID] = emptyEditorDescriptor; } void EditorRegistry::InitializeFromStorage() { //Get editors from the registry EditorRegistryReader registryReader; registryReader.AddEditors(this); this->SortInternalEditors(); this->RebuildInternalEditorMap(); // IPreferenceStore store = PlatformUI.getPreferenceStore(); // String defaultEditors = store // .getString(IPreferenceConstants.DEFAULT_EDITORS); // String chachedDefaultEditors = store // .getString(IPreferenceConstants.DEFAULT_EDITORS_CACHE); //If defaults has changed load it afterwards so it overrides the users // associations. //if (defaultEditors == null // || defaultEditors.equals(chachedDefaultEditors)) //{ this->SetProductDefaults("");//defaultEditors); this->LoadAssociations(); //get saved earlier state // } // else // { // loadAssociations(); //get saved earlier state // setProductDefaults(defaultEditors); // store.putValue(IPreferenceConstants.DEFAULT_EDITORS_CACHE, // defaultEditors); // } this->AddExternalEditorsToEditorMap(); } void EditorRegistry::SetProductDefaults(const QString& defaultEditors) { if (defaultEditors.isEmpty()) { return; } // Poco::StringTokenizer extEditors(defaultEditors, // IPreferenceConstants::SEPARATOR, Poco::StringTokenizer::TOK_TRIM | Poco::StringTokenizer::TOK_IGNORE_EMPTY); // while (extEditors.hasMoreTokens()) // { // String extEditor = extEditors.nextToken().trim(); // int index = extEditor.indexOf(':'); // if (extEditor.length() < 3 || index <= 0 || index // >= (extEditor.length() - 1)) // { // //Extension and id must have at least one char. // WorkbenchPlugin // .log("Error setting default editor. Could not parse '" + extEditor // + "'. Default editors should be specified as '*.ext1:editorId1;*.ext2:editorId2'"); //$NON-NLS-1$ //$NON-NLS-2$ // return; // } // String ext = extEditor.substring(0, index).trim(); // String editorId = extEditor.substring(index + 1).trim(); // FileEditorMapping mapping = getMappingFor(ext); // if (mapping == null) // { // WorkbenchPlugin // .log("Error setting default editor. Could not find mapping for '" // + ext + "'."); //$NON-NLS-1$ //$NON-NLS-2$ // continue; // } // EditorDescriptor editor = (EditorDescriptor) findEditor(editorId); // if (editor == null) // { // WorkbenchPlugin // .log("Error setting default editor. Could not find editor: '" // + editorId + "'."); //$NON-NLS-1$ //$NON-NLS-2$ // continue; // } // mapping.setDefaultEditor(editor); // } } bool EditorRegistry::ReadEditors( QHash& /*editorTable*/) { //Get the workbench plugin's working directory QString workbenchStatePath = WorkbenchPlugin::GetDefault()->GetDataLocation(); if (workbenchStatePath.isNull()) { return false; } // IPreferenceStore store = WorkbenchPlugin.getDefault() // .getPreferenceStore(); // Reader reader = null; // try // { // // Get the editors defined in the preferences store // String xmlString = store.getString(IPreferenceConstants.EDITORS); // if (xmlString == null || xmlString.length() == 0) // { // FileInputStream stream = new FileInputStream(workbenchStatePath // .append(IWorkbenchConstants.EDITOR_FILE_NAME) // .toOSString()); // reader = new BufferedReader(new InputStreamReader(stream, // "utf-8")); //$NON-NLS-1$ // } // else // { // reader = new StringReader(xmlString); // } // XMLMemento memento = XMLMemento.createReadRoot(reader); // EditorDescriptor editor; // IMemento[] edMementos = memento // .getChildren(IWorkbenchConstants.TAG_DESCRIPTOR); // // Get the editors and validate each one // for (int i = 0; i < edMementos.length; i++) // { // editor = new EditorDescriptor(); // boolean valid = editor.loadValues(edMementos[i]); // if (!valid) // { // continue; // } // if (editor.getPluginID() != null) // { // //If the editor is from a plugin we use its ID to look it // // up in the mapping of editors we // //have obtained from plugins. This allows us to verify that // // the editor is still valid // //and allows us to get the editor description from the // // mapping table which has // //a valid config element field. // EditorDescriptor validEditorDescritor = (EditorDescriptor) mapIDtoEditor // .get(editor.getId()); // if (validEditorDescritor != null) // { // editorTable.put(validEditorDescritor.getId(), // validEditorDescritor); // } // } // else // { //This is either from a program or a user defined // // editor // ImageDescriptor descriptor; // if (editor.getProgram() == null) // { // descriptor = new ProgramImageDescriptor(editor // .getFileName(), 0); // } // else // { // descriptor = new ExternalProgramImageDescriptor(editor // .getProgram()); // } // editor.setImageDescriptor(descriptor); // editorTable.put(editor.getId(), editor); // } // } // } // catch (IOException e) // { // try // { // if (reader != null) // { // reader.close(); // } // } // catch (IOException ex) // { // e.printStackTrace(); // } // //Ignore this as the workbench may not yet have saved any state // return false; // } // catch (WorkbenchException e) // { // ErrorDialog.openError((Shell) null, WorkbenchMessages.EditorRegistry_errorTitle, // WorkbenchMessages.EditorRegistry_errorMessage, // e.getStatus()); // return false; // } return true; } void EditorRegistry::ReadResources( QHash& /*editorTable*/, std::ostream& /*reader*/) { // XMLMemento memento = XMLMemento.createReadRoot(reader); // String versionString = memento.getString(IWorkbenchConstants.TAG_VERSION); // boolean versionIs31 = "3.1".equals(versionString); //$NON-NLS-1$ // // IMemento[] extMementos = memento // .getChildren(IWorkbenchConstants.TAG_INFO); // for (int i = 0; i < extMementos.length; i++) // { // String name = extMementos[i] // .getString(IWorkbenchConstants.TAG_NAME); // if (name == null) // { // name = "*"; //$NON-NLS-1$ // } // String extension = extMementos[i] // .getString(IWorkbenchConstants.TAG_EXTENSION); // IMemento[] idMementos = extMementos[i] // .getChildren(IWorkbenchConstants.TAG_EDITOR); // String[] editorIDs = new String[idMementos.length]; // for (int j = 0; j < idMementos.length; j++) // { // editorIDs[j] = idMementos[j] // .getString(IWorkbenchConstants.TAG_ID); // } // idMementos = extMementos[i] // .getChildren(IWorkbenchConstants.TAG_DELETED_EDITOR); // String[] deletedEditorIDs = new String[idMementos.length]; // for (int j = 0; j < idMementos.length; j++) // { // deletedEditorIDs[j] = idMementos[j] // .getString(IWorkbenchConstants.TAG_ID); // } // FileEditorMapping mapping = getMappingFor(name + "." + extension); //$NON-NLS-1$ // if (mapping == null) // { // mapping = new FileEditorMapping(name, extension); // } // List editors = new ArrayList(); // for (int j = 0; j < editorIDs.length; j++) // { // if (editorIDs[j] != null) // { // EditorDescriptor editor = (EditorDescriptor) editorTable // .get(editorIDs[j]); // if (editor != null) // { // editors.add(editor); // } // } // } // List deletedEditors = new ArrayList(); // for (int j = 0; j < deletedEditorIDs.length; j++) // { // if (deletedEditorIDs[j] != null) // { // EditorDescriptor editor = (EditorDescriptor) editorTable // .get(deletedEditorIDs[j]); // if (editor != null) // { // deletedEditors.add(editor); // } // } // } // // List defaultEditors = new ArrayList(); // // if (versionIs31) // { // parse the new format // idMementos = extMementos[i] // .getChildren(IWorkbenchConstants.TAG_DEFAULT_EDITOR); // String[] defaultEditorIds = new String[idMementos.length]; // for (int j = 0; j < idMementos.length; j++) // { // defaultEditorIds[j] = idMementos[j] // .getString(IWorkbenchConstants.TAG_ID); // } // for (int j = 0; j < defaultEditorIds.length; j++) // { // if (defaultEditorIds[j] != null) // { // EditorDescriptor editor = (EditorDescriptor) editorTable // .get(defaultEditorIds[j]); // if (editor != null) // { // defaultEditors.add(editor); // } // } // } // } // else // { // guess at pre 3.1 format defaults // if (!editors.isEmpty()) // { // EditorDescriptor editor = (EditorDescriptor) editors.get(0); // if (editor != null) // { // defaultEditors.add(editor); // } // } // defaultEditors.addAll(Arrays.asList(mapping.getDeclaredDefaultEditors())); // } // // // Add any new editors that have already been read from the registry // // which were not deleted. // IEditorDescriptor[] editorsArray = mapping.getEditors(); // for (int j = 0; j < editorsArray.length; j++) // { // if (!contains(editors, editorsArray[j]) // && !deletedEditors.contains(editorsArray[j])) // { // editors.add(editorsArray[j]); // } // } // // Map the editor(s) to the file type // mapping.setEditorsList(editors); // mapping.setDeletedEditorsList(deletedEditors); // mapping.setDefaultEditors(defaultEditors); // typeEditorMappings.put(mappingKeyFor(mapping), mapping); // } } bool EditorRegistry::Contains( const QList& editorsArray, IEditorDescriptor::Pointer editorDescriptor) { IEditorDescriptor::Pointer currentEditorDescriptor; for (QList::const_iterator i = editorsArray.begin(); i != editorsArray.end(); ++i) { currentEditorDescriptor = *i; if (currentEditorDescriptor->GetId() == editorDescriptor->GetId()) { return true; } } return false; } bool EditorRegistry::ReadResources( QHash& /*editorTable*/) { //Get the workbench plugin's working directory QString workbenchStatePath = WorkbenchPlugin::GetDefault()->GetDataLocation(); // XXX: nobody cares about this return value if (workbenchStatePath.isNull()) { return false; } // IPreferenceStore store = WorkbenchPlugin.getDefault() // .getPreferenceStore(); // Reader reader = null; // try // { // // Get the resource types // String xmlString = store.getString(IPreferenceConstants.RESOURCES); // if (xmlString == null || xmlString.length() == 0) // { // FileInputStream stream = new FileInputStream(workbenchStatePath // .append(IWorkbenchConstants.RESOURCE_TYPE_FILE_NAME) // .toOSString()); // reader = new BufferedReader(new InputStreamReader(stream, // "utf-8")); //$NON-NLS-1$ // } // else // { // reader = new StringReader(xmlString); // } // // Read the defined resources into the table // readResources(editorTable, reader); // } // catch (IOException e) // { // try // { // if (reader != null) // { // reader.close(); // } // } // catch (IOException ex) // { // ex.printStackTrace(); // } // MessageDialog.openError((Shell) null, WorkbenchMessages.EditorRegistry_errorTitle, // WorkbenchMessages.EditorRegistry_errorMessage); // return false; // } // catch (WorkbenchException e) // { // ErrorDialog.openError((Shell) null, WorkbenchMessages.EditorRegistry_errorTitle, // WorkbenchMessages.EditorRegistry_errorMessage, // e.getStatus()); // return false; // } return true; } bool EditorRegistry::LoadAssociations() { QHash editorTable; if (!this->ReadEditors(editorTable)) { return false; } return this->ReadResources(editorTable); } QString EditorRegistry::MappingKeyFor(const QString& type) { - // keep everyting lower case for case-sensitive platforms + // keep everything lower case for case-sensitive platforms return type.toLower(); } QString EditorRegistry::MappingKeyFor(FileEditorMapping::Pointer mapping) { return this->MappingKeyFor(mapping->GetName() + (mapping->GetExtension().size() == 0 ? "" : "." + mapping->GetExtension())); //$NON-NLS-1$ //$NON-NLS-2$ } void EditorRegistry::RebuildEditorMap() { this->RebuildInternalEditorMap(); this->AddExternalEditorsToEditorMap(); } void EditorRegistry::RebuildInternalEditorMap() { EditorDescriptor::Pointer desc; // Allocate a new map. mapIDtoEditor.clear(); this->InitialIdToEditorMap(mapIDtoEditor); // Add plugin editors. for (QList::iterator itr = sortedEditorsFromPlugins.begin(); itr != sortedEditorsFromPlugins.end(); ++itr) { desc = *itr; mapIDtoEditor[desc->GetId()] = desc; } } void EditorRegistry::SaveAssociations() { //Save the resource type descriptions // List editors = new ArrayList(); // IPreferenceStore store = WorkbenchPlugin.getDefault() // .getPreferenceStore(); // // XMLMemento memento = XMLMemento // .createWriteRoot(IWorkbenchConstants.TAG_EDITORS); // memento.putString(IWorkbenchConstants.TAG_VERSION, "3.1"); //$NON-NLS-1$ // FileEditorMapping maps[] = typeEditorMappings.userMappings(); // for (int mapsIndex = 0; mapsIndex < maps.length; mapsIndex++) // { // FileEditorMapping type = maps[mapsIndex]; // IMemento editorMemento = memento // .createChild(IWorkbenchConstants.TAG_INFO); // editorMemento.putString(IWorkbenchConstants.TAG_NAME, type // .getName()); // editorMemento.putString(IWorkbenchConstants.TAG_EXTENSION, type // .getExtension()); // IEditorDescriptor[] editorArray = type.getEditors(); // for (int i = 0; i < editorArray.length; i++) // { // EditorDescriptor editor = (EditorDescriptor) editorArray[i]; // if (!editors.contains(editor)) // { // editors.add(editor); // } // IMemento idMemento = editorMemento // .createChild(IWorkbenchConstants.TAG_EDITOR); // idMemento.putString(IWorkbenchConstants.TAG_ID, editorArray[i] // .getId()); // } // editorArray = type.getDeletedEditors(); // for (int i = 0; i < editorArray.length; i++) // { // EditorDescriptor editor = (EditorDescriptor) editorArray[i]; // if (!editors.contains(editor)) // { // editors.add(editor); // } // IMemento idMemento = editorMemento // .createChild(IWorkbenchConstants.TAG_DELETED_EDITOR); // idMemento.putString(IWorkbenchConstants.TAG_ID, editorArray[i] // .getId()); // } // editorArray = type.getDeclaredDefaultEditors(); // for (int i = 0; i < editorArray.length; i++) // { // EditorDescriptor editor = (EditorDescriptor) editorArray[i]; // if (!editors.contains(editor)) // { // editors.add(editor); // } // IMemento idMemento = editorMemento // .createChild(IWorkbenchConstants.TAG_DEFAULT_EDITOR); // idMemento.putString(IWorkbenchConstants.TAG_ID, editorArray[i] // .getId()); // } // } // Writer writer = null; // try // { // writer = new StringWriter(); // memento.save(writer); // writer.close(); // store.setValue(IPreferenceConstants.RESOURCES, writer.toString()); // } // catch (IOException e) // { // try // { // if (writer != null) // { // writer.close(); // } // } // catch (IOException ex) // { // ex.printStackTrace(); // } // MessageDialog.openError((Shell) null, "Saving Problems", //$NON-NLS-1$ // "Unable to save resource associations."); //$NON-NLS-1$ // return; // } // // memento = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_EDITORS); // Iterator itr = editors.iterator(); // while (itr.hasNext()) // { // EditorDescriptor editor = (EditorDescriptor) itr.next(); // IMemento editorMemento = memento // .createChild(IWorkbenchConstants.TAG_DESCRIPTOR); // editor.saveValues(editorMemento); // } // writer = null; // try // { // writer = new StringWriter(); // memento.save(writer); // writer.close(); // store.setValue(IPreferenceConstants.EDITORS, writer.toString()); // } // catch (IOException e) // { // try // { // if (writer != null) // { // writer.close(); // } // } // catch (IOException ex) // { // ex.printStackTrace(); // } // MessageDialog.openError((Shell) null, // "Error", "Unable to save resource associations."); //$NON-NLS-1$ //$NON-NLS-2$ // return; // } } void EditorRegistry::SetFileEditorMappings( const QList& newResourceTypes) { typeEditorMappings.Clear(); for (int i = 0; i < newResourceTypes.size(); i++) { FileEditorMapping::Pointer mapping = newResourceTypes[i]; typeEditorMappings.Put(this->MappingKeyFor(mapping), mapping); } //extensionImages = new HashMap(); this->RebuildEditorMap(); //firePropertyChange(PROP_CONTENTS); } void EditorRegistry::SetDefaultEditor(const QString& fileName, const QString& editorId) { EditorDescriptor::Pointer desc = this->FindEditor(editorId).Cast< EditorDescriptor> (); QList mapping = this->GetMappingForFilename( fileName); if (!mapping[0].IsNull()) { mapping[0]->SetDefaultEditor(desc); } if (!mapping[1].IsNull()) { mapping[1]->SetDefaultEditor(desc); } } QList EditorRegistry::SortEditors( const QList& unsortedList) { QList result(unsortedList); std::sort(result.begin(), result.end(), CmpIEditorDescriptor()); return result; } void EditorRegistry::SortInternalEditors() { qSort(sortedEditorsFromPlugins.begin(), sortedEditorsFromPlugins.end(), CmpEditorDescriptor()); } void EditorRegistry::EditorMap::PutDefault(const QString& key, FileEditorMapping::Pointer value) { defaultMap[key] = value; } void EditorRegistry::EditorMap::Put(const QString& key, FileEditorMapping::Pointer value) { QHash::iterator result = defaultMap.find(key); if (result != defaultMap.end()) { map[key] = value; } } FileEditorMapping::Pointer EditorRegistry::EditorMap::Get( const QString& key) { QHash::const_iterator result = map.find(key); if (result == map.end()) { return defaultMap[key]; } return result.value(); } void EditorRegistry::EditorMap::Clear() { defaultMap.clear(); map.clear(); } QList EditorRegistry::EditorMap::AllMappings() { QSet resultSet; QHash::const_iterator iter; for (iter = defaultMap.begin(); iter != defaultMap.end(); ++iter) { resultSet.insert(iter.value()); } for (iter = map.begin(); iter != map.end(); ++iter) { resultSet.insert(iter.value()); } return resultSet.toList(); } QList EditorRegistry::EditorMap::UserMappings() { return map.values(); } bool EditorRegistry::IsSystemInPlaceEditorAvailable(const QString& /*filename*/) { //return ComponentSupport.inPlaceEditorAvailable(filename); return false; } bool EditorRegistry::IsSystemExternalEditorAvailable( const QString& /*filename*/) { // QString::size_type nDot = filename.find_last_of('.'); // if (nDot != QString::npos) // { // QString strName = filename.substr(nDot); // return Program.findProgram(strName) != null; // } return false; } void EditorRegistry::RemoveEditorFromMapping( QHash& map, IEditorDescriptor::Pointer desc) { FileEditorMapping::Pointer mapping; for (QHash::iterator iter = map.begin(); iter != map.end(); ++iter) { mapping = iter.value(); QList editors(mapping->GetEditors()); QList::iterator result = std::find( editors.begin(), editors.end(), desc); if (result != editors.end()) { mapping->RemoveEditor(result->Cast ()); editors.erase(result); } if (editors.empty()) { map.erase(iter); break; } } } IExtensionPoint::Pointer EditorRegistry::GetExtensionPointFilter() { return Platform::GetExtensionRegistry()->GetExtensionPoint( PlatformUI::PLUGIN_ID(), WorkbenchRegistryConstants::PL_EDITOR); } QList EditorRegistry::GetUnifiedMappings() { QList standardMappings( dynamic_cast (PlatformUI::GetWorkbench() ->GetEditorRegistry())->GetFileEditorMappings()); QList allMappings(standardMappings); // mock-up content type extensions into IFileEditorMappings // IContentType [] contentTypes = Platform.getContentTypeManager().getAllContentTypes(); // for (int i = 0; i < contentTypes.length; i++) // { // IContentType type = contentTypes[i]; // String [] extensions = type.getFileSpecs(IContentType.FILE_EXTENSION_SPEC); // for (int j = 0; j < extensions.length; j++) // { // String extension = extensions[j]; // boolean found = false; // for (Iterator k = allMappings.iterator(); k.hasNext();) // { // IFileEditorMapping mapping = (IFileEditorMapping) k.next(); // if ("*".equals(mapping.getName()) // && extension.equals(mapping.getExtension())) // { //$NON-NLS-1$ // found = true; // break; // } // } // if (!found) // { // MockMapping mockMapping = new MockMapping(type, "*", extension); //$NON-NLS-1$ // allMappings.add(mockMapping); // } // } // // String [] filenames = type.getFileSpecs(IContentType.FILE_NAME_SPEC); // for (int j = 0; j < filenames.length; j++) // { // String wholename = filenames[j]; // int idx = wholename.indexOf('.'); // String name = idx == -1 ? wholename : wholename.substring(0, idx); // String extension = idx == -1 ? "" : wholename.substring(idx + 1); //$NON-NLS-1$ // // boolean found = false; // for (Iterator k = allMappings.iterator(); k.hasNext();) // { // IFileEditorMapping mapping = (IFileEditorMapping) k.next(); // if (name.equals(mapping.getName()) // && extension.equals(mapping.getExtension())) // { // found = true; // break; // } // } // if (!found) // { // MockMapping mockMapping = new MockMapping(type, name, extension); // allMappings.add(mockMapping); // } // } // } return allMappings; } MockMapping::MockMapping(/*IContentType type,*/const QString& name, const QString& ext) : extension(ext), filename(name) { //this.contentType = type; } IEditorDescriptor::Pointer MockMapping::GetDefaultEditor() { // QList candidates = PlatformUI::GetWorkbench()->GetEditorRegistry() // ->GetEditorsForContentType(contentType); // if (candidates.empty()) // { // return IEditorDescriptor::Pointer(); // } // return candidates[0]; return IEditorDescriptor::Pointer(); } QList MockMapping::GetEditors() const { // QList editorsForContentType = (dynamic_cast(PlatformUI // ::GetWorkbench()->GetEditorRegistry()) // ->GetEditorsForContentType(contentType); // return editorsForContentType; return QList(); } QList MockMapping::GetDeletedEditors() const { return QList(); } QString MockMapping::GetExtension() const { return extension; } QString MockMapping::GetLabel() const { return filename + '.' + extension; } QString MockMapping::GetName() const { return filename; } bool MockMapping::operator==(const Object* obj) const { if (const MockMapping* other = dynamic_cast(obj)) { if (this == other) { return true; } //MockMapping mapping = (MockMapping) obj; if (!(this->filename == other->filename)) { return false; } if (!(this->extension == other->extension)) { return false; } if (!(this->GetEditors() == other->GetEditors())) { return false; } return this->GetDeletedEditors() == other->GetDeletedEditors(); } return false; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorRegistry.h b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorRegistry.h index 3ac251dbc6..6716f0b9de 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorRegistry.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorRegistry.h @@ -1,754 +1,754 @@ /*============================================================================ 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 BERRYEDITORREGISTRY_H_ #define BERRYEDITORREGISTRY_H_ #include #include "berryIEditorRegistry.h" #include "berryIFileEditorMapping.h" #include "berryEditorDescriptor.h" #include "berryFileEditorMapping.h" namespace berry { /** * \ingroup org_blueberry_ui_internal * * Provides access to the collection of defined editors for resource types. */ class EditorRegistry : public IEditorRegistry { class RelatedRegistry { public: RelatedRegistry(EditorRegistry* editorRegistry); /** * Return the objects related to the type. * * @param type * @return the objects related to the type */ // public: QList GetRelatedObjects(IContentType type) { // IEditorDescriptor[] relatedObjects = (IEditorDescriptor[]) contentTypeToEditorMappings.get(type); // if (relatedObjects == null) { // return EMPTY; // } // return (IEditorDescriptor[]) WorkbenchActivityHelper.restrictArray(relatedObjects); // } /** * Return the objects related to the filename * @param fileName * @return the objects related to the filename */ public: QList GetRelatedObjects( const QString& fileName); private: EditorRegistry* editorRegistry; }; friend class RelatedRegistry; /** * Map of FileEditorMapping (extension to FileEditorMapping) Uses two * java.util.HashMap: one keeps the default which are set by the plugins and * the other keeps the changes made by the user through the preference page. */ class EditorMap { static QHash defaultMap; static QHash map; public: void Clear(); /** * Put a default mapping into the editor map. * * @param key the key to set * @param value the value to associate */ public: static void PutDefault(const QString& key, FileEditorMapping::Pointer value); /** * Put a mapping into the user editor map. * * @param key the key to set * @param value the value to associate */ public: void Put(const QString& key, FileEditorMapping::Pointer value); /** * Return the mapping associated to the key. First searches user * map, and then falls back to the default map if there is no match. May * return null * * @param key * the key to search for * @return the mapping associated to the key or null */ public: FileEditorMapping::Pointer Get(const QString& key); /** * Return all mappings. This will return default mappings overlayed with * user mappings. * * @return the mappings */ public: QList AllMappings(); /** * Return all user mappings. * * @return the mappings */ public: QList UserMappings(); }; struct CmpFileEditorMapping { bool operator()(const FileEditorMapping::Pointer& x, const FileEditorMapping::Pointer& y) const { return x->GetLabel() < y->GetLabel(); } }; struct CmpIEditorDescriptor { bool operator()(const IEditorDescriptor::Pointer& x, const IEditorDescriptor::Pointer& y) const { return x->GetLabel() < y->GetLabel(); } }; struct CmpEditorDescriptor { bool operator()(const EditorDescriptor::Pointer& x, const EditorDescriptor::Pointer& y) const { return x->GetLabel() < y->GetLabel(); } }; //private: Map contentTypeToEditorMappings = new HashMap(); /* * Cached images - these include images from registered editors (via * plugins) and others hence this table is not one to one with the mappings * table. It is in fact a superset of the keys one would find in * typeEditorMappings */ //private: Map extensionImages = new HashMap(); /** * Vector of EditorDescriptor - all the editors loaded from plugin files. * The list is kept in order to be able to show in the editor selection * dialog of the resource associations page. This list is sorted based on the * human readable label of the editor descriptor. * * @see #comparer */ private: QList sortedEditorsFromPlugins; // Map of EditorDescriptor - map editor id to editor. private: QHash mapIDtoEditor; // Map of FileEditorMapping (extension to FileEditorMapping) private: EditorMap typeEditorMappings; /* * Compares the labels from two IEditorDescriptor objects */ //private: // static final Comparator comparer = new Comparator() // { // private Collator collator = Collator.getInstance(); // // public int compare(Object arg0, Object arg1) // { // String s1 = ((IEditorDescriptor) arg0).getLabel(); // String s2 = ((IEditorDescriptor) arg1).getLabel(); // return collator.compare(s1, s2); // } // }; private: RelatedRegistry relatedRegistry; public: static const QString EMPTY_EDITOR_ID; // = "org.blueberry.ui.internal.emptyEditorTab" /** * Return an instance of the receiver. Adds listeners into the extension * registry for dynamic UI purposes. */ public: EditorRegistry(); /** * Add an editor for the given extensions with the specified (possibly null) * extended type. The editor is being registered from a plugin * * @param editor * The description of the editor (as obtained from the plugin * file and built by the registry reader) * @param extensions * Collection of file extensions the editor applies to * @param filenames * Collection of filenames the editor applies to * @param contentTypeVector * @param bDefault * Indicates whether the editor should be made the default editor * and hence appear first inside a FileEditorMapping * * This method is not API and should not be called outside the workbench * code. */ public: void AddEditorFromPlugin(EditorDescriptor::Pointer editor, const QList& extensions, const QList& filenames, const QList& contentTypeVector, bool bDefault); /** * Add external editors to the editor mapping. */ private: void AddExternalEditorsToEditorMap(); /* * (non-Javadoc) Method declared on IEditorRegistry. */ //public: void AddPropertyListener(IPropertyListener l) { // addListenerObject(l); // } /* * (non-Javadoc) Method declared on IEditorRegistry. */ public: IEditorDescriptor::Pointer FindEditor(const QString& id) override; /** * Fires a property changed event to all registered listeners. * * @param type the type of event * @see IEditorRegistry#PROP_CONTENTS */ // private: void FirePropertyChange(final int type) { // Object[] array = getListeners(); // for (int nX = 0; nX < array.length; nX++) { // final IPropertyListener l = (IPropertyListener) array[nX]; // Platform.run(new SafeRunnable() { // public: void run() { // l.propertyChanged(EditorRegistry.this, type); // } // }); // } // } /* * (non-Javadoc) Method declared on IEditorRegistry. * * @deprecated */ public: IEditorDescriptor::Pointer GetDefaultEditor() override; /* * (non-Javadoc) Method declared on IEditorRegistry. */ public: IEditorDescriptor::Pointer GetDefaultEditor(const QString& filename) override; /** * Return the (approximated) content type for a file with the given name. * * @param filename the filename * @return the content type or null if it could not be determined * @since 3.1 */ // private: IContentType::Pointer GuessAtContentType(const QString& filename) { // return Platform.getContentTypeManager().findContentTypeFor(filename); // } /** * Returns the default file image descriptor. * * @return the image descriptor */ // private: ImageDescriptor GetDefaultImage() { // // @issue what should be the default image? // return WorkbenchImages.getImageDescriptor(ISharedImages.IMG_OBJ_FILE); // } /* * (non-Javadoc) Method declared on IEditorRegistry. */ public: QList GetEditors(const QString& filename) override; /* * (non-Javadoc) Method declared on IEditorRegistry. */ public: QList GetFileEditorMappings() override; /* * (non-Javadoc) Method declared on IEditorRegistry. */ // public: ImageDescriptor GetImageDescriptor(String filename) { // return getImageDescriptor(filename, guessAtContentType(filename)); // } /** * Find the file editor mapping for the file extension. Returns * null if not found. * * @param ext * the file extension * @return the mapping, or null */ private: FileEditorMapping::Pointer GetMappingFor(const QString& ext); /** * Find the file editor mappings for the given filename. *

* Return an array of two FileEditorMapping items, where the first mapping * is for the entire filename, and the second mapping is for the filename's * extension only. These items can be null if no mapping exist on the * filename and/or filename's extension.

* * @param filename the filename * @return the mappings */ private: QList GetMappingForFilename(const QString& filename); /** * Return the editor descriptors pulled from the OS. *

* WARNING! The image described by each editor descriptor is *not* known by * the workbench's graphic registry. Therefore clients must take care to * ensure that if they access any of the images held by these editors that * they also dispose them *

* @return the editor descriptors */ //public: QList GetSortedEditorsFromOS(); /** * Return the editors loaded from plugins. * * @return the sorted array of editors declared in plugins * @see #comparer */ public: QList GetSortedEditorsFromPlugins(); /** - * Answer an intial id to editor map. This will create a new map and + * Answer an initial id to editor map. This will create a new map and * populate it with the default system editors. * * @param initialSize * the initial size of the map * @return the new map */ private: void InitialIdToEditorMap(QHash& map); /** * Add the system editors to the provided map. This will always add an * editor with an id of {@link #SYSTEM_EXTERNAL_EDITOR_ID} and may also add * an editor with id of {@link #SYSTEM_INPLACE_EDITOR_ID} if the system * configuration supports it. * * @param map the map to augment */ private: void AddSystemEditors(QHash& map); /** * Initialize the registry state from plugin declarations and preference * overrides. */ private: void InitializeFromStorage(); /** * Set the default editors according to the preference store which can be * overwritten in the file properties.ini. In the form: *

* ext1:id1;ext2:id2;... *

* * @param defaultEditors the default editors to set */ private: void SetProductDefaults(const QString& defaultEditors); /** * Read the editors defined in the preferences store. * * @param editorTable * Editor table to store the editor definitions. - * @return true if the table is built succesfully. + * @return true if the table is built successfully. */ private: bool ReadEditors(QHash& editorTable); /** * Read the file types and associate them to their defined editor(s). * * @param editorTable * The editor table containing the defined editors. * @param reader * Reader containing the preferences content for the resources. * * @throws WorkbenchException */ public: void ReadResources(QHash& editorTable, std::ostream& reader); /** * Determine if the editors list contains the editor descriptor. * * @param editorsArray * The list of editors * @param editorDescriptor * The editor descriptor * @return true if the editors list contains the editor descriptor */ private: bool Contains(const QList& editorsArray, IEditorDescriptor::Pointer editorDescriptor); /** * Creates the reader for the resources preferences defined in the * preference store. * * @param editorTable * The editor table containing the defined editors. - * @return true if the resources are read succesfully. + * @return true if the resources are read successfully. */ private: bool ReadResources(QHash& editorTable); /** * Load the serialized resource associations Return true if the operation * was successful, false otherwise */ private: bool LoadAssociations(); /** * Return a friendly version of the given key suitable for use in the editor * map. */ private: QString MappingKeyFor(const QString& type); /** * Return a key that combines the file's name and extension of the given * mapping * * @param mapping the mapping to generate a key for */ private: QString MappingKeyFor(FileEditorMapping::Pointer mapping); /** * Rebuild the editor map */ private: void RebuildEditorMap(); /** * Rebuild the internal editor mapping. */ private: void RebuildInternalEditorMap(); /* * (non-Javadoc) Method declared on IEditorRegistry. */ // public: void RemovePropertyListener(IPropertyListener l) { // removeListenerObject(l); // } /** * Save the registry to the filesystem by serializing the current resource * associations. */ public: void SaveAssociations(); /** * Set the collection of FileEditorMappings. The given collection is * converted into the internal hash table for faster lookup Each mapping * goes from an extension to the collection of editors that work on it. This * operation will rebuild the internal editor mappings. * * @param newResourceTypes - * te new file editor mappings. + * the new file editor mappings. */ public: void SetFileEditorMappings(const QList& newResourceTypes); /* * (non-Javadoc) Method declared on IEditorRegistry. */ public: void SetDefaultEditor(const QString& fileName, const QString& editorId) override; /** * Alphabetically sort the internal editors. * * @see #comparer */ private: QList SortEditors(const QList& unsortedList); /** * Alphabetically sort the internal editors. * * @see #comparer */ private: void SortInternalEditors(); /* * (non-Javadoc) * * @see org.blueberry.ui.IEditorRegistry#isSystemInPlaceEditorAvailable(String) */ public: bool IsSystemInPlaceEditorAvailable(const QString& filename) override; /* * (non-Javadoc) * * @see org.blueberry.ui.IEditorRegistry#isSystemExternalEditorAvailable(String) */ public: bool IsSystemExternalEditorAvailable(const QString& filename) override; /* * (non-Javadoc) * * @see org.blueberry.ui.IEditorRegistry#getSystemExternalEditorImageDescriptor(java.lang.String) */ // public: ImageDescriptor GetSystemExternalEditorImageDescriptor( // const QString& filename) { // Program externalProgram = null; // int extensionIndex = filename.lastIndexOf('.'); // if (extensionIndex >= 0) { // externalProgram = Program.findProgram(filename // .substring(extensionIndex)); // } // if (externalProgram == null) { // return null; // } // // return new ExternalProgramImageDescriptor(externalProgram); // } /** * Removes the entry with the value of the editor descriptor from the given * map. If the descriptor is the last descriptor in a given * FileEditorMapping then the mapping is removed from the map. * * @param map * the map to search * @param desc * the descriptor value to remove */ private: void RemoveEditorFromMapping(QHash& map, IEditorDescriptor::Pointer desc); private: IExtensionPoint::Pointer GetExtensionPointFilter(); /* (non-Javadoc) * @see org.blueberry.ui.IEditorRegistry#getDefaultEditor(java.lang.String, org.blueberry.core.runtime.content.IContentType) */ // public: IEditorDescriptor::Pointer GetDefaultEditor(const QString& fileName, IContentType contentType) { // return getEditorForContentType(fileName, contentType); // } /** * Return the editor for a file with a given content type. * * @param filename the file name * @param contentType the content type * @return the editor for a file with a given content type * @since 3.1 */ private: IEditorDescriptor::Pointer GetEditorForContentType(const QString& filename /*IContentType contentType*/); /* (non-Javadoc) * @see org.blueberry.ui.IEditorRegistry#getEditors(java.lang.String, org.blueberry.core.runtime.content.IContentType) */ // public: QList GetEditors(const QString& fileName, IContentType contentType) { // return findRelatedObjects(contentType, fileName, relatedRegistry); // } /* (non-Javadoc) * @see org.blueberry.ui.IEditorRegistry#getImageDescriptor(java.lang.String, org.blueberry.core.runtime.content.IContentType) */ // public: ImageDescriptor GetImageDescriptor(const QString filename, IContentType contentType) { // if (filename == null) { // return getDefaultImage(); // } // // if (contentType != null) { // IEditorDescriptor desc = getEditorForContentType(filename, contentType); // if (desc != null) { // ImageDescriptor anImage = (ImageDescriptor) extensionImages.get(desc); // if (anImage != null) { // return anImage; // } // anImage = desc.getImageDescriptor(); // extensionImages.put(desc, anImage); // return anImage; // } // } // // Lookup in the cache first... // String key = mappingKeyFor(filename); // ImageDescriptor anImage = (ImageDescriptor) extensionImages.get(key); // if (anImage != null) { // return anImage; // } // // // See if we have a mapping for the filename or extension // FileEditorMapping[] mapping = getMappingForFilename(filename); // for (int i = 0; i < 2; i++) { // if (mapping[i] != null) { // // Lookup in the cache first... // String mappingKey = mappingKeyFor(mapping[i]); // ImageDescriptor mappingImage = (ImageDescriptor) extensionImages // .get(key); // if (mappingImage != null) { // return mappingImage; // } // // Create it and cache it // IEditorDescriptor editor = mapping[i].getDefaultEditor(); // if (editor != null) { // mappingImage = editor.getImageDescriptor(); // extensionImages.put(mappingKey, mappingImage); // return mappingImage; // } // } // } // // // Nothing - time to look externally for the icon // anImage = getSystemExternalEditorImageDescriptor(filename); // if (anImage == null) { // anImage = getDefaultImage(); // } // // for dynamic UI - comment out the next line // //extensionImages.put(key, anImage); // return anImage; // // } /** * Find objects related to the content type. * * This method is temporary and exists only to back us off of the * soon-to-be-removed IContentTypeManager.IRelatedRegistry API. * * @param type * @param fileName * @param registry * @return the related objects */ private: QList FindRelatedObjects(/*IContentType type,*/ const QString& fileName, RelatedRegistry& registry); /** * Return the editors bound to this content type, either directly or indirectly. * * @param type the content type to check * @return the editors * @since 3.1 * * TODO: this should be rolled in with the above findRelatedObjects code */ // public: QList GetEditorsForContentType(IContentType type) { // ArrayList allRelated = new ArrayList(); // if (type == null) { // return new IEditorDescriptor [0]; // } // // Object [] related = relatedRegistry.getRelatedObjects(type); // for (int i = 0; i < related.length; i++) { // // we don't want to return duplicates // if (!allRelated.contains(related[i])) { // // if it's not filtered, add it to the list // if (!WorkbenchActivityHelper.filterItem(related[i])) { // allRelated.add(related[i]); // } // // } // } // // // now add any indirectly related objects, walking up the content type hierarchy // while ((type = type.getBaseType()) != null) { // related = relatedRegistry.getRelatedObjects(type); // for (int i = 0; i < related.length; i++) { // // we don't want to return duplicates // if (!allRelated.contains(related[i])) { // // if it's not filtered, add it to the list // if (!WorkbenchActivityHelper.filterItem(related[i])) { // allRelated.add(related[i]); // } // } // } // } // // return (IEditorDescriptor[]) allRelated.toArray(new IEditorDescriptor[allRelated.size()]); // } /** * Get filemappings for all defined filetypes, including those defined by content type. * * @return the filetypes * @since 3.1 */ public: QList GetUnifiedMappings(); }; class MockMapping : public IFileEditorMapping { //private: IContentType contentType; private: QString extension; private: QString filename; MockMapping(/*IContentType type,*/const QString& name, const QString& ext); public: IEditorDescriptor::Pointer GetDefaultEditor() override; public: QList GetEditors() const override; public: QList GetDeletedEditors() const override; public: QString GetExtension() const override; // public: ImageDescriptor GetImageDescriptor() { // IEditorDescriptor editor = getDefaultEditor(); // if (editor == null) { // return WorkbenchImages // .getImageDescriptor(ISharedImages.IMG_OBJ_FILE); // } // // return editor.getImageDescriptor(); // } public: QString GetLabel() const override; public: QString GetName() const override; /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public: bool operator==(const Object* obj) const override; }; } #endif /*BERRYEDITORREGISTRY_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorSashContainer.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorSashContainer.cpp index ea132a48e3..419749d786 100755 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorSashContainer.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorSashContainer.cpp @@ -1,605 +1,605 @@ /*============================================================================ 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 "berryEditorSashContainer.h" #include "berryPresentationSerializer.h" #include "berryWorkbenchConstants.h" #include "berryWorkbenchPlugin.h" #include "berryLayoutTree.h" #include "berryWorkbenchWindowConfigurer.h" #include "berryWorkbenchWindow.h" #include "berryQtDnDControlWidget.h" #include "tweaklets/berryGuiWidgetsTweaklet.h" #include #include namespace berry { const QString EditorSashContainer::DEFAULT_WORKBOOK_ID = "DefaultEditorWorkbook"; void EditorSashContainer::AddChild(const RelationshipInfo& info) { PartSashContainer::AddChild(info); this->UpdateStackButtons(); } void EditorSashContainer::ChildAdded(LayoutPart::Pointer child) { PartSashContainer::ChildAdded(child); if (child.Cast () != 0) { editorWorkbooks.push_back(child.Cast ()); } } void EditorSashContainer::ChildRemoved(LayoutPart::Pointer child) { PartSashContainer::ChildRemoved(child); if (child.Cast () != 0) { editorWorkbooks.removeAll(child.Cast()); if (activeEditorWorkbook == child) { this->SetActiveWorkbook(PartStack::Pointer(nullptr), false); } this->UpdateStackButtons(); } } PartStack::Pointer EditorSashContainer::CreateDefaultWorkbook() { PartStack::Pointer newWorkbook = this->NewEditorWorkbook(); newWorkbook->SetID(DEFAULT_WORKBOOK_ID); this->Add(newWorkbook); return newWorkbook; } void EditorSashContainer::AddDropSupport() { WorkbenchWindowConfigurer::Pointer winConfigurer = page->GetWorkbenchWindow().Cast()->GetWindowConfigurer(); QtDnDControlWidget* dropWidget = static_cast(GetParent()); dropWidget->SetTransferTypes(winConfigurer->GetTransfers()); dropWidget->AddDropListener(winConfigurer->GetDropTargetListener()); } PartStack::Pointer EditorSashContainer::NewEditorWorkbook() { PartStack::Pointer newWorkbook(new PartStack(page, true, PresentationFactoryUtil::ROLE_EDITOR)); QString str; QTextStream buf(&str); buf << newWorkbook->GetClassName() << newWorkbook.GetPointer(); newWorkbook->SetID(str); return newWorkbook; } QWidget* EditorSashContainer::CreateParent(QWidget* parentWidget) { //return Tweaklets::Get(GuiWidgetsTweaklet::KEY)->CreateComposite(parentWidget); return new QtDnDControlWidget(static_cast(parentWidget)); } void EditorSashContainer::DisposeParent() { this->parent = nullptr; } bool EditorSashContainer::IsActiveWorkbook(PartStack::Pointer workbook) { return activeEditorWorkbook == workbook; } PartStack::Pointer EditorSashContainer::CreateStack() { return this->NewEditorWorkbook(); } void EditorSashContainer::SetVisiblePart( ILayoutContainer::Pointer container, PartPane::Pointer visiblePart) { PartStack::Pointer stack = container.Cast(); if (stack == 0) return; stack->GetContainer().Cast()->SetActiveWorkbook(stack, true); stack->SetSelection(visiblePart); } LayoutPart::Pointer EditorSashContainer::GetVisiblePart( ILayoutContainer::Pointer container) { PartStack::Pointer refPart = container.Cast(); return refPart->GetSelection(); } EditorSashContainer::EditorSashContainer(const QString& editorId, WorkbenchPage* page, QWidget* parent) : PartSashContainer(editorId, page, parent) { this->CreateDefaultWorkbook(); } bool EditorSashContainer::AllowsAdd(LayoutPart::Pointer layoutPart) { return LayoutPart::AllowsAdd(layoutPart); } void EditorSashContainer::AddEditor(PartPane::Pointer pane, PartStack::Pointer stack) { //EditorStack workbook = getActiveWorkbook(); stack->Add(pane); } void EditorSashContainer::UpdateStackButtons() { // // This is applicable only when the new // // min/max behaviour is being used // Perspective persp = getPage().getActivePerspective(); // if (!Perspective.useNewMinMax(persp)) // return; // // // Find the upper Right editor stack // LayoutPart[] stacks = getChildren(); // EditorStack winner = getUpperRightEditorStack(stacks); // // // Now hide the buttons for all but the upper right stack // for (int i = 0; i < stacks.length; i++) // { // if (!(stacks[i] instanceof EditorStack) // ) // continue; // ((EditorStack) stacks[i]).showMinMax(stacks[i] == winner); // } // // // Force the stack's presentation state to match its perspective // persp.refreshEditorAreaVisibility(); } PartStack::Pointer EditorSashContainer::GetUpperRightEditorStack() { return this->GetUpperRightEditorStack(this->GetChildren()); } PartStack::Pointer EditorSashContainer::GetUpperRightEditorStack( const ILayoutContainer::ChildrenType& stacks) { // Find the upper Right editor stack PartStack::Pointer winner; QRect winnerRect; for (ILayoutContainer::ChildrenType::const_iterator iter = stacks.begin(); iter != stacks.end(); ++iter) { LayoutPart::Pointer part = *iter; if (part.Cast() == 0) continue; PartStack::Pointer stack = part.Cast(); QRect bb = stack->GetBounds(); if (iter == stacks.begin() || bb.y() < winnerRect.y() || (bb.y() == winnerRect.y() && bb.x() > winnerRect.x())) { winner = stack; winnerRect = bb; } } return winner; } PartStack::Pointer EditorSashContainer::GetActiveWorkbook() { if (activeEditorWorkbook == 0) { if (editorWorkbooks.size() < 1) { this->SetActiveWorkbook(this->CreateDefaultWorkbook(), false); } else { this->SetActiveWorkbook(editorWorkbooks.front(), false); } } return activeEditorWorkbook; } QString EditorSashContainer::GetActiveWorkbookID() { return this->GetActiveWorkbook()->GetID(); } QList EditorSashContainer::GetEditorWorkbooks() { return editorWorkbooks; } std::size_t EditorSashContainer::GetEditorWorkbookCount() { return editorWorkbooks.size(); } void EditorSashContainer::FindSashes(LayoutPart::Pointer pane, PartPane::Sashes& sashes) { //Find the sashes around the current editor and //then the sashes around the editor area. PartSashContainer::FindSashes(pane, sashes); ILayoutContainer::Pointer container = this->GetContainer(); if (container != 0) { container->FindSashes(LayoutPart::Pointer(this), sashes); } } void EditorSashContainer::RemoveAllEditors() { PartStack::Pointer currentWorkbook = this->GetActiveWorkbook(); // Iterate over a copy so the original can be modified. QList workbooks(editorWorkbooks); for (QList::iterator iter = workbooks.begin(); iter != workbooks.end(); ++iter) { PartStack::Pointer workbook = *iter; QList children = workbook->GetChildren(); for (QList::iterator childIter = children.begin(); childIter != children.end(); ++childIter) { workbook->Remove(*childIter); } if (workbook != currentWorkbook) { this->Remove(workbook); workbook->Dispose(); } } } void EditorSashContainer::RemoveEditor(PartPane::Pointer pane) { PartStack::Pointer workbook = pane->GetContainer().Cast(); if (workbook == 0) { return; } workbook->Remove(pane); // remove the editor workbook if empty if (workbook->GetItemCount() < 1 /* && editorWorkbooks.size() > 1*/) { // // If the user closes the last editor and the editor area // // is maximized, restore it // Perspective persp = getPage().getActivePerspective(); // if (Perspective.useNewMinMax(persp)) // { // if (persp.getPresentation().getMaximizedStack() instanceof EditorStack) // persp.getPresentation().getMaximizedStack(). // setState(IStackPresentationSite.STATE_RESTORED); // } this->Remove(workbook); workbook->Dispose(); } } bool EditorSashContainer::RestoreState(IMemento::Pointer memento) { //TODO EditorSashContainer restore state // MultiStatus // result = // new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.RootLayoutContainer_problemsRestoringPerspective, 0); bool result = true; // Remove the default editor workbook that is - // initialy created with the editor area. + // initially created with the editor area. // StartupThreading.runWithoutExceptions(new StartupRunnable() // { // // public void runWithException() throws Throwable // { PartStack::Pointer defaultWorkbook; for (ILayoutContainer::ChildrenType::iterator i = children.begin(); i != children.end(); ++i) { LayoutPart::Pointer child = *i; if (child->GetID() == DEFAULT_WORKBOOK_ID) { defaultWorkbook = child.Cast(); if (defaultWorkbook->GetItemCount() > 0) { defaultWorkbook = nullptr; } } } if (defaultWorkbook) { Remove(defaultWorkbook); } // }} // ); // Restore the relationship/layout QList infos(memento->GetChildren(WorkbenchConstants::TAG_INFO)); QHash mapIDtoPart; for (int i = 0; i < infos.size(); i++) { // Get the info details. IMemento::Pointer childMem = infos[i]; QString partID; childMem->GetString(WorkbenchConstants::TAG_PART, partID); QString relativeID; childMem->GetString(WorkbenchConstants::TAG_RELATIVE, relativeID); int relationship = 0; int left = 0, right = 0; if (!relativeID.isEmpty()) { childMem->GetInteger(WorkbenchConstants::TAG_RELATIONSHIP, relationship); childMem->GetInteger(WorkbenchConstants::TAG_RATIO_LEFT, left); childMem->GetInteger(WorkbenchConstants::TAG_RATIO_RIGHT, right); } PartStack::Pointer workbook; // StartupThreading.runWithoutExceptions(new StartupRunnable() // { // // public void runWithException() throws Throwable // { // Create the part. workbook = NewEditorWorkbook(); workbook->SetID(partID); // 1FUN70C: ITPUI:WIN - Shouldn't set Container when not active workbook->SetContainer(ILayoutContainer::Pointer(this)); // }} // ); IMemento::Pointer workbookMemento = childMem->GetChild( WorkbenchConstants::TAG_FOLDER); if (workbookMemento) { //result.add(workbook[0].restoreState(workbookMemento)); result &= workbook->RestoreState(workbookMemento); } const int myLeft = left, myRight = right, myRelationship = relationship; // StartupThreading.runWithoutExceptions(new StartupRunnable() // { // // public void runWithException() throws Throwable // { // Add the part to the layout if (relativeID.isEmpty()) { Add(workbook); } else { LayoutPart::Pointer refPart = mapIDtoPart[relativeID]; if (refPart) { Add(workbook, myRelationship, myLeft, myRight, refPart); } else { WorkbenchPlugin::Log("Unable to find part for ID: " + relativeID); } } // }} // ); mapIDtoPart[partID] = workbook; } return result; } bool EditorSashContainer::SaveState(IMemento::Pointer memento) { QList relationships(ComputeRelation()); // MultiStatus // result = // new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.RootLayoutContainer_problemsSavingPerspective, 0); bool result = true; for (int i = 0; i < relationships.size(); i++) { // Save the relationship info .. // private LayoutPart part; // private int relationship; // private float ratio; // private LayoutPart relative; const RelationshipInfo& info = relationships[i]; IMemento::Pointer childMem = memento->CreateChild( WorkbenchConstants::TAG_INFO); childMem->PutString(WorkbenchConstants::TAG_PART, info.part->GetID()); PartStack::Pointer stack = info.part.Cast(); if (stack) { IMemento::Pointer folderMem = childMem->CreateChild( WorkbenchConstants::TAG_FOLDER); //result.add(stack.saveState(folderMem)); result &= stack->SaveState(folderMem); } if (info.relative != 0) { childMem->PutString(WorkbenchConstants::TAG_RELATIVE, info.relative->GetID()); childMem->PutInteger(WorkbenchConstants::TAG_RELATIONSHIP, info.relationship); childMem->PutInteger(WorkbenchConstants::TAG_RATIO_LEFT, info.left); childMem->PutInteger(WorkbenchConstants::TAG_RATIO_RIGHT, info.right); } } return result; } void EditorSashContainer::SetActiveWorkbook(PartStack::Pointer newWorkbook, bool hasFocus) { if (newWorkbook != 0) { if (std::find(editorWorkbooks.begin(), editorWorkbooks.end(), newWorkbook) == editorWorkbooks.end()) { return; } } PartStack::Pointer oldWorkbook = activeEditorWorkbook; activeEditorWorkbook = newWorkbook; if (oldWorkbook != 0 && oldWorkbook != newWorkbook) { oldWorkbook->SetActive(StackPresentation::AS_INACTIVE); } if (newWorkbook != 0) { if (hasFocus) { newWorkbook->SetActive(StackPresentation::AS_ACTIVE_FOCUS); } else { newWorkbook->SetActive(StackPresentation::AS_ACTIVE_NOFOCUS); } } this->UpdateTabList(); } void EditorSashContainer::SetActiveWorkbookFromID(const QString& id) { for (QList::iterator iter = editorWorkbooks.begin(); iter != editorWorkbooks.end(); ++iter) { PartStack::Pointer workbook = *iter; if (workbook->GetID() == id) { this->SetActiveWorkbook(workbook, false); } } } PartStack::Pointer EditorSashContainer::GetWorkbookFromID(const QString& id) { for (QList::iterator iter = editorWorkbooks.begin(); iter != editorWorkbooks.end(); ++iter) { PartStack::Pointer workbook = *iter; if (workbook->GetID() == id) { return workbook; } } return PartStack::Pointer(nullptr); } void EditorSashContainer::UpdateTabList() { QWidget* parent = this->GetParent(); if (parent != nullptr) { // parent may be 0 on startup PartStack::Pointer wb(this->GetActiveWorkbook()); //TODO EditorSashContainer update tab list // if (wb == 0) // { // parent.setTabList(new Control[0]); // } // else // { // parent.setTabList(wb.getTabList()); // } } } void EditorSashContainer::CreateControl(QWidget* parent) { PartSashContainer::CreateControl(parent); ///let the user drop files/editor input on the editor area this->AddDropSupport(); } bool EditorSashContainer::IsCompressible() { //Added for bug 19524 return true; } bool EditorSashContainer::IsStackType(ILayoutContainer::Pointer toTest) { if (toTest.Cast() == 0) return false; return (toTest.Cast ()->GetAppearance() == PresentationFactoryUtil::ROLE_EDITOR); } bool EditorSashContainer::IsPaneType(LayoutPart::Pointer toTest) { if (toTest.Cast() == 0) return false; return (toTest.Cast ()->GetPartReference().Cast () != 0); } bool EditorSashContainer::RestorePresentationState(IMemento::Pointer /*areaMem*/) { QList workbooks = this->GetEditorWorkbooks(); for (QList::iterator iter = workbooks.begin(); iter != workbooks.end(); ++iter) { PartStack::Pointer workbook = *iter; IMemento::Pointer memento = workbook->GetSavedPresentationState(); if (memento == 0) { continue; } QList parts = workbook->GetPresentableParts(); PresentationSerializer serializer(parts); //StartupThreading.runWithoutExceptions(new StartupRunnable() // { // public void runWithException() throws Throwable // { workbook->GetPresentation()->RestoreState(&serializer, memento); // }} // ); } //return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", 0); //$NON-NLS-1$ return true; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorSite.h b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorSite.h index 917032f56b..6b6f63aa2c 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorSite.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorSite.h @@ -1,150 +1,150 @@ /*============================================================================ 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 BERRYEDITORSITE_H_ #define BERRYEDITORSITE_H_ #include "berryPartSite.h" #include "berryEditorDescriptor.h" #include "berryIEditorPart.h" #include "berryWorkbenchPage.h" #include "berryIEditorSite.h" #include "berryIEditorReference.h" namespace berry { /** * \ingroup org_blueberry_ui_internal * * An editor container manages the services for an editor. */ class EditorSite : public PartSite, public IEditorSite { /* package */ //static final int PROP_REUSE_EDITOR = -0x101; private: EditorDescriptor::Pointer desc; //ListenerList propChangeListeners = new ListenerList(1); // SubActionBars ab = null; /** * Initialize the local services. */ // void InitializeDefaultServices() { // // Register an implementation of the service appropriate for the // // EditorSite. // final IDragAndDropService editorDTService = new EditorSiteDragAndDropServiceImpl(); // serviceLocator.registerService(IDragAndDropService.class, editorDTService); // } protected: QString GetInitialScopeId() override; public: berryObjectMacro(EditorSite); /** * Constructs an EditorSite for an editor. */ EditorSite(IEditorReference::Pointer ref, IEditorPart::Pointer editor, WorkbenchPage* page, EditorDescriptor::Pointer desc); // void SetActionBars(SubActionBars bars) { // super.setActionBars(bars); // // if (bars instanceof IActionBars2) { // ab = new SubActionBars2((IActionBars2)bars, this); // } else { // ab = new SubActionBars(bars, this); // } // } // void ActivateActionBars(bool forceVisibility) { // if (ab != null) { // ab.activate(forceVisibility); // } // super.activateActionBars(forceVisibility); // } // void DeactivateActionBars(bool forceHide) { // if (ab != null) { // ab.deactivate(forceHide); // } // super.deactivateActionBars(forceHide); // } /** * Returns the editor action bar contributor for this editor. *

- * An action contributor is responsable for the creation of actions. + * An action contributor is responsible for the creation of actions. * By design, this contributor is used for one or more editors of the same type. * Thus, the contributor returned by this method is not owned completely * by the editor. It is shared. *

* * @return the editor action bar contributor */ // IEditorActionBarContributor::Pointer GetActionBarContributor() { // EditorActionBars bars = (EditorActionBars) getActionBars(); // if (bars != null) { // return bars.getEditorContributor(); // } // // return null; // } /** * Returns the extension editor action bar contributor for this editor. */ // IEditorActionBarContributor::Pointer GetExtensionActionBarContributor() { // EditorActionBars bars = (EditorActionBars) getActionBars(); // if (bars != null) { // return bars.getExtensionContributor(); // } // // return null; // } /** * Returns the editor */ IEditorPart::Pointer GetEditorPart(); EditorDescriptor::Pointer GetEditorDescriptor(); // void registerContextMenu(final MenuManager menuManager, // final ISelectionProvider selectionProvider, // final boolean includeEditorInput) { // registerContextMenu(getId(), menuManager, selectionProvider, // includeEditorInput); // } // // void registerContextMenu(final String menuId, // final MenuManager menuManager, // final ISelectionProvider selectionProvider, // final boolean includeEditorInput) { // if (menuExtenders == null) { // menuExtenders = new ArrayList(1); // } // // PartSite.registerContextMenu(menuId, menuManager, selectionProvider, // includeEditorInput, getPart(), menuExtenders); // } }; } #endif /*BERRYEDITORSITE_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerProxy.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerProxy.cpp index 7c23250034..92f2e9d911 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerProxy.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerProxy.cpp @@ -1,415 +1,415 @@ /*============================================================================ 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 "berryHandlerProxy.h" #include "berryIConfigurationElement.h" #include "berryIEvaluationContext.h" #include "berryIEvaluationService.h" #include "berryICommandService.h" #include "berryIContributor.h" #include "berryIEvaluationReference.h" #include "berryEvaluationResult.h" #include "berryExpression.h" #include "berryCoreException.h" #include "berryCommandExceptions.h" #include "berryUtil.h" #include "berryShell.h" #include "berryObjects.h" #include "berryObjectString.h" #include "berryUIElement.h" #include "berryRadioState.h" #include "berryRegistryToggleState.h" #include "berryHandlerEvent.h" #include "berryPlatformUI.h" #include "berryBundleUtility.h" #include "berryWorkbenchRegistryConstants.h" #include "berryStatus.h" #include "berryWorkbenchPlugin.h" #include namespace berry { QHash, HandlerProxy*> HandlerProxy::CEToProxyMap = QHash(); const QString HandlerProxy::PROP_ENABLED = "enabled"; HandlerProxy::HandlerProxy(const QString commandId, const SmartPointer& configurationElement, const QString handlerAttributeName, const SmartPointer enabledWhenExpression, IEvaluationService* evaluationService) : configurationElement(configurationElement) , enabledWhenExpression(enabledWhenExpression) , handlerAttributeName(handlerAttributeName) , evaluationService(evaluationService) , proxyEnabled(false) , commandId(commandId) , loadException(nullptr) { this->Register(); if (configurationElement.IsNull()) { throw ctkInvalidArgumentException( "The configuration element backing a handler proxy cannot be null"); } if (handlerAttributeName.isNull()) { throw ctkInvalidArgumentException( "The attribute containing the handler class must be known"); } if (enabledWhenExpression.IsNotNull() && evaluationService == nullptr) { throw ctkInvalidArgumentException( "We must have a handler service and evaluation service to support the enabledWhen expression"); } if (enabledWhenExpression.IsNotNull()) { SetProxyEnabled(false); RegisterEnablement(); } else { SetProxyEnabled(true); } CEToProxyMap.insert(configurationElement, this); this->UnRegister(false); } void HandlerProxy::UpdateStaleCEs(const QList >& replacements) { foreach (const IConfigurationElement::Pointer& ce, replacements) { QHash::const_iterator i = CEToProxyMap.find(ce); if (i != CEToProxyMap.end()) { (*i)->configurationElement = ce; } } } void HandlerProxy::SetEnabled(const Object::Pointer& evaluationContext) { IEvaluationContext* const context = dynamic_cast(evaluationContext.GetPointer()); if (context == nullptr) { return; } if (enabledWhenExpression.IsNotNull()) { try { SetProxyEnabled(enabledWhenExpression->Evaluate(context) == EvaluationResult::TRUE_EVAL); } catch (const CoreException& /*e*/) { // TODO should we log this exception, or just treat it as // a failure } } if (IsOkToLoad() && LoadHandler()) { handler->SetEnabled(evaluationContext); } } void HandlerProxy::Dispose() { if (handler.IsNotNull()) { handler->RemoveHandlerListener(GetHandlerListener()); handler->Dispose(); handler = nullptr; } if (evaluationService && enablementRef) { evaluationService->RemoveEvaluationListener(enablementRef); } enablementRef = nullptr; delete loadException; loadException = nullptr; } Object::Pointer HandlerProxy::Execute(const SmartPointer& event) { if (LoadHandler()) { if (!IsEnabled()) { Shell::Pointer shell = Util::GetShellToParentOn(); QWidget* parent = nullptr; if (shell.IsNotNull()) parent = shell->GetControl(); QMessageBox::information(parent, "Information", "The chosen operation is not enabled."); return Object::Pointer(nullptr); } return handler->Execute(event); } if(loadException != nullptr) - throw ExecutionException("Exception occured when loading the handler", *loadException); + throw ExecutionException("Exception occurred when loading the handler", *loadException); return Object::Pointer(nullptr); } bool HandlerProxy::IsEnabled() const { if (enabledWhenExpression.IsNotNull()) { // proxyEnabled reflects the enabledWhen clause if (!GetProxyEnabled()) { return false; } if (IsOkToLoad() && LoadHandler()) { return handler->IsEnabled(); } return true; } /* * There is no enabled when expression, so we just need to consult the * handler. */ if (IsOkToLoad() && LoadHandler()) { return handler->IsEnabled(); } return true; } bool HandlerProxy::IsHandled() const { if (configurationElement.IsNotNull() && handler.IsNull()) { return true; } if (IsOkToLoad() && LoadHandler()) { return handler->IsHandled(); } return false; } QString HandlerProxy::ToString() const { if (handler.IsNull()) { if (configurationElement.IsNotNull()) { const QString configurationElementAttribute = GetConfigurationElementAttribute(); if (!configurationElementAttribute.isEmpty()) { return configurationElementAttribute; } } return "HandlerProxy()"; } return handler->ToString(); } void HandlerProxy::UpdateElement(UIElement* element, const QHash& parameters) { if (checkedState.IsNotNull()) { ObjectBool::Pointer value = checkedState->GetValue().Cast(); element->SetChecked(value->GetValue()); } else if (radioState.IsNotNull()) { ObjectString::Pointer value = radioState->GetValue().Cast(); Object::Pointer parameter = parameters[RadioState::PARAMETER_ID]; element->SetChecked(value.IsNotNull() && parameter == value); } if (handler.IsNotNull()) { if (IElementUpdater::Pointer updater = handler.Cast()) { updater->UpdateElement(element, parameters); } } } void HandlerProxy::HandleStateChange(const SmartPointer& state, const Object::Pointer& oldValue) { if (state->GetId() == RegistryToggleState::STATE_ID) { checkedState = state; RefreshElements(); } else if (state->GetId() == RadioState::STATE_ID) { radioState = state; RefreshElements(); } if (IStateListener* stateListener = dynamic_cast(handler.GetPointer())) { stateListener->HandleStateChange(state, oldValue); } } SmartPointer HandlerProxy::GetConfigurationElement() const { return configurationElement; } QString HandlerProxy::GetAttributeName() const { return handlerAttributeName; } SmartPointer HandlerProxy::GetHandler() const { return handler; } void HandlerProxy::RegisterEnablement() { enablementRef = evaluationService->AddEvaluationListener( enabledWhenExpression, GetEnablementListener(), PROP_ENABLED); } void HandlerProxy::SetProxyEnabled(bool enabled) { proxyEnabled = enabled; } bool HandlerProxy::GetProxyEnabled() const { return proxyEnabled; } IPropertyChangeListener* HandlerProxy::GetEnablementListener() const { return const_cast(this); } void HandlerProxy::PropertyChange(const SmartPointer& event) { if (event->GetProperty() == PROP_ENABLED) { SetProxyEnabled(event->GetNewValue().IsNull() ? false : event->GetNewValue().Cast()->GetValue()); HandlerEvent::Pointer event(new HandlerEvent(IHandler::Pointer(this), true, false)); FireHandlerChanged(event); } } bool HandlerProxy::LoadHandler() const { if (handler.IsNull()) { HandlerProxy* self = const_cast(this); // Load the handler. try { if (configurationElement.IsNotNull()) { handler = configurationElement->CreateExecutableExtension(handlerAttributeName); if (handler.IsNotNull()) { handler->AddHandlerListener(GetHandlerListener()); self->SetEnabled(evaluationService == nullptr ? IEvaluationContext::Pointer(nullptr) : evaluationService->GetCurrentState()); self->RefreshElements(); return true; } else { const QString message = "The proxied handler was the wrong class"; IStatus::Pointer status( new Status(IStatus::ERROR_TYPE, PlatformUI::PLUGIN_ID(), 0, message, BERRY_STATUS_LOC)); WorkbenchPlugin::Log(message, status); configurationElement = nullptr; loadException = new ctkException("Class cast exception"); } } } catch (const CoreException& e) { const QString message = "The proxied handler for '" + configurationElement->GetAttribute(handlerAttributeName) + "' could not be loaded"; IStatus::Pointer status( new Status(IStatus::ERROR_TYPE, PlatformUI::PLUGIN_ID(), 0, message, e, BERRY_STATUS_LOC)); WorkbenchPlugin::Log(message, status); configurationElement = nullptr; loadException = e.clone(); } return false; } return true; } IHandlerListener* HandlerProxy::GetHandlerListener() const { return const_cast(this); } void HandlerProxy::HandlerChanged(const SmartPointer& handlerEvent) { HandlerEvent::Pointer event(new HandlerEvent(IHandler::Pointer(this), handlerEvent->IsEnabledChanged(), handlerEvent->IsHandledChanged())); FireHandlerChanged(event); } QString HandlerProxy::GetConfigurationElementAttribute() const { const QString attribute = configurationElement->GetAttribute(handlerAttributeName); if (attribute.isNull()) { QList children = configurationElement->GetChildren(handlerAttributeName); foreach (const IConfigurationElement::Pointer& child, children) { const QString childAttribute = child->GetAttribute(WorkbenchRegistryConstants::ATT_CLASS); if (!childAttribute.isNull()) { return childAttribute; } } } return attribute; } bool HandlerProxy::IsOkToLoad() const { if (configurationElement.IsNotNull() && handler.IsNull()) { const QString bundleId = configurationElement->GetContributor()->GetName(); return BundleUtility::IsActive(bundleId); } return true; } void HandlerProxy::RefreshElements() { if (commandId.isNull() || (!(handler.Cast()) && (checkedState.IsNull() && radioState.IsNull()))) { return; } ICommandService* cs = PlatformUI::GetWorkbench()->GetService(); cs->RefreshElements(commandId, QHash()); } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerProxy.h b/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerProxy.h index 82deb4cc46..dc4bdc1050 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerProxy.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerProxy.h @@ -1,227 +1,227 @@ /*============================================================================ 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 BERRYHANDLERPROXY_H #define BERRYHANDLERPROXY_H #include "berryAbstractHandlerWithState.h" #include "berryIElementUpdater.h" #include "berryIHandlerListener.h" #include "berryIPropertyChangeListener.h" namespace berry { struct IConfigurationElement; struct IEvaluationReference; struct IEvaluationService; class Expression; /** *

* A proxy for a handler that has been defined in XML. This delays the class * loading until the handler is really asked for information (besides the * priority or the command identifier). Asking a proxy for anything but the * attributes defined publicly in this class will cause the proxy to instantiate * the proxied handler. *

*/ class HandlerProxy : public AbstractHandlerWithState, public IElementUpdater, private IHandlerListener, private IPropertyChangeListener { public: berryObjectMacro(berry::HandlerProxy); private: static QHash, HandlerProxy*> CEToProxyMap; /** * */ static const QString PROP_ENABLED; // = "enabled"; /** * The configuration element from which the handler can be created. This * value will exist until the element is converted into a real class -- at * which point this value will be set to null. */ mutable SmartPointer configurationElement; /** * The enabledWhen expression for the handler. Only if this * expression evaluates to true (or the value is * null) should we consult the handler. */ const SmartPointer enabledWhenExpression; /** * The real handler. This value is null until the proxy is * forced to load the real handler. At this point, the configuration element * is converted, nulled out, and this handler gains a reference. */ mutable SmartPointer handler; /** * The name of the configuration element attribute which contains the * information necessary to instantiate the real handler. */ const QString handlerAttributeName; /** * The evaluation service to use when evaluating * enabledWhenExpression. This value may be * null only if the enabledWhenExpression is * null. */ IEvaluationService* evaluationService; SmartPointer enablementRef; bool proxyEnabled; QString commandId; // // state to support checked or radio commands. SmartPointer checkedState; SmartPointer radioState; // Exception that occurs while loading the proxied handler class mutable ctkException* loadException; public: /** * Constructs a new instance of HandlerProxy with all the * information it needs to try to avoid loading until it is needed. * * @param commandId the id for this handler * @param configurationElement * The configuration element from which the real class can be * loaded at run-time; must not be null. * @param handlerAttributeName * The name of the attribute or element containing the handler * executable extension; must not be null. * @param enabledWhenExpression * The name of the element containing the enabledWhen expression. * This should be a child of the * configurationElement. If this value is * null, then there is no enablement expression * (i.e., enablement will be delegated to the handler when * possible). * @param evaluationService * The evaluation service to manage enabledWhen expressions * trying to evaluate the enabledWhenExpression. * This value may be null only if the * enabledWhenExpression is null. */ HandlerProxy(const QString commandId, const SmartPointer& configurationElement, const QString handlerAttributeName, const SmartPointer enabledWhenExpression = SmartPointer(), IEvaluationService* evaluationService = nullptr); static void UpdateStaleCEs(const QList >& replacements); void SetEnabled(const Object::Pointer& evaluationContext) override; /** - * Passes the dipose on to the proxied handler, if it has been loaded. + * Passes the dispose on to the proxied handler, if it has been loaded. */ void Dispose() override; Object::Pointer Execute(const SmartPointer& event) override; bool IsEnabled() const override; bool IsHandled() const override; QString ToString() const override; /* * (non-Javadoc) * * @see org.eclipse.ui.commands.IElementUpdater#updateElement(org.eclipse.ui.menus.UIElement, * java.util.Map) */ void UpdateElement(UIElement* element, const QHash& parameters) override; /* (non-Javadoc) * @see org.eclipse.core.commands.IStateListener#handleStateChange(org.eclipse.core.commands.State, java.lang.Object) */ void HandleStateChange(const SmartPointer& state, const Object::Pointer& oldValue) override; /** * @return the config element for use with the PDE framework. */ SmartPointer GetConfigurationElement() const; QString GetAttributeName() const; /** * @return Returns the handler. */ SmartPointer GetHandler() const; private: /** * */ void RegisterEnablement(); void SetProxyEnabled(bool enabled); bool GetProxyEnabled() const; /** * @return */ IPropertyChangeListener* GetEnablementListener() const; using IPropertyChangeListener::PropertyChange; void PropertyChange(const SmartPointer& event) override; /** * Loads the handler, if possible. If the handler is loaded, then the member * variables are updated accordingly. * * @return true if the handler is now non-null; * false otherwise. */ bool LoadHandler() const; IHandlerListener* GetHandlerListener() const; void HandlerChanged(const SmartPointer& handlerEvent) override; /** - * Retrives the ConfigurationElement attribute according to the + * Retrieves the ConfigurationElement attribute according to the * handlerAttributeName. * * @return the handlerAttributeName value, may be null. */ QString GetConfigurationElementAttribute() const; bool IsOkToLoad() const; void RefreshElements(); }; } #endif // BERRYHANDLERPROXY_H diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryLayoutHelper.h b/Plugins/org.blueberry.ui.qt/src/internal/berryLayoutHelper.h index b99eea53c7..21dbaa28f6 100755 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryLayoutHelper.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryLayoutHelper.h @@ -1,76 +1,76 @@ /*============================================================================ 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 BERRYLAYOUTHELPER_H_ #define BERRYLAYOUTHELPER_H_ #include "berryViewFactory.h" #include "berryPartPane.h" namespace berry { class PageLayout; /** * Helper methods that the internal layout classes (PageLayout and * FolderLayout) utilize for activities support and view creation. * * @since 3.0 */ class LayoutHelper { private: /** * Not intended to be instantiated. */ LayoutHelper(); public: /** * Creates a series of listeners that will activate the provided view on the * provided page layout when IIdentifier enablement changes. The * rules for this activation are as follows:

*