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 { // cacheSt