diff --git a/CMake/FixMacOSInstaller.cmake b/CMake/FixMacOSInstaller.cmake new file mode 100644 index 0000000000..64fd30a7c2 --- /dev/null +++ b/CMake/FixMacOSInstaller.cmake @@ -0,0 +1,37 @@ +set(bundle_path "${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}/../..") +get_filename_component(bundle_path ${bundle_path} REALPATH) + +# Compile list of Qt frameworks in bundle +unset(qt_frameworks) +file(GLOB qt_framework_paths "${bundle_path}/Contents/Frameworks/Qt*.framework") +foreach(qt_framework_path ${qt_framework_paths}) + get_filename_component(qt_framework ${qt_framework_path} NAME_WE) + list(APPEND qt_frameworks ${qt_framework}) +endforeach() + +# For each Qt framework, change the style of dependencies to other +# Qt frameworks from @executable_path to @rpath. The install name tool +# only changes existing dependencies. +foreach(qt_framework ${qt_frameworks}) + set(in "${bundle_path}/Contents/Frameworks/${qt_framework}.framework/Versions/5/${qt_framework}") + foreach(other_qt_framework ${qt_frameworks}) + set(from "@executable_path/../Frameworks/${other_qt_framework}.framework/Versions/5/${other_qt_framework}") + set(to "@rpath/${other_qt_framework}.framework/Versions/5/${other_qt_framework}") + execute_process(COMMAND install_name_tool -change ${from} ${to} ${in}) + endforeach() +endforeach() + +# Do the same for QtWebEngineProcess +set(qtwebengineprocess_path "${bundle_path}/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess") +foreach(qt_framework ${qt_frameworks}) + set(from "@executable_path/../Frameworks/${qt_framework}.framework/Versions/5/${qt_framework}") + set(to "@rpath/${qt_framework}.framework/Versions/5/${qt_framework}") + execute_process(COMMAND install_name_tool -change ${from} ${to} ${qtwebengineprocess_path}) +endforeach() + +# Add corresponding rpath entries to the actual application and QtWebEngineProcess. +# The install name tool returns an error if an entry is already present. +get_filename_component(app ${bundle_path} NAME_WE) +set(app_path "${bundle_path}/Contents/MacOS/${app}") +execute_process(COMMAND install_name_tool -add_rpath "@executable_path/../Frameworks" ${app_path} ERROR_QUIET) +execute_process(COMMAND install_name_tool -add_rpath "@executable_path/../../../../.." ${qtwebengineprocess_path} ERROR_QUIET) diff --git a/CMake/MITKDashboardScript.TEMPLATE.cmake b/CMake/MITKDashboardScript.TEMPLATE.cmake index f319ca3a48..a5547205b7 100644 --- a/CMake/MITKDashboardScript.TEMPLATE.cmake +++ b/CMake/MITKDashboardScript.TEMPLATE.cmake @@ -1,147 +1,147 @@ # # OS: Ubuntu 9.04 2.6.28-18-generic # Hardware: x86_64 GNU/Linux # GPU: NA # # Note: The specific version and processor type of this machine should be reported in the # header above. Indeed, this file will be send to the dashboard as a NOTE file. cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # # Dashboard properties # set(MY_COMPILER "gcc-4.9.x") # For Windows, e.g. #set(MY_COMPILER "VC12.0") set(CTEST_CMAKE_COMMAND "/usr/bin/cmake") set(CTEST_CMAKE_GENERATOR "Unix Makefiles") set(CTEST_DASHBOARD_ROOT "/opt/dartclients") # For Windows, e.g. #set(CTEST_CMAKE_COMMAND "cmake") #set(CTEST_CMAKE_GENERATOR "Visual Studio 12 2013 Win64") #set(CTEST_DASHBOARD_ROOT "C:/dartclients") # The directory containing the Qt binaries -set(QT5_INSTALL_PREFIX "/home/user/Qt/5.6/gcc_64") +set(QT5_INSTALL_PREFIX "/home/user/Qt/5.11.1/gcc_64") # For Windows, e.g. -#set(QT5_INSTALL_PREFIX "C:/Qt/5.6/msvc2013_64") +#set(QT5_INSTALL_PREFIX "C:/Qt/5.11.1/msvc2013_64") set(QT_BINARY_DIR "${QT5_INSTALL_PREFIX}/bin") # # Dashboard options # set(WITH_KWSTYLE FALSE) set(WITH_MEMCHECK FALSE) set(WITH_COVERAGE FALSE) set(WITH_DOCUMENTATION FALSE) #set(DOCUMENTATION_ARCHIVES_OUTPUT_DIRECTORY ) # for example: $ENV{HOME}/Projects/Doxygen set(CTEST_BUILD_CONFIGURATION "Release") set(CTEST_TEST_TIMEOUT 500) if(UNIX) set(CTEST_BUILD_FLAGS "-j4") # Use multiple CPU cores to build else() set(CTEST_BUILD_FLAGS "") endif() # experimental: # - run_ctest() macro will be called *ONE* time # - binary directory will *NOT* be cleaned # continuous: # - run_ctest() macro will be called EVERY 5 minutes ... # - binary directory will *NOT* be cleaned # - configure/build will be executed *ONLY* if the repository has been updated # nightly: # - run_ctest() macro will be called *ONE* time # - binary directory *WILL BE* cleaned set(SCRIPT_MODE "experimental") # "experimental", "continuous", "nightly" # # Project specific properties # # In order to shorten the global path length, the build directory for each DartClient # uses the following abrevation sceme: # For build configuration: # Debug -> d # Release -> r # For scripte mode: # continuous -> c # nightly -> n # experimental -> e # Example directory: /MITK-sb-d-n/ for a nightly MITK superbuild in debug mode. set(short_of_ctest_build_configuration "") set(short_of_script_mode "") string(SUBSTRING ${CTEST_BUILD_CONFIGURATION} 0 1 short_of_ctest_build_configuration) string(SUBSTRING ${SCRIPT_MODE} 0 1 short_of_script_mode) set(CTEST_SOURCE_DIRECTORY "${CTEST_DASHBOARD_ROOT}/MITK") set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/MITK-sb-${short_of_ctest_build_configuration}-${short_of_script_mode}") # Create an initial cache file for MITK. This file is used to configure the MITK-Build. Use ADDITIONAL_CMAKECACHE_OPTION # to configure the MITK-Superbuild. The set(MITK_INITIAL_CACHE " # Example how to set a boolean variable in the MITK-Build via this script: #SET(MITK_ENABLE_TOF_HARDWARE \"TRUE\" CACHE INTERNAL \"Enable ToF Hardware\") # Example how to set a path variable in the MITK-Build via this script: #SET(MITK_PMD_LIB \"/home/kilgus/thomas/PMDSDK2/Linux_x86_64/bin/libpmdaccess2.so\" CACHE INTERNAL \"PMD lib\") ") set(ADDITIONAL_CMAKECACHE_OPTION " # Superbuild variables are not passed through to the MITK-Build (or any other build like ITK, VTK, ...) # Use the MITK_INITIAL_CACHE the pass variables to the MITK-Build. # add entries like this #MITK_USE_OpenCV:BOOL=OFF CMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH} ") # List of test that should be explicitly disabled on this machine set(TEST_TO_EXCLUDE_REGEX "") # set any extra environment variables here set(ENV{DISPLAY} ":0") find_program(CTEST_COVERAGE_COMMAND NAMES gcov) find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) find_program(CTEST_GIT_COMMAND NAMES git) # # Git repository - Overwrite the default value provided by the driver script # # The git repository containing MITK code #set(GIT_REPOSITORY "/home/username/MITK") # The branch of the MITK git repository to check out #set(GIT_BRANCH "bug-xxx-label") ########################################## # WARNING: DO NOT EDIT BEYOND THIS POINT # ########################################## # # Convenient macro allowing to download a file # macro(downloadFile url dest) file(DOWNLOAD "${url}" "${dest}" STATUS status) list(GET status 0 error_code) list(GET status 1 error_msg) if(error_code) message(FATAL_ERROR "error: Failed to download ${url} - ${error_msg}") endif() endmacro() # # Download and include setup script # if(NOT DEFINED GIT_BRANCH OR GIT_BRANCH STREQUAL "") set(IS_PHABRICATOR_URL FALSE) set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/MITKDashboardSetup.cmake") else() set(IS_PHABRICATOR_URL TRUE) string(REPLACE "/" "%252F" GIT_BRANCH_URL ${GIT_BRANCH}) set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH_URL}/CMake/MITKDashboardSetup.cmake?view=raw") endif() set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.setup) downloadFile("${url}" "${dest}") include(${dest}) diff --git a/CMake/mitkFunctionCreateMatchPointDeployedAlgorithm.cmake b/CMake/mitkFunctionCreateMatchPointDeployedAlgorithm.cmake index b94527c3a6..bcd24d2818 100644 --- a/CMake/mitkFunctionCreateMatchPointDeployedAlgorithm.cmake +++ b/CMake/mitkFunctionCreateMatchPointDeployedAlgorithm.cmake @@ -1,107 +1,107 @@ #! #! Create a Command Line App. #! #! \brief This function will create a command line executable and the scripts required to run it #! #! \param NAME (required) Name of the algorithm / cmake target #! \param DEPENDS (optional) Required MITK modules beyond MitkCommandLine #! \param PACKAGE_DEPENDS (optional) list of "packages" this command line app depends on (e.g. ITK, VTK, etc.) #! \param CPP_FILES (optional) list of cpp files, if it is not given NAME.cpp is assumed #! \param INCLUDE_DIRS (optional): All directories that should be added as include dirs to the project #! \param PROFILE (optional): The profile file that should be used for the algorithm. If not set it is "./.profile". #! \param NO_PROFILE_GEN (optional): Flag. If set no profile resource will be generated. #! \param ADDITIONAL_LIBS (optional) List of additional private libraries linked to this module. #! The folder containing the library will be added to the global list of library search paths. #! \param H_FILES (optional) List of public header files for this module. #! Assuming that there exists a file called MyApp.cpp, an example call looks like: #! \code #! mitkFunctionCreateCommandLineApp( #! NAME MyApp #! DEPENDS MitkCore MitkPlanarFigure #! PACKAGE_DEPENDS ITK VTK #! ) #! \endcode #! function(mitkFunctionCreateMatchPointDeployedAlgorithm) set(_function_params NAME # Name of the algorithm/target PROFILE # Profile of the algorithm that should be used ) set(_function_multiparams DEPENDS # list of modules this command line app depends on PACKAGE_DEPENDS # list of "packages" this command line app depends on (e.g. ITK, VTK, etc.) CPP_FILES # (optional) list of cpp files, if it is not given NAME.cpp is assumed INCLUDE_DIRS # include directories: [PUBLIC|PRIVATE|INTERFACE] ADDITIONAL_LIBS # list of addidtional private libraries linked to this module. H_FILES # list of header files: [PUBLIC|PRIVATE] ) set(_function_options NO_PROFILE_GEN #Flag that indicates that no profile resource should be generated. ) cmake_parse_arguments(ALG "${_function_options}" "${_function_params}" "${_function_multiparams}" ${ARGN}) if( NOT (DEFINED MITK_USE_MatchPoint) OR NOT (${MITK_USE_MatchPoint})) message(FATAL_ERROR "Need package Matchpoint to deploy MatchPoint Algorithms.") endif() if(NOT ALG_NAME) message(FATAL_ERROR "NAME argument cannot be empty.") endif() SET(ALG_TARGET "MDRA_${ALG_NAME}") if(NOT ALG_CPP_FILES) set(ALG_CPP_FILES "${ALG_NAME}.cpp") endif() IF(NOT ALG_PROFILE) set(ALG_PROFILE "${ALG_NAME}.profile") ENDIF(NOT ALG_PROFILE) IF(NOT ALG_NO_PROFILE_GEN) MESSAGE(STATUS "... generate MDRA profile for ${ALG_NAME} (from ${ALG_PROFILE})...") include(${MatchPoint_SOURCE_DIR}/CMake/mapFunctionCreateAlgorithmProfile.cmake) CREATE_ALGORITHM_PROFILE(${ALG_NAME} ${ALG_PROFILE}) MESSAGE(STATUS "... algorithm UID: ${ALGORITHM_PROFILE_UID}") ENDIF(NOT ALG_NO_PROFILE_GEN) MESSAGE(STATUS "... deploy MDRA algorithm ${ALG_NAME}...") ADD_LIBRARY(${ALG_TARGET} SHARED ${ALG_CPP_FILES} ${ALGORITHM_PROFILE_FILE}) SET_TARGET_PROPERTIES(${ALG_TARGET} PROPERTIES OUTPUT_NAME "mdra-${MatchPoint_VERSION_MAJOR}-${MatchPoint_VERSION_MINOR}_${ALG_NAME}" OUTPUT_NAME_DEBUG "mdra-D-${MatchPoint_VERSION_MAJOR}-${MatchPoint_VERSION_MINOR}_${ALG_NAME}" PREFIX "" ) mitk_use_modules(TARGET ${ALG_TARGET} MODULES ${ALG_DEPENDS} PACKAGES PRIVATE ITK MatchPoint ${ALG_PACKAGE_DEPENDS} ) target_include_directories(${ALG_TARGET} PRIVATE ${ALG_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) if(ALG_ADDITIONAL_LIBS) target_link_libraries(${ALG_TARGET} PRIVATE ${ALG_ADDITIONAL_LIBS}) get_property(_mitk_additional_library_search_paths GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) foreach(_lib_filepath ${ALG_ADDITIONAL_LIBS}) get_filename_component(_search_path "${_lib_filepath}" PATH) if(_search_path) list(APPEND _mitk_additional_library_search_paths "${_search_path}") endif() endforeach() if(_mitk_additional_library_search_paths) list(REMOVE_DUPLICATES _mitk_additional_library_search_paths) set_property(GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS ${_mitk_additional_library_search_paths}) endif() endif() - install(TARGETS ${ALG_TARGET} RUNTIME DESTINATION bin LIBRARY DESTINATION bin) + MITK_INSTALL(TARGETS ${ALG_TARGET}) endfunction() diff --git a/CMake/mitkFunctionCreateModule.cmake b/CMake/mitkFunctionCreateModule.cmake index e7c9811ee0..9ec5cd1148 100644 --- a/CMake/mitkFunctionCreateModule.cmake +++ b/CMake/mitkFunctionCreateModule.cmake @@ -1,652 +1,653 @@ ################################################################## # # mitk_create_module # #! Creates a module for the automatic module dependency system within MITK. #! #! Example: #! #! \code #! mitk_create_module( #! DEPENDS PUBLIC MitkCore #! PACKAGE_DEPENDS #! PRIVATE Qt5|Xml+Networking #! PUBLIC ITK|Watershed #! \endcode #! #! The parameter specifies the name of the module which is used #! to create a logical target name. The parameter is optional in case the #! MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME variable evaluates to TRUE. The #! module name will then be derived from the directory name in which this #! function is called. #! #! If set, the following variables will be used to validate the module name: #! #! MITK_MODULE_NAME_REGEX_MATCH The module name must match this regular expression. #! MITK_MODULE_NAME_REGEX_NOT_MATCH The module name must not match this regular expression. #! #! If the MITK_MODULE_NAME_PREFIX variable is set, the module name will be prefixed #! with its contents. #! #! A modules source files are specified in a separate CMake file usually #! called files.cmake, located in the module root directory. The #! mitk_create_module() macro evaluates the following CMake variables #! from the files.cmake file: #! #! - CPP_FILES A list of .cpp files #! - H_FILES A list of .h files without a corresponding .cpp file #! - TXX_FILES A list of .txx files #! - RESOURCE_FILES A list of files (resources) which are embedded into the module #! - MOC_H_FILES A list of Qt header files which should be processed by the MOC #! - UI_FILES A list of .ui Qt UI files #! - QRC_FILES A list of .qrc Qt resource files #! - DOX_FILES A list of .dox Doxygen files #! #! List of variables available after the function is called: #! - MODULE_NAME #! - MODULE_TARGET #! - MODULE_IS_ENABLED #! - MODULE_SUBPROJECTS #! #! \sa mitk_create_executable #! #! Parameters (all optional): #! #! \param The module name (also used as target name) #! \param FILES_CMAKE File name of a CMake file setting source list variables #! (defaults to files.cmake) #! \param VERSION Module version number, e.g. "1.2.0" #! \param AUTOLOAD_WITH A module target name identifying the module which will #! trigger the automatic loading of this module #! \param DEPRECATED_SINCE Marks this modules as deprecated since #! \param DESCRIPTION A description for this module #! #! Multi-value Parameters (all optional): #! #! \param SUBPROJECTS List of CDash labels #! \param INCLUDE_DIRS Include directories for this module: #! \verbatim #! [[PUBLIC|PRIVATE|INTERFACE] ...]... #! \endverbatim #! The default scope for include directories is PUBLIC. #! \param DEPENDS List of module dependencies: #! \verbatim #! [[PUBLIC|PRIVATE|INTERFACE] ...]... #! \endverbatim #! The default scope for module dependencies is PUBLIC. #! \param PACKAGE_DEPENDS List of public packages dependencies (e.g. Qt, VTK, etc.). #! Package dependencies have the following syntax: #! \verbatim #! [PUBLIC|PRIVATE|INTERFACE] PACKAGE[|COMPONENT1[+COMPONENT2]...] #! \endverbatim #! The default scope for package dependencies is PRIVATE. #! \param ADDITIONAL_LIBS List of additional private libraries linked to this module. #! The folder containing the library will be added to the global list of library search paths. #! \param CPP_FILES List of source files for this module. If the list is non-empty, #! the module does not need to provide a files.cmake file or FILES_CMAKE argument. #! \param H_FILES List of public header files for this module. It is recommended to use #! a files.cmake file instead. #! #! Options (optional) #! #! \param FORCE_STATIC Force building this module as a static library #! \param GCC_DEFAULT_VISIBILITY Do not use gcc visibility flags - all #! symbols will be exported #! \param NO_INIT Do not create CppMicroServices initialization code #! \param NO_FEATURE_INFO Do not create a feature info by calling add_feature_info() #! \param WARNINGS_NO_ERRORS Do not treat compiler warnings as errors # ################################################################## function(mitk_create_module) set(_macro_params VERSION # module version number, e.g. "1.2.0" EXPORT_DEFINE # export macro name for public symbols of this module (DEPRECATED) AUTOLOAD_WITH # a module target name identifying the module which will trigger the # automatic loading of this module FILES_CMAKE # file name of a CMake file setting source list variables # (defaults to files.cmake) DEPRECATED_SINCE # marks this modules as deprecated DESCRIPTION # a description for this module ) set(_macro_multiparams SUBPROJECTS # list of CDash labels INCLUDE_DIRS # include directories: [PUBLIC|PRIVATE|INTERFACE] INTERNAL_INCLUDE_DIRS # include dirs internal to this module (DEPRECATED) DEPENDS # list of modules this module depends on: [PUBLIC|PRIVATE|INTERFACE] DEPENDS_INTERNAL # list of modules this module internally depends on (DEPRECATED) PACKAGE_DEPENDS # list of "packages this module depends on (e.g. Qt, VTK, etc.): [PUBLIC|PRIVATE|INTERFACE] TARGET_DEPENDS # list of CMake targets this module should depend on ADDITIONAL_LIBS # list of addidtional private libraries linked to this module. CPP_FILES # list of cpp files H_FILES # list of header files: [PUBLIC|PRIVATE] ) set(_macro_options FORCE_STATIC # force building this module as a static library HEADERS_ONLY # this module is a headers-only library GCC_DEFAULT_VISIBILITY # do not use gcc visibility flags - all symbols will be exported NO_DEFAULT_INCLUDE_DIRS # do not add default include directories like "include" or "." NO_INIT # do not create CppMicroServices initialization code NO_FEATURE_INFO # do not create a feature info by calling add_feature_info() WARNINGS_NO_ERRORS # do not treat compiler warnings as errors EXECUTABLE # create an executable; do not use directly, use mitk_create_executable() instead C_MODULE # compile all source files as C sources CXX_MODULE # compile all source files as C++ sources ) cmake_parse_arguments(MODULE "${_macro_options}" "${_macro_params}" "${_macro_multiparams}" ${ARGN}) set(MODULE_NAME ${MODULE_UNPARSED_ARGUMENTS}) # ----------------------------------------------------------------- # Sanity checks if(NOT MODULE_NAME) if(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME) get_filename_component(MODULE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) else() message(SEND_ERROR "The module name must not be empty") endif() endif() set(_deprecated_args INTERNAL_INCLUDE_DIRS DEPENDS_INTERNAL EXPORT_DEFINE TARGET_DEPENDS HEADERS_ONLY) foreach(_deprecated_arg ${_deprecated_args}) if(MODULE_${_deprecated_arg}) message(WARNING "The ${_deprecated_arg} argument is deprecated") endif() endforeach() set(_module_type module) set(_Module_type Module) if(MODULE_EXECUTABLE) set(_module_type executable) set(_Module_type Executable) endif() if(MITK_MODULE_NAME_REGEX_MATCH) if(NOT ${MODULE_NAME} MATCHES ${MITK_MODULE_NAME_REGEX_MATCH}) message(SEND_ERROR "The ${_module_type} name \"${MODULE_NAME}\" does not match the regular expression \"${MITK_MODULE_NAME_REGEX_MATCH}\".") endif() endif() if(MITK_MODULE_NAME_REGEX_NOT_MATCH) if(${MODULE_NAME} MATCHES ${MITK_MODULE_NAME_REGEX_NOT_MATCH}) message(SEND_ERROR "The ${_module_type} name \"${MODULE_NAME}\" must not match the regular expression \"${MITK_MODULE_NAME_REGEX_NOT_MATCH}\".") endif() endif() if(MITK_MODULE_NAME_PREFIX AND NOT MODULE_NAME MATCHES "^${MITK_MODULE_NAME_PREFIX}.*$") set(MODULE_NAME "${MITK_MODULE_NAME_PREFIX}${MODULE_NAME}") endif() if(NOT MODULE_FILES_CMAKE) set(MODULE_FILES_CMAKE files.cmake) endif() if(NOT IS_ABSOLUTE ${MODULE_FILES_CMAKE}) set(MODULE_FILES_CMAKE ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_FILES_CMAKE}) endif() if(NOT MODULE_SUBPROJECTS) if(MITK_DEFAULT_SUBPROJECTS) set(MODULE_SUBPROJECTS ${MITK_DEFAULT_SUBPROJECTS}) elseif(TARGET MITK-Modules) set(MODULE_SUBPROJECTS MITK-Modules) endif() endif() # check if the subprojects exist as targets if(MODULE_SUBPROJECTS) foreach(subproject ${MODULE_SUBPROJECTS}) if(NOT TARGET ${subproject}) message(SEND_ERROR "The subproject ${subproject} does not have a corresponding target") endif() endforeach() endif() # ----------------------------------------------------------------- # Check if module should be build set(MODULE_TARGET ${MODULE_NAME}) # assume worst case set(MODULE_IS_ENABLED 0) # first we check if we have an explicit module build list if(MITK_MODULES_TO_BUILD) list(FIND MITK_MODULES_TO_BUILD ${MODULE_NAME} _MOD_INDEX) if(_MOD_INDEX EQUAL -1) set(MODULE_IS_EXCLUDED 1) endif() endif() if(NOT MODULE_IS_EXCLUDED) # first of all we check for the dependencies _mitk_parse_package_args(${MODULE_PACKAGE_DEPENDS}) mitk_check_module_dependencies(MODULES ${MODULE_DEPENDS} PACKAGES ${PACKAGE_NAMES} MISSING_DEPENDENCIES_VAR _MISSING_DEP PACKAGE_DEPENDENCIES_VAR PACKAGE_NAMES) if(_MISSING_DEP) if(MODULE_NO_FEATURE_INFO) message("${_Module_type} ${MODULE_NAME} won't be built, missing dependency: ${_MISSING_DEP}") endif() set(MODULE_IS_ENABLED 0) else() set(MODULE_IS_ENABLED 1) # now check for every package if it is enabled. This overlaps a bit with # MITK_CHECK_MODULE ... foreach(_package ${PACKAGE_NAMES}) if((DEFINED MITK_USE_${_package}) AND NOT (MITK_USE_${_package})) message("${_Module_type} ${MODULE_NAME} won't be built. Turn on MITK_USE_${_package} if you want to use it.") set(MODULE_IS_ENABLED 0) break() endif() endforeach() endif() endif() # ----------------------------------------------------------------- # Start creating the module if(MODULE_IS_ENABLED) # clear variables defined in files.cmake set(RESOURCE_FILES ) set(CPP_FILES ) set(H_FILES ) set(TXX_FILES ) set(DOX_FILES ) set(UI_FILES ) set(MOC_H_FILES ) set(QRC_FILES ) # clear other variables set(Q${KITNAME}_GENERATED_CPP ) set(Q${KITNAME}_GENERATED_MOC_CPP ) set(Q${KITNAME}_GENERATED_QRC_CPP ) set(Q${KITNAME}_GENERATED_UI_CPP ) # check and set-up auto-loading if(MODULE_AUTOLOAD_WITH) if(NOT TARGET "${MODULE_AUTOLOAD_WITH}") message(SEND_ERROR "The module target \"${MODULE_AUTOLOAD_WITH}\" specified as the auto-loading module for \"${MODULE_NAME}\" does not exist") endif() endif() set(_module_autoload_meta_target "${CMAKE_PROJECT_NAME}-autoload") # create a meta-target if it does not already exist if(NOT TARGET ${_module_autoload_meta_target}) add_custom_target(${_module_autoload_meta_target}) endif() if(NOT MODULE_EXPORT_DEFINE) set(MODULE_EXPORT_DEFINE ${MODULE_NAME}_EXPORT) endif() if(MITK_GENERATE_MODULE_DOT) message("MODULEDOTNAME ${MODULE_NAME}") foreach(dep ${MODULE_DEPENDS}) message("MODULEDOT \"${MODULE_NAME}\" -> \"${dep}\" ; ") endforeach(dep) endif(MITK_GENERATE_MODULE_DOT) if (EXISTS ${MODULE_FILES_CMAKE}) include(${MODULE_FILES_CMAKE}) endif() if(MODULE_CPP_FILES) list(APPEND CPP_FILES ${MODULE_CPP_FILES}) endif() if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src") # Preprend the "src" directory to the cpp file list set(_cpp_files ${CPP_FILES}) set(CPP_FILES ) foreach(_cpp_file ${_cpp_files}) list(APPEND CPP_FILES "src/${_cpp_file}") endforeach() endif() if(CPP_FILES OR RESOURCE_FILES OR UI_FILES OR MOC_H_FILES OR QRC_FILES) set(MODULE_HEADERS_ONLY 0) if(MODULE_C_MODULE) set_source_files_properties(${CPP_FILES} PROPERTIES LANGUAGE C) elseif(MODULE_CXX_MODULE) set_source_files_properties(${CPP_FILES} PROPERTIES LANGUAGE CXX) endif() else() set(MODULE_HEADERS_ONLY 1) if(MODULE_AUTOLOAD_WITH) message(SEND_ERROR "A headers only module cannot be auto-loaded") endif() endif() set(module_c_flags ) set(module_c_flags_debug ) set(module_c_flags_release ) set(module_cxx_flags ) set(module_cxx_flags_debug ) set(module_cxx_flags_release ) if(MODULE_GCC_DEFAULT_VISIBILITY OR NOT CMAKE_COMPILER_IS_GNUCXX) # We only support hidden visibility for gcc for now. Clang still has troubles with # correctly marking template declarations and explicit template instantiations as exported. # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 # and http://llvm.org/bugs/show_bug.cgi?id=10113 set(CMAKE_CXX_VISIBILITY_PRESET default) set(CMAKE_VISIBILITY_INLINES_HIDDEN 0) else() set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) endif() if(NOT MODULE_WARNINGS_NO_ERRORS) if(MSVC_VERSION) mitkFunctionCheckCAndCXXCompilerFlags("/WX" module_c_flags module_cxx_flags) else() mitkFunctionCheckCAndCXXCompilerFlags(-Werror module_c_flags module_cxx_flags) # The flag "c++0x-static-nonintegral-init" has been renamed in newer Clang # versions to "static-member-init", see # http://clang-developers.42468.n3.nabble.com/Wc-0x-static-nonintegral-init-gone-td3999651.html # # Also, older Clang and seemingly all gcc versions do not warn if unknown # "-no-*" flags are used, so CMake will happily append any -Wno-* flag to the # command line. This may get confusing if unrelated compiler errors happen and # the error output then additionally contains errors about unknown flags (which # is not the case if there were no compile errors). # # So instead of using -Wno-* we use -Wno-error=*, which will be properly rejected by # the compiler and if applicable, prints the specific warning as a real warning and # not as an error (although -Werror was given). mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=c++0x-static-nonintegral-init" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=static-member-init" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=unknown-warning" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=gnu" module_c_flags module_cxx_flags) + mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=class-memaccess" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=inconsistent-missing-override" module_c_flags module_cxx_flags) endif() endif() if(MODULE_FORCE_STATIC) set(_STATIC STATIC) else() set(_STATIC ) endif(MODULE_FORCE_STATIC) if(NOT MODULE_HEADERS_ONLY) if(NOT MODULE_NO_INIT OR RESOURCE_FILES) find_package(CppMicroServices QUIET NO_MODULE REQUIRED) endif() if(NOT MODULE_NO_INIT) usFunctionGenerateModuleInit(CPP_FILES) endif() set(binary_res_files ) set(source_res_files ) if(RESOURCE_FILES) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/resource") set(res_dir resource) elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Resources") set(res_dir Resources) else() message(SEND_ERROR "Resources specified but ${CMAKE_CURRENT_SOURCE_DIR}/resource directory not found.") endif() foreach(res_file ${RESOURCE_FILES}) if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${res_dir}/${res_file}) list(APPEND binary_res_files "${res_file}") else() list(APPEND source_res_files "${res_file}") endif() endforeach() # Add a source level dependencies on resource files usFunctionGetResourceSource(TARGET ${MODULE_TARGET} OUT CPP_FILES) endif() endif() if(MITK_USE_Qt5) if(UI_FILES) qt5_wrap_ui(Q${KITNAME}_GENERATED_UI_CPP ${UI_FILES}) endif() if(MOC_H_FILES) qt5_wrap_cpp(Q${KITNAME}_GENERATED_MOC_CPP ${MOC_H_FILES} OPTIONS -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) endif() if(QRC_FILES) qt5_add_resources(Q${KITNAME}_GENERATED_QRC_CPP ${QRC_FILES}) endif() endif() set(Q${KITNAME}_GENERATED_CPP ${Q${KITNAME}_GENERATED_CPP} ${Q${KITNAME}_GENERATED_UI_CPP} ${Q${KITNAME}_GENERATED_MOC_CPP} ${Q${KITNAME}_GENERATED_QRC_CPP}) mitkFunctionOrganizeSources( SOURCE ${CPP_FILES} HEADER ${H_FILES} TXX ${TXX_FILES} DOC ${DOX_FILES} UI ${UI_FILES} QRC ${QRC_FILES} MOC ${Q${KITNAME}_GENERATED_MOC_CPP} GEN_QRC ${Q${KITNAME}_GENERATED_QRC_CPP} GEN_UI ${Q${KITNAME}_GENERATED_UI_CPP} ) set(coverage_sources ${CPP_FILES} ${H_FILES} ${GLOBBED__H_FILES} ${CORRESPONDING__H_FILES} ${TXX_FILES} ${TOOL_CPPS} ${TOOL_GUI_CPPS}) if(MODULE_SUBPROJECTS) set_property(SOURCE ${coverage_sources} APPEND PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() # --------------------------------------------------------------- # Create the actual module target if(MODULE_HEADERS_ONLY) add_library(${MODULE_TARGET} INTERFACE) else() if(MODULE_EXECUTABLE) add_executable(${MODULE_TARGET} ${MODULE_CPP_FILES} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES}) set(_us_module_name main) else() add_library(${MODULE_TARGET} ${_STATIC} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES}) set(_us_module_name ${MODULE_TARGET}) endif() # Apply properties to the module target. target_compile_definitions(${MODULE_TARGET} PRIVATE US_MODULE_NAME=${_us_module_name}) if(MODULE_C_MODULE) if(module_c_flags) string(REPLACE " " ";" module_c_flags "${module_c_flags}") target_compile_options(${MODULE_TARGET} PRIVATE ${module_c_flags}) endif() if(module_c_flags_debug) string(REPLACE " " ";" module_c_flags_debug "${module_c_flags_debug}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_c_flags_debug}>) endif() if(module_c_flags_release) string(REPLACE " " ";" module_c_flags_release "${module_c_flags_release}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_c_flags_release}>) endif() else() if(module_cxx_flags) string(REPLACE " " ";" module_cxx_flags "${module_cxx_flags}") target_compile_options(${MODULE_TARGET} PRIVATE ${module_cxx_flags}) endif() if(module_cxx_flags_debug) string(REPLACE " " ";" module_cxx_flags_debug "${module_cxx_flags_debug}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_cxx_flags_debug}>) endif() if(module_cxx_flags_release) string(REPLACE " " ";" module_cxx_flags_release "${module_cxx_flags_release}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_cxx_flags_release}>) endif() endif() set_property(TARGET ${MODULE_TARGET} PROPERTY US_MODULE_NAME ${_us_module_name}) # Add additional library search directories to a global property which # can be evaluated by other CMake macros, e.g. our install scripts. if(MODULE_ADDITIONAL_LIBS) target_link_libraries(${MODULE_TARGET} PRIVATE ${MODULE_ADDITIONAL_LIBS}) get_property(_mitk_additional_library_search_paths GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) foreach(_lib_filepath ${MODULE_ADDITIONAL_LIBS}) get_filename_component(_search_path "${_lib_filepath}" PATH) if(_search_path) list(APPEND _mitk_additional_library_search_paths "${_search_path}") endif() endforeach() if(_mitk_additional_library_search_paths) list(REMOVE_DUPLICATES _mitk_additional_library_search_paths) set_property(GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS ${_mitk_additional_library_search_paths}) endif() endif() # add the target name to a global property which is used in the top-level # CMakeLists.txt file to export the target set_property(GLOBAL APPEND PROPERTY MITK_MODULE_TARGETS ${MODULE_TARGET}) if(MODULE_AUTOLOAD_WITH) # for auto-loaded modules, adapt the output directory add_dependencies(${_module_autoload_meta_target} ${MODULE_TARGET}) if(WIN32) set(_module_output_prop RUNTIME_OUTPUT_DIRECTORY) else() set(_module_output_prop LIBRARY_OUTPUT_DIRECTORY) endif() set(_module_output_dir ${CMAKE_${_module_output_prop}}/${MODULE_AUTOLOAD_WITH}) get_target_property(_module_is_imported ${MODULE_AUTOLOAD_WITH} IMPORTED) if(NOT _module_is_imported) # if the auto-loading module is not imported, get its location # and put the auto-load module relative to it. get_target_property(_module_output_dir ${MODULE_AUTOLOAD_WITH} ${_module_output_prop}) set_target_properties(${MODULE_TARGET} PROPERTIES ${_module_output_prop} ${_module_output_dir}/${MODULE_AUTOLOAD_WITH}) else() set_target_properties(${MODULE_TARGET} PROPERTIES ${_module_output_prop} ${CMAKE_${_module_output_prop}}/${MODULE_AUTOLOAD_WITH}) endif() set_target_properties(${MODULE_TARGET} PROPERTIES MITK_AUTOLOAD_DIRECTORY ${MODULE_AUTOLOAD_WITH}) # add the auto-load module name as a property set_property(TARGET ${MODULE_AUTOLOAD_WITH} APPEND PROPERTY MITK_AUTOLOAD_TARGETS ${MODULE_TARGET}) endif() if(binary_res_files) usFunctionAddResources(TARGET ${MODULE_TARGET} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${res_dir} FILES ${binary_res_files}) endif() if(source_res_files) usFunctionAddResources(TARGET ${MODULE_TARGET} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${res_dir} FILES ${source_res_files}) endif() if(binary_res_files OR source_res_files) usFunctionEmbedResources(TARGET ${MODULE_TARGET}) endif() if(MODULE_DEPRECATED_SINCE) set_property(TARGET ${MODULE_TARGET} PROPERTY MITK_MODULE_DEPRECATED_SINCE ${MODULE_DEPRECATED_SINCE}) endif() # create export macros if (NOT MODULE_EXECUTABLE) set(_export_macro_name ) if(MITK_LEGACY_EXPORT_MACRO_NAME) set(_export_macro_names EXPORT_MACRO_NAME ${MODULE_EXPORT_DEFINE} NO_EXPORT_MACRO_NAME ${MODULE_NAME}_NO_EXPORT DEPRECATED_MACRO_NAME ${MODULE_NAME}_DEPRECATED NO_DEPRECATED_MACRO_NAME ${MODULE_NAME}_NO_DEPRECATED ) endif() generate_export_header(${MODULE_NAME} ${_export_macro_names} EXPORT_FILE_NAME ${MODULE_NAME}Exports.h ) endif() target_include_directories(${MODULE_TARGET} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) endif() # --------------------------------------------------------------- # Properties for both header-only and compiled modules if(MODULE_HEADERS_ONLY) set(_module_property_type INTERFACE) else() set(_module_property_type PUBLIC) endif() if(MODULE_TARGET_DEPENDS) add_dependencies(${MODULE_TARGET} ${MODULE_TARGET_DEPENDS}) endif() if(MODULE_SUBPROJECTS AND NOT MODULE_HEADERS_ONLY) set_property(TARGET ${MODULE_TARGET} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) foreach(subproject ${MODULE_SUBPROJECTS}) add_dependencies(${subproject} ${MODULE_TARGET}) endforeach() endif() set(DEPENDS "${MODULE_DEPENDS}") if(NOT MODULE_NO_INIT AND NOT MODULE_HEADERS_ONLY) # Add a CppMicroServices dependency implicitly, since it is # needed for the generated "module initialization" code. set(DEPENDS "CppMicroServices;${DEPENDS}") endif() if(DEPENDS OR MODULE_PACKAGE_DEPENDS) mitk_use_modules(TARGET ${MODULE_TARGET} MODULES ${DEPENDS} PACKAGES ${MODULE_PACKAGE_DEPENDS} ) endif() if(NOT MODULE_C_MODULE) target_compile_features(${MODULE_TARGET} ${_module_property_type} ${MITK_CXX_FEATURES}) endif() # add include directories if(MODULE_INTERNAL_INCLUDE_DIRS) target_include_directories(${MODULE_TARGET} PRIVATE ${MODULE_INTERNAL_INCLUDE_DIRS}) endif() if(NOT MODULE_NO_DEFAULT_INCLUDE_DIRS) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(${MODULE_TARGET} ${_module_property_type} include) else() target_include_directories(${MODULE_TARGET} ${_module_property_type} .) endif() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(${MODULE_TARGET} PRIVATE src) endif() endif() target_include_directories(${MODULE_TARGET} ${_module_property_type} ${MODULE_INCLUDE_DIRS}) endif() # ----------------------------------------------------------------- # Record missing dependency information if(_MISSING_DEP) if(MODULE_DESCRIPTION) set(MODULE_DESCRIPTION "${MODULE_DESCRIPTION} (missing dependencies: ${_MISSING_DEP})") else() set(MODULE_DESCRIPTION "(missing dependencies: ${_MISSING_DEP})") endif() endif() if(NOT MODULE_NO_FEATURE_INFO) add_feature_info(${MODULE_NAME} MODULE_IS_ENABLED "${MODULE_DESCRIPTION}") endif() set(MODULE_NAME ${MODULE_NAME} PARENT_SCOPE) set(MODULE_TARGET ${MODULE_TARGET} PARENT_SCOPE) set(MODULE_IS_ENABLED ${MODULE_IS_ENABLED} PARENT_SCOPE) set(MODULE_SUBPROJECTS ${MODULE_SUBPROJECTS} PARENT_SCOPE) endfunction() diff --git a/CMake/mitkFunctionCreatePlugin.cmake b/CMake/mitkFunctionCreatePlugin.cmake index acbc2bc297..1c5faf618e 100644 --- a/CMake/mitkFunctionCreatePlugin.cmake +++ b/CMake/mitkFunctionCreatePlugin.cmake @@ -1,343 +1,344 @@ #! \brief Creates a MITK CTK plugin. #! #! This function should be called from the plugins CMakeLists.txt file. #! The target name is available after the macro call as ${PLUGIN_TARGET} #! to add additional libraries in your CMakeLists.txt. Include paths and link #! libraries are set depending on the value of the Required-Plugins header #! in your manifest_headers.cmake file. #! #! This function internally calls ctkMacroBuildPlugin() and adds support #! for Qt Help files and installers. #! #! Options: #! \param TEST_PLUGIN Mark this plug-in as a testing plug-in. #! \param NO_INSTALL Don't install this plug-in. #! #! Parameters: #! #! \param EXPORT_DIRECTIVE (required) The export directive to use in the generated #! _Exports.h file. #! #! Multi-value parameters (all optional): #! #! \param EXPORTED_INCLUDE_SUFFIXES A list of sub-directories which should #! be added to the current source directory. The resulting directories #! will be available in the set of include directories of depending plug-ins. #! \param MODULE_DEPENDS (optional) A list of Modules this plug-in depends on. #! \param PACKAGE_DEPENDS (optional) A list of external packages this plug-in depends on. #! \param DOXYGEN_TAGFILES (optional) Which external tag files should be available for the plugin documentation #! \param MOC_OPTIONS (optional) Additional options to pass to the Qt MOC compiler #! \param WARNINGS_NO_ERRORS (optional) Do not handle compiler warnings as errors function(mitk_create_plugin) # options set(arg_options TEST_PLUGIN # Mark this plug-in as a testing plug-in NO_INSTALL # Don't install this plug-in NO_QHP_TRANSFORM WARNINGS_NO_ERRORS ) # single value arguments set(arg_single EXPORT_DIRECTIVE # (required) TODO: could be generated via CMake as it is done for MITK modules already ) # multiple value arguments set(arg_multiple EXPORTED_INCLUDE_SUFFIXES # (optional) additional public include directories MODULE_DEPENDS # (optional) PACKAGE_DEPENDS DOXYGEN_TAGFILES MOC_OPTIONS SUBPROJECTS ) cmake_parse_arguments(_PLUGIN "${arg_options}" "${arg_single}" "${arg_multiple}" ${ARGN}) if(_PLUGIN_TEST_PLUGIN) set(_PLUGIN_NO_INSTALL 1) set(is_test_plugin "TEST_PLUGIN") else() set(is_test_plugin) endif() set(_PLUGIN_MOC_OPTIONS "-DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED ${_PLUGIN_MOC_OPTIONS}") set(PLUGIN_TARGET ${PROJECT_NAME}) mitk_check_module_dependencies(MODULES ${_PLUGIN_MODULE_DEPENDS} PACKAGES ${_PLUGIN_PACKAGE_DEPENDS} MISSING_DEPENDENCIES_VAR _missing_deps MODULE_DEPENDENCIES_VAR _module_deps PACKAGE_DEPENDENCIES_VAR _package_deps) if(_missing_deps) if(NOT MITK_BUILD_ALL_PLUGINS) message(SEND_ERROR "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_missing_deps}") else() message(STATUS "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_missing_deps}") endif() return() endif() # -------------- All dependencies are resolved ------------------ message(STATUS "Creating CTK plugin ${PROJECT_NAME}") include(files.cmake) set(_PLUGIN_CPP_FILES ${CPP_FILES}) set(_PLUGIN_MOC_H_FILES ${MOC_H_FILES}) set(_PLUGIN_UI_FILES ${UI_FILES}) set(_PLUGIN_CACHED_RESOURCE_FILES ${CACHED_RESOURCE_FILES}) set(_PLUGIN_TRANSLATION_FILES ${TRANSLATION_FILES}) set(_PLUGIN_QRC_FILES ${QRC_FILES}) set(_PLUGIN_H_FILES ${H_FILES}) set(_PLUGIN_TXX_FILES ${TXX_FILES}) set(_PLUGIN_DOX_FILES ${DOX_FILES}) set(_PLUGIN_CMAKE_FILES ${CMAKE_FILES} files.cmake) set(_PLUGIN_FILE_DEPENDENCIES ${FILE_DEPENDENCIES}) if(CTK_PLUGINS_OUTPUT_DIR) set(_output_dir "${CTK_PLUGINS_OUTPUT_DIR}") else() set(_output_dir "") endif() # Compute the plugin dependencies ctkFunctionGetTargetLibraries(_PLUGIN_target_libraries "") #------------------------------------------------------------# #------------------ Qt Help support -------------------------# set(PLUGIN_GENERATED_QCH_FILES ) if(BLUEBERRY_USE_QT_HELP AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_INPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/documentation/UserManual") # Create a list of Doxygen tag files from the plug-in dependencies set(PLUGIN_DOXYGEN_TAGFILES) foreach(_dep_target ${_PLUGIN_target_libraries}) string(REPLACE _ . _dep ${_dep_target}) get_target_property(_is_imported ${_dep_target} IMPORTED) if(_is_imported) get_target_property(_import_loc_debug ${_dep_target} IMPORTED_LOCATION_DEBUG) get_target_property(_import_loc_release ${_dep_target} IMPORTED_LOCATION_RELEASE) # There is not necessarily a debug and release build if(_import_loc_release) set(_import_loc ${_import_loc_release}) else() set(_import_loc ${_import_loc_debug}) endif() get_filename_component(_target_filename "${_import_loc}" NAME) # on windows there might be a Debug or Release subdirectory string(REGEX REPLACE "/bin/plugins/(Debug/|Release/)?${_target_filename}" "/Plugins/${_dep}/documentation/UserManual" plugin_tag_dir "${_import_loc}" ) else() set(plugin_tag_dir "${CMAKE_BINARY_DIR}/Plugins/${_dep}/documentation/UserManual") endif() set(_tag_file "${plugin_tag_dir}/${_dep_target}.tag") if(EXISTS ${_tag_file}) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} \"${_tag_file}=qthelp://${_dep}/bundle/\"") endif() endforeach() if(_PLUGIN_DOXYGEN_TAGFILES) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} ${_PLUGIN_DOXYGEN_TAGFILES}") endif() #message("PLUGIN_DOXYGEN_TAGFILES: ${PLUGIN_DOXYGEN_TAGFILES}") if(_PLUGIN_NO_QHP_TRANSFORM) set(_use_qhp_xsl 0) else() set(_use_qhp_xsl 1) endif() _FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP(PLUGIN_GENERATED_QCH_FILES ${_use_qhp_xsl}) list(APPEND _PLUGIN_CACHED_RESOURCE_FILES ${PLUGIN_GENERATED_QCH_FILES}) endif() #------------------------------------------------------------# #------------------ Create Plug-in --------------------------# mitkFunctionOrganizeSources( SOURCE ${_PLUGIN_CPP_FILES} HEADER ${_PLUGIN_H_FILES} TXX ${_PLUGIN_TXX_FILES} DOC ${_PLUGIN_DOX_FILES} UI ${_PLUGIN_UI_FILES} QRC ${_PLUGIN_QRC_FILES} ${_PLUGIN_CACHED_RESOURCE_FILES} META ${_PLUGIN_META_FILES} MOC ${MY_MOC_CPP} GEN_UI ${MY_UI_CPP} GEN_QRC ${MY_QRC_SRCS} ) ctkMacroBuildPlugin( NAME ${PLUGIN_TARGET} EXPORT_DIRECTIVE ${_PLUGIN_EXPORT_DIRECTIVE} SRCS ${_PLUGIN_CPP_FILES} ${_PLUGIN_H_FILES} ${CORRESPONDING__H_FILES} ${GLOBBED__H_FILES} MOC_SRCS ${_PLUGIN_MOC_H_FILES} MOC_OPTIONS ${_PLUGIN_MOC_OPTIONS} UI_FORMS ${_PLUGIN_UI_FILES} EXPORTED_INCLUDE_SUFFIXES ${_PLUGIN_EXPORTED_INCLUDE_SUFFIXES} RESOURCES ${_PLUGIN_QRC_FILES} TARGET_LIBRARIES ${_PLUGIN_target_libraries} CACHED_RESOURCEFILES ${_PLUGIN_CACHED_RESOURCE_FILES} TRANSLATIONS ${_PLUGIN_TRANSLATION_FILES} OUTPUT_DIR ${_output_dir} NO_INSTALL # we install the plug-in ourselves ${is_test_plugin} ) mitk_use_modules(TARGET ${PLUGIN_TARGET} MODULES ${_PLUGIN_MODULE_DEPENDS} PACKAGES ${_PLUGIN_PACKAGE_DEPENDS} ) set_property(TARGET ${PLUGIN_TARGET} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${PLUGIN_TARGET}) set_property(TARGET ${PLUGIN_TARGET} PROPERTY US_MODULE_NAME ${PLUGIN_TARGET}) set(plugin_c_flags) set(plugin_cxx_flags) if(NOT _PLUGIN_WARNINGS_NO_ERRORS) if(MSVC_VERSION) mitkFunctionCheckCAndCXXCompilerFlags("/WX" plugin_c_flags plugin_cxx_flags) else() mitkFunctionCheckCAndCXXCompilerFlags(-Werror plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=c++0x-static-nonintegral-init" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=static-member-init" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=unknown-warning" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=gnu" plugin_c_flags plugin_cxx_flags) + mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=cast-function-type" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=inconsistent-missing-override" plugin_c_flags plugin_cxx_flags) endif() endif() if(plugin_c_flags) string(REPLACE " " ";" plugin_c_flags "${plugin_c_flags}") target_compile_options(${PLUGIN_TARGET} PRIVATE ${plugin_c_flags}) endif() if(plugin_cxx_flags) string(REPLACE " " ";" plugin_cxx_flags "${plugin_cxx_flags}") target_compile_options(${PLUGIN_TARGET} PRIVATE ${plugin_cxx_flags}) endif() if(NOT MY_SUBPROJECTS) if(MITK_DEFAULT_SUBPROJECTS) set(MY_SUBPROJECTS ${MITK_DEFAULT_SUBPROJECTS}) elseif(TARGET MITK-Plugins) set(MY_SUBPROJECTS MITK-Plugins) endif() endif() if(MY_SUBPROJECTS) set_property(TARGET ${PLUGIN_TARGET} PROPERTY LABELS ${MY_SUBPROJECTS}) foreach(subproject ${MY_SUBPROJECTS}) add_dependencies(${subproject} ${PLUGIN_TARGET}) endforeach() endif() if(_PLUGIN_TEST_PLUGIN) find_package(CppUnit REQUIRED) target_include_directories(${PLUGIN_TARGET} PRIVATE ${CppUnit_INCLUDE_DIRS}) target_link_libraries(${PLUGIN_TARGET} PRIVATE ${CppUnit_LIBRARIES}) endif() if(mbilog_FOUND) target_link_libraries(${PLUGIN_TARGET} PRIVATE mbilog) endif() set(_PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") list(APPEND _PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") endif() set(PLUGIN_TARGET ${PLUGIN_TARGET} PARENT_SCOPE) #------------------------------------------------------------# #------------------ Installer support -----------------------# if(NOT _PLUGIN_NO_INSTALL) set(install_directories "") if(NOT MACOSX_BUNDLE_NAMES) set(install_directories bin/plugins) else(NOT MACOSX_BUNDLE_NAMES) foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND install_directories ${bundle_name}.app/Contents/MacOS/plugins) endforeach(bundle_name) endif(NOT MACOSX_BUNDLE_NAMES) foreach(install_subdir ${install_directories}) mitkFunctionInstallCTKPlugin(TARGETS ${PLUGIN_TARGET} DESTINATION ${install_subdir}) endforeach() set(_autoload_targets ) foreach(_dependency ${_module_deps}) get_target_property(_dep_autoloads ${_dependency} MITK_AUTOLOAD_TARGETS) if (_dep_autoloads) list(APPEND _autoload_targets ${_dep_autoloads}) endif() endforeach() # The MITK_AUTOLOAD_TARGETS property is used in the mitkFunctionInstallAutoLoadModules # macro which expects a list of plug-in targets. if (_autoload_targets) list(REMOVE_DUPLICATES _autoload_targets) set_target_properties(${PLUGIN_TARGET} PROPERTIES MITK_AUTOLOAD_TARGETS "${_autoload_targets}") endif() endif() endfunction() function(_FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP qch_file use_xsl) set(_manifest_path "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(NOT EXISTS ${_manifest_path}) message(FATAL_ERROR "${_manifest_path} not found") endif() include(${_manifest_path}) string(REPLACE "_" "." Plugin-SymbolicName "${PLUGIN_TARGET}") configure_file(${MITK_SOURCE_DIR}/Documentation/doxygen_plugin_manual.conf.in ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf ) set(_qhp_xsl_file "${MITK_SOURCE_DIR}/Documentation/qhp_toc.xsl") set(_generated_qhp_file "${PLUGIN_DOXYGEN_OUTPUT_DIR}/html/index.qhp") set(_transformed_qhp_file "${PLUGIN_DOXYGEN_OUTPUT_DIR}/html/${PLUGIN_TARGET}.qhp") set(${qch_file} "${CMAKE_CURRENT_BINARY_DIR}/resources/${PLUGIN_TARGET}.qch") set(_xsl_command ) if(use_xsl) set(_xsl_command COMMAND ${QT_XMLPATTERNS_EXECUTABLE} ${_qhp_xsl_file} ${_generated_qhp_file} -output ${_transformed_qhp_file}) endif() file(GLOB _file_dependencies "${PLUGIN_DOXYGEN_INPUT_DIR}/*") add_custom_command(OUTPUT ${${qch_file}} # Generate a Qt help project (index.qhp) with doxygen COMMAND ${DOXYGEN_EXECUTABLE} ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf # Use a XSL transformation to get rid of the top-level entry ${_xsl_command} # Generate the final Qt compressed help file (.qch) COMMAND ${QT_HELPGENERATOR_EXECUTABLE} ${_transformed_qhp_file} -o ${${qch_file}} DEPENDS ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf ${_file_dependencies} ) #set_source_files_properties(${qch_file} PROPERTIES GENERATED 1) set(${qch_file} ${${qch_file}} PARENT_SCOPE) endfunction() function(MACRO_CREATE_MITK_CTK_PLUGIN) message(SEND_ERROR "The function MACRO_CREATE_MITK_CTK_PLUGIN was renamed to mitk_create_plugin in MITK 2015.05.") endfunction() diff --git a/CMake/mitkFunctionGetMSVCVersion.cmake b/CMake/mitkFunctionGetMSVCVersion.cmake index 0bd5088116..551c3e5d55 100644 --- a/CMake/mitkFunctionGetMSVCVersion.cmake +++ b/CMake/mitkFunctionGetMSVCVersion.cmake @@ -1,57 +1,26 @@ #! \brief Get diverse visual studio ids not directly provided by CMake #! #! Sets the following variables in the parent scope #! VISUAL_STUDIO_VERSION_MAJOR - The Visual Studio Version #! VISUAL_STUDIO_PRODUCT_NAME - The Visual Studio Product Name function(mitkFunctionGetMSVCVersion ) if(MSVC) - if(MSVC_VERSION EQUAL 1600) - set(VISUAL_STUDIO_VERSION_MAJOR "10" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) - set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2010" PARENT_SCOPE) - elseif(MSVC_VERSION EQUAL 1700) - set(VISUAL_STUDIO_VERSION_MAJOR "11" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) - set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2012" PARENT_SCOPE) - elseif(MSVC_VERSION EQUAL 1800) - set(VISUAL_STUDIO_VERSION_MAJOR "12" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) - set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2013" PARENT_SCOPE) - elseif(MSVC_VERSION EQUAL 1900) - set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) - set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2015" PARENT_SCOPE) - elseif(MSVC_VERSION EQUAL 1910) - set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) - set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) - elseif(MSVC_VERSION EQUAL 1911) - set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "1" PARENT_SCOPE) - set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) - elseif(MSVC_VERSION EQUAL 1912) - set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "2" PARENT_SCOPE) - set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) - elseif(MSVC_VERSION EQUAL 1913) - set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "3" PARENT_SCOPE) - set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) - elseif(MSVC_VERSION EQUAL 1914) - set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) - set(VISUAL_STUDIO_VERSION_MINOR "4" PARENT_SCOPE) + if(MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 2000) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) + set(VISUAL_STUDIO_VERSION_MAJOR 14 PARENT_SCOPE) + string(SUBSTRING ${MSVC_VERSION} 3 -1 version_minor) + set(VISUAL_STUDIO_VERSION_MINOR ${version_minor} PARENT_SCOPE) else() - message(WARNING "Unknown Visual Studio version ${MSVC_VERSION}. Please update CMake/mitkFunctionGetMSVCVersion.cmake.") + message(WARNING "Unknown Visual Studio version ${MSVC_VERSION} (CMake/mitkFunctionGetMSVCVersion.cmake)") endif() if("${CMAKE_GENERATOR}" MATCHES ".*Win64") set(CMAKE_LIBRARY_ARCHITECTURE x64 PARENT_SCOPE) else() set(CMAKE_LIBRARY_ARCHITECTURE x86 PARENT_SCOPE) endif() endif() endfunction() diff --git a/CMake/mitkInstallRules.cmake b/CMake/mitkInstallRules.cmake index 9150bdd2c1..5e53b509da 100644 --- a/CMake/mitkInstallRules.cmake +++ b/CMake/mitkInstallRules.cmake @@ -1,77 +1,99 @@ # Install MITK icon and logo MITK_INSTALL(FILES "${MITK_SOURCE_DIR}/mitk.ico" "${MITK_SOURCE_DIR}/mitk.bmp") # Install Qt plugins if(MITK_USE_Qt5) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) get_filename_component(_qmake_path ${_qmake_location} DIRECTORY) if(WIN32) set(_prefix "") set(_ext ".dll") elseif(UNIX) set(_prefix "lib") if(APPLE) set(_ext ".dylib") else() set(_ext ".so") endif() endif() set(_install_DESTINATION "plugins/sqldrivers") MITK_INSTALL(FILES "${_qmake_path}/../plugins/sqldrivers/${_prefix}qsqlite${_ext}") set(_install_DESTINATION "plugins/imageformats") MITK_INSTALL(FILES "${_qmake_path}/../plugins/imageformats/${_prefix}qsvg${_ext}") set(_install_DESTINATION "plugins/iconengines") MITK_INSTALL(FILES "${_qmake_path}/../plugins/iconengines/${_prefix}qsvgicon${_ext}") # Install platform-specific Qt plugins set(_install_DESTINATION "plugins/platforms") if(WIN32) MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/qwindows.dll") elseif(APPLE) MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/libqcocoa.dylib") + elseif(UNIX) + MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/libqxcb.so") + + set(_install_DESTINATION "plugins/xcbglintegrations") + MITK_INSTALL(FILES "${_qmake_path}/../plugins/xcbglintegrations/libqxcb-glx-integration.so") + endif() + + # Install platform-specific Qt styles - set(_install_DESTINATION "plugins/styles") + set(_install_DESTINATION "plugins/styles") + + if(WIN32) + MITK_INSTALL(FILES "${_qmake_path}/../plugins/styles/qwindowsvistastyle.dll") + elseif(APPLE) MITK_INSTALL(FILES "${_qmake_path}/../plugins/styles/libqmacstyle.dylib") - elseif(UNIX) - MITK_INSTALL(FILES - "${_qmake_path}/../plugins/platforms/libqxcb.so" - "${_qmake_path}/../plugins/platforms/libqxcb-glx-integration.so") endif() # Install Qt WebEngine if(APPLE) set(_install_DESTINATION "../Frameworks/QtWebEngineCore.framework") get_filename_component(_real_path "${_qmake_path}/../lib/QtWebEngineCore.framework/Helpers" REALPATH) - MITK_INSTALL(DIRECTORY ${_real_path}) + MITK_INSTALL(DIRECTORY ${_real_path} USE_SOURCE_PERMISSIONS) - get_filename_component(_real_path "${_qmake_path}/../lib/QtWebEngineCore.framework/Resources" REALPATH) - MITK_INSTALL(DIRECTORY ${_real_path}) + # Translations are included in the Resources directory of + # QtWebEngineCore.framework and are installed by default. else() set(_install_DESTINATION "") if(WIN32) - MITK_INSTALL(FILES "${_qmake_path}/QtWebEngineProcess.exe") + MITK_INSTALL(PROGRAMS "${_qmake_path}/QtWebEngineProcess.exe") elseif(UNIX) - MITK_INSTALL(FILES "${_qmake_path}/../libexec/QtWebEngineProcess") + MITK_INSTALL(PROGRAMS "${_qmake_path}/../libexec/QtWebEngineProcess") endif() MITK_INSTALL(DIRECTORY "${_qmake_path}/../resources") set(_install_DESTINATION "translations") MITK_INSTALL(DIRECTORY "${_qmake_path}/../translations/qtwebengine_locales") endif() endif() -set(_install_DESTINATION "") # IMPORTANT: Restore default install destination! +set(_install_DESTINATION "") + +# Install MatchPoint binaries that are not auto-detected +if(MITK_USE_MatchPoint) + MITK_INSTALL(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" FILES_MATCHING PATTERN "MapUtilities*") + MITK_INSTALL(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" FILES_MATCHING PATTERN "MapAlgorithms*") +endif() + +# Install SimpleITK binaries that are not auto-detected +if(MITK_USE_SimpleITK) + MITK_INSTALL(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" FILES_MATCHING PATTERN "SimpleITK*") +endif() + +# IMPORTANT: Restore default install destination! Do not edit this file beyond this line! +set(_install_DESTINATION "") diff --git a/CMake/mitkMacroInstall.cmake b/CMake/mitkMacroInstall.cmake index 6613f7391d..3d0cb5e589 100644 --- a/CMake/mitkMacroInstall.cmake +++ b/CMake/mitkMacroInstall.cmake @@ -1,182 +1,201 @@ # # MITK specific install macro # # On Mac everything is installed for each bundle listed in MACOSX_BUNDLE_NAMES # by replacing the DESTINATION parameter. Everything else is passed to the CMake INSTALL command # # Usage: MITK_INSTALL( ) # macro(MITK_INSTALL) set(ARGS ${ARGN}) - set(install_directories "") list(FIND ARGS DESTINATION _destination_index) - # set(_install_DESTINATION "") if(_destination_index GREATER -1) message(SEND_ERROR "MITK_INSTALL macro must not be called with a DESTINATION parameter.") - ### This code was a try to replace a given DESTINATION - #math(EXPR _destination_index ${_destination_index} + 1) - #list(GET ARGS ${_destination_index} _install_DESTINATION) - #string(REGEX REPLACE ^bin "" _install_DESTINATION ${_install_DESTINATION}) else() + # If there is a FILES_MATCHING parameter we need to make sure that the + # DESTINATION parameter is located in front of it. + set(ARGS1 "") + set(ARGS2 "") + list(FIND ARGS FILES_MATCHING _files_matching_index) + if(_files_matching_index GREATER -1) + set(_index "0") + list(LENGTH ARGS _count) + while(_index LESS _files_matching_index ) + list(GET ARGS ${_index} _arg) + list(APPEND ARGS1 ${_arg}) + math(EXPR _index "${_index}+1") + endwhile() + while(_index LESS _count) + list(GET ARGS ${_index} _arg) + list(APPEND ARGS2 ${_arg}) + math(EXPR _index "${_index}+1") + endwhile() + else() + set(ARGS1 ${ARGS}) + endif() if(NOT MACOSX_BUNDLE_NAMES) - install(${ARGS} DESTINATION bin/${_install_DESTINATION}) + install(${ARGS1} DESTINATION bin/${_install_DESTINATION} ${ARGS2}) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) - install(${ARGS} DESTINATION ${bundle_name}.app/Contents/MacOS/${_install_DESTINATION}) + install(${ARGS1} DESTINATION ${bundle_name}.app/Contents/MacOS/${_install_DESTINATION} ${ARGS2}) endforeach() endif() endif() endmacro() # Fix _target_location # This is used in several install macros macro(_fixup_target) if(NOT intermediate_dir) if(WIN32) set(intermediate_dir Release) else() set(intermediate_dir .) endif() endif() mitkFunctionGetLibrarySearchPaths(_search_paths ${intermediate_dir}) install(CODE " set(_bundle_dest_dir \"${_bundle_dest_dir}\") if(_bundle_dest_dir) set(_bin_path \"\${CMAKE_INSTALL_PREFIX}/\${_bundle_dest_dir}\") else() set(_bin_path \"\${CMAKE_INSTALL_PREFIX}/bin\") endif() macro(gp_item_default_embedded_path_override item default_embedded_path_var) get_filename_component(_item_name \"\${item}\" NAME) get_filename_component(_item_path \"\${item}\" PATH) # We have to fix all path references to build trees for plugins if(NOT _item_path MATCHES \"\${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}\") # item with relative path or embedded path pointing to some build dir set(full_path \"full_path-NOTFOUND\") file(GLOB_RECURSE full_path \${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}/\${_item_name} ) list(LENGTH full_path full_path_length) if(full_path_length GREATER 1) list(GET full_path 0 full_path) endif() get_filename_component(_item_path \"\${full_path}\" PATH) endif() set(_plugins_path \"\${_bin_path}/plugins\") if(_item_path STREQUAL _plugins_path OR (_item_path MATCHES \"\${_plugins_path}/\" AND _item_name MATCHES \"liborg\") # this is for legacy BlueBerry bundle support ) # Only fix plugins message(\"override: \${item}\") message(\"found file: \${_item_path}/\${_item_name}\") if(APPLE) string(REPLACE \${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir} @executable_path \${default_embedded_path_var} \"\${_item_path}\" ) else() set(\${default_embedded_path_var} \"\${_item_path}\") endif() message(\"override result: \${\${default_embedded_path_var}}\") endif() endmacro(gp_item_default_embedded_path_override) macro(gp_resolved_file_type_override file type) if(NOT APPLE) get_filename_component(_file_path \"\${file}\" PATH) get_filename_component(_file_name \"\${file}\" NAME) if(_file_path MATCHES \"^\${CMAKE_INSTALL_PREFIX}\") set(\${type} \"local\") endif() if(_file_name MATCHES gdiplus) set(\${type} \"system\") endif(_file_name MATCHES gdiplus) endif() if(WIN32) if(file MATCHES \"BluetoothApis.dll\") set(\${type} \"system\" ) endif() endif() endmacro(gp_resolved_file_type_override) if(NOT APPLE) macro(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var) if(\${item} MATCHES \"blueberry_core_runtime\") get_filename_component(_item_name \${item} NAME) set(\${resolved_item_var} \"\${exepath}/plugins/\${_item_name}\") set(\${resolved_var} 1) endif() endmacro() endif() if(\"${_install_GLOB_PLUGINS}\" STREQUAL \"TRUE\") set(GLOBBED_PLUGINS ) set(_bb_runtime_lib \"\${_bin_path}/liborg_blueberry_core_runtime${CMAKE_SHARED_LIBRARY_SUFFIX}\") if(EXISTS \"\${_bb_runtime_lib}\") list(APPEND GLOBBED_PLUGINS \"\${_bb_runtime_lib}\") endif() # Iterate over all sub-directories which contain plug-ins # (BlueBerry plug-ins, Qt plug-ins, and auto-load modules) file(GLOB _children \"\${_bin_path}/*\") foreach(_child \${_children}) if(IS_DIRECTORY \${_child}) set(_plugins ) set(_modules ) file(GLOB_RECURSE _plugins \"\${_child}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") if(_plugins) list(APPEND GLOBBED_PLUGINS \${_plugins}) endif() # Now glob for all modules which might have a different extensions. # E.g. on MacOS plugins could have a .dylib extension as well as a .so extension if(NOT \"${CMAKE_SHARED_MODULE_SUFFIX}\" STREQUAL \"\" AND NOT \"${CMAKE_SHARED_MODULE_SUFFIX}\" STREQUAL \"${CMAKE_SHARED_LIBRARY_SUFFIX}\") file(GLOB_RECURSE _modules \"\${_child}/*${CMAKE_SHARED_MODULE_SUFFIX}\") endif() if(_modules) list(APPEND GLOBBED_PLUGINS \${_modules}) endif() endif() endforeach() endif() set(PLUGINS ) foreach(_plugin ${_install_PLUGINS} \${GLOBBED_PLUGINS}) get_filename_component(_plugin_realpath \${_plugin} REALPATH) list(APPEND PLUGINS \${_plugin_realpath}) endforeach() if(PLUGINS) list(REMOVE_DUPLICATES PLUGINS) endif(PLUGINS) message(\"globbed plugins: \${PLUGINS}\") set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) set(DIRS \"${_search_paths}\") set(_additional_search_paths ${_install_LIBRARY_DIRS}) if(_additional_search_paths) set(DIRS \"\${DIRS};\${_additional_search_paths}\") endif() foreach(_plugin \${PLUGINS}) get_filename_component(_pluginpath \${_plugin} PATH) list(APPEND DIRS \"\${_pluginpath}\") endforeach(_plugin) list(REMOVE_DUPLICATES DIRS) # use custom version of BundleUtilities include(BundleUtilities) fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${_target_location}\" \"\${PLUGINS}\" \"\${DIRS}\") + + if(APPLE) + include(FixMacOSInstaller) + endif() ") endmacro() diff --git a/CMake/mitkTestPluginGenerator.cmake b/CMake/mitkTestPluginGenerator.cmake index 753f8a5689..cf63eeefe3 100644 --- a/CMake/mitkTestPluginGenerator.cmake +++ b/CMake/mitkTestPluginGenerator.cmake @@ -1,113 +1,113 @@ if(BUILD_TESTING) set(proj GP) # Means GenerateProject (use a short name due to Windows limitations) set(test_project_out_dir "${MITK_BINARY_DIR}") set(test_project_source_dir "${MITK_BINARY_DIR}/${proj}") set(test_project_binary_dir "${MITK_BINARY_DIR}/${proj}-bin") add_test(NAME mitkPluginGeneratorCleanTest COMMAND ${CMAKE_COMMAND} -E remove_directory "${test_project_source_dir}" ) set_tests_properties(mitkPluginGeneratorCleanTest PROPERTIES LABELS "MITK;BlueBerry") add_test(NAME mitkPluginGeneratorCleanTest2 COMMAND ${CMAKE_COMMAND} -E remove_directory "${test_project_binary_dir}" ) set_tests_properties(mitkPluginGeneratorCleanTest2 PROPERTIES LABELS "MITK;BlueBerry") add_test(NAME mitkPluginGeneratorCleanTest3 COMMAND ${CMAKE_COMMAND} -E make_directory "${test_project_binary_dir}" ) set_tests_properties(mitkPluginGeneratorCleanTest3 PROPERTIES DEPENDS mitkPluginGeneratorCleanTest2 LABELS "MITK;BlueBerry") add_test(NAME mitkPluginGeneratorCreateTest COMMAND ${exec_target} --project-name "${proj}" --project-app-name "TestApp" -ps org.test.plugin -pn "Test Plugin" -vn "Test View" - -o ${test_project_out_dir} -y -n + -o ${test_project_out_dir} -y ) set_tests_properties(mitkPluginGeneratorCreateTest PROPERTIES DEPENDS "${exec_target};mitkPluginGeneratorCleanTest;mitkPluginGeneratorCleanTest3" LABELS "MITK;BlueBerry") set(configure_options -DMITK_DIR:PATH=${MITK_BINARY_DIR} -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER} -DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT} -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES} -G${CMAKE_GENERATOR} -C "${MITK_BINARY_DIR}/mitkTestInitialCache.txt" ) if(CMAKE_PREFIX_PATH) string (REPLACE ";" "$" CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH}") list(APPEND configure_options -DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH}) endif() if(CMAKE_CONFIGURATION_TYPES) foreach(config ${CMAKE_CONFIGURATION_TYPES}) add_test(NAME mitkPluginGeneratorConfigureTest-${config} CONFIGURATIONS ${config} WORKING_DIRECTORY "${test_project_binary_dir}" COMMAND ${CMAKE_COMMAND} ${configure_options} "${test_project_source_dir}") set_tests_properties(mitkPluginGeneratorConfigureTest-${config} PROPERTIES DEPENDS mitkPluginGeneratorCreateTest LABELS "MITK;BlueBerry") add_test(NAME mitkPluginGeneratorBuildTest-${config} CONFIGURATIONS ${config} COMMAND ${CMAKE_COMMAND} --build ${test_project_binary_dir} --config ${config}) set_tests_properties(mitkPluginGeneratorBuildTest-${config} PROPERTIES DEPENDS mitkPluginGeneratorConfigureTest-${config} LABELS "MITK;BlueBerry") endforeach() else() add_test(NAME mitkPluginGeneratorConfigureTest-${CMAKE_BUILD_TYPE} WORKING_DIRECTORY "${test_project_binary_dir}" COMMAND ${CMAKE_COMMAND} ${configure_options} -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} "${test_project_source_dir}") set_tests_properties(mitkPluginGeneratorConfigureTest-${CMAKE_BUILD_TYPE} PROPERTIES DEPENDS mitkPluginGeneratorCreateTest LABELS "MITK;BlueBerry") add_test(NAME mitkPluginGeneratorBuildTest-${CMAKE_BUILD_TYPE} COMMAND ${CMAKE_COMMAND} --build ${test_project_binary_dir} --config ${CMAKE_BUILD_TYPE}) set_tests_properties(mitkPluginGeneratorBuildTest-${CMAKE_BUILD_TYPE} PROPERTIES DEPENDS mitkPluginGeneratorConfigureTest-${CMAKE_BUILD_TYPE} LABELS "MITK;BlueBerry") endif() set(package_test_configurations) if(WIN32) # Only test packaging if build type is "Release" on Windows set(package_test_configurations CONFIGURATIONS Release) endif() if(NOT MITK_FAST_TESTING) if(WIN32) # Only test packaging if build type is "Release" on Windows add_test(NAME mitkPluginGeneratorPackageTest CONFIGURATIONS Release COMMAND ${CMAKE_COMMAND} --build ${test_project_binary_dir}/${proj}-build --config Release --target package) set_tests_properties(mitkPluginGeneratorPackageTest PROPERTIES DEPENDS mitkPluginGeneratorBuildTest-Release TIMEOUT 6000 LABELS "MITK;BlueBerry;PACKAGE_TESTS") elseif(CMAKE_BUILD_TYPE) add_test(mitkPluginGeneratorPackageTest ${CMAKE_COMMAND} --build ${test_project_binary_dir}/${proj}-build --config ${CMAKE_BUILD_TYPE} --target package) set_tests_properties(mitkPluginGeneratorPackageTest PROPERTIES DEPENDS mitkPluginGeneratorBuildTest-${CMAKE_BUILD_TYPE} TIMEOUT 6000 LABELS "MITK;BlueBerry;PACKAGE_TESTS") endif() endif() endif() diff --git a/CMakeExternals/Boost.cmake b/CMakeExternals/Boost.cmake index 581dc6ea93..76b7ff7aec 100644 --- a/CMakeExternals/Boost.cmake +++ b/CMakeExternals/Boost.cmake @@ -1,216 +1,216 @@ #----------------------------------------------------------------------------- # 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") 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) set(_boost_version 1_65_1) set(_boost_install_include_dir include/boost) if(WIN32) set(_boost_install_include_dir include/boost-${_boost_version}/boost) endif() set(_boost_libs ) set(_with_boost_libs ) set(_install_lib_dir ) # Set the boost root to the libraries install directory set(BOOST_ROOT "${ep_prefix}") if(MITK_USE_Boost_LIBRARIES) string(REPLACE ";" "," _boost_libs "${MITK_USE_Boost_LIBRARIES}") foreach(_boost_lib ${MITK_USE_Boost_LIBRARIES}) list(APPEND _with_boost_libs ${_with_boost_libs} --with-${_boost_lib}) endforeach() endif() if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_boost_address_model "address-model=64") else() set(_boost_address_model "address-model=32") endif() if(WIN32) set(_shell_extension .bat) set(_boost_layout) if(MSVC) mitkFunctionGetMSVCVersion() # Work around due to BOOST toolset limitations # Remove if task T24222 is fixed - if(${VISUAL_STUDIO_VERSION_MAJOR} EQUAL "14" AND ${VISUAL_STUDIO_VERSION_MINOR} GREATER "0") - set(VISUAL_STUDIO_VERSION_MINOR "1") - endif(${VISUAL_STUDIO_VERSION_MAJOR} EQUAL "14" AND ${VISUAL_STUDIO_VERSION_MINOR} GREATER "0") + if(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR GREATER 0) + set(VISUAL_STUDIO_VERSION_MINOR 1) + endif() # End Work around set(_boost_with_toolset "vc${VISUAL_STUDIO_VERSION_MAJOR}") if(${VISUAL_STUDIO_VERSION_MINOR}) set(_boost_with_toolset "${_boost_with_toolset}${VISUAL_STUDIO_VERSION_MINOR}") endif() set(_boost_toolset "msvc-${VISUAL_STUDIO_VERSION_MAJOR}.${VISUAL_STUDIO_VERSION_MINOR}") endif() set(_install_lib_dir "--libdir=/bin") set(WIN32_CMAKE_SCRIPT ${ep_prefix}/src/${proj}-cmake/MoveBoostLibsToLibDirForWindows.cmake) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeExternals/MoveBoostLibsToLibDirForWindows.cmake.in ${WIN32_CMAKE_SCRIPT} @ONLY) set(_windows_move_libs_cmd COMMAND ${CMAKE_COMMAND} -P ${WIN32_CMAKE_SCRIPT}) else() set(_shell_extension .sh) set(_boost_layout "--layout=tagged") endif() if(UNIX AND NOT APPLE) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(_boost_with_toolset "gcc") elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(_boost_with_toolset "clang") else() message(FATAL_ERROR "Compiler '${CMAKE_CXX_COMPILER_ID}' not supported. Use GNU or Clang instead.") endif() get_filename_component(_cxx_compiler_name "${CMAKE_CXX_COMPILER}" NAME) string(REGEX MATCH "^[0-9]+\\.[0-9]+" _compiler_version "${CMAKE_CXX_COMPILER_VERSION}") if(_cxx_compiler_name MATCHES "${_compiler_version}") set(_boost_toolset "${_boost_with_toolset}-${_compiler_version}") endif() endif() if(_boost_toolset) set(_boost_toolset "--toolset=${_boost_toolset}") endif() set (APPLE_SYSROOT_FLAG) if(APPLE) set(APPLE_CMAKE_SCRIPT ${ep_prefix}/src/${proj}-cmake/ChangeBoostLibsInstallNameForMac.cmake) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeExternals/ChangeBoostLibsInstallNameForMac.cmake.in ${APPLE_CMAKE_SCRIPT} @ONLY) set(_macos_change_install_name_cmd COMMAND ${CMAKE_COMMAND} -P ${APPLE_CMAKE_SCRIPT}) # Set OSX_SYSROOT if (NOT ${CMAKE_OSX_SYSROOT} STREQUAL "") set (APPLE_SYSROOT_FLAG --sysroot=${CMAKE_OSX_SYSROOT}) endif() endif() set(_boost_variant "$<$:debug>$<$:release>") set(_boost_link shared) if(NOT BUILD_SHARED_LIBS) set(_boost_link static) endif() set(_boost_cxxflags ) if(CMAKE_CXX_FLAGS OR MITK_CXX14_FLAG) set(_boost_cxxflags "cxxflags=${MITK_CXX14_FLAG} ${CMAKE_CXX_FLAGS}") endif() set(_boost_linkflags ) if(BUILD_SHARED_LIBS AND _install_rpath_linkflag) set(_boost_linkflags "linkflags=${_install_rpath_linkflag}") endif() set(_build_cmd "/b2" ${APPLE_SYSROOT_FLAG} ${_boost_toolset} ${_boost_layout} "--prefix=" ${_install_lib_dir} ${_with_boost_libs} # Use the option below to view the shell commands (for debugging) #-d+4 variant=${_boost_variant} link=${_boost_link} ${_boost_cxxflags} ${_boost_linkflags} ${_boost_address_model} threading=multi runtime-link=shared # Some distributions site config breaks boost build # For example on Gentoo: http://stackoverflow.com/questions/23013433/how-to-install-modular-boost --ignore-site-config -q ) if(MITK_USE_Boost_LIBRARIES) set(_boost_build_cmd BUILD_COMMAND ${_build_cmd} install ${_macos_change_install_name_cmd} ${_windows_move_libs_cmd}) else() set(_boost_build_cmd BUILD_COMMAND ${CMAKE_COMMAND} -E echo "copying Boost headers..." COMMAND ${CMAKE_COMMAND} -E copy_directory "/boost" "/${_boost_install_include_dir}") endif() set(_boost_patch_cmd ) if(WIN32) if(MSVC) if(NOT (VISUAL_STUDIO_VERSION_MAJOR LESS 14)) set(_boost_patch_cmd PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/Boost.patch) endif() endif() endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/boost_${_boost_version}.7z URL_MD5 72ab92cb936f93d33b8b313aee2dd47a BINARY_DIR "${ep_prefix}/src/${proj}" ${_boost_patch_cmd} CONFIGURE_COMMAND "/bootstrap${_shell_extension}" --with-toolset=${_boost_with_toolset} --with-libraries=${_boost_libs} "--prefix=" ${_boost_build_cmd} INSTALL_COMMAND "" # done in BUILD_COMMAND DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} install_dir) if(WIN32) set(BOOST_LIBRARYDIR "${install_dir}/lib") endif() # Manual install commands (for a MITK super-build install) # until the Boost CMake system is used. # We just copy the include directory install(DIRECTORY "${install_dir}/${_boost_install_include_dir}" DESTINATION "include" COMPONENT dev ) if(MITK_USE_Boost_LIBRARIES) # Copy the boost libraries file(GLOB _boost_libs "${install_dir}/lib/libboost*.so*" "${install_dir}/lib/libboost*.dylib") install(FILES ${_boost_libs} DESTINATION "lib" COMPONENT runtime) file(GLOB _boost_libs "${install_dir}/bin/libboost*.dll") install(FILES ${_boost_libs} DESTINATION "bin" COMPONENT runtime) file(GLOB _boost_libs "${install_dir}/lib/libboost*.lib" "${install_dir}/lib/libboost*.a") install(FILES ${_boost_libs} DESTINATION "lib" COMPONENT dev) endif() else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/CTK.cmake b/CMakeExternals/CTK.cmake index 6614b6efd1..c1a3945745 100644 --- a/CMakeExternals/CTK.cmake +++ b/CMakeExternals/CTK.cmake @@ -1,103 +1,103 @@ #----------------------------------------------------------------------------- # CTK #----------------------------------------------------------------------------- if(MITK_USE_CTK) # Sanity checks if(DEFINED CTK_DIR AND NOT EXISTS ${CTK_DIR}) message(FATAL_ERROR "CTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj CTK) set(proj_DEPENDENCIES DCMTK) set(CTK_DEPENDS ${proj}) if(NOT DEFINED CTK_DIR) - set(revision_tag 0c2a619a) + set(revision_tag fc06bedc) # Revision currently points to commit in https://github.com/kislinsk/CTK.git set(ctk_optional_cache_args ) if(MITK_USE_Python) list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=ON -DCTK_ENABLE_Python_Wrapping:BOOL=ON -DCTK_APP_ctkSimplePythonShell:BOOL=ON -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} ) else() list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=OFF -DCTK_ENABLE_Python_Wrapping:BOOL=OFF -DCTK_APP_ctkSimplePythonShell:BOOL=OFF ) endif() if(NOT MITK_USE_Python) list(APPEND ctk_optional_cache_args -DDCMTK_CMAKE_DEBUG_POSTFIX:STRING=d ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND ctk_optional_cache_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() FOREACH(type RUNTIME ARCHIVE LIBRARY) IF(DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY) LIST(APPEND mitk_optional_cache_args -DCTK_PLUGIN_${type}_OUTPUT_DIRECTORY:PATH=${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}) ENDIF() ENDFOREACH() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/CTK_${revision_tag}.tar.gz - URL_MD5 e1f94ba0199eccf335ec2c2b48e155da + URL_MD5 c500f54dd6d2ce2803d705cbb663d2f2 # PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/CTK.patch UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${ctk_optional_cache_args} # The CTK PluginFramework cannot cope with # a non-empty CMAKE_DEBUG_POSTFIX for the plugin # libraries yet. -DCMAKE_DEBUG_POSTFIX:STRING= -DCTK_QT_VERSION:STRING=5 -DQt5_DIR=${Qt5_DIR} -DGit_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DCTK_LIB_CommandLineModules/Backend/LocalProcess:BOOL=ON -DCTK_LIB_CommandLineModules/Frontend/QtGui:BOOL=ON -DCTK_LIB_PluginFramework:BOOL=ON -DCTK_LIB_DICOM/Widgets:BOOL=ON -DCTK_LIB_XNAT/Core:BOOL=ON -DCTK_PLUGIN_org.commontk.eventadmin:BOOL=ON -DCTK_PLUGIN_org.commontk.configadmin:BOOL=ON -DCTK_USE_GIT_PROTOCOL:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} -DqRestAPI_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/qRestAPI_c5e4c2a7_patched.tar.gz -DPythonQt_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/PythonQt_e39be131.tar.gz # From https://github.com/kislinsk/PythonQt.git CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(CTK_DIR ${binary_dir}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/DCMQI.cmake b/CMakeExternals/DCMQI.cmake index 429e612dc0..b4740c5fb0 100644 --- a/CMakeExternals/DCMQI.cmake +++ b/CMakeExternals/DCMQI.cmake @@ -1,59 +1,59 @@ #----------------------------------------------------------------------------- # DCMQI #----------------------------------------------------------------------------- if(MITK_USE_DCMQI) # Sanity checks if(DEFINED DCMQI_DIR AND NOT EXISTS ${DCMQI_DIR}) message(FATAL_ERROR "DCMQI_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMQI) set(proj_DEPENDENCIES DCMTK ITK) set(DCMQI_DEPENDS ${proj}) if(NOT DEFINED DCMQI_DIR) set(additional_cmake_args) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} GIT_REPOSITORY https://github.com/nolden/dcmqi.git - GIT_TAG 8772b4e8d4babeb6e828b3fdb834cb9a4d1d7997 + GIT_TAG d067f81c8a8e43900b91861f771013406868672f UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} #-DCMAKE_INSTALL_PREFIX:PATH= -DBUILD_SHARED_LIBS:BOOL=ON -DDCMQI_BUILD_APPS:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} -DITK_DIR:PATH=${ITK_DIR} -DITK_NO_IO_FACTORY_REGISTER_MANAGER:BOOL=ON -DDCMQI_SUPERBUILD:BOOL=OFF -DDCMQI_CMAKE_CXX_STANDARD:STRING=14 CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(DCMQI_DIR ${binary_dir}) #set(${proj}_DIR ${ep_prefix}) #message(${proj}_DIR: ${${proj}_DIR}) #mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/DCMTK.cmake b/CMakeExternals/DCMTK.cmake index 76b0143a1e..54a10d3eac 100644 --- a/CMakeExternals/DCMTK.cmake +++ b/CMakeExternals/DCMTK.cmake @@ -1,64 +1,62 @@ #----------------------------------------------------------------------------- # DCMTK #----------------------------------------------------------------------------- if(MITK_USE_DCMTK) # Sanity checks if(DEFINED DCMTK_DIR AND NOT EXISTS ${DCMTK_DIR}) message(FATAL_ERROR "DCMTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMTK) set(proj_DEPENDENCIES ) set(DCMTK_DEPENDS ${proj}) if(NOT DEFINED DCMTK_DIR) if(DCMTK_DICOM_ROOT_ID) set(DCMTK_CXX_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") set(DCMTK_C_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") endif() set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - # specific version post-3.6.2 without the API change which breaks DCMQI - # 065a4b + 525490 - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmtk_2ceb446c.tar.gz - URL_MD5 a4802436feffdb135d7d1e1e8917d1fa + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmtk_29f9de10.tar.gz + URL_MD5 c4b13ef2e694f3b8c50d7181fc959f4a CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${additional_args} "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${DCMTK_CXX_FLAGS}" "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${DCMTK_C_FLAGS}" -DDCMTK_ENABLE_CXX11:BOOL=ON -DDCMTK_ENABLE_STL:BOOL=ON -DDCMTK_WITH_DOXYGEN:BOOL=OFF -DDCMTK_WITH_ZLIB:BOOL=OFF # see bug #9894 -DDCMTK_WITH_OPENSSL:BOOL=OFF # see bug #9894 -DDCMTK_WITH_PNG:BOOL=OFF # see bug #9894 -DDCMTK_WITH_TIFF:BOOL=OFF # see bug #9894 -DDCMTK_WITH_XML:BOOL=OFF # see bug #9894 -DDCMTK_WITH_ICONV:BOOL=OFF # see bug #9894 CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(DCMTK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/ITK-VNL-2018-05-16.patch b/CMakeExternals/ITK-VNL-2018-05-16.patch new file mode 100644 index 0000000000..4832f7f38d --- /dev/null +++ b/CMakeExternals/ITK-VNL-2018-05-16.patch @@ -0,0 +1,2048 @@ +diff --git a/Modules/ThirdParty/VNL/src/vxl/CMakeLists.txt b/Modules/ThirdParty/VNL/src/vxl/CMakeLists.txt +index 2b85b7bc79..4c66ee43b4 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/CMakeLists.txt ++++ b/Modules/ThirdParty/VNL/src/vxl/CMakeLists.txt +@@ -12,26 +12,51 @@ + # Root vxl + # + # vxl-maintainers@lists.sf.net +-cmake_minimum_required(VERSION 2.8.9 FATAL_ERROR) +- +-# Set policies for cmake +-if( POLICY CMP0003 ) +- cmake_policy(SET CMP0003 NEW) +-endif() +-# Use @rpath on OS X +-if( POLICY CMP0042 ) +- cmake_policy(SET CMP0042 NEW) ++if( "${CMAKE_CXX_STANDARD}" MATCHES "(11|14|17|20)") ++ # If building for modern C++ language standards, ++ # require use of newer cmake version ++ cmake_minimum_required(VERSION 3.9.5 FATAL_ERROR) ++else() ++ cmake_minimum_required(VERSION 3.3.0 FATAL_ERROR) + endif() ++# Set policies consistent with newer versions of cmake ++# to ease integration with projects that require newer ++# cmake versions. ++ ++foreach(p ++ ## Only policies introduced after the cmake_minimum_required ++ ## version need to explicitly be set to NEW. ++ ++ ##----- Policies Introduced by CMake 3.10¶ ++ CMP0071 #: Let AUTOMOC and AUTOUIC process GENERATED files. ++ CMP0070 #: Define file(GENERATE) behavior for relative paths. ++ ##----- Policies Introduced by CMake 3.9 ++ CMP0069 #: INTERPROCEDURAL_OPTIMIZATION is enforced when enabled. ++ CMP0068 #: RPATH settings on macOS do not affect install_name. ++ ##----- Policies Introduced by CMake 3.8 ++ CMP0067 #: Honor language standard in try_compile() source-file signature. ++ ##----- Policies Introduced by CMake 3.7 ++ CMP0066 #: Honor per-config flags in try_compile() source-file signature. ++ ##----- Policies Introduced by CMake 3.4 ++ CMP0065 #: Do not add flags to export symbols from executables without the ENABLE_EXPORTS target property. ++ CMP0064 #: Support new TEST if() operator. ++ ) ++ if(POLICY ${p}) ++ cmake_policy(SET ${p} NEW) ++ endif() ++endforeach() + +-# Honor visibility properties for static libraries +-if( POLICY CMP0063 ) +- cmake_policy(SET CMP0063 NEW) +-endif() + + project(vxl) + + include(CMakeDependentOption) + ++#Disable overzealous compiler warning. If the definition is truely missing a link error will be created. ++include(CheckCXXCompilerFlag) ++CHECK_CXX_COMPILER_FLAG(-Wno-undefined-var-template HAS_NO_UNDEFINED_VAR_TEMPLATE) ++if( HAS_NO_UNDEFINED_VAR_TEMPLATE ) ++ add_definitions( -Wno-undefined-var-template ) ++endif() + + find_program( MEMORYCHECK_COMMAND valgrind ) + if(MEMORYCHECK_COMMAND) +@@ -113,6 +138,7 @@ option(VXL_LEGACY_ERROR_REPORTING "Use old error reporting methods rather than e + if(VXL_LEGACY_ERROR_REPORTING) + add_definitions( -DVXL_LEGACY_ERROR_REPORTING ) + endif() ++option(VXL_RUN_FAILING_TESTS "Enable long-time failing tests. If tests are failing for a long time, turn them off by default." OFF) + + # Option to build Windows Unicode support, the string + # type of which is wchar_t, each character is a 16-bit unsigned integer. +@@ -232,7 +258,7 @@ add_subdirectory(core) + + # Optionally build the contributed libraries + if( EXISTS ${CMAKE_CURRENT_LIST_DIR}/contrib/CMakeLists.txt ) +- CMAKE_DEPENDENT_OPTION(BUILD_CONTRIB "Build the contributed libraries?" ON "BUILD_CORE_GEOMETRY;BUILD_CORE_NUMERICS;BUILD_CORE_UTILITIES;BUILD_CORE_SERIALISATION;BUILD_CORE_IMAGING" OFF) ++ CMAKE_DEPENDENT_OPTION(BUILD_CONTRIB "Build the contributed libraries?" OFF "BUILD_CORE_GEOMETRY;BUILD_CORE_NUMERICS;BUILD_CORE_UTILITIES;BUILD_CORE_SERIALISATION;BUILD_CORE_IMAGING" OFF) + add_subdirectory(contrib) + endif() + +diff --git a/Modules/ThirdParty/VNL/src/vxl/CTestConfig.cmake b/Modules/ThirdParty/VNL/src/vxl/CTestConfig.cmake +deleted file mode 100644 +index f2620f7bf6..0000000000 +--- a/Modules/ThirdParty/VNL/src/vxl/CTestConfig.cmake ++++ /dev/null +@@ -1,8 +0,0 @@ +-# CTest Configuration for VXL +-set(CTEST_PROJECT_NAME "VXL") +-set(CTEST_NIGHTLY_START_TIME "22:00:00 EST") +- +-set(CTEST_DROP_METHOD "http") +-set(CTEST_DROP_SITE "open.cdash.org") +-set(CTEST_DROP_LOCATION "/submit.php?project=vxl") +-set(CTEST_DROP_SITE_CDASH TRUE) +diff --git a/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/FindClipper.cmake b/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/FindClipper.cmake +new file mode 100644 +index 0000000000..ad941254ff +--- /dev/null ++++ b/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/FindClipper.cmake +@@ -0,0 +1,41 @@ ++# ++# Find a CLIPPER library ++# ++# This file is used to manage using either a natively provided CLIPPER library or the one in v3p if provided. ++# ++# ++# As per the standard scheme the following definitions are used ++# CLIPPER_INCLUDE_DIR - where to find clipper.hxx ++# CLIPPER_LIBRARIES - the set of libraries to include to use CLIPPER. ++# CLIPPER_FOUND - TRUE, if available somewhere on the system. ++ ++# Additionally ++# VXL_USING_NATIVE_CLIPPER - True if we are using a CLIPPER library provided outside vxl (or v3p) ++ ++if( NOT CLIPPER_FOUND ) ++ ++ # If this FORCE variable is unset or is FALSE, try to find a native library. ++ if( NOT VXL_FORCE_V3P_CLIPPER ) ++ # ./FindGEOTIFF.cmake does this instead... ++ #include( ${MODULE_PATH}/NewCMake/FindGEOTIFF.cmake ) ++ find_package( CLIPPER QUIET ) ++ if( CLIPPER_FOUND ) ++ set(VXL_USING_NATIVE_CLIPPER "YES") ++ endif() ++ endif() ++ ++ # ++ # At some point, in a "release" version, it is possible that someone ++ # will not have the v3p clipper library, so make sure the headers ++ # exist. ++ # ++ if( NOT CLIPPER_FOUND ) ++ if(EXISTS ${VXL_ROOT_SOURCE_DIR}/v3p/clipper/clipper.h) ++ set( CLIPPER_FOUND "YES" ) ++ set( CLIPPER_INCLUDE_DIR ${clipper_BINARY_DIR} ${clipper_SOURCE_DIR}) ++ set( CLIPPER_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_DIR}/include/vxl/v3p/clipper) ++ set( CLIPPER_LIBRARIES clipper ) ++ endif() ++ endif() ++ ++endif() +diff --git a/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/NewCMake/FindOpenCL.cmake b/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/NewCMake/FindOpenCL.cmake +index 69e9ea9371..9ba8283a63 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/NewCMake/FindOpenCL.cmake ++++ b/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/NewCMake/FindOpenCL.cmake +@@ -69,9 +69,11 @@ if(APPLE) + endif() + + if(UNIX) +- find_path( OPENCL_INCLUDE_PATH CL/cl_gl.h PATHS /usr/include /usr/include/nvidia-current /usr/local/cuda/include) +- find_path(OPENCL_LIBRARY_PATH libOpenCL.so PATHS /usr/lib /usr/lib/nvidia-current /usr/local/cuda/lib64 ${OPENCL_LIBRARY_PATH} ) +- find_library(OPENCL_LIBRARIES NAMES libOpenCL.so PATHS /usr/lib /usr/lib/nvidia-current ${OPENCL_LIBRARY_PATH} ) ++ file(GLOB AMD_DIR /opt/AMDAPPSDK-*/include) ++ find_path( OPENCL_INCLUDE_PATH CL/cl_gl.h PATHS /usr/include /usr/include/nvidia-current /usr/local/cuda/include HINTS ${AMD_DIR}) ++ file(GLOB AMD_DIR /opt/AMDAPPSDK-*/lib/x86_64/sdk /opt/AMDAPPSDK-*/lib/x86_64) ++ find_path(OPENCL_LIBRARY_PATH libOpenCL.so PATHS /usr/lib /usr/lib64 /usr/lib/nvidia-current /usr/local/cuda/lib64 ${OPENCL_LIBRARY_PATH} HINTS ${AMD_DIR} ) ++ find_library(OPENCL_LIBRARIES NAMES libOpenCL.so PATHS /usr/lib /usr/lib64 /usr/lib/nvidia-current ${OPENCL_LIBRARY_PATH} ) + if(OPENCL_INCLUDE_PATH) + if(OPENCL_LIBRARIES) + set(OPENCL_FOUND "YES") +diff --git a/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/NewCMake/readme.txt b/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/NewCMake/readme.txt +index b69c359257..9387e9b15c 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/NewCMake/readme.txt ++++ b/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/NewCMake/readme.txt +@@ -5,9 +5,9 @@ To facilitate the deprecation of modules, place code similar to the + following in the FindXXX.cmake as soon as it becomes part of a CMake + release: + +-# FIXME: When cmake_minimum_version reaches 2.6.2 the FindXXX ++# FIXME: When cmake_minimum_version reaches 3.3.0 the FindXXX + # module in this directory is not needed anymore. +-IF(CMAKE_MINIMUM_REQUIRED_VERSION GREATER 2.6.1) ++IF(CMAKE_MINIMUM_REQUIRED_VERSION GREATER 3.3.0) + MESSAGE(FATAL_ERROR + "FindXXX not needed in vxl; it is now available in CMake.") +-ENDIF(CMAKE_MINIMUM_REQUIRED_VERSION GREATER 2.6.1) ++ENDIF(CMAKE_MINIMUM_REQUIRED_VERSION GREATER 3.3.0) +diff --git a/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/VXLGenerateExportHeader.cmake b/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/VXLGenerateExportHeader.cmake +index b0d7dd49cd..ad54658342 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/VXLGenerateExportHeader.cmake ++++ b/Modules/ThirdParty/VNL/src/vxl/config/cmake/Modules/VXLGenerateExportHeader.cmake +@@ -1,13 +1,5 @@ +-# This version of GenerateExportHeader extends CMake's version to provide the +-# _TEMPLATE_EXPORT macro. For templated class declarations, Windows +-# must not have the export specification, while GCC must have the export +-# specification. +-# +-# This macro is for templates with explicit instantiations built into a library. +-# +-# To avoid inadvertently overriding CMake's or another package's +-# GenerateExportHeader, this version is named differently and adds a prefix to +-# all global identifiers. ++# Distributed under the OSI-approved BSD 3-Clause License. See accompanying ++# file Copyright.txt or https://cmake.org/licensing for details. + + #.rst: + # VXLGenerateExportHeader +@@ -28,10 +20,12 @@ + # [EXPORT_FILE_NAME ] + # [DEPRECATED_MACRO_NAME ] + # [NO_EXPORT_MACRO_NAME ] ++# [INCLUDE_GUARD_NAME ] + # [STATIC_DEFINE ] + # [NO_DEPRECATED_MACRO_NAME ] + # [DEFINE_NO_DEPRECATED] + # [PREFIX_NAME ] ++# [CUSTOM_CONTENT_FROM_VARIABLE ] + # ) + # + # +@@ -71,9 +65,10 @@ + # + # The CMake fragment will generate a file in the + # ``${CMAKE_CURRENT_BINARY_DIR}`` called ``somelib_export.h`` containing the +-# macros ``SOMELIB_EXPORT``, ``SOMELIB_TEMPLATE_EXPORT``, ``SOMELIB_NO_EXPORT``, +-# ``SOMELIB_DEPRECATED``, ``SOMELIB_DEPRECATED_EXPORT`` and +-# ``SOMELIB_DEPRECATED_NO_EXPORT``. ++# macros ``SOMELIB_EXPORT``, ``SOMELIB_NO_EXPORT``, ``SOMELIB_DEPRECATED``, ++# ``SOMELIB_DEPRECATED_EXPORT`` and ``SOMELIB_DEPRECATED_NO_EXPORT``. ++# They will be followed by content taken from the variable specified by ++# the ``CUSTOM_CONTENT_FROM_VARIABLE`` option, if any. + # The resulting file should be installed with other headers in the library. + # + # The ``BASE_NAME`` argument can be used to override the file name and the +@@ -91,7 +86,7 @@ + # ``OTHER_NAME_EXPORT``, ``OTHER_NAME_NO_EXPORT`` and ``OTHER_NAME_DEPRECATED`` + # etc. + # +-# The ``BASE_NAME`` may be overridden by specifiying other options in the ++# The ``BASE_NAME`` may be overridden by specifying other options in the + # function. For example: + # + # .. code-block:: cmake +@@ -191,19 +186,6 @@ + # :prop_tgt:`CXX_VISIBILITY_PRESET <_VISIBILITY_PRESET>` and + # :prop_tgt:`VISIBILITY_INLINES_HIDDEN` instead. + +-#============================================================================= +-# Copyright 2011 Stephen Kelly +-# +-# Distributed under the OSI-approved BSD License (the "License"); +-# see accompanying file Copyright.txt for details. +-# +-# This software is distributed WITHOUT ANY WARRANTY; without even the +-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-# See the License for more information. +-#============================================================================= +-# (To distribute this file outside of CMake, substitute the full +-# License text for the above reference.) +- + include(CMakeParseArguments) + include(CheckCXXCompilerFlag) + +@@ -218,7 +200,7 @@ macro(_vxl_test_compiler_hidden_visibility) + + if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.2") + set(GCC_TOO_OLD TRUE) +- elseif(CMAKE_COMPILER_IS_GNUC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.2") ++ elseif(CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.2") + set(GCC_TOO_OLD TRUE) + elseif(CMAKE_CXX_COMPILER_ID MATCHES Intel AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0") + set(_INTEL_TOO_OLD TRUE) +@@ -236,14 +218,15 @@ macro(_vxl_test_compiler_hidden_visibility) + check_cxx_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) + check_cxx_compiler_flag(-fvisibility-inlines-hidden + COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) +- option(USE_COMPILER_HIDDEN_VISIBILITY +- "Use HIDDEN visibility support if available." ON) +- mark_as_advanced(USE_COMPILER_HIDDEN_VISIBILITY) + endif() + endmacro() + + macro(_vxl_test_compiler_has_deprecated) ++ # NOTE: Some Embarcadero compilers silently compile __declspec(deprecated) ++ # without error, but this is not a documented feature and the attribute does ++ # not actually generate any warnings. + if(CMAKE_CXX_COMPILER_ID MATCHES Borland ++ OR CMAKE_CXX_COMPILER_ID MATCHES Embarcadero + OR CMAKE_CXX_COMPILER_ID MATCHES HP + OR GCC_TOO_OLD + OR CMAKE_CXX_COMPILER_ID MATCHES PGI +@@ -270,8 +253,6 @@ macro(_VXL_DO_SET_MACRO_VALUES TARGET_LIBRARY) + set(DEFINE_DEPRECATED) + set(DEFINE_EXPORT) + set(DEFINE_IMPORT) +- set(DEFINE_TEMPLATE_EXPORT) +- set(DEFINE_TEMPLATE_IMPORT) + set(DEFINE_NO_EXPORT) + + if (COMPILER_HAS_DEPRECATED_ATTR) +@@ -288,12 +269,12 @@ macro(_VXL_DO_SET_MACRO_VALUES TARGET_LIBRARY) + set(DEFINE_IMPORT "__declspec(dllimport)") + set(DEFINE_TEMPLATE_EXPORT) + set(DEFINE_TEMPLATE_IMPORT) +- elseif(COMPILER_HAS_HIDDEN_VISIBILITY AND USE_COMPILER_HIDDEN_VISIBILITY) ++ elseif(COMPILER_HAS_HIDDEN_VISIBILITY) + set(DEFINE_EXPORT "__attribute__((visibility(\"default\")))") + set(DEFINE_IMPORT "__attribute__((visibility(\"default\")))") ++ set(DEFINE_NO_EXPORT "__attribute__((visibility(\"hidden\")))") + set(DEFINE_TEMPLATE_EXPORT "${DEFINE_EXPORT}") + set(DEFINE_TEMPLATE_IMPORT "${DEFINE_IMPORT}") +- set(DEFINE_NO_EXPORT "__attribute__((visibility(\"hidden\")))") + endif() + endif() + endmacro() +@@ -301,10 +282,10 @@ endmacro() + macro(_VXL_DO_GENERATE_EXPORT_HEADER TARGET_LIBRARY) + # Option overrides + set(options DEFINE_NO_DEPRECATED) +- set(oneValueArgs PREFIX_NAME BASE_NAME EXPORT_MACRO_NAME +- TEMPLATE_EXPORT_MACRO_NAME EXPORT_FILE_NAME ++ set(oneValueArgs PREFIX_NAME BASE_NAME EXPORT_MACRO_NAME EXPORT_FILE_NAME ++ TEMPLATE_EXPORT_MACRO_NAME + DEPRECATED_MACRO_NAME NO_EXPORT_MACRO_NAME STATIC_DEFINE +- NO_DEPRECATED_MACRO_NAME) ++ NO_DEPRECATED_MACRO_NAME CUSTOM_CONTENT_FROM_VARIABLE INCLUDE_GUARD_NAME) + set(multiValueArgs) + + cmake_parse_arguments(_GEH "${options}" "${oneValueArgs}" "${multiValueArgs}" +@@ -339,9 +320,7 @@ macro(_VXL_DO_GENERATE_EXPORT_HEADER TARGET_LIBRARY) + if(_GEH_TEMPLATE_EXPORT_MACRO_NAME) + set(TEMPLATE_EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_TEMPLATE_EXPORT_MACRO_NAME}) + endif() +- if(NOT CMAKE_VERSION VERSION_LESS 2.8.12) +- string(MAKE_C_IDENTIFIER ${EXPORT_MACRO_NAME} EXPORT_MACRO_NAME) +- endif() ++ string(MAKE_C_IDENTIFIER ${EXPORT_MACRO_NAME} EXPORT_MACRO_NAME) + if(_GEH_EXPORT_FILE_NAME) + if(IS_ABSOLUTE ${_GEH_EXPORT_FILE_NAME}) + set(EXPORT_FILE_NAME ${_GEH_EXPORT_FILE_NAME}) +@@ -352,43 +331,47 @@ macro(_VXL_DO_GENERATE_EXPORT_HEADER TARGET_LIBRARY) + if(_GEH_DEPRECATED_MACRO_NAME) + set(DEPRECATED_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_DEPRECATED_MACRO_NAME}) + endif() +- if(NOT CMAKE_VERSION VERSION_LESS 2.8.12) +- string(MAKE_C_IDENTIFIER ${DEPRECATED_MACRO_NAME} DEPRECATED_MACRO_NAME) +- endif() ++ string(MAKE_C_IDENTIFIER ${DEPRECATED_MACRO_NAME} DEPRECATED_MACRO_NAME) + if(_GEH_NO_EXPORT_MACRO_NAME) + set(NO_EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_NO_EXPORT_MACRO_NAME}) + endif() +- if(NOT CMAKE_VERSION VERSION_LESS 2.8.12) +- string(MAKE_C_IDENTIFIER ${NO_EXPORT_MACRO_NAME} NO_EXPORT_MACRO_NAME) +- endif() ++ string(MAKE_C_IDENTIFIER ${NO_EXPORT_MACRO_NAME} NO_EXPORT_MACRO_NAME) + if(_GEH_STATIC_DEFINE) + set(STATIC_DEFINE ${_GEH_PREFIX_NAME}${_GEH_STATIC_DEFINE}) + endif() +- if(NOT CMAKE_VERSION VERSION_LESS 2.8.12) +- string(MAKE_C_IDENTIFIER ${STATIC_DEFINE} STATIC_DEFINE) +- endif() ++ string(MAKE_C_IDENTIFIER ${STATIC_DEFINE} STATIC_DEFINE) + + if(_GEH_DEFINE_NO_DEPRECATED) +- set(DEFINE_NO_DEPRECATED TRUE) ++ set(DEFINE_NO_DEPRECATED 1) ++ else() ++ set(DEFINE_NO_DEPRECATED 0) + endif() + + if(_GEH_NO_DEPRECATED_MACRO_NAME) + set(NO_DEPRECATED_MACRO_NAME + ${_GEH_PREFIX_NAME}${_GEH_NO_DEPRECATED_MACRO_NAME}) + endif() +- if(NOT CMAKE_VERSION VERSION_LESS 2.8.12) +- string(MAKE_C_IDENTIFIER ${NO_DEPRECATED_MACRO_NAME} NO_DEPRECATED_MACRO_NAME) +- endif() ++ string(MAKE_C_IDENTIFIER ${NO_DEPRECATED_MACRO_NAME} NO_DEPRECATED_MACRO_NAME) + +- set(INCLUDE_GUARD_NAME "${EXPORT_MACRO_NAME}_H") ++ if(_GEH_INCLUDE_GUARD_NAME) ++ set(INCLUDE_GUARD_NAME ${_GEH_INCLUDE_GUARD_NAME}) ++ else() ++ set(INCLUDE_GUARD_NAME "${EXPORT_MACRO_NAME}_H") ++ endif() + + get_target_property(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY} DEFINE_SYMBOL) + + if(NOT EXPORT_IMPORT_CONDITION) + set(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY}_EXPORTS) + endif() +- if(NOT CMAKE_VERSION VERSION_LESS 2.8.12) +- string(MAKE_C_IDENTIFIER ${EXPORT_IMPORT_CONDITION} EXPORT_IMPORT_CONDITION) ++ string(MAKE_C_IDENTIFIER ${EXPORT_IMPORT_CONDITION} EXPORT_IMPORT_CONDITION) ++ ++ if(_GEH_CUSTOM_CONTENT_FROM_VARIABLE) ++ if(DEFINED "${_GEH_CUSTOM_CONTENT_FROM_VARIABLE}") ++ set(CUSTOM_CONTENT "${${_GEH_CUSTOM_CONTENT_FROM_VARIABLE}}") ++ else() ++ set(CUSTOM_CONTENT "") ++ endif() + endif() + + configure_file("${_VXL_GENERATE_EXPORT_HEADER_MODULE_DIR}/vxlexportheader.cmake.in" +@@ -418,6 +401,9 @@ function(vxl_add_compiler_export_flags) + _vxl_test_compiler_hidden_visibility() + _vxl_test_compiler_has_deprecated() + ++ option(USE_COMPILER_HIDDEN_VISIBILITY ++ "Use HIDDEN visibility support if available." ON) ++ mark_as_advanced(USE_COMPILER_HIDDEN_VISIBILITY) + if(NOT (USE_COMPILER_HIDDEN_VISIBILITY AND COMPILER_HAS_HIDDEN_VISIBILITY)) + # Just return if there are no flags to add. + return() +@@ -434,6 +420,7 @@ function(vxl_add_compiler_export_flags) + if(ARGC GREATER 0) + set(${ARGV0} "${EXTRA_FLAGS}" PARENT_SCOPE) + else() +- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_FLAGS}" PARENT_SCOPE) ++ string(APPEND CMAKE_CXX_FLAGS " ${EXTRA_FLAGS}") ++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE) + endif() + endfunction() +diff --git a/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/VXLIntrospectionConfig.cmake b/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/VXLIntrospectionConfig.cmake +index a921edcf51..1d1ebc6e72 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/VXLIntrospectionConfig.cmake ++++ b/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/VXLIntrospectionConfig.cmake +@@ -752,11 +752,10 @@ if(NOT VCL_CXX_HAS_HEADER_LIMITS) + message(FATAL_ERROR "Compiler is required to have limits.h") + else() + PERFORM_CMAKE_TEST_RUN(${VXL_PLFM_TEST_FILE} VCL_NUMERIC_LIMITS_HAS_INFINITY) +- # ITK does not require has_infinity +- #if(NOT VCL_NUMERIC_LIMITS_HAS_INFINITY) +- #message(FATAL_ERROR "Compiler is required to have has_infinity.") +- #endif() +- #unset(VCL_NUMERIC_LIMITS_HAS_INFINITY) ++ if(NOT VCL_NUMERIC_LIMITS_HAS_INFINITY) ++ message(FATAL_ERROR "Compiler is required to have has_infinity.") ++ endif() ++ unset(VCL_NUMERIC_LIMITS_HAS_INFINITY) + endif() + unset(VCL_CXX_HAS_HEADER_LIMITS) + +diff --git a/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/vxl_shared_link_test/CMakeLists.txt b/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/vxl_shared_link_test/CMakeLists.txt +index 7b6e95b121..f2133fdffd 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/vxl_shared_link_test/CMakeLists.txt ++++ b/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/vxl_shared_link_test/CMakeLists.txt +@@ -1,12 +1,32 @@ + # vxl/config/cmake/config/vxl_shared_link_test/CMakeLists.txt + # +-cmake_minimum_required(VERSION 2.8.9 FATAL_ERROR) +-if(POLICY CMP0025) +- cmake_policy(SET CMP0025 NEW) +-endif() +-if(POLICY CMP0042) +- cmake_policy(SET CMP0042 NEW) +-endif() ++cmake_minimum_required(VERSION 3.3.0 FATAL_ERROR) ++# Set policies consistent with newer versions of cmake ++# to ease integration with projects that require newer ++# cmake versions. ++ ++foreach(p ++ ## Only policies introduced after the cmake_minimum_required ++ ## version need to explicitly be set to NEW. ++ ++ ##----- Policies Introduced by CMake 3.10¶ ++ CMP0071 #: Let AUTOMOC and AUTOUIC process GENERATED files. ++ CMP0070 #: Define file(GENERATE) behavior for relative paths. ++ ##----- Policies Introduced by CMake 3.9 ++ CMP0069 #: INTERPROCEDURAL_OPTIMIZATION is enforced when enabled. ++ CMP0068 #: RPATH settings on macOS do not affect install_name. ++ ##----- Policies Introduced by CMake 3.8 ++ CMP0067 #: Honor language standard in try_compile() source-file signature. ++ ##----- Policies Introduced by CMake 3.7 ++ CMP0066 #: Honor per-config flags in try_compile() source-file signature. ++ ##----- Policies Introduced by CMake 3.4 ++ CMP0065 #: Do not add flags to export symbols from executables without the ENABLE_EXPORTS target property. ++ CMP0064 #: Support new TEST if() operator. ++ ) ++ if(POLICY ${p}) ++ cmake_policy(SET ${p} NEW) ++ endif() ++endforeach() + project(vxl_pic_compatible) + + add_library(cmTryCompileStaticLib STATIC static_src.cxx) +diff --git a/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/vxl_utils.cmake b/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/vxl_utils.cmake +index 3ae1f1c166..6222df72fe 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/vxl_utils.cmake ++++ b/Modules/ThirdParty/VNL/src/vxl/config/cmake/config/vxl_utils.cmake +@@ -112,27 +112,21 @@ macro( vxl_add_library ) + if("${VXL_INSTALL_INCLUDE_DIR}" STREQUAL "include/vxl") + ## Identify the relative path for installing the header files and txx files + string(REPLACE ${VXL_ROOT_SOURCE_DIR} "${VXL_INSTALL_INCLUDE_DIR}" relative_install_path ${CMAKE_CURRENT_SOURCE_DIR}) +- ## Added in 2.8.11 http://stackoverflow.com/questions/19460707/how-to-set-include-directories-from-a-cmakelists-txt-file +- if(${CMAKE_VERSION} VERSION_GREATER 2.8.11.2) +- target_include_directories(${lib_name} +- PUBLIC +- $ +- $ +- ) +- endif() ++ target_include_directories(${lib_name} ++ PUBLIC ++ $ ++ $ ++ ) + else() + set(relative_install_path "${VXL_INSTALL_INCLUDE_DIR}") + if(DEFINED header_install_dir) + set(relative_install_path "${relative_install_path}/${header_install_dir}") + endif() +- ## Added in 2.8.11 http://stackoverflow.com/questions/19460707/how-to-set-include-directories-from-a-cmakelists-txt-file +- if(${CMAKE_VERSION} VERSION_GREATER 2.8.11.2) +- target_include_directories(${lib_name} +- PUBLIC +- $ +- $ +- ) +- endif() ++ target_include_directories(${lib_name} ++ PUBLIC ++ $ ++ $ ++ ) + endif() + INSTALL_NOBASE_HEADER_FILES(${relative_install_path} ${lib_srcs}) + endif() +@@ -181,23 +175,14 @@ macro(SET_VXL_LIBRARY_PROPERTIES) + message(FATAL_ERROR "INSTALL_DIR REQUIRED when using USE_HIDDEN_VISIBILITY") + endif() + +- if (BUILD_SHARED_LIBS OR (APPLE AND NOT BUILD_SHARED_LIBS)) ++ if (BUILD_SHARED_LIBS OR (APPLE AND NOT BUILD_SHARED_LIBS) ) #APPLE Respects hidden visibility for static builds + # export flags are only added when building shared libs, they cause + # mismatched visibility warnings when building statically. +- if(CMAKE_VERSION VERSION_LESS 2.8.12) +- # future DEPRECATION notice from cmake: +- # "The add_compiler_export_flags function is obsolete. +- # Use the CXX_VISIBILITY_PRESET and VISIBILITY_INLINES_HIDDEN +- # target properties instead." +- add_compiler_export_flags(my_abi_flags) +- set_property(TARGET ${LSLHVP_TARGET_NAME} APPEND PROPERTY COMPILE_FLAGS "${my_abi_flags}") +- else() +- if (USE_COMPILER_HIDDEN_VISIBILITY) +- # Prefer to use target properties supported by newer cmake +- set_target_properties(${LSLHVP_TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) +- set_target_properties(${LSLHVP_TARGET_NAME} PROPERTIES C_VISIBILITY_PRESET hidden) +- set_target_properties(${LSLHVP_TARGET_NAME} PROPERTIES VISIBILITY_INLINES_HIDDEN 1) +- endif() ++ if (USE_COMPILER_HIDDEN_VISIBILITY) ++ # Prefer to use target properties supported by newer cmake ++ set_target_properties(${LSLHVP_TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) ++ set_target_properties(${LSLHVP_TARGET_NAME} PROPERTIES C_VISIBILITY_PRESET hidden) ++ set_target_properties(${LSLHVP_TARGET_NAME} PROPERTIES VISIBILITY_INLINES_HIDDEN 1) + endif() + endif() + endif() +diff --git a/Modules/ThirdParty/VNL/src/vxl/config/cmake/export/VXLCreateProject.cmake b/Modules/ThirdParty/VNL/src/vxl/config/cmake/export/VXLCreateProject.cmake +index b2e8c964a9..e0142c79ca 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/config/cmake/export/VXLCreateProject.cmake ++++ b/Modules/ThirdParty/VNL/src/vxl/config/cmake/export/VXLCreateProject.cmake +@@ -22,11 +22,7 @@ set(VXL_CMAKE_DOXYGEN_DIR ${VXL_ROOT_SOURCE_DIR}/config/cmake/doxygen) + get_property(VXLTargets_MODULES GLOBAL PROPERTY VXLTargets_MODULES) + + set(VXL_CONFIG_CMAKE_DIR "share/vxl/cmake") +-if(${CMAKE_VERSION} VERSION_LESS 2.8.12) +- set(INTERFACE_LINK_OPTION "") +-else() +- set(INTERFACE_LINK_OPTION "EXPORT_LINK_INTERFACE_LIBRARIES") +-endif() ++set(INTERFACE_LINK_OPTION "EXPORT_LINK_INTERFACE_LIBRARIES") + + if(VXLTargets_MODULES) + export(TARGETS +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/CMakeLists.txt b/Modules/ThirdParty/VNL/src/vxl/core/CMakeLists.txt +index 78a984911b..b6af7c2591 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/CMakeLists.txt ++++ b/Modules/ThirdParty/VNL/src/vxl/core/CMakeLists.txt +@@ -9,12 +9,6 @@ doxygen_add_package(core-L2 "Level-2 Vision Libraries") + doxygen_add_package(core-L2E "Level-2 Vision Libraries (Experimental)") + doxygen_add_package(core-test "Test Framework") + +-# +-# Do platform-specific configuration. +-# configure files +-# +-vxl_configure_file(${CMAKE_CURRENT_LIST_DIR}/vxl_config.h.in ${PROJECT_BINARY_DIR}/vxl_config.h ${VXL_INSTALL_INCLUDE_DIR}) +-include_directories(${PROJECT_BINARY_DIR}) + + set(global_sources + vxl_copyright.h +@@ -28,6 +22,13 @@ else() + endif() + INSTALL_NOBASE_HEADER_FILES(${prefix} ${global_sources}) + ++# ++# Do platform-specific configuration. ++# configure files ++# ++vxl_configure_file(${CMAKE_CURRENT_LIST_DIR}/vxl_config.h.in ${PROJECT_BINARY_DIR}/vxl_config.h ${prefix}) ++include_directories(${PROJECT_BINARY_DIR}) ++ + if(BUILD_CORE_UTILITIES) + # POSIX layer + add_subdirectory(vpl) +@@ -122,7 +123,7 @@ endif() + + + # video +-CMAKE_DEPENDENT_OPTION (BUILD_CORE_VIDEO "Build VXL's core video libraries" ON ++CMAKE_DEPENDENT_OPTION (BUILD_CORE_VIDEO "Build VXL's core video libraries" OFF + "BUILD_CORE_UTILITIES;BUILD_CORE_IMAGING" OFF) + if (BUILD_CORE_VIDEO) + add_subdirectory(vidl) +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/CMakeLists.txt b/Modules/ThirdParty/VNL/src/vxl/core/vnl/CMakeLists.txt +index a48b5640bf..59231aa70f 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/CMakeLists.txt ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/CMakeLists.txt +@@ -24,6 +24,10 @@ option(VNL_CONFIG_THREAD_SAFE + option(VNL_CONFIG_ENABLE_SSE2 + "Enable Streaming SIMD Extensions 2 optimisations (hardware dependant). Currently broken. For use by VNL developers only." OFF) + #endif() ++if(VNL_CONFIG_ENABLE_SSE2) ++ # Tested on ubuntu and Mac. ctest becomes unstable and failures change between runs. ++ message(FATAL_ERROR "VNL_CONFIG_ENABLE_SSE2 option currently fails testing on all platforms, this is not suitable for use at the momemnt.") ++endif() + + option(VNL_CONFIG_ENABLE_SSE2_ROUNDING + "Enable Streaming SIMD Extensions 2 implementation of rounding (hardware dependant)." +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/tests/test_convolve.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/tests/test_convolve.cxx +index 71e6e80d0a..1f14291ed6 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/tests/test_convolve.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/tests/test_convolve.cxx +@@ -63,7 +63,6 @@ void test_convolve() + + TEST_NEAR("vnl_convolve() with_fft(16384)", (r9-r10).two_norm(), 0.0, 1e-6); + std::cout << "Done FFT-2-based 10000x2000 convolution in " << ms2/double(ntimes) << " milliseconds\n"; +- TEST("vnl_convolve() timing: should be at least 2.5x faster", 5*ms2 < 2*ms1, true); + + vnl_vector r11; + const std::clock_t timer_05 = std::clock(); +@@ -73,7 +72,6 @@ void test_convolve() + const int ms3 = ( timer_06 - timer_05)/ (CLOCKS_PER_SEC/1000); + TEST_NEAR("vnl_convolve() with_fft(12800)", (r9-r11).two_norm(), 0.0, 1e-6); + std::cout << "Done FFT-2,5-based 10000x2000 convolution in " << ms3/double(ntimes) << " milliseconds\n"; +- TEST("vnl_convolve() timing: should even be faster", 2*ms3 < 3*ms2, true); + + vnl_vector r12; + const std::clock_t timer_07 = std::clock(); +@@ -83,7 +81,6 @@ void test_convolve() + const int ms4 = ( timer_08 - timer_07)/ (CLOCKS_PER_SEC/1000); + TEST_NEAR("vnl_convolve() with_fft(27648)", (r9-r12).two_norm(), 0.0, 1e-6); + std::cout << "Done FFT-2,3-based 10000x2000 convolution in " << ms4/double(ntimes) << " milliseconds\n"; +- TEST("vnl_convolve() timing: should be slower", 5*ms4 > 3*ms2, true); + + double c1_data[] = { -1, 0, 1, 2, 3, 4 }; + vnl_vector c1(6, 6, c1_data); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_brent.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_brent.cxx +index 89eb069622..c1c99263ae 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_brent.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_brent.cxx +@@ -23,7 +23,7 @@ double vnl_brent::minimize_given_bounds(double ax, double bx, double cx, + double tol, + double *xmin) + { +- assert( xmin != NULL ); ++ assert( xmin != VXL_NULLPTR ); + this->set_x_tolerance( tol ); + *xmin = vnl_brent_minimizer::minimize_given_bounds( ax, bx, cx ); + return vnl_brent_minimizer::f_at_last_minimum(); +@@ -33,7 +33,7 @@ double vnl_brent::minimize_given_bounds_and_1st_f(double ax, double bx, + double fb, double cx, + double tol, double *xmin) + { +- assert( xmin != NULL ); ++ assert( xmin != VXL_NULLPTR ); + this->set_x_tolerance( tol ); + *xmin = vnl_brent_minimizer::minimize_given_bounds_and_one_f( ax, bx, cx, fb ); + return vnl_brent_minimizer::f_at_last_minimum(); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_complex_generalized_schur.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_complex_generalized_schur.cxx +index 24f9607238..214d4957a5 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_complex_generalized_schur.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_complex_generalized_schur.cxx +@@ -30,10 +30,10 @@ bool vnl_generalized_schur(vnl_matrix > *A, + assert(B->rows() == B->cols()); + + long n = A->rows(); +- assert(alpha!=0); alpha->set_size(n); alpha->fill(0); +- assert(beta!=0); beta ->set_size(n); beta ->fill(0); +- assert(L!=0); L ->set_size(n, n); L ->fill(0); +- assert(R!=0); R ->set_size(n, n); R ->fill(0); ++ assert(alpha!=VXL_NULLPTR); alpha->set_size(n); alpha->fill(0); ++ assert(beta!=VXL_NULLPTR); beta ->set_size(n); beta ->fill(0); ++ assert(L!=VXL_NULLPTR); L ->set_size(n, n); L ->fill(0); ++ assert(R!=VXL_NULLPTR); R ->set_size(n, n); R ->fill(0); + + long sdim = 0; + long lwork = 1000 + (8*n + 16); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_convolve.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_convolve.hxx +index 3c5f3f0895..a92377cf5c 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_convolve.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_convolve.hxx +@@ -47,7 +47,7 @@ vnl_vector vnl_convolve_cyclic(vnl_vector const& v1, vnl_vector const + if (n == 1) return vnl_vector(1, U(v1[0]*v2[0])); + + if (use_fft) +- return vnl_convolve_cyclic_using_fft(v1, v2, (U*)0); ++ return vnl_convolve_cyclic_using_fft(v1, v2, (U*)VXL_NULLPTR); + + vnl_vector ret(n, (U)0); // all elements already initialized to zero + for (unsigned int k=0; k vnl_convolve_using_fft(vnl_vector const& v1, vnl_vector co + vnl_vector w1(n, U(0)); for (unsigned i=0; i w2(n, U(0)); for (unsigned i=0; i(v1.size()+v2.size()-1, v1.size()+v2.size()-1, w1.data_block()); + } +@@ -98,7 +98,7 @@ vnl_vector vnl_convolve(vnl_vector const& v1, vnl_vector const& v2, int + if (v2.size() == 1) return v1*v2[0]; + + if (use_fft != 0) +- return vnl_convolve_using_fft(v1, v2, (T*)0, use_fft); ++ return vnl_convolve_using_fft(v1, v2, (T*)VXL_NULLPTR, use_fft); + + unsigned int n = v1.size() + v2.size() - 1; + vnl_vector ret(n, (T)0); // all elements already initialized to zero +@@ -120,7 +120,7 @@ vnl_vector vnl_convolve(vnl_vector const& v1, vnl_vector const& v2, U + return vnl_vector(0); + + if (use_fft != 0) +- return vnl_convolve_using_fft(v1, v2, (U*)0, use_fft); ++ return vnl_convolve_using_fft(v1, v2, (U*)VXL_NULLPTR, use_fft); + + unsigned int n = v1.size() + v2.size() - 1; + vnl_vector ret(n, (U)0); // all elements already initialized to zero +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_fft_prime_factors.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_fft_prime_factors.hxx +index 32f784ba87..a11870bf6f 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_fft_prime_factors.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_fft_prime_factors.hxx +@@ -9,7 +9,7 @@ + + template + vnl_fft_prime_factors::vnl_fft_prime_factors() +- : trigs_(0) ++ : trigs_(VXL_NULLPTR) + , number_(0) + { + } +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_generalized_schur.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_generalized_schur.cxx +index 497da54958..d7d7b1960c 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_generalized_schur.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_generalized_schur.cxx +@@ -30,11 +30,11 @@ bool vnl_generalized_schur(vnl_matrix *A, + assert(A->cols() == B->cols()); + + long n = A->rows(); +- assert(alphar!=0); alphar->set_size(n); alphar->fill(0); +- assert(alphai!=0); alphai->set_size(n); alphai->fill(0); +- assert(beta!=0); beta ->set_size(n); beta ->fill(0); +- assert(L!=0); L ->set_size(n, n); L ->fill(0); +- assert(R!=0); R ->set_size(n, n); R ->fill(0); ++ assert(alphar!=VXL_NULLPTR); alphar->set_size(n); alphar->fill(0); ++ assert(alphai!=VXL_NULLPTR); alphai->set_size(n); alphai->fill(0); ++ assert(beta!=VXL_NULLPTR); beta ->set_size(n); beta ->fill(0); ++ assert(L!=VXL_NULLPTR); L ->set_size(n, n); L ->fill(0); ++ assert(R!=VXL_NULLPTR); R ->set_size(n, n); R ->fill(0); + + long sdim = 0; + long lwork = 1000 + (8*n + 16); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_lbfgs.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_lbfgs.cxx +index 9d125ea561..d1d84918bc 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_lbfgs.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_lbfgs.cxx +@@ -77,7 +77,7 @@ bool vnl_lbfgs::minimize(vnl_vector& x) + std::cerr << "vnl_lbfgs: "; + + double best_f = 0; +- vnl_vector best_x = x; ++ vnl_vector best_x; + + bool ok; + this->num_evaluations_ = 0; +@@ -105,8 +105,8 @@ bool vnl_lbfgs::minimize(vnl_vector& x) + best_f = f; + } + +-#define print_(i,a,b,c,d) std::cerr<ls_ = NULL; ++ this->ls_ = VXL_NULLPTR; + } + + virtual ~lsqrVNL() +@@ -88,7 +88,7 @@ vnl_lsqr::~vnl_lsqr() + } + + // Requires number_of_residuals() of workspace in rw. +-int vnl_lsqr::aprod_(long* mode, long* m, long* n, double* x, double* y, long* /*leniw*/, long* /*lenrw*/, long* /*iw*/, double* rw, void* userdata) ++int vnl_lsqr::aprod_(const long* mode, const long* m, const long* n, double* x, double* y, long* /*leniw*/, long* /*lenrw*/, long* /*iw*/, double* rw, void* userdata) + { + // + // THIS CODE IS DEPRECATED +@@ -123,7 +123,7 @@ int vnl_lsqr::minimize(vnl_vector& result) + long n = ls_->get_number_of_unknowns(); + double damp = 0; + long leniw = 1; +- long* iw = 0; ++ long* iw = VXL_NULLPTR; + long lenrw = m; + #ifdef __GNUC__ + double rw[m]; +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_lsqr.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_lsqr.h +index 6ab8d07f69..8ca0959993 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_lsqr.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_lsqr.h +@@ -74,7 +74,7 @@ class VNL_ALGO_EXPORT vnl_lsqr + double result_norm_; + long return_code_; + +- static int aprod_(long* mode, long* m, long* n, double* x, double* y, ++ static int aprod_(const long* mode, const long* m, const long* n, double* x, double* y, + long* leniw, long* lenrw, long* iw, double* rw, + void* userdata); + }; +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_matrix_inverse.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_matrix_inverse.h +index 56e54c1fb4..12d93958e0 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_matrix_inverse.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_matrix_inverse.h +@@ -35,7 +35,7 @@ template + struct vnl_matrix_inverse : public vnl_svd + { + vnl_matrix_inverse(vnl_matrix const & M): vnl_svd(M) { } +- ~vnl_matrix_inverse() {} ++ ~vnl_matrix_inverse() VXL_OVERRIDE {} + + operator vnl_matrix () const { return this->inverse(); } + }; +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_qr.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_qr.hxx +index fb19f73d27..e48bbed9f7 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_qr.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_qr.hxx +@@ -199,10 +199,10 @@ vnl_vector vnl_qr::solve(const vnl_vector& b) const + vnl_linpack_qrsl(qrdc_out_.data_block(), + &n, &n, &p, + qraux_.data_block(), +- b_data, (T*)0, Qt_B.data_block(), ++ b_data, (T*)VXL_NULLPTR, Qt_B.data_block(), + x.data_block(), +- (T*)0/*residual*/, +- (T*)0/*Ax*/, ++ (T*)VXL_NULLPTR/*residual*/, ++ (T*)VXL_NULLPTR/*Ax*/, + &JOB, + &info); + +@@ -230,11 +230,11 @@ vnl_vector vnl_qr::QtB(const vnl_vector& b) const + &n, &n, &p, + qraux_.data_block(), + b_data, +- (T*)0, // A: Qb ++ (T*)VXL_NULLPTR, // A: Qb + Qt_B.data_block(), // B: Q'b +- (T*)0, // C: x +- (T*)0, // D: residual +- (T*)0, // E: Ax ++ (T*)VXL_NULLPTR, // C: x ++ (T*)VXL_NULLPTR, // D: residual ++ (T*)VXL_NULLPTR, // E: Ax + &JOB, + &info); + +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_sparse_symmetric_eigensystem.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_sparse_symmetric_eigensystem.cxx +index 025e0f07cc..dd4d49bc91 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_sparse_symmetric_eigensystem.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_sparse_symmetric_eigensystem.cxx +@@ -29,7 +29,7 @@ void sse_op_callback(const long* n, + const double* p, + double* q) + { +- assert(current_system != 0); ++ assert(current_system != VXL_NULLPTR); + + current_system->CalculateProduct(*n,*m,p,q); + } +@@ -46,7 +46,7 @@ void sse_iovect_callback(const long* n, + const long* j, + const long* k) + { +- assert(current_system != 0); ++ assert(current_system != VXL_NULLPTR); + + if (*k==0) + current_system->SaveVectors(*n,*m,q,*j-*m); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_svd_economy.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_svd_economy.hxx +index bb20b6b7e8..a2e7c825b4 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_svd_economy.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/algo/vnl_svd_economy.hxx +@@ -45,7 +45,7 @@ vnl_svd_economy::vnl_svd_economy( vnl_matrix const& M ) : + vnl_linpack_svdc_economy((real_t*)X, &m_, &m_, &n_, + wspace.data_block(), + espace.data_block(), +- 0, &ldu, ++ VXL_NULLPTR, &ldu, + vspace.data_block(), &n_, + work.data_block(), + &job, &info); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/basic_operation_timings.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/basic_operation_timings.cxx +index 625b9b51b8..592a05a8af 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/basic_operation_timings.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/basic_operation_timings.cxx +@@ -17,7 +17,7 @@ + const unsigned nstests = 10; + + +-void fill_with_rng(double * begin, double * end, double a, double b, vnl_random &rng) ++void fill_with_rng(double * begin, const double * end, double a, double b, vnl_random &rng) + { + while (begin != end) + { +@@ -26,7 +26,7 @@ void fill_with_rng(double * begin, double * end, double a, double b, vnl_random + } + } + +-void fill_with_rng(float * begin, float * end, float a, float b, vnl_random &rng) ++void fill_with_rng(float * begin, const float * end, float a, float b, vnl_random &rng) + { + while (begin != end) + { +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_arithmetic.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_arithmetic.cxx +index b269ba6ba6..db889e64fc 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_arithmetic.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_arithmetic.cxx +@@ -15,10 +15,10 @@ + // --- dynamic ------------------------------ + + #define NewMat(mat, r,c,data) \ +- assert( sizeof(data) >= r*c*sizeof(double) ); \ ++ assert( sizeof(data) >= (r)*(c)*sizeof(double) ); \ + vnl_matrix mat( data, r, c ) + #define NewVec(vec, n,data) \ +- assert( sizeof(data) >= n*sizeof(double) ); \ ++ assert( sizeof(data) >= (n)*sizeof(double) ); \ + vnl_vector vec( data, n ) + + static +@@ -35,10 +35,10 @@ test_arithmetic_dynamic() + // --- ref ---------------------------------- + + #define NewMat(mat, r,c,data) \ +- assert( sizeof(data) >= r*c*sizeof(double) ); \ ++ assert( sizeof(data) >= (r)*(c)*sizeof(double) ); \ + vnl_matrix_ref mat( r, c, data ) + #define NewVec(vec, n,data) \ +- assert( sizeof(data) >= n*sizeof(double) ); \ ++ assert( sizeof(data) >= (n)*sizeof(double) ); \ + vnl_vector_ref vec( n, data ) + + static +@@ -55,10 +55,10 @@ test_arithmetic_ref() + #undef NewVec + + #define NewMat(mat, r,c,data) \ +- assert( sizeof(data) >= r*c*sizeof(double) ); \ ++ assert( sizeof(data) >= (r)*(c)*sizeof(double) ); \ + vnl_matrix_fixed mat( data ) + #define NewVec(vec, n,data) \ +- assert( sizeof(data) >= n*sizeof(double) ); \ ++ assert( sizeof(data) >= (n)*sizeof(double) ); \ + vnl_vector_fixed vec( data ) + + void +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_matlab.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_matlab.cxx +index 4b60e8a01d..a6502a2243 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_matlab.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_matlab.cxx +@@ -32,7 +32,7 @@ + // get a byte-swapped file, short of reading in a native file and swapping it + // and writing it back out, and that isn't any easier. + void matlab_write_swapped(std::ostream &f, +- float *array, ++ const float *array, + unsigned size, + char const *name) + { +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_matrix.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_matrix.cxx +index 8919c4a4fc..2fdac67c58 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_matrix.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_matrix.cxx +@@ -62,7 +62,7 @@ void test_int() + try { m0.get(0,25); } // Raise out of bounds exception. + catch(...) { exceptionThrownAndCaught = true; } + TEST("Out of bounds get(0,25)", exceptionThrownAndCaught, true); +- ++ + exceptionThrownAndCaught = false; + try { m0.get(25,0); } // Raise out of bounds exception. + catch(...) { exceptionThrownAndCaught = true; } +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_na.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_na.cxx +index 7f371724e6..aed9edafb4 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_na.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_na.cxx +@@ -9,9 +9,9 @@ + + + #define print_hex(p) \ +- std::hex<(&p)[sizeof(p)-1]; \ ++ std::hex<(&(p))[sizeof(p)-1]; \ + for (unsigned int i=2; i<=sizeof(p); ++i) \ +- std::cout<(&p))[sizeof(p)-i]; \ ++ std::cout<(&(p)))[sizeof(p)-i]; \ + std::cout<(&p)[sizeof(p)-1]; \ ++ std::hex<(&(p))[sizeof(p)-1]; \ + for (unsigned int i=2; i<=sizeof(p); ++i) \ +- std::cout<(&p))[sizeof(p)-i]; \ ++ std::cout<(&(p)))[sizeof(p)-i]; \ + std::cout<(0)); ++ TEST("==", z_int==0L, true); ++ vnl_rational z_uint(static_cast(0) ); ++ TEST("==", z_uint==0L, true); ++ ++ vnl_rational z_short(static_cast(0)); ++ TEST("==", z_short==0L, true); ++ vnl_rational z_ushort(static_cast(0) ); ++ TEST("==", z_ushort==0L, true); ++ ++ vnl_rational z_long(static_cast(0)); ++ TEST("==", z_long==0L, true); ++ vnl_rational z_ulong(static_cast(0)); ++ TEST("==", z_ulong==0L, true); ++#if 0 ++ vnl_rational z_mixed(static_cast(0), static_cast(1) ); ++ TEST("==", z_mixed==0L, true); ++#endif ++ + TEST("==", a==-5L, true); + TEST("==", 5L==-a, true); + TEST("==", b==-7, true); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_sym_matrix.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_sym_matrix.cxx +index b49115fe54..a77f7b4518 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_sym_matrix.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/tests/test_sym_matrix.cxx +@@ -83,7 +83,7 @@ void test_int() + try { sm1.get(0,25); } // Raise out of bounds exception. + catch(...) { exceptionThrownAndCaught = true; } + TEST("Out of bounds get(0,25)", exceptionThrownAndCaught, true); +- ++ + exceptionThrownAndCaught = false; + try { sm1.get(25,0); } // Raise out of bounds exception. + catch(...) { exceptionThrownAndCaught = true; } +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_c_na_vector.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_c_na_vector.hxx +index e5ec177ee1..2d6af99d6e 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_c_na_vector.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_c_na_vector.hxx +@@ -153,8 +153,8 @@ template VNL_EXPORT void vnl_c_na_vector_inf_norm(T const *, unsigned, S *) + #undef VNL_C_NA_VECTOR_INSTANTIATE_ordered + #define VNL_C_NA_VECTOR_INSTANTIATE_ordered(T) \ + VNL_C_NA_VECTOR_INSTANTIATE_norm(T, vnl_c_na_vector::abs_t); \ +-template class VNL_EXPORT vnl_c_na_vector; \ +-template VNL_EXPORT std::ostream& print_na_vector(std::ostream &,T const *,unsigned) ++template class vnl_c_na_vector; \ ++template std::ostream& print_na_vector(std::ostream &,T const *,unsigned) + + + #undef VNL_C_NA_VECTOR_INSTANTIATE_unordered +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_c_vector.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_c_vector.hxx +index eb558a937a..37e1221e85 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_c_vector.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_c_vector.hxx +@@ -441,7 +441,7 @@ template VNL_EXPORT void vnl_c_vector_inf_norm(T const *, unsigned, S *) + #undef VNL_C_VECTOR_INSTANTIATE_ordered + #define VNL_C_VECTOR_INSTANTIATE_ordered(T) \ + VNL_C_VECTOR_INSTANTIATE_norm(T, vnl_c_vector::abs_t); \ +-template class VNL_EXPORT vnl_c_vector; \ ++template class vnl_c_vector; \ + template VNL_EXPORT std::ostream& print_vector(std::ostream &,T const *,unsigned) + + #undef VNL_C_VECTOR_INSTANTIATE_unordered +@@ -450,7 +450,7 @@ VCL_DO_NOT_INSTANTIATE(T vnl_c_vector::max_value(T const *, unsigned), T(0)) + VCL_DO_NOT_INSTANTIATE(T vnl_c_vector::min_value(T const *, unsigned), T(0)); \ + VCL_DO_NOT_INSTANTIATE(unsigned vnl_c_vector::arg_max(T const *, unsigned), 0U); \ + VCL_DO_NOT_INSTANTIATE(unsigned vnl_c_vector::arg_min(T const *, unsigned), 0U); \ +-template class VNL_EXPORT vnl_c_vector; \ ++template class vnl_c_vector; \ + VNL_C_VECTOR_INSTANTIATE_norm(T, vnl_c_vector::abs_t); + + #ifndef DOXYGEN_SHOULD_SKIP_THIS +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_file_matrix.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_file_matrix.h +index e831cfb116..7ee40fb0e2 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_file_matrix.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_file_matrix.h +@@ -30,7 +30,7 @@ class VNL_TEMPLATE_EXPORT vnl_file_matrix : public vnl_matrix + vnl_file_matrix(char const* filename); + + operator safe_bool () const +- { return (ok_)? VCL_SAFE_BOOL_TRUE : 0; } ++ { return (ok_)? VCL_SAFE_BOOL_TRUE : VXL_NULLPTR; } + bool operator!() const + { return !ok_; } + +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_file_vector.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_file_vector.h +index 99cd366e85..8d5c9a78bf 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_file_vector.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_file_vector.h +@@ -31,7 +31,7 @@ class VNL_TEMPLATE_EXPORT vnl_file_vector : public vnl_vector + vnl_file_vector(char const* filename); + + operator safe_bool () const +- { return (ok_)? VCL_SAFE_BOOL_TRUE : 0; } ++ { return (ok_)? VCL_SAFE_BOOL_TRUE : VXL_NULLPTR; } + bool operator!() const + { return !ok_; } + +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_math.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_math.cxx +index 1f6bd5f718..8d3f9a8cfc 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_math.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_math.cxx +@@ -26,7 +26,7 @@ + #endif + + #elif VXL_HAS_STD_ISFINITE || VXL_HAS_STD_ISNAN || VXL_HAS_STD_ISNORMAL +-# include ++# include + # if VXL_HAS_STD_ISFINITE + # define finite std::isfinite + # define finitef std::isfinite +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_math.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_math.h +index 4a7e4a7669..c66e3df9ab 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_math.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_math.h +@@ -153,41 +153,28 @@ namespace vnl_math + namespace vnl_math + { + #if VXL_FULLCXX11SUPPORT +- // Prefer to use perfect forwarding to the std library if C++11 features are available. +- //http://stackoverflow.com/questions/9864125/c11-how-to-alias-a-function +- template +- auto isnan(Args&&... args) -> decltype(std::isnan(std::forward(args)...)) { +- return std::isnan(std::forward(args)...); ++ using std::isnan; ++ // Ensure proper conversion to bool type. ++ // Return a signed integer type has been seen with the following ++ // compilers/libstdc++: ++ // g++ (GCC) 7.2.1 20170829 (Red Hat 7.2.1-1) ++ // g++ (GCC) 6.3.1 20170216 (Red Hat 6.3.1-3) ++ template ++ bool isinf(TArg&& arg) ++ { ++ return bool(std::isinf(std::forward(arg))); + } +- template +- auto isinf(Args&&... args) -> decltype(std::isinf(std::forward(args)...)) { +- return std::isinf(std::forward(args)...); +- } +- template +- auto isfinite(Args&&... args) -> decltype(std::isfinite(std::forward(args)...)) { +- return std::isfinite(std::forward(args)...); +- } +- template +- auto isnormal(Args&&... args) -> decltype(std::isnormal(std::forward(args)...)) { +- return std::isnormal(std::forward(args)...); +- } +- template +- auto max(Args&&... args) -> decltype(std::max(std::forward(args)...)) { +- return std::max(std::forward(args)...); +- } +- template +- auto min(Args&&... args) -> decltype(std::min(std::forward(args)...)) { +- return std::min(std::forward(args)...); +- } +- //cbrt is defined in C++11 +- template +- auto cuberoot(Args&&... args) -> decltype(std::cbrt(std::forward(args)...)) { +- return std::cbrt(std::forward(args)...); +- } +- template +- auto hypot(Args&&... args) -> decltype(std::hypot(std::forward(args)...)) { +- return std::hypot(std::forward(args)...); ++ using std::isfinite; ++ using std::isnormal; ++ using std::max; ++ using std::min; ++ using std::cbrt; ++ template ++ TArg cuberoot(TArg&& arg) ++ { ++ return std::cbrt(std::forward(arg)); + } ++ using std::hypot; + #else + // isnan + inline bool isnan(char) { return false; } +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_print.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_print.h +index d818e12015..c001352b08 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_print.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_print.h +@@ -46,7 +46,7 @@ std::ostream &vnl_matlab_print(std::ostream &, + template VNL_TEMPLATE_EXPORT + std::ostream &vnl_matlab_print(std::ostream &, + vnl_diag_matrix const&, +- char const *variable_name =0, ++ char const *variable_name =VXL_NULLPTR, + vnl_matlab_print_format =vnl_matlab_print_format_default); + + //: print a vnl_matrix. +@@ -54,7 +54,7 @@ std::ostream &vnl_matlab_print(std::ostream &, + template VNL_TEMPLATE_EXPORT + std::ostream &vnl_matlab_print(std::ostream &, + vnl_matrix const&, +- char const *variable_name =0, ++ char const *variable_name =VXL_NULLPTR, + vnl_matlab_print_format =vnl_matlab_print_format_default); + + //: print a vnl_matrix_fixed. +@@ -62,7 +62,7 @@ std::ostream &vnl_matlab_print(std::ostream &, + template VNL_TEMPLATE_EXPORT + std::ostream &vnl_matlab_print(std::ostream &, + vnl_matrix_fixed const&, +- char const *variable_name =0, ++ char const *variable_name =VXL_NULLPTR, + vnl_matlab_print_format =vnl_matlab_print_format_default); + + //: print a vnl_matrix_ref. +@@ -70,7 +70,7 @@ std::ostream &vnl_matlab_print(std::ostream &, + template VNL_TEMPLATE_EXPORT + std::ostream &vnl_matlab_print(std::ostream &, + vnl_matrix_ref const &, +- char const *variable_name =0, ++ char const *variable_name =VXL_NULLPTR, + vnl_matlab_print_format =vnl_matlab_print_format_default); + + //: print a vnl_vector. +@@ -78,7 +78,7 @@ std::ostream &vnl_matlab_print(std::ostream &, + template VNL_TEMPLATE_EXPORT + std::ostream &vnl_matlab_print(std::ostream &, + vnl_vector const &, +- char const *variable_name =0, ++ char const *variable_name =VXL_NULLPTR, + vnl_matlab_print_format =vnl_matlab_print_format_default); + + //: print a vnl_vector_fixed. +@@ -86,7 +86,7 @@ std::ostream &vnl_matlab_print(std::ostream &, + template VNL_TEMPLATE_EXPORT + std::ostream &vnl_matlab_print(std::ostream &, + vnl_vector_fixed const &, +- char const *variable_name =0, ++ char const *variable_name =VXL_NULLPTR, + vnl_matlab_print_format =vnl_matlab_print_format_default); + + +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_print2.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_print2.h +index bdac336023..061e7b0e11 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_print2.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_print2.h +@@ -61,7 +61,7 @@ template + inline + vnl_matlab_print_proxy + vnl_matlab_print(T const &obj, +- char const *name = 0, ++ char const *name = VXL_NULLPTR, + vnl_matlab_print_format format = vnl_matlab_print_format_default) + { + return vnl_matlab_print_proxy(obj, name, format); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_read.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_read.h +index 788c583ab8..5e56ac93d4 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_read.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_read.h +@@ -33,8 +33,8 @@ template class vnl_matrix; + // If the data in the file cannot reasonably be read into the destination, abort(). + // + // The vector/matrix will be resized if necessary. +-template VNL_TEMPLATE_EXPORT bool vnl_matlab_read_or_die(std::istream &, vnl_vector &, char const *name =0); +-template VNL_TEMPLATE_EXPORT bool vnl_matlab_read_or_die(std::istream &, vnl_matrix &, char const *name =0); ++template VNL_TEMPLATE_EXPORT bool vnl_matlab_read_or_die(std::istream &, vnl_vector &, char const *name =VXL_NULLPTR); ++template VNL_TEMPLATE_EXPORT bool vnl_matlab_read_or_die(std::istream &, vnl_matrix &, char const *name =VXL_NULLPTR); + + // ------------------------------ less easy ------------------------------ + +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matrix_fixed_ref.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matrix_fixed_ref.hxx +index a48b31f269..5f276ef576 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matrix_fixed_ref.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matrix_fixed_ref.hxx +@@ -536,7 +536,7 @@ vnl_matrix_fixed_ref::read_ascii(std::istream& s) const + + template + vnl_matrix_fixed_ref & +-vnl_matrix_fixed_ref::flipud() ++vnl_matrix_fixed_ref::flipud() + { + for (unsigned int r1 = 0; 2*r1+1 < nrows; ++r1) + { +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_numeric_traits.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_numeric_traits.cxx +index 72046e8162..0fc9533336 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_numeric_traits.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_numeric_traits.cxx +@@ -57,7 +57,7 @@ VXL_CONSTEXPR_VAR unsigned long long vnl_numeric_traits::one + #endif + + VXL_CONSTEXPR_VAR bool vnl_numeric_traits::maxval VCL_STATIC_CONST_INIT_INT_DEFN(true); +-VXL_CONSTEXPR_VAR char vnl_numeric_traits::maxval VCL_STATIC_CONST_INIT_INT_DEFN(char(255)<0?127:255); ++VXL_CONSTEXPR_VAR char vnl_numeric_traits::maxval VCL_STATIC_CONST_INIT_INT_DEFN(char(255)<0?127:char(255)); + // It is 127 when "char" is signed and 255 when "char" is unsigned. + VXL_CONSTEXPR_VAR unsigned char vnl_numeric_traits::maxval VCL_STATIC_CONST_INIT_INT_DEFN(255); + VXL_CONSTEXPR_VAR signed char vnl_numeric_traits::maxval VCL_STATIC_CONST_INIT_INT_DEFN(127); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_random.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_random.cxx +index cd3e202c38..8cdb8f8582 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_random.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_random.cxx +@@ -89,7 +89,7 @@ void vnl_random::reseed(unsigned long seed) + for (int j=0;j<1000;j++) lrand32(); + } + +-void vnl_random::reseed(unsigned long seed[vnl_random_array_size]) ++void vnl_random::reseed(const unsigned long seed[vnl_random_array_size]) + { + mz_array_position = 0UL; + mz_borrow = 0L; +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_random.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_random.h +index faaa00a187..de5391ac8a 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_random.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_random.h +@@ -81,7 +81,7 @@ class VNL_EXPORT vnl_random + void reseed(unsigned long); + + //: Starts a new deterministic sequence from an already declared generator using the provided seed. +- void reseed(unsigned long[vnl_random_array_size]); ++ void reseed(const unsigned long[vnl_random_array_size]); + + //: This restarts the sequence of random numbers. + // Restarts so that it repeats +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_rational.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_rational.cxx +index a43759f0ab..293fd07b87 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_rational.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_rational.cxx +@@ -6,9 +6,8 @@ + #include // for vnl_numeric_traits::maxval + #include + +-//: Creates a rational from a double. +-// This is done by computing the continued fraction approximation for d. +-vnl_rational::vnl_rational(double d) ++template ++inline void makeNumDen( FloatingType d, long &num_, long &den_) + { + bool sign = d<0; + if (sign) d = -d; +@@ -29,6 +28,20 @@ vnl_rational::vnl_rational(double d) + // no need to normalize() since prev_num and prev_den have guaranteed a gcd=1 + } + ++//: Creates a rational from a double. ++// This is done by computing the continued fraction approximation for d. ++vnl_rational::vnl_rational(double d) ++{ ++ makeNumDen(d,num_,den_); ++} ++ ++//: Creates a rational from a double. ++// This is done by computing the continued fraction approximation for d. ++vnl_rational::vnl_rational(float f) ++{ ++ makeNumDen(f,num_,den_); ++} ++ + //: Multiply/assign: replace lhs by lhs * rhs + // Note that 0 * Inf and Inf * 0 are undefined. + // Also note that there could be integer overflow during this calculation! +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_rational.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_rational.h +index f36caab39a..9afa439ee5 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_rational.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_rational.h +@@ -80,21 +80,45 @@ class VNL_EXPORT vnl_rational + // Also serves as automatic cast from long to vnl_rational. + // The only input which is not allowed is (0,0); + // the denominator is allowed to be 0, to represent +Inf or -Inf. +- inline vnl_rational(long num = 0L, long den = 1L) ++ ++ inline vnl_rational() ++ : num_(0L), den_(1L) { normalize(); } ++ ++ inline vnl_rational(long num) ++ : num_(num), den_(1L) { assert(num!=0||den_!=0); normalize(); } ++ inline vnl_rational(long num, long den) + : num_(num), den_(den) { assert(num!=0||den!=0); normalize(); } +- //: Creates a rational with given numerator and denominator. +- // Note these are not automatic type conversions because of a bug +- // in the Borland compiler. Since these just convert their +- // arguments to long anyway, there is no harm in letting +- // the long overload be used for automatic conversions. +- explicit inline vnl_rational(int num, int den = 1) ++ ++ inline vnl_rational(unsigned long num) ++ : num_(num), den_(1L) { assert(num!=0||den_!=0); normalize(); } ++ inline vnl_rational(unsigned long num, unsigned long den) ++ : num_(num), den_(den) { assert(num!=0||den!=0); normalize(); } ++ ++ inline vnl_rational(int num) ++ : num_(num), den_(1L) { assert(num!=0||den_!=0); normalize(); } ++ inline vnl_rational(int num, int den) + : num_(num), den_(den) { assert(num!=0||den!=0); normalize(); } +- explicit inline vnl_rational(unsigned int num, unsigned int den = 1) ++ ++ inline vnl_rational(unsigned int num) ++ : num_((long)num), den_(1L) { assert(num!=0||den_!=0); normalize(); } ++ inline vnl_rational(unsigned int num, unsigned int den) + : num_((long)num), den_((long)den) { assert(num!=0||den!=0); normalize(); } ++ ++ inline vnl_rational(short num) ++ : num_(num), den_(1L) { assert(num!=0||den_!=0); normalize(); } ++ inline vnl_rational(short num, short den) ++ : num_(num), den_(den) { assert(num!=0||den!=0); normalize(); } ++ ++ inline vnl_rational(unsigned short num) ++ : num_(num), den_(1L) { assert(num!=0||den_!=0); normalize(); } ++ inline vnl_rational(unsigned short num, unsigned short den) ++ : num_(num), den_(den) { assert(num!=0||den!=0); normalize(); } ++ + //: Creates a rational from a double. + // This is done by computing the continued fraction approximation for d. + // Note that this is explicitly \e not an automatic type conversion. +- explicit vnl_rational(double d); ++ vnl_rational(double d); ++ vnl_rational(float d); + // Copy constructor + inline vnl_rational(vnl_rational const& from) + : num_(from.numerator()), den_(from.denominator()) {} +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sample.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sample.cxx +index e699962126..9d5d745436 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sample.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sample.cxx +@@ -11,7 +11,7 @@ + #include + #include + +-#include // dont_vxl_filter ++#include // dont_vxl_filter + + #if !VXL_STDLIB_HAS_DRAND48 + // rand() is not always a good random number generator, +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix.h +index a3429de673..d012cf7b73 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix.h +@@ -94,7 +94,7 @@ class VNL_TEMPLATE_EXPORT vnl_sparse_matrix_pair + return *this; + } + +- struct less : public std::binary_function ++ struct less + { + bool operator() (vnl_sparse_matrix_pair const& p1, vnl_sparse_matrix_pair const& p2) { + return p1.first < p2.first; +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix_linear_system.cxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix_linear_system.cxx +index 7584d8da9e..608b488339 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix_linear_system.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix_linear_system.cxx +@@ -77,6 +77,6 @@ void vnl_sparse_matrix_linear_system::apply_preconditioner(vnl_vector + px = dot_product(x,jacobi_precond_); + } + +-template class VNL_EXPORT vnl_sparse_matrix_linear_system; +-template class VNL_EXPORT vnl_sparse_matrix_linear_system; ++template class vnl_sparse_matrix_linear_system; ++template class vnl_sparse_matrix_linear_system; + +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix_linear_system.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix_linear_system.h +index 8fbe755e74..091425bd8f 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix_linear_system.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sparse_matrix_linear_system.h +@@ -35,8 +35,6 @@ class VNL_TEMPLATE_EXPORT vnl_sparse_matrix_linear_system : public vnl_linear_sy + vnl_sparse_matrix_linear_system(vnl_sparse_matrix const& A, vnl_vector const& b) : + vnl_linear_system(A.columns(), A.rows()), A_(A), b_(b), jacobi_precond_() {} + +- virtual ~vnl_sparse_matrix_linear_system() {} +- + //: Implementations of the vnl_linear_system virtuals. + void multiply(vnl_vector const& x, vnl_vector & b) const; + //: Implementations of the vnl_linear_system virtuals. +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sse.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sse.h +index e06ef30d33..bfc4a3a733 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sse.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sse.h +@@ -77,8 +77,8 @@ + # define VNL_SSE_HEAP_STORE(pf) _mm_storeu_##pf + # define VNL_SSE_HEAP_LOAD(pf) _mm_loadu_##pf + # if VNL_CONFIG_THREAD_SAFE +-# define VNL_SSE_ALLOC(n,s,a) new char[n*s] +-# define VNL_SSE_FREE(v,n,s) delete [] static_cast(v) ++# define VNL_SSE_ALLOC(n,s,a) new char[(n)*(s)] ++# define VNL_SSE_FREE(v,n,s) (delete [] static_cast(v)) + # else + # define VNL_SSE_ALLOC(n,s,a) vnl_alloc::allocate((n == 0) ? 8 : (n * s)); + # define VNL_SSE_FREE(v,n,s) if (v) vnl_alloc::deallocate(v, (n == 0) ? 8 : (n * s)); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sym_matrix.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sym_matrix.h +index d1adbb1d8a..3922fca8eb 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sym_matrix.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_sym_matrix.h +@@ -29,7 +29,7 @@ class VNL_TEMPLATE_EXPORT vnl_sym_matrix + { + public: + //: Construct an empty symmetric matrix. +- vnl_sym_matrix(): data_(0), index_(0), nn_(0) {} ++ vnl_sym_matrix(): data_(VXL_NULLPTR), index_(VXL_NULLPTR), nn_(0) {} + + //: Construct a symmetric matrix of size nn by nn. + explicit vnl_sym_matrix(unsigned nn): +@@ -222,7 +222,7 @@ inline vnl_sym_matrix::vnl_sym_matrix(vnl_matrix const& that): + + template + inline vnl_sym_matrix::vnl_sym_matrix(vnl_sym_matrix const& that): +- data_(0), index_(0), nn_(0) ++ data_(VXL_NULLPTR), index_(VXL_NULLPTR), nn_(0) + { + set_size(that.rows()); + update(that); +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector.h b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector.h +index 3fb0a9207f..5053a4e172 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector.h +@@ -134,7 +134,7 @@ class VNL_TEMPLATE_EXPORT vnl_vector + vnl_vector(vnl_vector const &, vnl_matrix const &, vnl_tag_mul); // v * M + vnl_vector(vnl_vector &that, vnl_tag_grab) + : num_elmts(that.num_elmts), data(that.data) +- { that.num_elmts=0; that.data=0; } // "*this" now uses "that"'s data. ++ { that.num_elmts=0; that.data=VXL_NULLPTR; } // "*this" now uses "that"'s data. + // + #endif + +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector.hxx +index 0e995a8ce3..1af97626ca 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector.hxx +@@ -65,7 +65,7 @@ + #define vnl_vector_alloc_blah(size) \ + do { \ + this->num_elmts = (size); \ +- this->data = size ? vnl_c_vector::allocate_T(size) : 0; \ ++ this->data = (size) ? vnl_c_vector::allocate_T(size) : 0; \ + } while (false) + + // This macro deallocates the dynamic storage used by a vnl_vector. +@@ -288,7 +288,7 @@ void vnl_vector::clear() + if (data) { + destroy(); + num_elmts = 0; +- data = 0; ++ data = VXL_NULLPTR; + } + } + +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector_fixed_ref.hxx b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector_fixed_ref.hxx +index 7317b90c72..13879ea79a 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector_fixed_ref.hxx ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_vector_fixed_ref.hxx +@@ -123,7 +123,7 @@ vnl_vector_fixed_ref_const::print( std::ostream& s ) const + // instantiation macros for vnl_vector_fixed_ref : + + #define VNL_VECTOR_FIXED_REF_INSTANTIATE(T,n) \ +-template class VNL_EXPORT vnl_vector_fixed_ref; \ +-template class VNL_EXPORT vnl_vector_fixed_ref_const ++template class vnl_vector_fixed_ref; \ ++template class vnl_vector_fixed_ref_const + + #endif // vnl_vector_fixed_ref_hxx_ +diff --git a/Modules/ThirdParty/VNL/src/vxl/core/vxl_version.h b/Modules/ThirdParty/VNL/src/vxl/core/vxl_version.h +index 152aeab849..a37ecc38b7 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/core/vxl_version.h ++++ b/Modules/ThirdParty/VNL/src/vxl/core/vxl_version.h +@@ -26,9 +26,9 @@ + + //: Version date. This is updated every day. + // Formats are year=CCYY, month=MM, day=DD +-#define VXL_VERSION_DATE_YEAR 2017 +-#define VXL_VERSION_DATE_MONTH 12 +-#define VXL_VERSION_DATE_DAY 08 ++#define VXL_VERSION_DATE_YEAR 2018 ++#define VXL_VERSION_DATE_MONTH 05 ++#define VXL_VERSION_DATE_DAY 16 + + //: Helper macros to create strings with the preprocessor. + #define VXL_VERSION_TO_STRING(s) VXL_VERSION_TO_STRING0(s) +diff --git a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/CMakeLists.txt b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/CMakeLists.txt +index 431bbae68a..f9f4816083 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/CMakeLists.txt ++++ b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/CMakeLists.txt +@@ -445,7 +445,6 @@ if(BUILD_TESTING) + add_subdirectory(tests) + endif() + +-# Disabled in ITK to avoid find_package(X11) +-if(BUILD_EXAMPLES AND 0) ++if(BUILD_EXAMPLES) + add_subdirectory(examples) + endif() +diff --git a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/libf2c/comptry.bat b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/libf2c/comptry.bat +index 2ae4565113..0dc84531c9 100755 +--- a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/libf2c/comptry.bat ++++ b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/libf2c/comptry.bat +@@ -1,5 +1,5 @@ +-%1 %2 %3 %4 %5 %6 %7 %8 %9 +-if errorlevel 1 goto nolonglong +-exit 0 +-:nolonglong +-%1 -DNO_LONG_LONG %2 %3 %4 %5 %6 %7 %8 %9 ++%1 %2 %3 %4 %5 %6 %7 %8 %9 ++if errorlevel 1 goto nolonglong ++exit 0 ++:nolonglong ++%1 -DNO_LONG_LONG %2 %3 %4 %5 %6 %7 %8 %9 +diff --git a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/libf2c/scomptry.bat b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/libf2c/scomptry.bat +index 69be841b91..2c11a97e45 100755 +--- a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/libf2c/scomptry.bat ++++ b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/libf2c/scomptry.bat +@@ -1,5 +1,5 @@ +-%1 -DWRITE_ARITH_H -DNO_FPINIT %2 %3 %4 %5 %6 %7 %8 %9 +-if errorlevel 1 goto nolonglong +-exit 0 +-:nolonglong +-%1 -DNO_LONG_LONG -DWRITE_ARITH_H -DNO_FPINIT %2 %3 %4 %5 %6 %7 %8 %9 ++%1 -DWRITE_ARITH_H -DNO_FPINIT %2 %3 %4 %5 %6 %7 %8 %9 ++if errorlevel 1 goto nolonglong ++exit 0 ++:nolonglong ++%1 -DNO_LONG_LONG -DWRITE_ARITH_H -DNO_FPINIT %2 %3 %4 %5 %6 %7 %8 %9 +diff --git a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsmrBase.cxx b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsmrBase.cxx +index 6053b93203..067b1abebb 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsmrBase.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsmrBase.cxx +@@ -16,6 +16,7 @@ + * + *=========================================================================*/ + #include "lsmrBase.h" ++#include "vcl_compiler_detection.h" + + #include + #include +@@ -40,7 +41,7 @@ lsmrBase::lsmrBase() + this->btol = 1e-6; + this->conlim = 1.0 / ( 10 * sqrt( this->eps ) ); + this->itnlim = 10; +- this->nout = NULL; ++ this->nout = VXL_NULLPTR; + this->istop = 0; + this->itn = 0; + this->normA = 0.0; +diff --git a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsmrDense.cxx b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsmrDense.cxx +index 799bc0538b..b0ccf84890 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsmrDense.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsmrDense.cxx +@@ -16,10 +16,11 @@ + * + *=========================================================================*/ + #include "lsmrDense.h" ++#include "vcl_compiler_detection.h" + + lsmrDense::lsmrDense() + { +- this->A = 0; ++ this->A = VXL_NULLPTR; + } + + +diff --git a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsqrDense.cxx b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsqrDense.cxx +index c62c3953a8..8d55fc088a 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsqrDense.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/linalg/lsqrDense.cxx +@@ -17,10 +17,11 @@ + *=========================================================================*/ + + #include "lsqrDense.h" ++#include "vcl_compiler_detection.h" + + lsqrDense::lsqrDense() + { +- this->A = 0; ++ this->A = VXL_NULLPTR; + } + + +diff --git a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/sparse/spMatrix.h b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/sparse/spMatrix.h +index 38300975a4..c30ff15ac8 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/sparse/spMatrix.h ++++ b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/sparse/spMatrix.h +@@ -175,15 +175,15 @@ + * Macro function that adds data to a imaginary element in the matrix by + * a pointer. + */ +-#define spADD_IMAG_ELEMENT(element,imag) *(element+1) += imag ++#define spADD_IMAG_ELEMENT(element,imag) *((element)+1) += imag + + /*! + * Macro function that adds data to a complex element in the matrix by + * a pointer. + */ + #define spADD_COMPLEX_ELEMENT(element,real,imag) \ +-{ *(element) += real; \ +- *(element+1) += imag; \ ++{ *(element) += (real); \ ++ *((element)+1) += (imag); \ + } + + /*! +@@ -191,10 +191,10 @@ + * specified by the given template. + */ + #define spADD_REAL_QUAD(template,real) \ +-{ *((template).Element1) += real; \ +- *((template).Element2) += real; \ +- *((template).Element3Negated) -= real; \ +- *((template).Element4Negated) -= real; \ ++{ *((template).Element1) += (real); \ ++ *((template).Element2) += (real); \ ++ *((template).Element3Negated) -= (real); \ ++ *((template).Element4Negated) -= (real); \ + } + + /*! +@@ -202,10 +202,10 @@ + * elements specified by the given template. + */ + #define spADD_IMAG_QUAD(template,imag) \ +-{ *((template).Element1+1) += imag; \ +- *((template).Element2+1) += imag; \ +- *((template).Element3Negated+1) -= imag; \ +- *((template).Element4Negated+1) -= imag; \ ++{ *((template).Element1+1) += (imag); \ ++ *((template).Element2+1) += (imag); \ ++ *((template).Element3Negated+1) -= (imag); \ ++ *((template).Element4Negated+1) -= (imag); \ + } + + /*! +@@ -213,14 +213,14 @@ + * elements specified by the given template. + */ + #define spADD_COMPLEX_QUAD(template,real,imag) \ +-{ *((template).Element1) += real; \ +- *((template).Element2) += real; \ +- *((template).Element3Negated) -= real; \ +- *((template).Element4Negated) -= real; \ +- *((template).Element1+1) += imag; \ +- *((template).Element2+1) += imag; \ +- *((template).Element3Negated+1) -= imag; \ +- *((template).Element4Negated+1) -= imag; \ ++{ *((template).Element1) += (real); \ ++ *((template).Element2) += (real); \ ++ *((template).Element3Negated) -= (real); \ ++ *((template).Element4Negated) -= (real); \ ++ *((template).Element1+1) += (imag); \ ++ *((template).Element2+1) += (imag); \ ++ *((template).Element3Negated+1) -= (imag); \ ++ *((template).Element4Negated+1) -= (imag); \ + } + + /* +diff --git a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/triangle.c b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/triangle.c +index e9b55d33d5..b11058fd9d 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/triangle.c ++++ b/Modules/ThirdParty/VNL/src/vxl/v3p/netlib/triangle.c +@@ -9232,6 +9232,8 @@ int arraysize; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation((unsigned int) arraysize); ++ if (pivot == arraysize)//JLM without this test, pivot can equal arraysize and segfault ++ pivot--; + pivotx = sortarray[pivot][0]; + pivoty = sortarray[pivot][1]; + /* Split the array. */ +@@ -9308,6 +9310,8 @@ int axis; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation((unsigned int) arraysize); ++ if (pivot == arraysize)//JLM/SES without this test, pivot can equal arraysize and segfault ++ pivot--; + pivot1 = sortarray[pivot][axis]; + pivot2 = sortarray[pivot][1 - axis]; + /* Split the array. */ +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/CMakeLists.txt b/Modules/ThirdParty/VNL/src/vxl/vcl/CMakeLists.txt +index 89e2b99f71..fed3b8e268 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/CMakeLists.txt ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/CMakeLists.txt +@@ -73,7 +73,7 @@ if( VXL_MANUAL_GENERATE_NEW_COMPILER_DETECTION_HEADERS ) + cxx_long_long_type # long long type, as defined in N1811. + cxx_noexcept # Exception specifications, as defined in N3050. + cxx_nonstatic_member_init # Non-static data member initialization, as defined in N2756. +- cxx_nullptr # Null pointer, as defined in N2431. ++ cxx_VXL_NULLPTR # Null pointer, as defined in N2431. + cxx_override # Override control override keyword, as defined in N2928, N3206 and N3272. + cxx_range_for # Range-based for, as defined in N2930. + cxx_raw_string_literals # Raw string literals, as defined in N2442. +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/compilers/VXL_COMPILER_INFO_AppleClang_CXX.h b/Modules/ThirdParty/VNL/src/vxl/vcl/compilers/VXL_COMPILER_INFO_AppleClang_CXX.h +index 196ab2d503..7ff70236c4 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/compilers/VXL_COMPILER_INFO_AppleClang_CXX.h ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/compilers/VXL_COMPILER_INFO_AppleClang_CXX.h +@@ -226,7 +226,7 @@ + # define VXL_COMPILER_CXX_NONSTATIC_MEMBER_INIT 0 + # endif + +-# if ((__clang_major__ * 100) + __clang_minor__) >= 400 && __has_feature(cxx_nullptr) ++# if ((__clang_major__ * 100) + __clang_minor__) >= 400 && __has_feature(cxx_VXL_NULLPTR) + # define VXL_COMPILER_CXX_NULLPTR 1 + # else + # define VXL_COMPILER_CXX_NULLPTR 0 +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/compilers/VXL_COMPILER_INFO_Clang_CXX.h b/Modules/ThirdParty/VNL/src/vxl/vcl/compilers/VXL_COMPILER_INFO_Clang_CXX.h +index 752ad86223..cae90561d2 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/compilers/VXL_COMPILER_INFO_Clang_CXX.h ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/compilers/VXL_COMPILER_INFO_Clang_CXX.h +@@ -225,7 +225,7 @@ + # define VXL_COMPILER_CXX_NONSTATIC_MEMBER_INIT 0 + # endif + +-# if ((__clang_major__ * 100) + __clang_minor__) >= 301 && __has_feature(cxx_nullptr) ++# if ((__clang_major__ * 100) + __clang_minor__) >= 301 && __has_feature(cxx_VXL_NULLPTR) + # define VXL_COMPILER_CXX_NULLPTR 1 + # else + # define VXL_COMPILER_CXX_NULLPTR 0 +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_atomic_count.cxx b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_atomic_count.cxx +index 43ba3e5feb..605e73114a 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_atomic_count.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_atomic_count.cxx +@@ -1,7 +1,7 @@ + #include + #include + +-#define TEST(str,x,y) vcl_printf(str ": "); if (x!=y) { vcl_printf("FAILED\n"); status = 1; } else { vcl_printf("PASSED\n"); } ++#define TEST(str,x,y) vcl_printf(str ": "); if ((x)!=(y)) { vcl_printf("FAILED\n"); status = 1; } else { vcl_printf("PASSED\n"); } + + int test_atomic_count_main(int /*argc*/,char* /*argv*/[]) + { +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_cmath.cxx b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_cmath.cxx +index 5ca2b758e6..ebc552b521 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_cmath.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_cmath.cxx +@@ -24,7 +24,7 @@ int test_cmath_main(int /*argc*/,char* /*argv*/[]) + + #define macro(var, type) \ + do { \ +- if (vcl_abs(var) == var && vcl_abs(- var) == var) \ ++ if (vcl_abs(var) == (var) && vcl_abs(- (var)) == (var)) \ + vcl_cout << "vcl_abs(" #type ") PASSED" << vcl_endl; \ + else \ + vcl_cerr << "vcl_abs(" #type ") *** FAILED *** " << vcl_endl; \ +@@ -58,7 +58,7 @@ do { \ + do { \ + T x = 2; \ + T y = vcl_sqrt(x); \ +- if (vcl_abs(x - y*y) < eps) \ ++ if (vcl_abs(x - y*y) < (eps)) \ + vcl_cout << "vcl_sqrt(" #T ") PASSED" << vcl_endl; \ + else \ + vcl_cout << "vcl_sqrt(" #T ") *** FAILED *** " << vcl_endl; \ +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_limits.cxx b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_limits.cxx +index 4d4fb1aa24..40ed03dd02 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_limits.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_limits.cxx +@@ -49,8 +49,8 @@ void test_static_const_definition() + #undef TEST_TYPE + } + +-#define TEST(m,x,y) if ((x)!=(y)) { vcl_cout<< "FAIL: " << m << '\n'; fail=true; } \ +- else { vcl_cout<< "PASS: " << m << '\n'; } ++#define TEST(m,x,y) if ((x)!=(y)) { vcl_cout<< "FAIL: " << (m) << '\n'; fail=true; } \ ++ else { vcl_cout<< "PASS: " << (m) << '\n'; } + + int test_limits_main(int /*argc*/, char* /*argv*/[]) + { +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_memory.cxx b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_memory.cxx +index a76e92d467..b87977af9f 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_memory.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_memory.cxx +@@ -14,14 +14,14 @@ struct A + + struct B: public A {}; + +-static int function_call(vcl_auto_ptr a) ++static int function_call(vcl_unique_ptr a) + { + return a.get()? 1:0; + } + + static A* get_A(A& a) { return &a; } + +-static vcl_auto_ptr generate_auto_ptr () { return vcl_auto_ptr(new A); } ++static vcl_unique_ptr generate_auto_ptr () { return vcl_unique_ptr(new A); } + + int test_memory_main(int /*argc*/,char* /*argv*/[]) + { +@@ -29,11 +29,11 @@ int test_memory_main(int /*argc*/,char* /*argv*/[]) + + // Keep everything in a subscope so we can detect leaks. + { +- vcl_auto_ptr pa0; +- vcl_auto_ptr pa1(new A()); +- vcl_auto_ptr pb1(new B()); +- vcl_auto_ptr pa2(new B()); +- vcl_auto_ptr pa3(pb1); ++ vcl_unique_ptr pa0; ++ vcl_unique_ptr pa1(new A()); ++ vcl_unique_ptr pb1(new B()); ++ vcl_unique_ptr pa2(new B()); ++ vcl_unique_ptr pa3(vcl_move(pb1)); + + A* ptr = get_A(*pa1); + ASSERT(ptr == pa1.get(), +@@ -55,12 +55,12 @@ int test_memory_main(int /*argc*/,char* /*argv*/[]) + delete pa0.release(); + ASSERT(!pa0.get(), "auto_ptr holds an object after release()"); + +- pa1 = pa3; ++ pa1 = vcl_move(pa3); + ASSERT(!pa3.get(), "auto_ptr holds an object after assignment to another"); + ASSERT(pa1.get(), + "auto_ptr does not hold an object after assignment from another"); + +- int copied = function_call(pa2); ++ int copied = function_call(vcl_move(pa2)); + ASSERT(copied, "auto_ptr did not receive ownership in called function"); + ASSERT(!pa2.get(), "auto_ptr did not release ownership to called function"); + +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_sstream.cxx b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_sstream.cxx +index 32e454954d..9bbbe02526 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_sstream.cxx ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_sstream.cxx +@@ -2,7 +2,7 @@ + #include + #include + +-#define AssertEq(x,y) {status+=((x)==(y))?0:1;vcl_cout<<"TEST ["< 2 ) ++# define VCL_GCC_83 ++# elif (__GNUC_MINOR__ > 1 ) ++# define VCL_GCC_82 ++# elif (__GNUC_MINOR__ > 0 ) ++# define VCL_GCC_81 ++# else ++# define VCL_GCC_80 ++# endif + # else + # error "Dunno about this gcc" + # endif +@@ -897,7 +908,7 @@ __inline int vcl_snprintf(char *outBuf, size_t size, const char *format, ...) + #define vcl_uninitialized_copy std::uninitialized_copy + #define vcl_uninitialized_fill std::uninitialized_fill + #define vcl_uninitialized_fill_n std::uninitialized_fill_n +-#define vcl_auto_ptr std::auto_ptr ++#define vcl_auto_ptr vcl_auto_ptr + #define vcl_bad_alloc std::bad_alloc + #define vcl_set_new_handler std::set_new_handler + #define vcl_accumulate std::accumulate +diff --git a/Modules/ThirdParty/VNL/src/vxl/vcl/vcl_memory.h b/Modules/ThirdParty/VNL/src/vxl/vcl/vcl_memory.h +index b15a5f4368..da038dd721 100644 +--- a/Modules/ThirdParty/VNL/src/vxl/vcl/vcl_memory.h ++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/vcl_memory.h +@@ -2,6 +2,19 @@ + #define vcl_memory_h_ + + #include ++#include + #include "vcl_compiler.h" + ++// Needed to provide backwards compatibility between C++11 and older compilers ++// https://softwareengineering.stackexchange.com/questions/291141/how-to-handle-design-changes-for-auto-ptr-deprecation-in-c11 ++#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER > 540) ++ template ++ using vcl_unique_ptr = std::unique_ptr; ++ #define vcl_move( value ) std::move(value) ++#else ++// NOTE: THIS DOES NOT MEET THE STANDARDS FOR A UNIQUE POINTER! ++# define vcl_unique_ptr std::auto_ptr ++# define vcl_move( value ) value ++#endif ++ + #endif // vcl_memory_h_ diff --git a/CMakeExternals/ITK.cmake b/CMakeExternals/ITK.cmake index cf66989655..0109ff72a3 100644 --- a/CMakeExternals/ITK.cmake +++ b/CMakeExternals/ITK.cmake @@ -1,77 +1,77 @@ #----------------------------------------------------------------------------- # ITK #----------------------------------------------------------------------------- # Sanity checks if(DEFINED ITK_DIR AND NOT EXISTS ${ITK_DIR}) message(FATAL_ERROR "ITK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj ITK) set(proj_DEPENDENCIES GDCM) if(MITK_USE_OpenCV) list(APPEND proj_DEPENDENCIES OpenCV) endif() if(MITK_USE_HDF5) list(APPEND proj_DEPENDENCIES HDF5) endif() set(ITK_DEPENDS ${proj}) if(NOT DEFINED ITK_DIR) set(additional_cmake_args -DUSE_WRAP_ITK:BOOL=OFF) if(MITK_USE_OpenCV) list(APPEND additional_cmake_args -DModule_ITKVideoBridgeOpenCV:BOOL=ON -DOpenCV_DIR:PATH=${OpenCV_DIR} ) endif() # Keep the behaviour of ITK 4.3 which by default turned on ITK Review # see MITK bug #17338 list(APPEND additional_cmake_args -DModule_ITKReview:BOOL=ON # for 4.7, the OpenJPEG is needed by review but the variable must be set -DModule_ITKOpenJPEG:BOOL=ON ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/InsightToolkit-4.13.0.tar.xz URL_MD5 3badf70cfb0093054453f66c5974c5a4 # work with external GDCM - # PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/ITK-4.11.0.patch + PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/ITK-VNL-2018-05-16.patch CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} -DBUILD_EXAMPLES:BOOL=OFF -DITK_USE_SYSTEM_GDCM:BOOL=ON -DGDCM_DIR:PATH=${GDCM_DIR} -DITK_USE_SYSTEM_HDF5:BOOL=ON -DHDF5_DIR:PATH=${HDF5_DIR} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(ITK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/OpenCV.cmake b/CMakeExternals/OpenCV.cmake index fcc38cd141..bbf8c8715f 100644 --- a/CMakeExternals/OpenCV.cmake +++ b/CMakeExternals/OpenCV.cmake @@ -1,98 +1,100 @@ #----------------------------------------------------------------------------- # OpenCV #----------------------------------------------------------------------------- if(MITK_USE_OpenCV) # Sanity checks if(DEFINED OpenCV_DIR AND NOT EXISTS ${OpenCV_DIR}) message(FATAL_ERROR "OpenCV_DIR variable is defined but corresponds to non-existing directory") endif() set(proj OpenCV) set(proj_DEPENDENCIES) set(OpenCV_DEPENDS ${proj}) if(NOT DEFINED OpenCV_DIR) set(additional_cmake_args -DBUILD_opencv_java:BOOL=OFF -DBUILD_opencv_ts:BOOL=OFF -DBUILD_PERF_TESTS:BOOL=OFF ) if(MITK_USE_Python) set(CV_PACKAGE_PATH -DPYTHON_PACKAGES_PATH:PATH=${ep_prefix}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages) list(APPEND additional_cmake_args -DBUILD_opencv_python:BOOL=ON -DBUILD_opencv_python3:BOOL=ON #-DBUILD_NEW_PYTHON_SUPPORT:BOOL=ON -DPYTHON_DEBUG_LIBRARY:FILEPATH=${PYTHON_DEBUG_LIBRARY} -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} ${CV_PACKAGE_PATH} #-DPYTHON_LIBRARIES=${PYTHON_LIBRARY} #-DPYTHON_DEBUG_LIBRARIES=${PYTHON_DEBUG_LIBRARIES} ) else() list(APPEND additional_cmake_args -DBUILD_opencv_python:BOOL=OFF -DBUILD_opencv_python3:BOOL=OFF -DBUILD_opencv_python_bindings_generator:BOOL=OFF #-DBUILD_NEW_PYTHON_SUPPORT:BOOL=OFF ) endif() # 12-05-02, muellerm, added QT usage by OpenCV if QT is used in MITK # 12-09-11, muellerm, removed automatic usage again, since this will struggle with the MITK Qt application object if(MITK_USE_Qt5) list(APPEND additional_cmake_args -DWITH_QT:BOOL=OFF -DWITH_QT_OPENGL:BOOL=OFF -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() - set(opencv_url ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/opencv-3.4.1.zip) - set(opencv_url_md5 8464ce888f4c283895626950bada1e44) + set(opencv_url ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/opencv-3.4.1.tar.gz) + set(opencv_url_md5 a0b7a47899e67b3490ea31edc4f6e8e6) ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${opencv_url} URL_MD5 ${opencv_url_md5} CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} -DBUILD_TESTS:BOOL=OFF -DBUILD_DOCS:BOOL=OFF -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_DOXYGEN_DOCS:BOOL=OFF -DWITH_CUDA:BOOL=OFF -DWITH_VTK:BOOL=OFF -DENABLE_CXX11:BOOL=ON + -DWITH_IPP:BOOL=OFF + -DBUILD_IPP_IW:BOOL=OFF ${additional_cmake_args} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(OpenCV_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index bbeefc4676..58ef8a6fea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1347 +1,1347 @@ set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.10) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) #----------------------------------------------------------------------------- # See https://cmake.org/cmake/help/v3.10/manual/cmake-policies.7.html for details #----------------------------------------------------------------------------- set(project_policies ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") mark_as_advanced(MITK_EXTENSION_DIRS) #----------------------------------------------------------------------------- # 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 2016.11.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Update CMake module path #----------------------------------------------------------------------------- set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake) get_filename_component(MITK_CMAKE_EXTENSION_DIR ${MITK_CMAKE_EXTENSION_DIR} ABSOLUTE) 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(CTestUseLaunchers) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) include(mitkFunctionGenerateProjectXml) include(mitkFunctionEnableBuildConfiguration) include(mitkFunctionWhitelists) include(mitkFunctionAddExternalProject) 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() #----------------------------------------------------------------------------- # Check miminum Mac OS X version #----------------------------------------------------------------------------- # The minimum supported Mac OS X version is 10.9. If you use a version less than 10.9, there is no guarantee that the build still works. if(APPLE) exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE osx_version) if (osx_version VERSION_LESS "10.9") message(WARNING "Detected OS X version \"${osx_version}\" is not supported anymore. Minimum required OS X version is 10.9 or greater.") endif() if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.9) message(WARNING "Detected OS X deployment target \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" is not supported anymore. Minimum required OS X version is 10.9 or greater.") endif() endif() #----------------------------------------------------------------------------- # Check miminum compiler versions #----------------------------------------------------------------------------- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # require at least gcc 4.9 as provided by ppa:ubuntu-toolchain-r/test for Ubuntu 14.04 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) message(FATAL_ERROR "GCC version must be at least 4.9 If you are using Ubuntu 14.04, you can easily install gcc and g++ 4.9 (or any later version available) in addition to your version ${CMAKE_CXX_COMPILER_VERSION}: sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-4.9 g++-4.9 Make sure to explicitly specify these compilers when configuring MITK: CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-4.9 CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-4.9 For more information on the proposed PPA see the Toolchain Updates section of https://wiki.ubuntu.com/ToolChain.") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # require at least clang 3.4 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) message(FATAL_ERROR "Clang version must be at least 3.4") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # require at least clang 5.0 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) message(FATAL_ERROR "Apple Clang version must be at least 5.0") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # require at least Visual Studio 2015 - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) - message(FATAL_ERROR "Microsoft Visual Studio 2015 Update 3 or newer required") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) + message(FATAL_ERROR "Microsoft Visual Studio 2017 or newer required") endif() else() message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang (Linux or Apple), GCC and MSVC.") endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 14) 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++14 flag for targets. # However, compile flag checks also need to be done with -std=c++14. # The MITK_CXX14_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++14" MITK_CXX14_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) #----------------------------------------------------------------------------- macro(env_option name doc value) set(_value $ENV{${name}}) if("${_value}" STREQUAL "") set(_value ${value}) endif() option(${name} "${doc}" ${_value}) endmacro() # ----------------------------------------- # 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) env_option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) env_option(MITK_BUILD_EXAMPLES "Build the MITK Examples" OFF) option(MITK_ENABLE_PIC_READER "Enable support for reading the DKFZ pic file format." ON) mark_as_advanced(MITK_BUILD_ALL_APPS MITK_ENABLE_PIC_READER ) # ----------------------------------------- # Qt version related variables env_option(MITK_USE_Qt5 "Use Qt 5 library" ON) if(MITK_USE_Qt5) - set(MITK_QT5_MINIMUM_VERSION 5.6.0) + set(MITK_QT5_MINIMUM_VERSION 5.11.1) set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets Xml XmlPatterns WebEngineWidgets UiTools Help LinguistTools) if(APPLE) set(MITK_QT5_COMPONENTS ${MITK_QT5_COMPONENTS} DBus) endif() find_package(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS} REQUIRED) endif() set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") include(CMakeExternals/ExternalProjectList.cmake) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMakeExternals) get_filename_component(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR} ABSOLUTE) 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 env_option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) env_option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" 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() 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) # ----------------------------------------- # Custom dependency logic 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") # only windows can't build python in debug mode if(MITK_USE_Python AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND WIN32) message(WARNING "Disabling Python support. Building MITK Python in debug mode on Windowsis not supported!") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) set(MITK_USE_Numpy OFF CACHE BOOL "Use Numpy" FORCE) set(MITK_USE_SimpleITK OFF CACHE BOOL "Use SimpleITK" FORCE) elseif(MITK_USE_Python) set(MITK_USE_ZLIB ON) if(NOT MITK_USE_Numpy) message("> Forcing MITK_USE_Numpy to ON because of MITK_USE_Python") set(MITK_USE_Numpy ON CACHE BOOL "Use Numpy" FORCE) endif() if(NOT MITK_USE_SimpleITK) message("> Forcing MITK_USE_SimpleITK to ON because of MITK_USE_Python") set(MITK_USE_SimpleITK ON CACHE BOOL "Use SimpleITK" FORCE) endif() find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) elseif(MITK_USE_Python AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND WIN32) message(WARNING "Disabling Python support. Building MITK Python in debug mode on Windowsis not supported!") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) 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() #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) list(APPEND CTEST_PROJECT_SUBPROJECTS MITK-Core MITK-CoreUI MITK-IGT MITK-ToF MITK-DTI MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # 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 **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(GenerateExportHeader) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionConvertXPSchema) 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(mitkFunctionTestPlugin) 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 #----------------------------------------------------------------------------- # Required and enabled C++14 features for all MITK code. # These are added as PUBLIC compile features to all MITK modules. set(MITK_CXX_FEATURES cxx_auto_type cxx_decltype cxx_enum_forward_declarations cxx_extended_friend_declarations cxx_extern_templates cxx_final cxx_lambdas cxx_local_type_template_args cxx_long_long_type cxx_nullptr cxx_override cxx_range_for cxx_right_angle_brackets cxx_rvalue_references cxx_static_assert cxx_strong_enums cxx_template_template_parameters cxx_trailing_return_types cxx_variadic_macros ) 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) #----------------------------------------------------------------------------- # 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 CoreApp and mitkWorkbench 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) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING 1) 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 Mac OSX all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/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() #----------------------------------------------------------------------------- # 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_CXX14_FLAG}") set(MITK_CXX_FLAGS_DEBUG ) set(MITK_CXX_FLAGS_RELEASE ) set(MITK_EXE_LINKER_FLAGS ) set(MITK_SHARED_LINKER_FLAGS ) find_package(OpenMP) if (OPENMP_FOUND) set(MITK_C_FLAGS "${MITK_C_FLAGS} ${OpenMP_C_FLAGS}") set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -D_WIN32_WINNT=0x0501 -DPOCO_NO_UNWINDOWS -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 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-array-bounds -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_EXTENSION_DIRS}) set(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake/PackageDepends) get_filename_component(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR} ABSOLUTE) 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.65" "1.65.1") # 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) # 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() 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_Python) find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) if(MITK_USE_Numpy) find_package(Numpy REQUIRED) endif() endif() link_directories(${Boost_LIBRARY_DIRS}) if(MITK_USE_OpenIGTLink) link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() if(MITK_USE_SimpleITK) link_directories(${SimpleITK_LIBRARY_DIRS}) endif() if(MITK_USE_OpenCL) find_package(OpenCL REQUIRED) 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) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) option(MITK_ENABLE_RENDERING_TESTING OFF "Enable the MITK rendering tests. Requires x-server in Linux.") #Rendering testing does not work for Linux nightlies, thus it is disabled per default #and activated for Mac and Windows. if(WIN32 OR APPLE) set(MITK_ENABLE_RENDERING_TESTING ON) endif() mark_as_advanced( MITK_ENABLE_RENDERING_TESTING ) # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) # Initial cache for ProjectTemplate and PluginGenerator tests configure_file( CMake/mitkTestInitialCache.txt.in ${MITK_BINARY_DIR}/mitkTestInitialCache.txt @ONLY ) # 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( std::exception & excp ) { fprintf(stderr,\"%s\\n\",excp.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 external project template if(MITK_USE_BLUEBERRY) include(mitkTestProjectTemplate) 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 custom targets representing CDash subprojects #----------------------------------------------------------------------------- foreach(subproject ${CTEST_PROJECT_SUBPROJECTS}) if(NOT TARGET ${subproject} AND NOT subproject MATCHES "Unlabeled") add_custom_target(${subproject}) endif() endforeach() #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Utilities) add_subdirectory(Modules) include("${CMAKE_CURRENT_SOURCE_DIR}/Modules/ModuleList.cmake") mitkFunctionWhitelistModules(MITK MITK_MODULES) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_MODULES_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Modules) get_filename_component(MITK_MODULES_EXTENSION_DIR ${MITK_MODULES_EXTENSION_DIR} ABSOLUTE) 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() add_subdirectory(Wrapping) if(MITK_USE_BLUEBERRY) set(BLUEBERRY_XPDOC_OUTPUT_DIR ${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/) # Plug-in testing (needs some work to be enabled again) if(BUILD_TESTING) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp") if(TARGET CoreApp) get_target_property(_is_macosx_bundle CoreApp MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp.app/Contents/MacOS/CoreApp") endif() endif() set(BLUEBERRY_TEST_APP_ID "org.mitk.qt.coreapplication") endif() 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_EXTENSION_DIRS}) set(MITK_PLUGINS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Plugins) get_filename_component(MITK_PLUGINS_EXTENSION_DIR ${MITK_PLUGINS_EXTENSION_DIR} ABSOLUTE) 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 include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") set(mitk_apps_fullpath ) 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 "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${directory_name}^^${option_name}") 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 #----------------------------------------------------------------------------- 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) # MITK_APPS is set in Applications/AppList.cmake (included somewhere above # if MITK_USE_BLUEBERRY is set to ON). if(MITK_APPS) set(activated_apps_no 0) list(LENGTH MITK_APPS app_count) # Check how many apps have been enabled # If more than one app has been activated, the we use the # default CPack configuration. Otherwise that apps configuration # will be used, if present. 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) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() 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 ${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 "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/Applications/${target_dir}/CPackConfig.cmake") configure_file(${PROJECT_SOURCE_DIR}/Applications/${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() endif() # 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() #----------------------------------------------------------------------------- # 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/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox index 7dfbe99186..96ad095432 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox @@ -1,217 +1,216 @@ /** \page BuildInstructionsPage Build Instructions \tableofcontents \section BuildInstructions_Introduction Introduction The CMake-based build system of MITK supports a "superbuild" process, meaning that it will download, configure, and build all required third-party libraries (except Qt) automatically. These instructions will show you how to use the MITK superbuild. \note This page explains explicitly how to build MITK itself. If you want to create your own project based on MITK, the process described below is completely automated. Please see \ref HowToNewProject. For more advanced users, the last sections explains how to inject custom build libraries into the superbuild process. \section BuildInstructions_Prerequisites Prerequisites You need: -# Git from http://git-scm.com (there are also numerous third-party graphical clients available). We recomment using Git, but see below for a way how to get the current source code without using it. -# CMake (version \minimumCMakeVersion or higher) - -# Qt 5.6 or 5.7.1 if you plan to develop Qt-based + -# Qt 5.10.1 if you plan to develop Qt-based applications - -# If you are using Mac OS X you need an XCode installation as it + -# If you are using macOS you need an XCode installation as it provides the neccessary compilers and SDKs \section BuildInstructions_Qt A note about Qt As we do not provide Qt in the MITK superbuild you need to install Qt manually. -Installing Qt dramatically improved since Qt 5, as The Qt Company provides -sophisticated online installers for all -supported platforms. +The Qt Company provides online installers +for all supported platforms. \section BuildInstructions_Get_Source Get a source tree Since MITK is under active development we recommend to use Git to check out the latest stable release from the homepage. If you decide to use the most current nightly release, make sure to get a stable tree: Check the MITK dashboard before checking out. If the build tree is not clean, you can specify an older revision for the checkout or get a stable tar ball from www.mitk.org. To clone MITK's current Git repository do: \code git clone https://phabricator.mitk.org/source/mitk.git MITK \endcode \section BuildInstructions_Build_With_CMake Build MITK with CMake Create a new directory for the superbuild binary tree, change to it and call CMake: In the shell (assuming your current directory is the same as the one where you issued the git clone command): \code mkdir MITK-superbuild cd MITK-superbuild ccmake ../MITK \endcode If you use Windows or prefer to use the CMake GUI, start the CMake GUI and enter the location of the source tree and binary tree, choose a suitable generator and configure the project. CMake will present you a couple of options, these are the most important ones: - CMAKE_PREFIX_PATH The path to your Qt installation, e.g., C:/Qt/5.6/msvc2013_64 or /home/user/Qt/5.6/gcc_64 - MITK_USE_ACVD Build MITK code which depends on ACVD (this will download and build ACVD) - MITK_USE_BLUEBERRY Build the BlueBerry application framework - MITK_USE_Boost_LIBRARIES If you need binary Boost libraries, specify them here. - MITK_USE_OpenCV Build MITK code which depends on OpenCV (this will download and build OpenCV 2.4) - MITK_USE_Python Enables Python wrapping in MITK. This will also configure ITK, VTK, and OpenCV (if enabled) to build Python wrappers. - MITK_USE_Qt5 Build MITK code which depends on Qt 5 If you are satisfied with the configuration of your MITK superbuild, generate the project files with CMake by pressing "Generate". Linux and Mac OS X users usually just enter "make" (optionally supplying the number threads to be used for a parallel build): \code make -j6 \endcode Windows users using Visual Studio can open the generated MITK-superbuild.sln solution file in the MITK-superbuild directory and start the build by building the BUILD_ALL project. \section BuildInstructions_Customize Customize your MITK superbuild The MITK superbuild configures MITK as well as all external libraries. The build directories of these libraries, and of MITK itself are located inside the MITK-superbuild directory. For example, the directory layout may look like: \code MITK-superbuild |- ep "external projects" |-bin |-lib |-include |-src |- MITK-build \endcode To change the configuration of the MITK build itself, choose the MITK-build directory as the binary directory in the CMake GUI (not the MITK-superbuild directory). After generating the project files, build the MITK project by either issuing "make" in the MITK-build directory (Linux, Mac OS X), or by opening MITK-build/MITK.sln (Windows). You may also change the configuration of any project configured via the superbuild process. Make sure to also build the changed project and also the projects which depend on it. \section BuildInstructions_Running Running Applications On Linux, just execute the application you want to run. MITK executables are located in MITK-superbuild/MITK-build/bin On Windows, the PATH environment variable must contain the directories containing the third-party libraries. This is automatically done from Visual Studio. For running the applications directly use the generated batch files in the MITK-superbuild/MITK-build/bin. \section BuildInstructions_Documentation Documentation If you have the Doxygen documentation tool installed, you get a new project (Visual Studio) or "make" target named "doc". You can build this to generate the HTML documentation of MITK in the Documentation/Doxygen directory of your MITK-build binary tree or in the MITK_DOXYGEN_OUTPUT_DIR CMake variable (if specified). \section BuildInstructions_Extending Extend MITK on your own (using the application framework BlueBerry) Please see \ref NewPluginPage \section BuildInstructions_As_Toolkit Use MITK in your own project (as a toolkit) To use MITK in your external project, add the CMake command find_package(MITK REQUIRED) to your CMakeLists.txt and make use of the CMake macros mitk_create_module() and mitk_create_executable() provided by MITK. Here is a very basic example CMakeLists.txt including MITK as a project: \code cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(MyProject) find_package(MITK 2016.11 REQUIRED) add_executable(MyApp main.cpp) target_link_libraries(MyApp MitkCore) \endcode with the main.ccp being \code #include #include int main() { MITK_INFO << "Hello world!"; return 0; } \endcode \section BuildInstructions_Advanced_Customization Superbuild customization You can inject pre-build third-party libraries into the MITK superbuild by setting certain CMake variables before the first configure step. MITK will then use these third-party libraries instead of downloading and building them by itself. Note that you must take care of configuring those libraries with all options MITK requires. The variables listed below are provided for injecting third-party libraries. Their occurrence in the CMake GUI or in ccmake may depend on specific MITK_USE_* options set to ON. You may also use the variable names below without the EXTERNAL_ prefix, for example when providing their values on a command line call to CMake. - EXTERNAL_BOOST_ROOT Set this variable to your custom Boost installation - EXTERNAL_CTK_DIR Set this variable to your CTK binary tree (the directory containing the CTKConfig.cmake file) - EXTERNAL_CableSwig_DIR Set this variable to your CableSwig binary tree for Python wrapping (the directory containing the CableSwigConfig.cmake file) - EXTERNAL_DCMTK_DIR Set this variable to your DCMTK binary tree (the directory containing the DCMTKConfig.cmake file) - EXTERNAL_GDCM_DIR Set this variable to your GDCM binary tree (the directory containing the GDCMConfig.cmake file) - EXTERNAL_ITK_DIR Set this variable to your ITK binary tree (the directory containing the ITKConfig.cmake file) - EXTERNAL_OpenCV_DIR Set this variable to your OpenCV binary tree (the directory containing the OpenCVConfig.cmake file) - EXTERNAL_VTK_DIR Set this variable to your VTK binary tree (the directory containing the VTKConfig.cmake file) To set CMake options before the first configure step is invoked, supply them on the command line, i.e. \code ccmake -DITK_DIR:PATH=/opt/ITK-release ../MITK \endcode */ diff --git a/Modules/CEST/src/mitkCustomTagParser.cpp b/Modules/CEST/src/mitkCustomTagParser.cpp index a65ccf6f35..c057044c32 100644 --- a/Modules/CEST/src/mitkCustomTagParser.cpp +++ b/Modules/CEST/src/mitkCustomTagParser.cpp @@ -1,797 +1,797 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCustomTagParser.h" #include #include #include #include "mitkIPropertyPersistence.h" #include "usGetModuleContext.h" #include "usModule.h" #include "usModuleContext.h" #include "usModuleResource.h" #include "usModuleResourceStream.h" #include #include #include #include #include #include #include #include namespace { mitk::IPropertyPersistence *GetPersistenceService() { mitk::IPropertyPersistence *result = nullptr; std::vector> persRegisters = us::GetModuleContext()->GetServiceReferences(); if (!persRegisters.empty()) { if (persRegisters.size() > 1) { MITK_WARN << "Multiple property description services found. Using just one."; } result = us::GetModuleContext()->GetService(persRegisters.front()); } return result; }; } const std::string mitk::CustomTagParser::m_CESTPropertyPrefix = "CEST."; const std::string mitk::CustomTagParser::m_OffsetsPropertyName = m_CESTPropertyPrefix + "Offsets"; const std::string mitk::CustomTagParser::m_RevisionPropertyName = m_CESTPropertyPrefix + "Revision"; const std::string mitk::CustomTagParser::m_JSONRevisionPropertyName = m_CESTPropertyPrefix + "revision_json"; const std::string mitk::CustomTagParser::m_RevisionIndependentMapping = "\n" " \"sProtConsistencyInfo.tSystemType\" : \"SysType\",\n" " \"sProtConsistencyInfo.flNominalB0\" : \"NominalB0\",\n" " \"sTXSPEC.asNucleusInfo[0].lFrequency\" : \"FREQ\",\n" " \"sTXSPEC.asNucleusInfo[0].flReferenceAmplitude\" : \"RefAmp\",\n" " \"alTR[0]\" : \"TR\",\n" " \"alTE[0]\" : \"TE\",\n" " \"lAverages\" : \"averages\",\n" " \"lRepetitions\" : \"repetitions\",\n" " \"adFlipAngleDegree[0]\" : \"ImageFlipAngle\",\n" " \"lTotalScanTimeSec\" : \"TotalScanTime\","; const std::string mitk::CustomTagParser::m_DefaultJsonString = "{\n" " \"default mapping, corresponds to revision 1416\" : \"revision_json\",\n" " \"sWiPMemBlock.alFree[1]\" : \"AdvancedMode\",\n" " \"sWiPMemBlock.alFree[2]\" : \"RecoveryMode\",\n" " \"sWiPMemBlock.alFree[3]\" : \"DoubleIrrMode\",\n" " \"sWiPMemBlock.alFree[4]\" : \"BinomMode\",\n" " \"sWiPMemBlock.alFree[5]\" : \"MtMode\",\n" " \"sWiPMemBlock.alFree[6]\" : \"PreparationType\",\n" " \"sWiPMemBlock.alFree[7]\" : \"PulseType\",\n" " \"sWiPMemBlock.alFree[8]\" : \"SamplingType\",\n" " \"sWiPMemBlock.alFree[9]\" : \"SpoilingType\",\n" " \"sWiPMemBlock.alFree[10]\" : \"measurements\",\n" " \"sWiPMemBlock.alFree[11]\" : \"NumberOfPulses\",\n" " \"sWiPMemBlock.alFree[12]\" : \"NumberOfLockingPulses\",\n" " \"sWiPMemBlock.alFree[13]\" : \"PulseDuration\",\n" " \"sWiPMemBlock.alFree[14]\" : \"DutyCycle\",\n" " \"sWiPMemBlock.alFree[15]\" : \"RecoveryTime\",\n" " \"sWiPMemBlock.alFree[16]\" : \"RecoveryTimeM0\",\n" " \"sWiPMemBlock.alFree[17]\" : \"ReadoutDelay\",\n" " \"sWiPMemBlock.alFree[18]\" : \"BinomDuration\",\n" " \"sWiPMemBlock.alFree[19]\" : \"BinomDistance\",\n" " \"sWiPMemBlock.alFree[20]\" : \"BinomNumberofPulses\",\n" " \"sWiPMemBlock.alFree[21]\" : \"BinomPreRepetions\",\n" " \"sWiPMemBlock.alFree[22]\" : \"BinomType\",\n" " \"sWiPMemBlock.adFree[1]\" : \"Offset\",\n" " \"sWiPMemBlock.adFree[2]\" : \"B1Amplitude\",\n" " \"sWiPMemBlock.adFree[3]\" : \"AdiabaticPulseMu\",\n" " \"sWiPMemBlock.adFree[4]\" : \"AdiabaticPulseBW\",\n" " \"sWiPMemBlock.adFree[5]\" : \"AdiabaticPulseLength\",\n" " \"sWiPMemBlock.adFree[6]\" : \"AdiabaticPulseAmp\",\n" " \"sWiPMemBlock.adFree[7]\" : \"FermiSlope\",\n" " \"sWiPMemBlock.adFree[8]\" : \"FermiFWHM\",\n" " \"sWiPMemBlock.adFree[9]\" : \"DoubleIrrDuration\",\n" " \"sWiPMemBlock.adFree[10]\" : \"DoubleIrrAmplitude\",\n" " \"sWiPMemBlock.adFree[11]\" : \"DoubleIrrRepetitions\",\n" " \"sWiPMemBlock.adFree[12]\" : \"DoubleIrrPreRepetitions\"\n" "}"; mitk::CustomTagParser::CustomTagParser(std::string relevantFile) : m_ClosestInternalRevision(""), m_ClosestExternalRevision("") { std::string pathToDirectory; std::string fileName; itksys::SystemTools::SplitProgramPath(relevantFile, pathToDirectory, fileName); m_DicomDataPath = pathToDirectory; m_ParseStrategy = "Automatic"; m_RevisionMappingStrategy = "Fuzzy"; } std::string mitk::CustomTagParser::ExtractRevision(std::string sequenceFileName) { //all rules are case insesitive. Thus we convert everything to lower case //in order to check everything only once. std::string cestPrefix = "cest"; std::string cestPrefix2 = "_cest"; std::string cestPrefix3 = "\\cest"; //this version covers the fact that the strings extracted //from the SIEMENS tag has an additional prefix that is seperated by backslash. std::string revisionPrefix = "_rev"; std::transform(sequenceFileName.begin(), sequenceFileName.end(), sequenceFileName.begin(), ::tolower); bool isCEST = sequenceFileName.compare(0, cestPrefix.length(), cestPrefix) == 0; std::size_t foundPosition = 0; if (!isCEST) { foundPosition = sequenceFileName.find(cestPrefix2); isCEST = foundPosition != std::string::npos; } if (!isCEST) { foundPosition = sequenceFileName.find(cestPrefix3); isCEST = foundPosition != std::string::npos; } if (!isCEST) { mitkThrow() << "Invalid CEST sequence file name. No CEST prefix found. Could not extract revision."; } foundPosition = sequenceFileName.find(revisionPrefix, foundPosition); if (foundPosition == std::string::npos) { mitkThrow() << "Invalid CEST sequence file name. No revision prefix was found in CEST sequence file name. Could not extract revision."; } std::string revisionString = sequenceFileName.substr(foundPosition + revisionPrefix.length(), std::string::npos); std::size_t firstNoneNumber = revisionString.find_first_not_of("0123456789"); if (firstNoneNumber != std::string::npos) { revisionString.erase(firstNoneNumber, std::string::npos); } return revisionString; } bool mitk::CustomTagParser::IsT1Sequence(std::string preparationType, std::string recoveryMode, std::string spoilingType, std::string revisionString) { bool isT1 = false; // if a forced parse strategy is set, use that one if ("T1" == m_ParseStrategy) { return true; } if ("CEST/WASABI" == m_ParseStrategy) { return false; } if (("T1Recovery" == preparationType) || ("T1Inversion" == preparationType)) { isT1 = true; } // How to interpret the recoveryMode depends on the age of the sequence // older sequences use 0 = false and 1 = true, newer ones 1 = false and 2 = true. // A rough rule of thumb is to assume that if the SpoilingType is 0, then the first // convention is chosen, if it is 1, then the second applies. Otherwise // we assume revision 1485 and newer to follow the new convention. // This unfortunate heuristic is due to somewhat arbitrary CEST sequence implementations. if (!isT1) { std::string thisIsTrue = "1"; std::string thisIsFalse = "0"; if ("0" == spoilingType) { thisIsFalse = "0"; thisIsTrue = "1"; } else if ("1" == spoilingType) { thisIsFalse = "1"; thisIsTrue = "2"; } else { int revisionNrWeAssumeToBeDifferenciating = 1485; if (std::stoi(revisionString) - revisionNrWeAssumeToBeDifferenciating < 0) { thisIsFalse = "0"; thisIsTrue = "1"; } else { thisIsFalse = "1"; thisIsTrue = "2"; } } if (thisIsFalse == recoveryMode) { isT1 = false; } else if (thisIsTrue == recoveryMode) { isT1 = true; } } return isT1; } mitk::PropertyList::Pointer mitk::CustomTagParser::ParseDicomPropertyString(std::string dicomPropertyString) { auto results = mitk::PropertyList::New(); if ("" == dicomPropertyString) { //MITK_ERROR << "Could not parse empty custom dicom string"; return results; } std::map privateParameters; // convert hex to ascii // the Siemens private tag contains the information like this // "43\52\23\34" we jump over each \ and convert the number int len = dicomPropertyString.length(); std::string asciiString; for (int i = 0; i < len; i += 3) { std::string byte = dicomPropertyString.substr(i, 2); auto chr = (char)(int)strtol(byte.c_str(), nullptr, 16); asciiString.push_back(chr); } // extract parameter list std::size_t beginning = asciiString.find("### ASCCONV BEGIN ###") + 21; std::size_t ending = asciiString.find("### ASCCONV END ###"); std::string parameterListString = asciiString.substr(beginning, ending - beginning); boost::replace_all(parameterListString, "\r\n", "\n"); boost::char_separator newlineSeparator("\n"); boost::tokenizer> parameters(parameterListString, newlineSeparator); for (const auto ¶meter : parameters) { std::vector parts; boost::split(parts, parameter, boost::is_any_of("=")); if (parts.size() == 2) { parts[0].erase(std::remove(parts[0].begin(), parts[0].end(), ' '), parts[0].end()); parts[1].erase(parts[1].begin(), parts[1].begin() + 1); // first character is a space privateParameters[parts[0]] = parts[1]; } } std::string revisionString = ""; try { revisionString = ExtractRevision(privateParameters["tSequenceFileName"]); } catch (const std::exception &e) { MITK_ERROR << "Cannot deduce revision information. Reason: "<< e.what(); return results; } results->SetProperty(m_RevisionPropertyName, mitk::StringProperty::New(revisionString)); std::string jsonString = GetRevisionAppropriateJSONString(revisionString); boost::property_tree::ptree root; std::istringstream jsonStream(jsonString); try { boost::property_tree::read_json(jsonStream, root); } - catch (boost::property_tree::json_parser_error e) + catch (const boost::property_tree::json_parser_error &e) { mitkThrow() << "Could not parse json file. Error was:\n" << e.what(); } for (auto it : root) { if (it.second.empty()) { std::string propertyName = m_CESTPropertyPrefix + it.second.data(); if (m_JSONRevisionPropertyName == propertyName) { results->SetProperty(propertyName, mitk::StringProperty::New(it.first)); } else { results->SetProperty(propertyName, mitk::StringProperty::New(privateParameters[it.first])); } } else { MITK_ERROR << "Currently no support for nested dicom tag descriptors in json file."; } } std::string sampling = ""; std::string offset = ""; std::string measurements = ""; bool hasSamplingInformation = results->GetStringProperty("CEST.SamplingType", sampling); results->GetStringProperty("CEST.Offset", offset); results->GetStringProperty("CEST.measurements", measurements); if ("" == measurements) { std::string stringRepetitions = ""; std::string stringAverages = ""; results->GetStringProperty("CEST.repetitions", stringRepetitions); results->GetStringProperty("CEST.averages", stringAverages); std::stringstream measurementStream; try { measurementStream << std::stoi(stringRepetitions) + std::stoi(stringAverages); measurements = measurementStream.str(); MITK_INFO << "Could not find measurements, assuming repetitions + averages. Which is: " << measurements; } catch (const std::invalid_argument &ia) { MITK_ERROR << "Could not find measurements, fallback assumption of repetitions + averages could not be determined either: " << ia.what(); } } std::string preparationType = ""; std::string recoveryMode = ""; std::string spoilingType = ""; results->GetStringProperty("CEST.PreparationType", preparationType); results->GetStringProperty("CEST.RecoveryMode", recoveryMode); results->GetStringProperty("CEST.SpoilingType", spoilingType); if (this->IsT1Sequence(preparationType, recoveryMode, spoilingType, revisionString)) { MITK_INFO << "Parsed as T1 image"; mitk::LocaleSwitch localeSwitch("C"); std::stringstream trecStream; std::string trecPath = m_DicomDataPath + "/TREC.txt"; std::ifstream list(trecPath.c_str()); if (list.good()) { std::string currentTime; while (std::getline(list, currentTime)) { trecStream << currentTime << " "; } } else { MITK_WARN << "Assumed T1, but could not load TREC at " << trecPath; } results->SetStringProperty("CEST.TREC", trecStream.str().c_str()); } else { MITK_INFO << "Parsed as CEST or WASABI image"; } if (hasSamplingInformation) { std::string offsets = GetOffsetString(sampling, offset, measurements); results->SetStringProperty(m_OffsetsPropertyName.c_str(), offsets.c_str()); } else { MITK_WARN << "Could not determine sampling type."; } - + //persist all properties mitk::IPropertyPersistence *persSrv = GetPersistenceService(); if (persSrv) { auto propertyMap = results->GetMap(); for (auto const &prop : *propertyMap) { PropertyPersistenceInfo::Pointer info = PropertyPersistenceInfo::New(); std::string key = prop.first; std::replace(key.begin(), key.end(), '.', '_'); info->SetNameAndKey(prop.first, key); persSrv->AddInfo(info); } } return results; } mitk::PropertyList::Pointer mitk::CustomTagParser::ParseDicomProperty(mitk::TemporoSpatialStringProperty *dicomProperty) { if (!dicomProperty) { MITK_ERROR << "DICOM property empty"; } auto results = mitk::PropertyList::New(); if (dicomProperty) { results = ParseDicomPropertyString(dicomProperty->GetValue()); } return results; } std::vector mitk::CustomTagParser::GetInternalRevisions() { const std::vector configs = us::GetModuleContext()->GetModule()->FindResources("/", "*.json", false); std::vector availableRevisionsVector; for (auto const resource : configs) { availableRevisionsVector.push_back(std::stoi(resource.GetBaseName())); } return availableRevisionsVector; } std::vector mitk::CustomTagParser::GetExternalRevisions() { std::string stringToJSONDirectory = GetExternalJSONDirectory(); std::string prospectiveJsonsPath = stringToJSONDirectory + "/*.json"; std::set JsonFiles; Poco::Glob::glob(prospectiveJsonsPath, JsonFiles, Poco::Glob::GLOB_CASELESS); std::vector availableRevisionsVector; for (auto const jsonpath : JsonFiles) { std::string jsonDir; std::string jsonName; itksys::SystemTools::SplitProgramPath(jsonpath, jsonDir, jsonName); std::string revision = itksys::SystemTools::GetFilenameWithoutExtension(jsonName); // disregard jsons which contain letters in their name bool onlyNumbers = (revision.find_first_not_of("0123456789") == std::string::npos); if(onlyNumbers) { availableRevisionsVector.push_back(std::stoi(revision)); } } return availableRevisionsVector; } std::string mitk::CustomTagParser::GetClosestLowerRevision(std::string revisionString, std::vector availableRevisionsVector) { // descending order std::sort(availableRevisionsVector.begin(), availableRevisionsVector.end(), std::greater<>()); int revision = std::stoi(revisionString); int index = 0; int numberOfRevisions = availableRevisionsVector.size(); while (index < numberOfRevisions) { // current mapping still has a higher revision number if ((availableRevisionsVector[index] - revision) > 0) { ++index; } else { break; } } if (index < numberOfRevisions) { std::stringstream foundRevisionStream; foundRevisionStream << availableRevisionsVector[index]; return foundRevisionStream.str(); } return ""; } void mitk::CustomTagParser::GetClosestLowerRevision(std::string revisionString) { m_ClosestInternalRevision = GetClosestLowerRevision(revisionString, GetInternalRevisions()); m_ClosestExternalRevision = GetClosestLowerRevision(revisionString, GetExternalRevisions()); if ("Strict" == m_RevisionMappingStrategy && !((0 == m_ClosestInternalRevision.compare(revisionString)) || (0 == m_ClosestExternalRevision.compare(revisionString)))) { // strict revision mapping and neither revision does match the dicom meta data std::stringstream errorMessageStream; errorMessageStream << "\nCould not parse dicom data in strict mode, data revision " << revisionString << " has no known matching parameter mapping. To use the closest known older parameter mapping select the " << "\"Fuzzy\" revision mapping option when loading the data.\n" << "\nCurrently known revision mappings are:\n Precompiled:"; for (const auto revision : GetInternalRevisions()) { errorMessageStream << " " << revision; } errorMessageStream << "\n External:"; for (const auto revision : GetExternalRevisions()) { errorMessageStream << " " << revision; } errorMessageStream << "\n\nExternal revision mapping descriptions should be located at\n\n"; std::string stringToJSONDirectory = GetExternalJSONDirectory(); errorMessageStream << stringToJSONDirectory; errorMessageStream << "\n\nTo provide an external mapping for this revision create a " << revisionString << ".json there. You might need to create the directory first."; mitkThrow() << errorMessageStream.str(); } } std::string mitk::CustomTagParser::GetRevisionAppropriateJSONString(std::string revisionString) { std::string returnValue = ""; if ("" == revisionString) { MITK_WARN << "Could not extract revision"; } else { GetClosestLowerRevision(revisionString); bool useExternal = false; bool useInternal = false; if ("" != m_ClosestExternalRevision) { useExternal = true; } if ("" != m_ClosestInternalRevision) { useInternal = true; } if (useExternal && useInternal) { if (std::stoi(m_ClosestInternalRevision) > std::stoi(m_ClosestExternalRevision)) { useExternal = false; } } if (useExternal) { std::string stringToJSONDirectory = GetExternalJSONDirectory(); std::string prospectiveJsonPath = stringToJSONDirectory + "/" + m_ClosestExternalRevision + ".json"; std::ifstream externalJSON(prospectiveJsonPath.c_str()); if (externalJSON.good()) { MITK_INFO << "Found external json for CEST parameters at " << prospectiveJsonPath; std::stringstream buffer; buffer << externalJSON.rdbuf(); returnValue = buffer.str(); useInternal = false; } } if (useInternal) { std::string filename = m_ClosestInternalRevision + ".json"; us::ModuleResource jsonResource = us::GetModuleContext()->GetModule()->GetResource(filename); if (jsonResource.IsValid() && jsonResource.IsFile()) { MITK_INFO << "Found no external json for CEST parameters. Closest internal mapping is for revision " << m_ClosestInternalRevision; us::ModuleResourceStream jsonStream(jsonResource); std::stringstream buffer; buffer << jsonStream.rdbuf(); returnValue = buffer.str(); } } } if ("" == returnValue) { MITK_WARN << "Could not identify parameter mapping for the given revision " << revisionString << ", using default mapping."; returnValue = m_DefaultJsonString; } // inject the revision independent mapping before the first newline { returnValue.insert(returnValue.find("\n"), m_RevisionIndependentMapping); } return returnValue; } std::string mitk::CustomTagParser::GetOffsetString(std::string samplingType, std::string offset, std::string measurements) { mitk::LocaleSwitch localeSwitch("C"); std::stringstream results; std::string normalizationIndicatingOffset = "-300"; double offsetDouble = 0.0; int measurementsInt = 0; bool validOffset = false; bool validMeasurements = false; if ("" != offset) { validOffset = true; offsetDouble = std::stod(offset); } if ("" != measurements) { validMeasurements = true; measurementsInt = std::stoi(measurements); } std::vector offsetVector; if (validOffset && validMeasurements) { for (int step = 0; step < measurementsInt -1; ++step) { double currentOffset = -offsetDouble + 2 * step * offsetDouble / (measurementsInt - 2.0); offsetVector.push_back(currentOffset); } } else { MITK_WARN << "Invalid offset or measurements, offset calculation will only work for list sampling type."; } if (samplingType == "1" || samplingType == "Regular") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (const auto& entry : offsetVector) { results << entry << " "; } } } else if (samplingType == "2" || samplingType == "Alternating") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (auto& entry : offsetVector) { entry = std::abs(entry); } std::sort(offsetVector.begin(), offsetVector.end(), std::greater<>()); for (unsigned int index = 0; index < offsetVector.size(); ++index) { offsetVector[index] = std::pow(-1, index) * offsetVector[index]; } for (auto& entry : offsetVector) { results << entry << " "; } } } else if (samplingType == "3" || samplingType == "List") { std::string listPath = m_DicomDataPath + "/LIST.txt"; std::ifstream list(listPath.c_str()); if (list.good()) { std::string currentOffset; while (std::getline(list, currentOffset)) { results << currentOffset << " "; } } else { MITK_ERROR << "Could not load list at " << listPath; } } else if (samplingType == "4" || samplingType == "SingleOffset") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (int step = 0; step < measurementsInt - 1; ++step) { results << offsetDouble << " "; } } } else { MITK_WARN << "Encountered unknown sampling type."; } std::string resultString = results.str(); // replace multiple spaces by a single space std::string::iterator newEnditerator = std::unique(resultString.begin(), resultString.end(), [=](char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); } ); resultString.erase(newEnditerator, resultString.end()); if ((resultString.length() > 0) && (resultString.at(resultString.length() - 1) == ' ')) { resultString.erase(resultString.end() - 1, resultString.end()); } if ((resultString.length() > 0) && (resultString.at(0) == ' ')) { resultString.erase(resultString.begin(), ++(resultString.begin())); } return resultString; } void mitk::CustomTagParser::SetParseStrategy(std::string parseStrategy) { m_ParseStrategy = parseStrategy; } void mitk::CustomTagParser::SetRevisionMappingStrategy(std::string revisionMappingStrategy) { m_RevisionMappingStrategy = revisionMappingStrategy; } std::string mitk::CustomTagParser::GetExternalJSONDirectory() { std::string moduleLocation = us::GetModuleContext()->GetModule()->GetLocation(); std::string stringToModule; std::string libraryName; itksys::SystemTools::SplitProgramPath(moduleLocation, stringToModule, libraryName); std::stringstream jsonDirectory; jsonDirectory << stringToModule << "/CESTRevisionMapping"; return jsonDirectory.str(); } diff --git a/Modules/Chart/CMakeLists.txt b/Modules/Chart/CMakeLists.txt index ef1102c255..102806e36d 100644 --- a/Modules/Chart/CMakeLists.txt +++ b/Modules/Chart/CMakeLists.txt @@ -1,9 +1,4 @@ -SET (CHART_QT_MINIMUM_VERSION 5.10.0) -IF (Qt5WebEngineWidgets_VERSION VERSION_LESS CHART_QT_MINIMUM_VERSION) - MESSAGE(AUTHOR_WARNING "MitkChart module requires at least ${CHART_QT_MINIMUM_VERSION}. Install this Qt version or above if you want to use MitkChart with full functionality.") -ENDIF() - MITK_CREATE_MODULE( DEPENDS MitkCore PACKAGE_DEPENDS PRIVATE Qt5|WebEngineWidgets ) diff --git a/Modules/Chart/include/QmitkChartWidget.h b/Modules/Chart/include/QmitkChartWidget.h index 6eed0726a3..648181df9f 100644 --- a/Modules/Chart/include/QmitkChartWidget.h +++ b/Modules/Chart/include/QmitkChartWidget.h @@ -1,219 +1,218 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkC3jsWidget_h #define QmitkC3jsWidget_h #include #include #include #include /*! \brief QmitkChartWidget is a widget to display various charts based on the javascript chart library C3js. * \details Data is added via AddData1D() or AddData2D().\n * There can be multiple charts (of different types with different properties) created by calling AddData1D or AddData2D multiple times.\n\n * The following chart types are supported: * * line chart: http://c3js.org/samples/simple_multiple.html * * bar chart: http://c3js.org/samples/chart_bar.html * * spline chart: http://c3js.org/samples/chart_spline.html * * pie chart: http://c3js.org/samples/chart_pie.html * * scatter chart: http://c3js.org/samples/chart_scatter.html * * area chart: http://c3js.org/samples/chart_area.html * * area spline chart: http://c3js.org/samples/chart_area.html * * Technical details: The javascript code is embedded in a QWebEngineView. The actual js code is implemented in resource\Chart.js. * \sa http://c3js.org for further information about the used javaScript library. -* \warning We had issues with Qt versions <5.10. So we highly encourage to use Qt 5.10 or newer if this module is used. * \ingroup Modules/Chart */ class MITKCHART_EXPORT QmitkChartWidget : public QWidget { Q_OBJECT public: /*! * \brief enum of diagram types. */ - enum class ChartType { + enum class ChartType { bar, /*!< bar chart, see http://c3js.org/samples/chart_bar.html */ line, /*!< line chart, see http://c3js.org/samples/simple_multiple.html */ spline, /*!< spline chart (smoothed line chart), see http://c3js.org/samples/chart_spline.html */ pie, /*!< pie chart, see http://c3js.org/samples/chart_pie.html*/ area, /*!< area chart, see http://c3js.org/samples/chart_area.html*/ area_spline, /*!< area-spline chart, see http://c3js.org/samples/chart_area.html*/ scatter /*!< scatter chart, see http://c3js.org/samples/chart_scatter.html*/ }; /*! * \brief enum of chart style (modifies background and line color). */ enum class ChartStyle { darkstyle, /*!< background color: dark gray, line color: blue */ lightstyle /*!< background color: white, line color: blue */ }; enum class LineStyle { solid, dashed }; enum class AxisScale { linear, log }; /*! * \brief enum of legend position. * See http://c3js.org/reference.html#legend-position */ enum class LegendPosition { bottom, right, inset }; explicit QmitkChartWidget(QWidget* parent = nullptr); ~QmitkChartWidget() override; /*! * \brief Adds 1D data to the widget * \details internally, the list is converted to a map with increasing integers keys starting at 0. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void AddData1D(const std::vector& data1D, const std::string& label, ChartType chartType = ChartType::bar); /*! * \brief Adds 2D data to the widget. Call repeatedly for displaying multiple charts. * \details each entry represents a data point: key: value --> x-value: y-value. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry - * \note the data can be cleared with ClearDiagram() + * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void AddData2D(const std::map& data2D, const std::string& label, ChartType chartType = ChartType::bar); /*! * \brief Removes data from the widget, works for 1D and 2D Data * \param label the name of the data that is also used as identifier. * \note All data can be cleared with ClearDiagram() * \throws Invalid Argument Exception when the label cannot be found */ void RemoveData(const std::string& label); /*! * \brief Sets the color of one data entry (identifier is previously assigned label) * \details the color name can be "red" or a hex number (#FF0000). * \warning Either define all data entries with a color or no data entry. If a mixed approach is used, * C3 choses the color of the data entry (that could be the same as a user defined color). * \note If an unknown label is given, nothing happens. * \sa https://www.w3schools.com/cssref/css_colors.asp */ void SetColor(const std::string& label, const std::string& colorName); /*! * \brief Sets the line style of one data entry (identifier is previously assigned label) * \details two line styles are possible: LineStyle::solid and LineStyle::dashed. * The default line style is solid. * \note If an unknown label is given, nothing happens. * \warning only sets the line style if the current chart type is ChartType::line. * However, the line style remains also if the chart changes (e.g. new chart type) */ void SetLineStyle(const std::string& label, LineStyle style); /*! * \brief Sets the axis scale to either linear (default) or logarithmic. */ void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string& label); void SetYAxisLabel(const std::string& label); /*! * \brief Sets a title for the chart. */ void SetTitle(const std::string &title); /*! * \brief Changes the chart type for all data entries and reloads the chart */ void SetChartTypeForAllDataAndReload(ChartType type); /*! * \brief Sets the chart type for a data entry * \details for available types, see ChartType * \note If an unknown label is given, nothing happens. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. * \sa DiagramType for available types */ void SetChartType(const std::string& label, ChartType type); /*! * \brief Sets the legend position. * \details Default position is bottom. * \sa LegendPosition for available types */ void SetLegendPosition(LegendPosition position); void SetShowLegend(bool show); /*! * \brief Displays the chart in the widget * \param showSubChart if a subchart is displayed inside the widget or not (see http://c3js.org/samples/options_subchart.html). * \exception if no data has been provided (\sa AddData1D AddData2D) */ void Show(bool showSubChart=false); /*! * \brief Either displays the dataPoints or not * \param showDataPoints if dataPoints are displayed inside the widget or not. * \details: example for not showing points: http://c3js.org/samples/point_show.html * example for showing the points: http://c3js.org/samples/simple_multiple.html */ void SetShowDataPoints(bool showDataPoints); /*! * \brief Clears all data inside and resets the widget. */ void Clear(); /*! * \brief Changes the theme of the widget. */ void SetTheme(ChartStyle themeEnabled); /*! * \brief Reloads the chart in the widget * \details reloading may be needed to display added data in an existing chart * \param showSubChart if a subchart is displayed inside the widget or not. */ void Reload(bool showSubChart); public slots: void OnLoadFinished(bool isLoadSuccessful); signals: void PageSuccessfullyLoaded(); private: class Impl; std::unique_ptr m_Impl; }; #endif diff --git a/Modules/Chart/src/QmitkChartWidget.cpp b/Modules/Chart/src/QmitkChartWidget.cpp index 40372dc85b..63eba0a440 100644 --- a/Modules/Chart/src/QmitkChartWidget.cpp +++ b/Modules/Chart/src/QmitkChartWidget.cpp @@ -1,498 +1,494 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include -#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) - #include -#endif +#include #include #include #include "mitkExceptionMacro.h" class QmitkChartWidget::Impl final { public: explicit Impl(QWidget* parent); ~Impl(); Impl(const Impl&) = delete; Impl& operator=(const Impl&) = delete; void AddData1D(const std::vector& data1D, const std::string& label, QmitkChartWidget::ChartType chartType); void AddData2D(const std::map& data2D, const std::string& label, QmitkChartWidget::ChartType chartType); void RemoveData(const std::string& label); void ClearData(); void SetColor(const std::string& label, const std::string& colorName); void SetLineStyle(const std::string& label, LineStyle style); void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string& label); void SetYAxisLabel(const std::string& label); void SetTitle(const std::string &title); void SetLegendPosition(LegendPosition position); void SetShowLegend(bool show); void SetShowDataPoints(bool showDataPoints = false); void Show(bool showSubChart); void SetChartType(QmitkChartWidget::ChartType chartType); void SetChartTypeByLabel(const std::string& label, QmitkChartWidget::ChartType chartType); std::string ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const; void ClearJavaScriptChart(); void InitializeJavaScriptChart(); void CallJavaScriptFuntion(const QString& command); private: using ChartxyDataVector = std::vector>; std::string GetUniqueLabelName(const QList& labelList, const std::string& label) const; QmitkChartxyData* GetDataElementByLabel(const std::string& label) const; QList GetDataLabels(const ChartxyDataVector& c3xyData) const; QWebChannel* m_WebChannel; QWebEngineView* m_WebEngineView; QmitkChartData m_C3Data; ChartxyDataVector m_C3xyData; std::map m_ChartTypeToName; std::map m_LegendPositionToName; std::map m_LineStyleToName; std::map m_AxisScaleToName; }; QmitkChartWidget::Impl::Impl(QWidget* parent) : m_WebChannel(new QWebChannel(parent)) , m_WebEngineView(new QWebEngineView(parent)) { //disable context menu for QWebEngineView m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu); //Set the webengineview to an initial empty page. The actual chart will be loaded once the data is calculated. m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html"))); m_WebEngineView->page()->setWebChannel(m_WebChannel); - #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) - m_WebEngineView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); - #endif + m_WebEngineView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); connect(m_WebEngineView, SIGNAL(loadFinished(bool)), parent, SLOT(OnLoadFinished(bool))); auto layout = new QGridLayout(parent); layout->setMargin(0); layout->addWidget(m_WebEngineView); parent->setLayout(layout); m_ChartTypeToName.emplace(ChartType::bar, "bar"); m_ChartTypeToName.emplace(ChartType::line, "line"); m_ChartTypeToName.emplace(ChartType::spline, "spline"); m_ChartTypeToName.emplace(ChartType::pie, "pie"); m_ChartTypeToName.emplace(ChartType::area, "area"); m_ChartTypeToName.emplace(ChartType::area_spline, "area-spline"); m_ChartTypeToName.emplace(ChartType::scatter, "scatter"); m_LegendPositionToName.emplace(LegendPosition::bottom, "bottom"); m_LegendPositionToName.emplace(LegendPosition::right, "right"); m_LegendPositionToName.emplace(LegendPosition::inset, "inset"); m_LineStyleToName.emplace(LineStyle::solid, "solid"); m_LineStyleToName.emplace(LineStyle::dashed, "dashed"); m_AxisScaleToName.emplace(AxisScale::linear, ""); m_AxisScaleToName.emplace(AxisScale::log, "log"); } QmitkChartWidget::Impl::~Impl() { } void QmitkChartWidget::Impl::AddData1D(const std::vector& data1D, const std::string& label, QmitkChartWidget::ChartType chartType) { std::map transformedData2D; unsigned int count = 0; //transform the 1D data to 2D data for (const auto& ele : data1D) { transformedData2D[count] = ele; count++; } AddData2D(transformedData2D, label, chartType); } void QmitkChartWidget::Impl::AddData2D(const std::map& data2D, const std::string& label, QmitkChartWidget::ChartType chartType) { QMap data2DConverted; for (const auto& aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } const std::string chartTypeName(m_ChartTypeToName.at(chartType)); auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, label); if (chartType == ChartType::scatter) { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } m_C3xyData.push_back(std::make_unique(data2DConverted, QVariant(QString::fromStdString(uniqueLabel)), QVariant(QString::fromStdString(chartTypeName)))); } void QmitkChartWidget::Impl::RemoveData(const std::string& label) { for (ChartxyDataVector::iterator iter = m_C3xyData.begin(); iter != m_C3xyData.end(); ++iter) { if ((*iter)->GetLabel().toString().toStdString() == label) { m_C3xyData.erase(iter); return; } } throw std::invalid_argument("Cannot Remove Data because the label does not exist."); } void QmitkChartWidget::Impl::ClearData() { for (auto& xyData : m_C3xyData) { m_WebChannel->deregisterObject(xyData.get()); } m_C3xyData.clear(); } std::string CheckForCorrectHex(const std::string& colorName) { std::regex rgx("([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"); std::smatch match; if (!colorName.empty() && colorName.at(0)!='#' && std::regex_search(colorName.begin(), colorName.end(), match, rgx)) { return "#" + colorName; } else { return colorName; } } void QmitkChartWidget::Impl::SetColor(const std::string& label, const std::string& colorName) { auto element = GetDataElementByLabel(label); if (element) { auto colorChecked = CheckForCorrectHex(colorName); element->SetColor(QVariant(QString::fromStdString(colorName))); } } void QmitkChartWidget::Impl::SetLineStyle(const std::string& label, LineStyle style) { auto element = GetDataElementByLabel(label); //only has effect with chart type line if (element && element->GetChartType() == QVariant(QString::fromStdString(ConvertChartTypeToString(ChartType::line)))) { const std::string lineStyleName(m_LineStyleToName.at(style)); element->SetLineStyle(QVariant(QString::fromStdString(lineStyleName))); } } void QmitkChartWidget::Impl::SetYAxisScale(AxisScale scale) { const std::string axisScaleName(m_AxisScaleToName.at(scale)); m_C3Data.SetYAxisScale(QString::fromStdString(axisScaleName)); } QmitkChartxyData* QmitkChartWidget::Impl::GetDataElementByLabel(const std::string& label) const { for (const auto& qmitkChartxyData : m_C3xyData) { if (qmitkChartxyData->GetLabel().toString() == label.c_str()) { return qmitkChartxyData.get(); } } MITK_WARN << "label " << label << " not found in QmitkChartWidget"; return nullptr; } QList QmitkChartWidget::Impl::GetDataLabels(const ChartxyDataVector& c3xyData) const { QList dataLabels; for (auto element = c3xyData.begin(); element != c3xyData.end(); ++element) { dataLabels.push_back((*element)->GetLabel()); } return dataLabels; } void QmitkChartWidget::Impl::SetXAxisLabel(const std::string& label) { m_C3Data.SetXAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetYAxisLabel(const std::string& label) { m_C3Data.SetYAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetTitle(const std::string& title) { m_C3Data.SetTitle(QString::fromStdString(title)); } void QmitkChartWidget::Impl::SetLegendPosition(QmitkChartWidget::LegendPosition legendPosition) { const std::string legendPositionName(m_LegendPositionToName.at(legendPosition)); m_C3Data.SetLegendPosition(QString::fromStdString(legendPositionName)); } void QmitkChartWidget::Impl::SetShowLegend(bool show) { m_C3Data.SetShowLegend(show); } void QmitkChartWidget::Impl::SetShowDataPoints(bool showDataPoints) { if (showDataPoints == true) { m_C3Data.SetDataPointSize(3); } else { m_C3Data.SetDataPointSize(0); } } void QmitkChartWidget::Impl::Show(bool showSubChart) { if (m_C3xyData.empty()) { mitkThrow() << "no data available for display in chart"; } m_C3Data.SetAppearance(showSubChart, m_C3xyData.front()->GetChartType() == QVariant("pie")); InitializeJavaScriptChart(); } void QmitkChartWidget::Impl::SetChartType(QmitkChartWidget::ChartType chartType) { for (auto iterator = m_C3xyData.begin(); iterator != m_C3xyData.end(); ++iterator) { SetChartTypeByLabel((*iterator)->GetLabel().toString().toStdString(), chartType); } auto chartTypeName = ConvertChartTypeToString(chartType); const QString command = QString::fromStdString("transformView('" + chartTypeName + "')"); CallJavaScriptFuntion(command); } void QmitkChartWidget::Impl::SetChartTypeByLabel(const std::string& label, QmitkChartWidget::ChartType chartType) { auto element = GetDataElementByLabel(label); if (element) { if (chartType == ChartType::scatter) { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } auto chartTypeName = ConvertChartTypeToString(chartType); element->SetChartType(QVariant(QString::fromStdString(chartTypeName))); } } std::string QmitkChartWidget::Impl::ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const { return m_ChartTypeToName.at(chartType); } void QmitkChartWidget::Impl::CallJavaScriptFuntion(const QString& command) { m_WebEngineView->page()->runJavaScript(command); } void QmitkChartWidget::Impl::ClearJavaScriptChart() { m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html"))); } void QmitkChartWidget::Impl::InitializeJavaScriptChart() { m_WebChannel->registerObject(QStringLiteral("chartData"), &m_C3Data); unsigned count = 0; for (auto& xyData : m_C3xyData) { QString variableName = "xyData" + QString::number(count); m_WebChannel->registerObject(variableName, xyData.get()); count++; } m_WebEngineView->load(QUrl(QStringLiteral("qrc:///C3js/QmitkChartWidget.html"))); } std::string QmitkChartWidget::Impl::GetUniqueLabelName(const QList& labelList, const std::string& label) const { QString currentLabel = QString::fromStdString(label); int counter = 0; while (labelList.contains(currentLabel)) { currentLabel = QString::fromStdString(label + std::to_string(counter)); counter++; } return currentLabel.toStdString(); } QmitkChartWidget::QmitkChartWidget(QWidget* parent) : QWidget(parent) , m_Impl(new Impl(this)) { } QmitkChartWidget::~QmitkChartWidget() { } void QmitkChartWidget::AddData2D(const std::map& data2D, const std::string& label, ChartType type) { m_Impl->AddData2D(data2D, label, type); } void QmitkChartWidget::SetColor(const std::string& label, const std::string& colorName) { m_Impl->SetColor(label, colorName); } void QmitkChartWidget::SetLineStyle(const std::string& label, LineStyle style) { m_Impl->SetLineStyle(label, style); } void QmitkChartWidget::SetYAxisScale(AxisScale scale) { m_Impl->SetYAxisScale(scale); } void QmitkChartWidget::AddData1D(const std::vector& data1D, const std::string& label, ChartType type) { m_Impl->AddData1D(data1D, label, type); } void QmitkChartWidget::RemoveData(const std::string& label) { m_Impl->RemoveData(label); } void QmitkChartWidget::SetXAxisLabel(const std::string & label) { m_Impl->SetXAxisLabel(label); } void QmitkChartWidget::SetYAxisLabel(const std::string & label) { m_Impl->SetYAxisLabel(label); } void QmitkChartWidget::SetTitle(const std::string & title) { m_Impl->SetTitle(title); } void QmitkChartWidget::SetShowDataPoints(bool showDataPoints) { m_Impl->SetShowDataPoints(showDataPoints); } void QmitkChartWidget::SetChartTypeForAllDataAndReload(ChartType type) { m_Impl->SetChartType(type); } void QmitkChartWidget::SetChartType(const std::string& label, ChartType type) { m_Impl->SetChartTypeByLabel(label, type); } void QmitkChartWidget::SetLegendPosition(LegendPosition position) { m_Impl->SetLegendPosition(position); } void QmitkChartWidget::SetShowLegend(bool show) { m_Impl->SetShowLegend(show); } void QmitkChartWidget::Show(bool showSubChart) { m_Impl->Show(showSubChart); } void QmitkChartWidget::Clear() { m_Impl->ClearData(); m_Impl->ClearJavaScriptChart(); } void QmitkChartWidget::OnLoadFinished(bool isLoadSuccessful) { if(isLoadSuccessful) { emit PageSuccessfullyLoaded(); } } void QmitkChartWidget::SetTheme(ChartStyle themeEnabled) { QString command; if (themeEnabled == ChartStyle::darkstyle) { command = QString("changeTheme('dark')"); } else { command = QString("changeTheme('light')"); } m_Impl->CallJavaScriptFuntion(command); } void QmitkChartWidget::Reload(bool showSubChart) { QString subChartString; if (showSubChart) { subChartString = "true"; } else { subChartString = "false"; } const QString command = QString("ReloadChart(" + subChartString + ")"); m_Impl->CallJavaScriptFuntion(command); } diff --git a/Modules/Classification/CLCore/src/mitkConfigurationHolder.cpp b/Modules/Classification/CLCore/src/mitkConfigurationHolder.cpp index 2bd98ff032..0112585583 100644 --- a/Modules/Classification/CLCore/src/mitkConfigurationHolder.cpp +++ b/Modules/Classification/CLCore/src/mitkConfigurationHolder.cpp @@ -1,312 +1,312 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include mitk::ConfigurationHolder::ConfigurationHolder() : m_ValueType(DT_UNINIZIALIZED) { m_GroupValue.clear(); } void mitk::ConfigurationHolder::SetBool(bool value) { m_BoolValue = value; m_ValueType = DT_BOOL; } void mitk::ConfigurationHolder::SetUnsignedInt(unsigned int value) { m_UIntValue = value; m_ValueType = DT_UINT; } void mitk::ConfigurationHolder::SetInt(int value) { m_IntValue = value; m_ValueType = DT_INT; } void mitk::ConfigurationHolder::SetDouble(double value) { m_DoubleValue = value; m_ValueType = DT_DOUBLE; } void mitk::ConfigurationHolder::SetString(std::string value) { m_StringValue = value; m_ValueType = DT_STRING; } void mitk::ConfigurationHolder::ClearGroup() { m_GroupValue.clear(); m_ValueType = DT_GROUP; } void mitk::ConfigurationHolder::AddToGroup(std::string id, const ConfigurationHolder &value) { m_GroupValue[id] = value; m_ValueType = DT_GROUP; } bool mitk::ConfigurationHolder::AsBool() { switch (m_ValueType) { case DT_UNINIZIALIZED: mitkThrow() << "No value stored"; break; case DT_BOOL: return m_BoolValue; break; case DT_UINT: return m_UIntValue; break; case DT_INT: return m_IntValue; break; case DT_DOUBLE: return (m_DoubleValue > 1 || m_DoubleValue < -1); break; case DT_STRING: return (m_StringValue != "0"); break; case DT_GROUP: mitkThrow() << "Cannot convert group data to bool"; break; default: mitkThrow() << "Unkown Data Type."; break; } } unsigned int mitk::ConfigurationHolder::AsUnsignedInt() { unsigned int result; std::istringstream ss(m_StringValue); ss >> result; switch (m_ValueType) { case DT_UNINIZIALIZED: mitkThrow() << "No value stored"; break; case DT_BOOL: return m_BoolValue; break; case DT_UINT: return m_UIntValue; break; case DT_INT: return m_IntValue; break; case DT_DOUBLE: return m_DoubleValue; break; case DT_STRING: return result; break; case DT_GROUP: mitkThrow() << "Cannot convert group data to bool"; break; default: mitkThrow() << "Unkown Data Type."; break; } } int mitk::ConfigurationHolder::AsInt() { int result; std::istringstream ss(m_StringValue); ss >> result; switch (m_ValueType) { case DT_UNINIZIALIZED: mitkThrow() << "No value stored"; break; case DT_BOOL: return m_BoolValue; break; case DT_UINT: return m_UIntValue; break; case DT_INT: return m_IntValue; break; case DT_DOUBLE: return m_DoubleValue; break; case DT_STRING: return result; break; case DT_GROUP: mitkThrow() << "Cannot convert group data to bool"; break; default: mitkThrow() << "Unkown Data Type."; break; } } double mitk::ConfigurationHolder::AsDouble() { double result; std::istringstream ss(m_StringValue); ss >> result; switch (m_ValueType) { case DT_UNINIZIALIZED: mitkThrow() << "No value stored"; break; case DT_BOOL: return m_BoolValue; break; case DT_UINT: return m_UIntValue; break; case DT_INT: return m_IntValue; break; case DT_DOUBLE: return m_DoubleValue > 1; break; case DT_STRING: return result; break; case DT_GROUP: mitkThrow() << "Cannot convert group data to bool"; break; default: mitkThrow() << "Unkown Data Type."; break; } } std::string mitk::ConfigurationHolder::AsString() { std::ostringstream strs; switch (m_ValueType) { case DT_UNINIZIALIZED: mitkThrow() << "No value stored"; break; case DT_BOOL: strs << m_BoolValue; break; case DT_UINT: strs << m_UIntValue; break; case DT_INT: strs << m_IntValue; break; case DT_DOUBLE: strs << m_DoubleValue; break; case DT_STRING: return m_StringValue; break; case DT_GROUP: mitkThrow() << "Cannot convert group data to bool"; break; default: mitkThrow() << "Unkown Data Type."; break; } return strs.str(); } std::vector mitk::ConfigurationHolder::AsStringVector() { if (m_ValueType != DT_GROUP) mitkThrow() << "No Group Data, cannot convert to String Vector"; std::vector result; for (auto iter = m_GroupValue.begin(); iter != m_GroupValue.end(); ++iter) { result.push_back((*iter).second.AsString()); } return result; } mitk::ConfigurationHolder& mitk::ConfigurationHolder::At(std::string id) { return m_GroupValue[id]; } bool mitk::ConfigurationHolder::AsBool(bool value) { try { return this->AsBool(); } - catch (mitk::Exception) + catch (const mitk::Exception &) { return value; } } unsigned int mitk::ConfigurationHolder::AsUnsignedInt(unsigned int value) { try { return this->AsUnsignedInt(); } - catch (mitk::Exception) + catch (const mitk::Exception &) { return value; } } int mitk::ConfigurationHolder::AsInt(int value) { try { return this->AsInt(); } - catch (mitk::Exception) + catch (const mitk::Exception &) { return value; } } double mitk::ConfigurationHolder::AsDouble(double value) { try { return this->AsDouble(); } - catch (mitk::Exception) + catch (const mitk::Exception &) { return value; } } std::string mitk::ConfigurationHolder::AsString(std::string value) { try { return this->AsString(); } - catch (mitk::Exception) + catch (const mitk::Exception &) { return value; } -} \ No newline at end of file +} diff --git a/Modules/Core/TestingHelper/include/mitkTestingMacros.h b/Modules/Core/TestingHelper/include/mitkTestingMacros.h index 5427a407ad..add4e7e557 100644 --- a/Modules/Core/TestingHelper/include/mitkTestingMacros.h +++ b/Modules/Core/TestingHelper/include/mitkTestingMacros.h @@ -1,395 +1,395 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkTestingMacros_h #define mitkTestingMacros_h #include #include #include #include #include #include #include #include #include #include namespace mitk { /** @brief Indicate a failed test. */ class TestFailedException : public std::exception { public: TestFailedException() {} }; } /** * @brief Output some text without generating a terminating newline. Include * * @ingroup MITKTestingAPI */ #define MITK_TEST_OUTPUT_NO_ENDL(x) std::cout x; /** * @brief Output some text. * * @ingroup MITKTestingAPI */ #define MITK_TEST_OUTPUT(x) MITK_TEST_OUTPUT_NO_ENDL(x << "\n") /** * @brief Do some general test preparations. Must be called first in the * main test function. * * @deprecatedSince{2013_09} Use MITK_TEST_SUITE_REGISTRATION instead. * @ingroup MITKTestingAPI */ #define MITK_TEST_BEGIN(testName) \ std::string mitkTestName(#testName); \ mitk::TestManager::GetInstance()->Initialize(); \ try \ { /** * @brief Fail and finish test with message MSG * * @deprecatedSince{2013_09} Use CPPUNIT_FAIL instead * @ingroup MITKTestingAPI */ #define MITK_TEST_FAILED_MSG(MSG) \ MITK_TEST_OUTPUT(MSG) \ throw mitk::TestFailedException(); /** * @brief Must be called last in the main test function. * * @deprecatedSince{2013_09} Use MITK_TEST_SUITE_REGISTRATION instead. * @ingroup MITKTestingAPI */ #define MITK_TEST_END() \ } \ catch (const mitk::TestFailedException &) \ { \ MITK_TEST_OUTPUT(<< "Further test execution skipped.") \ mitk::TestManager::GetInstance()->TestFailed(); \ } \ catch (const std::exception &ex) \ { \ MITK_TEST_OUTPUT(<< "std::exception occured " << ex.what()) \ mitk::TestManager::GetInstance()->TestFailed(); \ } \ if (mitk::TestManager::GetInstance()->NumberOfFailedTests() > 0) \ { \ MITK_TEST_OUTPUT(<< mitkTestName << ": [DONE FAILED] , subtests passed: " \ << mitk::TestManager::GetInstance()->NumberOfPassedTests() \ << " failed: " \ << mitk::TestManager::GetInstance()->NumberOfFailedTests()) \ return EXIT_FAILURE; \ } \ else \ { \ MITK_TEST_OUTPUT(<< mitkTestName << ": " << mitk::TestManager::GetInstance()->NumberOfPassedTests() \ << " tests [DONE PASSED]") \ return EXIT_SUCCESS; \ } /** * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT or CPPUNIT_ASSERT_MESSAGE instead. */ #define MITK_TEST_CONDITION(COND, MSG) \ MITK_TEST_OUTPUT_NO_ENDL(<< MSG) \ if (!(COND)) \ { \ mitk::TestManager::GetInstance()->TestFailed(); \ MITK_TEST_OUTPUT(<< " [FAILED]\n" \ << "In " \ << __FILE__ \ << ", line " \ << __LINE__ \ << ": " #COND " : [FAILED]") \ } \ else \ { \ MITK_TEST_OUTPUT(<< " [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } /** * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT or CPPUNIT_ASSERT_MESSAGE instead. */ #define MITK_TEST_CONDITION_REQUIRED(COND, MSG) \ MITK_TEST_OUTPUT_NO_ENDL(<< MSG) \ if (!(COND)) \ { \ MITK_TEST_FAILED_MSG(<< " [FAILED]\n" \ << " +--> in " \ << __FILE__ \ << ", line " \ << __LINE__ \ << ", expression is false: \"" #COND "\"") \ } \ else \ { \ MITK_TEST_OUTPUT(<< " [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } /** * \brief Begin block which should be checked for exceptions * * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT_THROW instead. * @ingroup MITKTestingAPI * * This macro, together with MITK_TEST_FOR_EXCEPTION_END, can be used * to test whether a code block throws an expected exception. The test FAILS if the * exception is NOT thrown. A simple example: * MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ImageFileReaderException) typedef itk::ImageFileReader< itk::Image > ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName("/tmp/not-existing"); reader->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ImageFileReaderException) * */ #define MITK_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ try \ { /** * @deprecatedSince{2013_09} */ #define MITK_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) \ mitk::TestManager::GetInstance()->TestFailed(); \ MITK_TEST_OUTPUT(<< "Expected an '" << #EXCEPTIONCLASS << "' exception. [FAILED]") \ } \ - catch (EXCEPTIONCLASS) \ + catch (const EXCEPTIONCLASS &) \ { \ MITK_TEST_OUTPUT(<< "Caught an expected '" << #EXCEPTIONCLASS << "' exception. [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } /** * @brief Simplified version of MITK_TEST_FOR_EXCEPTION_BEGIN / END for * a single statement * * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT_THROW instead. * @ingroup MITKTestingAPI */ #define MITK_TEST_FOR_EXCEPTION(EXCEPTIONCLASS, STATEMENT) \ MITK_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ STATEMENT; \ MITK_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) /** * @brief Testing macro to test if two objects are equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. * Feel free to implement mitk::Equal for your own datatype or purpose. * * @param EXPECTED First object. * @param ACTUAL Second object. * @param MSG Message to appear with the test. * @throw Throws mitkException if a nullptr pointer is given as input. */ #define MITK_ASSERT_EQUAL(EXPECTED, ACTUAL, MSG) \ if (((EXPECTED).IsNull()) || ((ACTUAL).IsNull())) \ { \ mitkThrow() << "mitk::Equal does not work with nullptr pointer input."; \ } \ CPPUNIT_ASSERT_MESSAGE(MSG, mitk::Equal(*(EXPECTED), *(ACTUAL), mitk::eps, true)) /** * @brief Testing macro to test if two objects are not equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. * * @deprecatedSince{2013_09} Use MITK_ASSERT_NOT_EQUAL instead. * * @param OBJ1 First object. * @param OBJ2 Second object. * @param MSG Message to appear with the test. * * \sa MITK_TEST_EQUAL */ #define MITK_TEST_NOT_EQUAL(OBJ1, OBJ2, MSG) \ CPPUNIT_ASSERT_MESSAGE(MSG, !mitk::Equal(*(OBJ1), *(OBJ2), mitk::eps, true)) /** * @brief Testing macro to test if two objects are not equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. * * @param OBJ1 First object. * @param OBJ2 Second object. * @param MSG Message to appear with the test. * @throw Throws mitkException if a nullptr pointer is given as input. * * \sa MITK_ASSERT_EQUAL */ #define MITK_ASSERT_NOT_EQUAL(OBJ1, OBJ2, MSG) \ if (((OBJ1).IsNull()) || ((OBJ2).IsNull())) \ { \ mitkThrow() << "mitk::Equal does not work with nullptr pointer input."; \ } \ CPPUNIT_ASSERT_MESSAGE(MSG, !mitk::Equal(*(OBJ1), *(OBJ2), mitk::eps, true)) /** * @brief Registers the given test suite. * * @ingroup MITKTestingAPI * * @param TESTSUITE_NAME The name of the test suite class, without "TestSuite" * at the end. */ #define MITK_TEST_SUITE_REGISTRATION(TESTSUITE_NAME) \ int TESTSUITE_NAME##Test(int /*argc*/, char * /*argv*/ []) \ { \ int result = 0; \ try \ { \ CppUnit::TextUi::TestRunner runner; \ runner.addTest(TESTSUITE_NAME##TestSuite::suite()); \ result = runner.run() ? 0 : 1; \ } \ catch (const mitk::TestNotRunException& e) \ { \ MITK_WARN << "Test not run: " << e.GetDescription(); \ result = 77; \ } \ return result; \ } /** * @brief Adds a test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases. * The macro internally just calls the CPPUNIT_TEST macro. * * @param TESTMETHOD The name of the member funtion test. */ #define MITK_TEST(TESTMETHOD) CPPUNIT_TEST(TESTMETHOD) /** * @brief Adds a parameterized test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases * which need custom parameters. * * @param TESTMETHOD The name of the member function test. * @param ARGS A std::vector object containing test parameter. * * @note Use the macro MITK_PARAMETERIZED_TEST only if you know what * you are doing. If you are not sure, use MITK_TEST instead. */ #define MITK_PARAMETERIZED_TEST(TESTMETHOD, ARGS) \ \ { \ std::string testName = #TESTMETHOD; \ for (std::size_t i = 0; i < ARGS.size(); ++i) \ { \ testName += "_" + ARGS[i]; \ } \ CPPUNIT_TEST_SUITE_ADD_TEST((new mitk::TestCaller( \ context.getTestNameFor(testName), &TestFixtureType::TESTMETHOD, context.makeFixture(), args))); \ } /** * @brief Adds a parameterized test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases * which need parameters from the command line. * * @warning Use the macro MITK_PARAMETERIZED_CMD_LINE_TEST only * if you know what you are doing. If you are not sure, use * MITK_TEST instead. MITK_PARAMETERIZED_CMD_LINE_TEST is meant * for migrating from ctest to CppUnit. If you implement new * tests, the MITK_TEST macro will be sufficient. * * @param TESTMETHOD The name of the member function test. */ #define MITK_PARAMETERIZED_CMD_LINE_TEST(TESTMETHOD) \ CPPUNIT_TEST_SUITE_ADD_TEST((new mitk::TestCaller( \ context.getTestNameFor(#TESTMETHOD), &TestFixtureType::TESTMETHOD, context.makeFixture()))); /** * @brief Adds a parameterized test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases * which need one custom parameter. * * @param TESTMETHOD The name of the member function test. * @param arg1 A custom string parameter being passed to the fixture. * * @note Use the macro MITK_PARAMETERIZED_TEST_1 only if you know what * you are doing. If you are not sure, use MITK_TEST instead. * * @see MITK_PARAMETERIZED_TEST */ #define MITK_PARAMETERIZED_TEST_1(TESTMETHOD, arg1) \ \ { \ std::vector args; \ args.push_back(arg1); \ MITK_PARAMETERIZED_TEST(TESTMETHOD, args) \ } /** * @brief Adds a parameterized test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases * which need two custom parameter. * * @param TESTMETHOD The name of the member function test. * @param arg1 A custom string parameter being passed to the fixture. * * @note Use the macro MITK_PARAMETERIZED_TEST_2 only if you know what * you are doing. If you are not sure, use MITK_TEST instead. * * @see MITK_PARAMETERIZED_TEST */ #define MITK_PARAMETERIZED_TEST_2(TESTMETHOD, arg1, arg2) \ \ { \ std::vector args; \ args.push_back(arg1); \ args.push_back(arg2); \ MITK_PARAMETERIZED_TEST(TESTMETHOD, args) \ } #endif diff --git a/Modules/Core/src/Controllers/mitkLimitedLinearUndo.cpp b/Modules/Core/src/Controllers/mitkLimitedLinearUndo.cpp index 0c97653d03..76ac781141 100644 --- a/Modules/Core/src/Controllers/mitkLimitedLinearUndo.cpp +++ b/Modules/Core/src/Controllers/mitkLimitedLinearUndo.cpp @@ -1,238 +1,240 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkLimitedLinearUndo.h" #include mitk::LimitedLinearUndo::LimitedLinearUndo() : m_UndoLimit(0) { // nothing to do } mitk::LimitedLinearUndo::~LimitedLinearUndo() { // delete undo and redo list this->ClearList(&m_UndoList); this->ClearList(&m_RedoList); } void mitk::LimitedLinearUndo::ClearList(UndoContainer *list) { while (!list->empty()) { UndoStackItem *item = list->back(); list->pop_back(); delete item; } } bool mitk::LimitedLinearUndo::SetOperationEvent(UndoStackItem *stackItem) { auto *operationEvent = dynamic_cast(stackItem); if (!operationEvent) return false; // clear the redolist, if a new operation is saved if (!m_RedoList.empty()) { this->ClearList(&m_RedoList); InvokeEvent(RedoEmptyEvent()); } - if (m_UndoLimit > 0 && m_UndoList.size() == m_UndoLimit) + if (0 != m_UndoLimit && m_UndoList.size() == m_UndoLimit) { + auto item = m_UndoList.front(); m_UndoList.pop_front(); + delete item; } m_UndoList.push_back(operationEvent); InvokeEvent(UndoNotEmptyEvent()); return true; } bool mitk::LimitedLinearUndo::Undo(bool fine) { if (fine) { // undo one object event ID return Undo(); } else { // undo one group event ID int oeid = FirstObjectEventIdOfCurrentGroup( m_UndoList); // get the Object Event ID of the first item with a differnt Group ID (as seen from the end of stack) return Undo(oeid); } } bool mitk::LimitedLinearUndo::Undo() { if (m_UndoList.empty()) return false; int undoObjectEventId = m_UndoList.back()->GetObjectEventId(); return Undo(undoObjectEventId); } bool mitk::LimitedLinearUndo::Undo(int oeid) { if (m_UndoList.empty()) return false; bool rc = true; do { m_UndoList.back()->ReverseAndExecute(); m_RedoList.push_back(m_UndoList.back()); // move to redo stack m_UndoList.pop_back(); InvokeEvent(RedoNotEmptyEvent()); if (m_UndoList.empty()) { InvokeEvent(UndoEmptyEvent()); rc = false; break; } } while (m_UndoList.back()->GetObjectEventId() >= oeid); // Update. Check Rendering Mechanism where to request updates mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return rc; } bool mitk::LimitedLinearUndo::Redo(bool) { return Redo(); } bool mitk::LimitedLinearUndo::Redo() { if (m_RedoList.empty()) return false; int redoObjectEventId = m_RedoList.back()->GetObjectEventId(); return Redo(redoObjectEventId); } bool mitk::LimitedLinearUndo::Redo(int oeid) { if (m_RedoList.empty()) return false; do { m_RedoList.back()->ReverseAndExecute(); m_UndoList.push_back(m_RedoList.back()); m_RedoList.pop_back(); InvokeEvent(UndoNotEmptyEvent()); if (m_RedoList.empty()) { InvokeEvent(RedoEmptyEvent()); break; } } while (m_RedoList.back()->GetObjectEventId() <= oeid); // Update. This should belong into the ExecuteOperation() of OperationActors, but it seems not to be used everywhere mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return true; } void mitk::LimitedLinearUndo::Clear() { this->ClearList(&m_UndoList); InvokeEvent(UndoEmptyEvent()); this->ClearList(&m_RedoList); InvokeEvent(RedoEmptyEvent()); } void mitk::LimitedLinearUndo::ClearRedoList() { this->ClearList(&m_RedoList); InvokeEvent(RedoEmptyEvent()); } bool mitk::LimitedLinearUndo::RedoListEmpty() { return m_RedoList.empty(); } std::size_t mitk::LimitedLinearUndo::GetUndoLimit() const { return m_UndoLimit; } void mitk::LimitedLinearUndo::SetUndoLimit(std::size_t undoLimit) { if (undoLimit != m_UndoLimit) { if (m_UndoList.size() > undoLimit) { m_UndoList.erase(m_UndoList.begin(), m_UndoList.end() - undoLimit); } m_UndoLimit = undoLimit; } } int mitk::LimitedLinearUndo::GetLastObjectEventIdInList() { return m_UndoList.back()->GetObjectEventId(); } int mitk::LimitedLinearUndo::GetLastGroupEventIdInList() { return m_UndoList.back()->GetGroupEventId(); } mitk::OperationEvent *mitk::LimitedLinearUndo::GetLastOfType(OperationActor *destination, OperationType opType) { // When/where is this function needed? In CoordinateSupplier... for (auto iter = m_UndoList.rbegin(); iter != m_UndoList.rend(); ++iter) { auto *opEvent = dynamic_cast(*iter); if (!opEvent) continue; if (opEvent->GetOperation() != nullptr && opEvent->GetOperation()->GetOperationType() == opType && opEvent->IsValid() && opEvent->GetDestination() == destination) return opEvent; } return nullptr; } int mitk::LimitedLinearUndo::FirstObjectEventIdOfCurrentGroup(mitk::LimitedLinearUndo::UndoContainer &stack) { int currentGroupEventId = stack.back()->GetGroupEventId(); int firstObjectEventId = -1; for (auto iter = stack.rbegin(); iter != stack.rend(); ++iter) { if ((*iter)->GetGroupEventId() == currentGroupEventId) { firstObjectEventId = (*iter)->GetObjectEventId(); } else break; } return firstObjectEventId; } diff --git a/Modules/Core/src/DataManagement/mitkMaterial.cpp b/Modules/Core/src/DataManagement/mitkMaterial.cpp index 506e29ce46..ce5c37f3f7 100644 --- a/Modules/Core/src/DataManagement/mitkMaterial.cpp +++ b/Modules/Core/src/DataManagement/mitkMaterial.cpp @@ -1,380 +1,380 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkMaterial.h" #include "mitkBaseRenderer.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkVtkInterpolationProperty.h" #include "mitkVtkRepresentationProperty.h" #include mitk::Material::Material(Color color, double opacity) { InitializeStandardValues(); SetColor(color); SetColorCoefficient(GetColorCoefficient()); SetSpecularColor(GetSpecularColor()); SetSpecularCoefficient(GetSpecularCoefficient()); SetSpecularPower(GetSpecularPower()); SetOpacity(opacity); SetInterpolation(GetInterpolation()); SetRepresentation(GetRepresentation()); SetLineWidth(GetLineWidth()); m_Name = ""; } mitk::Material::Material(double red, double green, double blue, double opacity) { InitializeStandardValues(); SetColor(red, green, blue); SetColorCoefficient(GetColorCoefficient()); SetSpecularColor(GetSpecularColor()); SetSpecularCoefficient(GetSpecularCoefficient()); SetSpecularPower(GetSpecularPower()); SetOpacity(opacity); SetInterpolation(GetInterpolation()); SetRepresentation(GetRepresentation()); SetLineWidth(GetLineWidth()); m_Name = ""; } mitk::Material::Material(double red, double green, double blue, double colorCoefficient, double specularCoefficient, double specularPower, double opacity) { InitializeStandardValues(); SetColor(red, green, blue); SetColorCoefficient(colorCoefficient); SetSpecularColor(GetSpecularColor()); SetSpecularCoefficient(specularCoefficient); SetSpecularPower(specularPower); SetOpacity(opacity); SetInterpolation(GetInterpolation()); SetRepresentation(GetRepresentation()); SetLineWidth(GetLineWidth()); m_Name = ""; } mitk::Material::Material(mitk::Material::Color color, double colorCoefficient, double specularCoefficient, double specularPower, double opacity) { InitializeStandardValues(); SetColor(color); SetColorCoefficient(colorCoefficient); SetSpecularColor(GetSpecularColor()); SetSpecularCoefficient(specularCoefficient); SetSpecularPower(specularPower); SetOpacity(opacity); SetInterpolation(GetInterpolation()); SetRepresentation(GetRepresentation()); SetLineWidth(GetLineWidth()); } mitk::Material::Material() { InitializeStandardValues(); SetColor(GetColor()); SetColorCoefficient(GetColorCoefficient()); SetSpecularColor(GetSpecularColor()); SetSpecularCoefficient(GetSpecularCoefficient()); SetSpecularPower(GetSpecularPower()); SetOpacity(GetOpacity()); SetInterpolation(GetInterpolation()); SetRepresentation(GetRepresentation()); SetLineWidth(GetLineWidth()); } mitk::Material::Material(const Material &property) : itk::Object() { Initialize(property); } mitk::Material::Material( const Material &property, double red, double green, double blue, double opacity, std::string name) { Initialize(property); SetColor(red, green, blue); SetOpacity(opacity); SetName(name); } bool mitk::Material::Assignable(const Material &other) const { try { const auto &otherinstance = dynamic_cast(other); // dear compiler, please don't optimize this away! Thanks. otherinstance.GetOpacity(); return true; } - catch (std::bad_cast) + catch (const std::bad_cast &) { } return false; } mitk::Material &mitk::Material::operator=(const mitk::Material &other) { try { const auto &otherProp(dynamic_cast(other)); Initialize(otherProp); } - catch (std::bad_cast) + catch (const std::bad_cast &) { // nothing to do then } return *this; } void mitk::Material::SetColor(mitk::Material::Color color) { m_Color = color; Modified(); } void mitk::Material::SetColor(double red, double green, double blue) { m_Color.Set(red, green, blue); Modified(); } void mitk::Material::SetColorCoefficient(double coefficient) { m_ColorCoefficient = coefficient; Modified(); } void mitk::Material::SetSpecularColor(mitk::Material::Color specularColor) { m_SpecularColor = specularColor; Modified(); } void mitk::Material::SetSpecularColor(double red, double green, double blue) { m_SpecularColor.Set(red, green, blue); Modified(); } void mitk::Material::SetSpecularCoefficient(double specularCoefficient) { m_SpecularCoefficient = specularCoefficient; Modified(); } void mitk::Material::SetSpecularPower(double specularPower) { m_SpecularPower = specularPower; Modified(); } void mitk::Material::SetOpacity(double opacity) { m_Opacity = opacity; Modified(); } void mitk::Material::SetInterpolation(InterpolationType interpolation) { m_Interpolation = interpolation; Modified(); } void mitk::Material::SetRepresentation(RepresentationType representation) { m_Representation = representation; Modified(); } void mitk::Material::SetLineWidth(float lineWidth) { m_LineWidth = lineWidth; Modified(); } mitk::Material::Color mitk::Material::GetColor() const { return m_Color; } double mitk::Material::GetColorCoefficient() const { return m_ColorCoefficient; } mitk::Material::Color mitk::Material::GetSpecularColor() const { return m_SpecularColor; } double mitk::Material::GetSpecularCoefficient() const { return m_SpecularCoefficient; } double mitk::Material::GetSpecularPower() const { return m_SpecularPower; } double mitk::Material::GetOpacity() const { return m_Opacity; } mitk::Material::InterpolationType mitk::Material::GetInterpolation() const { return m_Interpolation; } mitk::Material::RepresentationType mitk::Material::GetRepresentation() const { return m_Representation; } int mitk::Material::GetVtkInterpolation() const { switch (m_Interpolation) { case (Flat): return VTK_FLAT; case (Gouraud): return VTK_GOURAUD; case (Phong): return VTK_PHONG; } return VTK_GOURAUD; } int mitk::Material::GetVtkRepresentation() const { switch (m_Representation) { case (Points): return VTK_POINTS; case (Wireframe): return VTK_WIREFRAME; case (Surface): return VTK_SURFACE; } return VTK_SURFACE; } float mitk::Material::GetLineWidth() const { return m_LineWidth; } void mitk::Material::Initialize(const Material &property) { this->SetColor(property.GetColor()); this->SetColorCoefficient(property.GetColorCoefficient()); this->SetSpecularColor(property.GetSpecularColor()); this->SetSpecularCoefficient(property.GetSpecularCoefficient()); this->SetSpecularPower(property.GetSpecularPower()); this->SetOpacity(property.GetOpacity()); this->SetInterpolation(property.GetInterpolation()); this->SetRepresentation(property.GetRepresentation()); this->SetLineWidth(property.GetLineWidth()); this->SetName(property.GetName()); } bool mitk::Material::operator==(const Material &property) const { const auto *other = dynamic_cast(&property); if (other == nullptr) return false; else return (m_Color == other->GetColor() && m_ColorCoefficient == other->GetColorCoefficient() && m_SpecularColor == other->GetSpecularColor() && m_SpecularCoefficient == other->GetSpecularCoefficient() && m_SpecularPower == other->GetSpecularPower() && m_Opacity == other->GetOpacity() && m_Interpolation == other->GetInterpolation() && m_Name == other->GetName() && m_Representation == other->GetRepresentation() && m_LineWidth == other->GetLineWidth()); } void mitk::Material::InitializeStandardValues() { m_Color.Set(0.5, 0.5, 0.0); m_ColorCoefficient = 0.5; m_SpecularColor.Set(1.0, 1.0, 1.0); m_SpecularCoefficient = 0.5; m_SpecularPower = 10.0; m_Opacity = 1.0; m_Interpolation = Gouraud; m_Representation = Surface; m_LineWidth = 1.0; m_Name = ""; } void mitk::Material::Update() { this->SetColor(this->GetColor()); this->SetColorCoefficient(this->GetColorCoefficient()); this->SetSpecularColor(this->GetSpecularColor()); this->SetSpecularCoefficient(this->GetSpecularCoefficient()); this->SetSpecularPower(this->GetSpecularPower()); this->SetOpacity(this->GetOpacity()); this->SetInterpolation(this->GetInterpolation()); this->SetRepresentation(this->GetRepresentation()); } void mitk::Material::PrintSelf(std::ostream &os, itk::Indent /* unused */) const { os << "Name: " << GetName() << std::endl; os << "Color: " << GetColor() << std::endl; os << "ColorCoefficient" << GetColorCoefficient() << std::endl; os << "SpecularColor: " << GetSpecularColor() << std::endl; os << "SpecularCoefficient: " << GetSpecularCoefficient() << std::endl; os << "SpecularPower: " << GetSpecularPower() << std::endl; os << "Opacity: " << GetOpacity() << std::endl; os << "Line width: " << GetLineWidth() << std::endl; switch (GetInterpolation()) { case (Flat): os << "Interpolation: Flat" << std::endl; break; case (Gouraud): os << "Interpolation: Gouraud" << std::endl; break; case (Phong): os << "Interpolation: Phong" << std::endl; break; } switch (GetRepresentation()) { case (Points): os << "Representation: Points" << std::endl; break; case (Wireframe): os << "Representation: Wireframe" << std::endl; break; case (Surface): os << "Representation: Surface" << std::endl; break; } } diff --git a/Modules/Core/src/DataManagement/mitkPropertyDescriptions.cpp b/Modules/Core/src/DataManagement/mitkPropertyDescriptions.cpp index a2f49982ab..bafae1c07b 100644 --- a/Modules/Core/src/DataManagement/mitkPropertyDescriptions.cpp +++ b/Modules/Core/src/DataManagement/mitkPropertyDescriptions.cpp @@ -1,168 +1,168 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPropertyDescriptions.h" #include #include #include mitk::PropertyDescriptions::PropertyDescriptions() { } mitk::PropertyDescriptions::~PropertyDescriptions() { } bool mitk::PropertyDescriptions::AddDescription(const std::string &propertyName, const std::string &description, const std::string &className, bool overwrite) { if (propertyName.empty()) return false; DescriptionMap &descriptions = m_Descriptions[className]; std::pair ret = descriptions.insert(std::make_pair(propertyName, description)); if (!ret.second && overwrite) { ret.first->second = description; ret.second = true; } return ret.second; } bool mitk::PropertyDescriptions::AddDescriptionRegEx(const std::string &propertyRegEx, const std::string &description, const std::string &className, bool overwrite) { if (propertyRegEx.empty()) return false; try { std::regex checker(propertyRegEx); // no exception => valid we can change the info } - catch (std::regex_error) + catch (const std::regex_error &) { return false; } DescriptionMap &descriptions = m_DescriptionsRegEx[className]; std::pair ret = descriptions.insert(std::make_pair(propertyRegEx, description)); if (!ret.second && overwrite) { ret.first->second = description; ret.second = true; } return ret.second; } std::string mitk::PropertyDescriptions::GetDescription(const std::string &propertyName, const std::string &className, bool allowNameRegEx) const { if (!propertyName.empty()) { auto descriptionsIter = m_Descriptions.find(className); if (descriptionsIter != m_Descriptions.cend()) { auto iter = descriptionsIter->second.find(propertyName); if (iter != descriptionsIter->second.end()) return iter->second; } } if (allowNameRegEx && !propertyName.empty()) { auto selector = [propertyName](const DescriptionMap::value_type &x) { std::regex ex(x.first); return std::regex_match(propertyName, ex); }; auto descriptionsIter = m_DescriptionsRegEx.find(className); if (descriptionsIter != m_DescriptionsRegEx.cend()) { auto finding = std::find_if(descriptionsIter->second.cbegin(), descriptionsIter->second.cend(), selector); if (finding != descriptionsIter->second.cend()) return finding->second; } } return ""; } bool mitk::PropertyDescriptions::HasDescription(const std::string &propertyName, const std::string &className, bool allowNameRegEx) const { if (!propertyName.empty()) { auto descriptionsIter = m_Descriptions.find(className); if (descriptionsIter != m_Descriptions.cend()) { auto iter = descriptionsIter->second.find(propertyName); if (iter != descriptionsIter->second.end()) return true; } } if (allowNameRegEx && !propertyName.empty()) { auto selector = [propertyName](const DescriptionMap::value_type &x) { std::regex ex(x.first); return std::regex_match(propertyName, ex); }; auto descriptionsIter = m_DescriptionsRegEx.find(className); if (descriptionsIter != m_DescriptionsRegEx.cend()) { auto finding = std::find_if(descriptionsIter->second.cbegin(), descriptionsIter->second.cend(), selector); if (finding != descriptionsIter->second.cend()) return true; } } return false; } void mitk::PropertyDescriptions::RemoveAllDescriptions(const std::string &className) { m_Descriptions[className].clear(); m_DescriptionsRegEx[className].clear(); } void mitk::PropertyDescriptions::RemoveDescription(const std::string &propertyName, const std::string &className) { if (!propertyName.empty()) { m_Descriptions[className].erase(propertyName); m_DescriptionsRegEx[className].erase(propertyName); } } diff --git a/Modules/Core/test/mitkAccessByItkTest.cpp b/Modules/Core/test/mitkAccessByItkTest.cpp index 827366d8e3..295e115339 100644 --- a/Modules/Core/test/mitkAccessByItkTest.cpp +++ b/Modules/Core/test/mitkAccessByItkTest.cpp @@ -1,310 +1,310 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "mitkTestingMacros.h" #include #include #define TestImageType(type, dim) \ MITK_TEST_CONDITION(typeid(type) == typeid(TPixel) && dim == VDimension, \ "Checking for correct type itk::Image<" #type "," #dim ">") #define TestVectorImageType(type, dim) \ MITK_TEST_CONDITION(typeid(type) == typeid(TPixel) && dim == VDimension && \ typeid(itk::VariableLengthVector) == typeid(typename ImageType::PixelType), \ "Checking for correct type itk::VectorImage<" #type "," #dim ">") class AccessByItkTest { public: typedef AccessByItkTest Self; typedef itk::Image IntImage2D; typedef itk::Image IntImage3D; typedef itk::Image FloatImage2D; typedef itk::Image FloatImage3D; typedef itk::VectorImage IntVectorImage3D; enum EImageType { Unknown = 0, Int2D, Int3D, Float2D, Float3D }; void testAccessByItk() { mitk::Image::Pointer mitkIntImage2D = createMitkImage(); mitk::Image::ConstPointer mitkIntImage3D(createMitkImage()); mitk::Image::ConstPointer mitkFloatImage2D(createMitkImage()); mitk::Image::Pointer mitkFloatImage3D = createMitkImage(); AccessByItk(mitkIntImage2D, AccessItkImage); AccessByItk(mitkIntImage3D, AccessItkImage); AccessByItk(mitkFloatImage2D, AccessItkImage); AccessByItk(mitkFloatImage3D, AccessItkImage); AccessByItk_n(mitkIntImage2D, AccessItkImage, (Int2D, 2)); AccessByItk_n(mitkIntImage3D, AccessItkImage, (Int3D, 2)); AccessByItk_n(mitkFloatImage2D, AccessItkImage, (Float2D, 2)); AccessByItk_n(mitkFloatImage3D, AccessItkImage, (Float3D, 2)); mitk::Image::Pointer mitkIntVectorImage3D = createMitkImage(2); // Test for wrong pixel type (the AccessByItk macro multi-plexes integral // types only by default) - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessByItk(mitkIntVectorImage3D, AccessItkImage); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) // Test for correct handling of vector images AccessVectorPixelTypeByItk(mitkIntVectorImage3D, AccessItkImage); AccessVectorPixelTypeByItk_n(mitkIntVectorImage3D, AccessItkImage, (Int3D, 2)); } void testAccessFixedDimensionByItk() { mitk::Image::Pointer mitkIntImage2D = createMitkImage(); mitk::Image::ConstPointer mitkIntImage3D(createMitkImage()); mitk::Image::ConstPointer mitkFloatImage2D(createMitkImage()); mitk::Image::Pointer mitkFloatImage3D = createMitkImage(); AccessFixedDimensionByItk(mitkIntImage2D, AccessItkImage, 2); AccessFixedDimensionByItk(mitkIntImage3D, AccessItkImage, 3); AccessFixedDimensionByItk(mitkFloatImage2D, AccessItkImage, 2); AccessFixedDimensionByItk(mitkFloatImage3D, AccessItkImage, 3); AccessFixedDimensionByItk_n(mitkIntImage2D, AccessItkImage, 2, (Int2D, 2)); AccessFixedDimensionByItk_n(mitkIntImage3D, AccessItkImage, 3, (Int3D, 2)); AccessFixedDimensionByItk_n(mitkFloatImage2D, AccessItkImage, 2, (Float2D, 2)); AccessFixedDimensionByItk_n(mitkFloatImage3D, AccessItkImage, 3, (Float3D, 2)); // Test for wrong dimension - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessFixedDimensionByItk(mitkFloatImage3D, AccessItkImage, 2); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessFixedDimensionByItk_n(mitkFloatImage3D, AccessItkImage, 2, (Float3D, 2)); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) } void testAccessFixedPixelTypeByItk() { mitk::Image::Pointer mitkIntImage2D = createMitkImage(); mitk::Image::ConstPointer mitkIntImage3D(createMitkImage()); mitk::Image::ConstPointer mitkFloatImage2D(createMitkImage()); mitk::Image::Pointer mitkFloatImage3D = createMitkImage(); AccessFixedPixelTypeByItk(mitkIntImage2D, AccessItkImage, (int)(float)); AccessFixedPixelTypeByItk(mitkIntImage3D, AccessItkImage, (int)(float)); AccessFixedPixelTypeByItk(mitkFloatImage2D, AccessItkImage, (int)(float)); AccessFixedPixelTypeByItk(mitkFloatImage3D, AccessItkImage, (int)(float)); AccessFixedPixelTypeByItk_n(mitkIntImage2D, AccessItkImage, (int)(float), (Int2D, 2)); AccessFixedPixelTypeByItk_n(mitkIntImage3D, AccessItkImage, (int)(float), (Int3D, 2)); AccessFixedPixelTypeByItk_n(mitkFloatImage2D, AccessItkImage, (int)(float), (Float2D, 2)); AccessFixedPixelTypeByItk_n(mitkFloatImage3D, AccessItkImage, (int)(float), (Float3D, 2)); // Test for wrong pixel type - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessFixedPixelTypeByItk(mitkFloatImage3D, AccessItkImage, (int)); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessFixedPixelTypeByItk_n(mitkFloatImage3D, AccessItkImage, (int), (Float3D, 2)); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) } void testAccessFixedTypeByItk() { mitk::Image::Pointer mitkIntImage2D = createMitkImage(); mitk::Image::ConstPointer mitkIntImage3D(createMitkImage()); mitk::Image::ConstPointer mitkFloatImage2D(createMitkImage()); mitk::Image::Pointer mitkFloatImage3D = createMitkImage(); AccessFixedTypeByItk(mitkIntImage2D, AccessItkImage, (int)(float), (2)(3)); AccessFixedTypeByItk(mitkIntImage3D, AccessItkImage, (int)(float), (2)(3)); AccessFixedTypeByItk(mitkFloatImage2D, AccessItkImage, (int)(float), (2)(3)); AccessFixedTypeByItk(mitkFloatImage3D, AccessItkImage, (int)(float), (2)(3)); AccessFixedTypeByItk_n(mitkIntImage2D, AccessItkImage, (int)(float), (2)(3), (Int2D, 2)); AccessFixedTypeByItk_n(mitkIntImage3D, AccessItkImage, (int)(float), (2)(3), (Int3D, 2)); AccessFixedTypeByItk_n(mitkFloatImage2D, AccessItkImage, (int)(float), (2)(3), (Float2D, 2)); AccessFixedTypeByItk_n(mitkFloatImage3D, AccessItkImage, (int)(float), (2)(3), (Float3D, 2)); // Test for wrong dimension - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessFixedTypeByItk(mitkFloatImage3D, AccessItkImage, (float), (2)); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessFixedTypeByItk_n(mitkFloatImage3D, AccessItkImage, (float), (2), (Float3D, 2)); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) // Test for wrong pixel type - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessFixedTypeByItk(mitkFloatImage3D, AccessItkImage, (int), (3)); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) - MITK_TEST_FOR_EXCEPTION_BEGIN(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::AccessByItkException) AccessFixedTypeByItk_n(mitkFloatImage3D, AccessItkImage, (int), (3), (Float3D, 2)); - MITK_TEST_FOR_EXCEPTION_END(const mitk::AccessByItkException &) + MITK_TEST_FOR_EXCEPTION_END(mitk::AccessByItkException) } void testAccessTwoImagesFixedDimensionByItk() { mitk::Image::Pointer mitkIntImage2D = createMitkImage(); mitk::Image::ConstPointer mitkFloatImage2D(createMitkImage()); AccessTwoImagesFixedDimensionByItk(mitkIntImage2D, mitkFloatImage2D, AccessTwoItkImages, 2); } template void AccessItkImage(const itk::Image *, EImageType param1 = Unknown, int param2 = 0, int param3 = 0) { switch (param1) { case Int2D: TestImageType(int, 2) break; case Int3D: TestImageType(int, 3) break; case Float2D: TestImageType(float, 2) break; case Float3D: TestImageType(float, 3) break; default: break; } if (param2) { MITK_TEST_CONDITION(param2 == 2, "Checking for correct second parameter") } if (param3) { MITK_TEST_CONDITION(param3 == 3, "Checking for correct third parameter") } } template void AccessItkImage(itk::VectorImage *, EImageType param1 = Unknown, int param2 = 0, int param3 = 0) { typedef itk::VectorImage ImageType; switch (param1) { case Int2D: TestVectorImageType(int, 2) break; case Int3D: TestVectorImageType(int, 3) break; case Float2D: TestVectorImageType(float, 2) break; case Float3D: TestVectorImageType(float, 3) break; default: break; } if (param2) { MITK_TEST_CONDITION(param2 == 2, "Checking for correct second parameter") } if (param3) { MITK_TEST_CONDITION(param3 == 3, "Checking for correct third parameter") } } private: template void AccessTwoItkImages(itk::Image * /*itkImage1*/, itk::Image * /*itkImage2*/) { if (!(typeid(int) == typeid(TPixel1) && typeid(float) == typeid(TPixel2) && VDimension1 == 2 && VDimension2 == 2)) { throw std::runtime_error("Image type mismatch"); } } template mitk::Image::Pointer createMitkImage() { typename ImageType::Pointer itkImage = ImageType::New(); typename ImageType::IndexType start; start.Fill(0); typename ImageType::SizeType size; size.Fill(3); typename ImageType::RegionType region; region.SetSize(size); region.SetIndex(start); itkImage->SetRegions(region); itkImage->Allocate(); return mitk::GrabItkImageMemory(itkImage); } template mitk::Image::Pointer createMitkImage(std::size_t vectorLength) { typename ImageType::Pointer itkImage = ImageType::New(); typename ImageType::IndexType start; start.Fill(0); typename ImageType::SizeType size; size.Fill(3); typename ImageType::RegionType region; region.SetSize(size); region.SetIndex(start); itkImage->SetRegions(region); itkImage->SetVectorLength(vectorLength); itkImage->Allocate(); return mitk::GrabItkImageMemory(itkImage); } }; int mitkAccessByItkTest(int /*argc*/, char * /*argv*/ []) { MITK_TEST_BEGIN("AccessByItk") AccessByItkTest accessTest; MITK_TEST_OUTPUT(<< "Testing AccessByItk macro") accessTest.testAccessByItk(); MITK_TEST_OUTPUT(<< "Testing AccessFixedDimensionByItk macro") accessTest.testAccessFixedDimensionByItk(); MITK_TEST_OUTPUT(<< "Testing AccessFixedTypeByItk macro") accessTest.testAccessFixedTypeByItk(); MITK_TEST_OUTPUT(<< "Testing AccessFixedPixelTypeByItk macro") accessTest.testAccessFixedPixelTypeByItk(); MITK_TEST_OUTPUT(<< "Testing AccessTwoImagesFixedDimensionByItk macro") accessTest.testAccessTwoImagesFixedDimensionByItk(); MITK_TEST_END() } diff --git a/Modules/Core/test/mitkDataStorageTest.cpp b/Modules/Core/test/mitkDataStorageTest.cpp index a76907f313..815dcd668c 100644 --- a/Modules/Core/test/mitkDataStorageTest.cpp +++ b/Modules/Core/test/mitkDataStorageTest.cpp @@ -1,878 +1,878 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "mitkColorProperty.h" #include "mitkDataNode.h" #include "mitkGroupTagProperty.h" #include "mitkImage.h" #include "mitkReferenceCountWatcher.h" #include "mitkStringProperty.h" #include "mitkSurface.h" #include "mitkDataStorage.h" #include "mitkIOUtil.h" #include "mitkMessage.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateData.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateProperty.h" #include "mitkNodePredicateSource.h" #include "mitkStandaloneDataStorage.h" //#include "mitkPicFileReader.h" #include "mitkTestingMacros.h" void TestDataStorage(mitk::DataStorage *ds, std::string filename); namespace mitk { class TestStandaloneDataStorage : public StandaloneDataStorage { public: mitkClassMacro(TestStandaloneDataStorage, mitk::DataStorage); itkFactorylessNewMacro(Self) itkCloneMacro(Self) std::map GetModifiedObserverTags() const { return m_NodeModifiedObserverTags; } std::map GetDeletedObserverTags() const { return m_NodeDeleteObserverTags; } protected: TestStandaloneDataStorage() {} }; } class DSEventReceiver // Helper class for event testing { public: const mitk::DataNode *m_NodeAdded; const mitk::DataNode *m_NodeRemoved; DSEventReceiver() : m_NodeAdded(nullptr), m_NodeRemoved(nullptr) {} void OnAdd(const mitk::DataNode *node) { m_NodeAdded = node; } void OnRemove(const mitk::DataNode *node) { m_NodeRemoved = node; } }; /// /// \brief a class for checking if the datastorage is really thread safe /// /// Therefore it listens to a node contained in the datastorage. when this node /// gets removed and deleted, this class gets informed by calling OnObjectDelete(). /// in OnObjectDelete() an empty node gets added. this must not cause a deadlock /// struct ItkDeleteEventListener { ItkDeleteEventListener(mitk::DataStorage *ds) : m_Node(nullptr), m_DataStorage(ds), m_DeleteObserverTag(0) {} void SetNode(mitk::DataNode *_Node) { if (m_Node) return; m_Node = _Node; itk::MemberCommand::Pointer onObjectDelete = itk::MemberCommand::New(); onObjectDelete->SetCallbackFunction(this, &ItkDeleteEventListener::OnObjectDelete); m_DeleteObserverTag = m_Node->AddObserver(itk::DeleteEvent(), onObjectDelete); } void OnObjectDelete(const itk::Object * /*caller*/, const itk::EventObject &) { mitk::DataNode::Pointer node = mitk::DataNode::New(); m_DataStorage->Add(node); // SHOULD NOT CAUSE A DEADLOCK! m_DataStorage->Remove(node); // tidy up: remove the empty node again m_Node = nullptr; } protected: mitk::DataNode *m_Node; mitk::DataStorage::Pointer m_DataStorage; unsigned int m_DeleteObserverTag; }; //## Documentation //## main testing method //## NOTE: the current Singleton implementation of DataTreeStorage will lead to crashes if a testcase fails //## and therefore mitk::DataStorage::ShutdownSingleton() is not called. int mitkDataStorageTest(int argc, char *argv[]) { MITK_TEST_BEGIN("DataStorageTest"); // muellerm: test observer tag remove mitk::TestStandaloneDataStorage::Pointer testDS = mitk::TestStandaloneDataStorage::New(); mitk::DataNode::Pointer n1 = mitk::DataNode::New(); testDS->Add(n1); MITK_TEST_CONDITION_REQUIRED(testDS->GetModifiedObserverTags().size() == 1, "Testing if modified" " observer was added."); MITK_TEST_CONDITION_REQUIRED(testDS->GetDeletedObserverTags().size() == 1, "Testing if delete" " observer was added."); testDS->Remove(n1); MITK_TEST_CONDITION_REQUIRED(testDS->GetModifiedObserverTags().size() == 0, "Testing if modified" " observer was removed."); MITK_TEST_CONDITION_REQUIRED(testDS->GetDeletedObserverTags().size() == 0, "Testing if delete" " observer was removed."); /* Create StandaloneDataStorage */ MITK_TEST_OUTPUT(<< "Create StandaloneDataStorage : "); mitk::StandaloneDataStorage::Pointer sds; try { sds = mitk::StandaloneDataStorage::New(); MITK_TEST_CONDITION_REQUIRED(sds.IsNotNull(), "Testing Instatiation"); } catch (...) { MITK_TEST_FAILED_MSG(<< "Exception during creation of StandaloneDataStorage"); } MITK_TEST_OUTPUT(<< "Testing StandaloneDataStorage: "); MITK_TEST_CONDITION_REQUIRED(argc > 1, "Testing correct test invocation"); TestDataStorage(sds, argv[1]); // TODO: Add specific StandaloneDataStorage Tests here sds = nullptr; MITK_TEST_END(); } //##Documentation //## @brief Test for the DataStorage class and its associated classes (e.g. the predicate classes) //## This method will be called once for each subclass of DataStorage void TestDataStorage(mitk::DataStorage *ds, std::string filename) { /* DataStorage valid? */ MITK_TEST_CONDITION_REQUIRED(ds != nullptr, "DataStorage valid?"); // Take the ItkImageFile Reader for the .nrrd data format. // (was previously pic which is now deprecated format) mitk::Image::Pointer image = mitk::IOUtil::Load(filename); // create some DataNodes to fill the ds mitk::DataNode::Pointer n1 = mitk::DataNode::New(); // node with image and name property // mitk::Image::Pointer image = mitk::Image::New(); // unsigned int imageDimensions[] = { 10, 10, 10, 10 }; // mitk::PixelType pt(typeid(int)); // image->Initialize( pt, 4, imageDimensions ); n1->SetData(image); n1->SetProperty("name", mitk::StringProperty::New("Node 1 - Image Node")); mitk::DataStorage::SetOfObjects::Pointer parents1 = mitk::DataStorage::SetOfObjects::New(); mitk::DataNode::Pointer n2 = mitk::DataNode::New(); // node with surface and name and color properties mitk::Surface::Pointer surface = mitk::Surface::New(); n2->SetData(surface); n2->SetProperty("name", mitk::StringProperty::New("Node 2 - Surface Node")); mitk::Color color; color.Set(1.0f, 1.0f, 0.0f); n2->SetColor(color); n2->SetProperty("Resection Proposal 1", mitk::GroupTagProperty::New()); mitk::DataStorage::SetOfObjects::Pointer parents2 = mitk::DataStorage::SetOfObjects::New(); parents2->InsertElement(0, n1); // n1 (image node) is source of n2 (surface node) mitk::DataNode::Pointer n3 = mitk::DataNode::New(); // node without data but with name property n3->SetProperty("name", mitk::StringProperty::New("Node 3 - Empty Node")); n3->SetProperty("Resection Proposal 1", mitk::GroupTagProperty::New()); n3->SetProperty("Resection Proposal 2", mitk::GroupTagProperty::New()); mitk::DataStorage::SetOfObjects::Pointer parents3 = mitk::DataStorage::SetOfObjects::New(); parents3->InsertElement(0, n2); // n2 is source of n3 mitk::DataNode::Pointer n4 = mitk::DataNode::New(); // node without data but with color property n4->SetColor(color); n4->SetProperty("Resection Proposal 2", mitk::GroupTagProperty::New()); mitk::DataStorage::SetOfObjects::Pointer parents4 = mitk::DataStorage::SetOfObjects::New(); parents4->InsertElement(0, n2); parents4->InsertElement(1, n3); // n2 and n3 are sources of n4 mitk::DataNode::Pointer n5 = mitk::DataNode::New(); // extra node n5->SetProperty("name", mitk::StringProperty::New("Node 5")); try /* adding objects */ { /* Add an object */ ds->Add(n1, parents1); MITK_TEST_CONDITION_REQUIRED((ds->GetAll()->Size() == 1) && (ds->GetAll()->GetElement(0) == n1), "Testing Adding a new object"); /* Check exception on adding the same object again */ MITK_TEST_OUTPUT(<< "Check exception on adding the same object again: "); - MITK_TEST_FOR_EXCEPTION(..., ds->Add(n1, parents1)); + MITK_TEST_FOR_EXCEPTION(std::exception, ds->Add(n1, parents1)); MITK_TEST_CONDITION(ds->GetAll()->Size() == 1, "Test if object count is correct after exception"); /* Add an object that has a source object */ ds->Add(n2, parents2); MITK_TEST_CONDITION_REQUIRED(ds->GetAll()->Size() == 2, "Testing Adding an object that has a source object"); /* Add some more objects needed for further tests */ ds->Add(n3, parents3); // n3 object that has name property and one parent ds->Add(n4, parents4); // n4 object that has color property ds->Add(n5); // n5 has no parents MITK_TEST_CONDITION_REQUIRED(ds->GetAll()->Size() == 5, "Adding some more objects needed for further tests"); } catch (...) { MITK_TEST_FAILED_MSG(<< "Exeption during object creation"); } try /* object retrieval methods */ { /* Requesting all Objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetAll(); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((stlAll.size() == 5) // check if all tree nodes are in resultset && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n5) != stlAll.end()), "Testing GetAll()"); } /* Requesting a named object */ { mitk::NodePredicateProperty::Pointer predicate( mitk::NodePredicateProperty::New("name", mitk::StringProperty::New("Node 2 - Surface Node"))); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n2), "Requesting a named object"); } /* Requesting objects of specific data type */ { mitk::NodePredicateDataType::Pointer predicate(mitk::NodePredicateDataType::New("Image")); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1), "Requesting objects of specific data type") } /* Requesting objects of specific dimension */ { mitk::NodePredicateDimension::Pointer predicate(mitk::NodePredicateDimension::New(4)); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1), "Requesting objects of specific dimension") } /* Requesting objects with specific data object */ { mitk::NodePredicateData::Pointer predicate(mitk::NodePredicateData::New(image)); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1), "Requesting objects with specific data object") } /* Requesting objects with nullptr data */ { mitk::NodePredicateData::Pointer predicate(mitk::NodePredicateData::New(nullptr)); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 3) && (std::find(all->begin(), all->end(), n3) != all->end()) && (std::find(all->begin(), all->end(), n4) != all->end()) && (std::find(all->begin(), all->end(), n5) != all->end()), "Requesting objects with nullptr data"); } /* Requesting objects that meet a conjunction criteria */ { mitk::NodePredicateDataType::Pointer p1 = mitk::NodePredicateDataType::New("Surface"); mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("color", mitk::ColorProperty::New(color)); mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New(); predicate->AddPredicate(p1); predicate->AddPredicate(p2); // objects must be of datatype "Surface" and have red color (= n2) const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n2), "Requesting objects that meet a conjunction criteria"); } /* Requesting objects that meet a disjunction criteria */ { mitk::NodePredicateDataType::Pointer p1(mitk::NodePredicateDataType::New("Image")); mitk::NodePredicateProperty::Pointer p2( mitk::NodePredicateProperty::New("color", mitk::ColorProperty::New(color))); mitk::NodePredicateOr::Pointer predicate = mitk::NodePredicateOr::New(); predicate->AddPredicate(p1); predicate->AddPredicate(p2); // objects must be of datatype "Surface" or have red color (= n1, n2, n4) const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 3) && (std::find(all->begin(), all->end(), n1) != all->end()) && (std::find(all->begin(), all->end(), n2) != all->end()) && (std::find(all->begin(), all->end(), n4) != all->end()), "Requesting objects that meet a disjunction criteria"); } /* Requesting objects that do not meet a criteria */ { mitk::ColorProperty::Pointer cp = mitk::ColorProperty::New(color); mitk::NodePredicateProperty::Pointer proppred(mitk::NodePredicateProperty::New("color", cp)); mitk::NodePredicateNot::Pointer predicate(mitk::NodePredicateNot::New(proppred)); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 3) // check if correct objects are in resultset && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n5) != stlAll.end()), "Requesting objects that do not meet a criteria"); } /* Requesting *direct* source objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n3, nullptr, true); // Get direct parents of n3 (=n2) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 1) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()), "Requesting *direct* source objects"); } /* Requesting *all* source objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n3, nullptr, false); // Get all parents of n3 (= n1 + n2) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 2) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()), "Requesting *all* source objects"); // check if n1 and n2 are the resultset } /* Requesting *all* sources of object with multiple parents */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, nullptr, false); // Get all parents of n4 (= n1 + n2 + n3) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n1 and n2 and n3 are the resultset , "Requesting *all* sources of object with multiple parents"); } /* Requesting *direct* derived objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, nullptr, true); // Get direct childs of n1 (=n2) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 1) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) // check if n1 is the resultset , "Requesting *direct* derived objects"); } ///* Requesting *direct* derived objects with multiple parents/derivations */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n2, nullptr, true); // Get direct childs of n2 (=n3 + n4) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 2) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n3 is the resultset && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) // check if n4 is the resultset , "Requesting *direct* derived objects with multiple parents/derivations"); } //* Requesting *all* derived objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, nullptr, false); // Get all childs of n1 (=n2, n3, n4) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()), "Requesting *all* derived objects"); } /* Checking for circular source relationships */ { parents1->InsertElement(0, n4); // make n1 derived from n4 (which is derived from n2, which is derived from n1) const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources( n4, nullptr, false); // Get all parents of n4 (= n1 + n2 + n3, not n4 itself and not multiple versions of the nodes!) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n1 and n2 and n3 are the resultset , "Checking for circular source relationships"); } ///* Checking for circular derivation relationships can not be performed, because the internal derivations /// datastructure // can not be accessed from the outside. (Therefore it should not be possible to create these circular relations // */ //* Checking GroupTagProperty */ { mitk::GroupTagProperty::Pointer tp = mitk::GroupTagProperty::New(); mitk::NodePredicateProperty::Pointer pred(mitk::NodePredicateProperty::New("Resection Proposal 1", tp)); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(pred); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 2) // check if n2 and n3 are in resultset && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()), "Checking GroupTagProperty"); } /* Checking GroupTagProperty 2 */ { mitk::GroupTagProperty::Pointer tp = mitk::GroupTagProperty::New(); mitk::NodePredicateProperty::Pointer pred(mitk::NodePredicateProperty::New("Resection Proposal 2", tp)); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(pred); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 2) // check if n3 and n4 are in resultset && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()), "Checking GroupTagProperty 2"); } /* Checking direct sources with condition */ { mitk::NodePredicateDataType::Pointer pred = mitk::NodePredicateDataType::New("Surface"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, true); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 1) // check if n2 is in resultset && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()), "checking direct sources with condition"); } /* Checking all sources with condition */ { mitk::NodePredicateDataType::Pointer pred = mitk::NodePredicateDataType::New("Image"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, false); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 1) // check if n1 is in resultset && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()), "Checking all sources with condition"); } /* Checking all sources with condition with empty resultset */ { mitk::NodePredicateDataType::Pointer pred = mitk::NodePredicateDataType::New("VesselTree"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, false); MITK_TEST_CONDITION(all->Size() == 0, "Checking all sources with condition with empty resultset"); // check if resultset is empty } /* Checking direct derivations with condition */ { mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New("color"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, pred, true); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 1) // check if n2 is in resultset && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()), "Checking direct derivations with condition"); } /* Checking all derivations with condition */ { mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New("color"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, pred, false); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION((all->Size() == 2) // check if n2 and n4 are in resultset && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()), "Checking direct derivations with condition"); } /* Checking named node method */ MITK_TEST_CONDITION(ds->GetNamedNode("Node 2 - Surface Node") == n2, "Checking named node method"); MITK_TEST_CONDITION(ds->GetNamedNode(std::string("Node 2 - Surface Node")) == n2, "Checking named node(std::string) method"); /* Checking named node method with wrong name */ MITK_TEST_CONDITION(ds->GetNamedNode("This name does not exist") == nullptr, "Checking named node method with wrong name"); /* Checking named object method */ MITK_TEST_CONDITION(ds->GetNamedObject("Node 1 - Image Node") == image, "Checking named object method"); MITK_TEST_CONDITION(ds->GetNamedObject(std::string("Node 1 - Image Node")) == image, "Checking named object(std::string) method"); /* Checking named object method with wrong DataType */ MITK_TEST_CONDITION(ds->GetNamedObject("Node 1 - Image Node") == nullptr, "Checking named object method with wrong DataType"); /* Checking named object method with wrong name */ MITK_TEST_CONDITION(ds->GetNamedObject("This name does not exist") == nullptr, "Checking named object method with wrong name"); /* Checking GetNamedDerivedNode with valid name and direct derivation only */ MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 2 - Surface Node", n1, true) == n2, "Checking GetNamedDerivedNode with valid name & direct derivation only"); /* Checking GetNamedDerivedNode with invalid Name and direct derivation only */ MITK_TEST_CONDITION(ds->GetNamedDerivedNode("wrong name", n1, true) == nullptr, "Checking GetNamedDerivedNode with invalid name & direct derivation only"); /* Checking GetNamedDerivedNode with invalid Name and direct derivation only */ MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 3 - Empty Node", n1, false) == n3, "Checking GetNamedDerivedNode with invalid name & direct derivation only"); /* Checking GetNamedDerivedNode with valid Name but direct derivation only */ MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 3 - Empty Node", n1, true) == nullptr, "Checking GetNamedDerivedNode with valid Name but direct derivation only"); /* Checking GetNode with valid predicate */ { mitk::NodePredicateDataType::Pointer p(mitk::NodePredicateDataType::New("Image")); MITK_TEST_CONDITION(ds->GetNode(p) == n1, "Checking GetNode with valid predicate"); } /* Checking GetNode with invalid predicate */ { mitk::NodePredicateDataType::Pointer p(mitk::NodePredicateDataType::New("PointSet")); MITK_TEST_CONDITION(ds->GetNode(p) == nullptr, "Checking GetNode with invalid predicate"); } } // object retrieval methods catch (...) { MITK_TEST_FAILED_MSG(<< "Exeption during object retrieval (GetXXX() Methods)"); } try /* object removal methods */ { /* Checking removal of a node without relations */ { mitk::DataNode::Pointer extra = mitk::DataNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); int refCountbeforeDS = watcher->GetReferenceCount(); ds->Add(extra); MITK_TEST_CONDITION(ds->GetNamedNode("extra") == extra, "Adding extra node"); ds->Remove(extra); MITK_TEST_CONDITION((ds->GetNamedNode("extra") == nullptr) && (refCountbeforeDS == watcher->GetReferenceCount()), "Checking removal of a node without relations"); extra = nullptr; } /* Checking removal of a node with a parent */ { mitk::DataNode::Pointer extra = mitk::DataNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); int refCountbeforeDS = watcher->GetReferenceCount(); ds->Add(extra, n1); // n1 is parent of extra MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1 , "Adding extra node"); ds->Remove(extra); MITK_TEST_CONDITION((ds->GetNamedNode("extra") == nullptr) && (refCountbeforeDS == watcher->GetReferenceCount()) && (ds->GetDerivations(n1)->Size() == 1), "Checking removal of a node with a parent"); extra = nullptr; } /* Checking removal of a node with two parents */ { mitk::DataNode::Pointer extra = mitk::DataNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); int refCountbeforeDS = watcher->GetReferenceCount(); mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New(); p->push_back(n1); p->push_back(n2); ds->Add(extra, p); // n1 and n2 are parents of extra MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1 && (ds->GetDerivations(n2)->Size() == 3), "add extra node"); ds->Remove(extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == nullptr) && (refCountbeforeDS == watcher->GetReferenceCount()) && (ds->GetDerivations(n1)->Size() == 1) // after remove, only n2 should be derived from n1 && (ds->GetDerivations(n2)->Size() == 2) // after remove, only n3 and n4 should be derived from n2 , "Checking removal of a node with two parents"); extra = nullptr; } /* Checking removal of a node with two derived nodes */ { mitk::DataNode::Pointer extra = mitk::DataNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); int refCountbeforeDS = watcher->GetReferenceCount(); ds->Add(extra); mitk::DataNode::Pointer d1 = mitk::DataNode::New(); d1->SetProperty("name", mitk::StringProperty::New("d1")); ds->Add(d1, extra); mitk::DataNode::Pointer d2 = mitk::DataNode::New(); d2->SetProperty("name", mitk::StringProperty::New("d2")); ds->Add(d2, extra); MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1") == d1) && (ds->GetNamedNode("d2") == d2) && (ds->GetSources(d1)->Size() == 1) // extra should be source of d1 && (ds->GetSources(d2)->Size() == 1) // extra should be source of d2 && (ds->GetDerivations(extra)->Size() == 2) // d1 and d2 should be derived from extra , "add extra node"); ds->Remove(extra); MITK_TEST_CONDITION((ds->GetNamedNode("extra") == nullptr) && (ds->GetNamedNode("d1") == d1) && (ds->GetNamedNode("d2") == d2) && (refCountbeforeDS == watcher->GetReferenceCount()) && (ds->GetSources(d1)->Size() == 0) // after remove, d1 should not have a source anymore && (ds->GetSources(d2)->Size() == 0) // after remove, d2 should not have a source anymore , "Checking removal of a node with two derived nodes"); extra = nullptr; } /* Checking removal of a node with two parents and two derived nodes */ { mitk::DataNode::Pointer extra = mitk::DataNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); mitk::ReferenceCountWatcher::Pointer n1watcher = new mitk::ReferenceCountWatcher(n1); int refCountbeforeDS = watcher->GetReferenceCount(); mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New(); p->push_back(n1); p->push_back(n2); ds->Add(extra, p); // n1 and n2 are parents of extra mitk::DataNode::Pointer d1 = mitk::DataNode::New(); d1->SetProperty("name", mitk::StringProperty::New("d1x")); ds->Add(d1, extra); mitk::DataNode::Pointer d2 = mitk::DataNode::New(); d2->SetProperty("name", mitk::StringProperty::New("d2x")); ds->Add(d2, extra); MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1x") == d1) && (ds->GetNamedNode("d2x") == d2) && (ds->GetSources(d1)->Size() == 1) // extra should be source of d1 && (ds->GetSources(d2)->Size() == 1) // extra should be source of d2 && (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1 && (ds->GetDerivations(n2)->Size() == 3) // n3, n4 and extra should be derived from n2 && (ds->GetDerivations(extra)->Size() == 2) // d1 and d2 should be derived from extra , "add extra node"); ds->Remove(extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == nullptr) && (ds->GetNamedNode("d1x") == d1) && (ds->GetNamedNode("d2x") == d2) && (refCountbeforeDS == watcher->GetReferenceCount()) && (ds->GetDerivations(n1)->Size() == 1) // after remove, only n2 should be derived from n1 && (ds->GetDerivations(n2)->Size() == 2) // after remove, only n3 and n4 should be derived from n2 && (ds->GetSources(d1)->Size() == 0) // after remove, d1 should not have a source anymore && (ds->GetSources(d2)->Size() == 0) // after remove, d2 should not have a source anymore , "Checking removal of a node with two parents and two derived nodes"); extra = nullptr; } } catch (...) { MITK_TEST_FAILED_MSG(<< "Exeption during object removal methods"); } /* Checking for node is it's own parent exception */ { - MITK_TEST_FOR_EXCEPTION_BEGIN(...); + MITK_TEST_FOR_EXCEPTION_BEGIN(std::exception); mitk::DataNode::Pointer extra = mitk::DataNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New(); p->push_back(n1); p->push_back(extra); // extra is parent of extra!!! ds->Add(extra, p); - MITK_TEST_FOR_EXCEPTION_END(...); + MITK_TEST_FOR_EXCEPTION_END(std::exception); } /* Checking reference count of node after add and remove */ { mitk::DataNode::Pointer extra = mitk::DataNode::New(); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New(); p->push_back(n1); p->push_back(n3); ds->Add(extra, p); extra = nullptr; ds->Remove(ds->GetNamedNode("extra")); MITK_TEST_CONDITION(watcher->GetReferenceCount() == 0, "Checking reference count of node after add and remove"); } /* Checking removal of a node with two derived nodes [ dataStorage->GetDerivations( rootNode )] see bug #3426 */ { mitk::DataNode::Pointer extra = mitk::DataNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); ds->Add(extra); mitk::DataNode::Pointer d1y = mitk::DataNode::New(); d1y->SetProperty("name", mitk::StringProperty::New("d1y")); mitk::ReferenceCountWatcher::Pointer watcherD1y = new mitk::ReferenceCountWatcher(d1y); int refCountbeforeDS = watcherD1y->GetReferenceCount(); ds->Add(d1y, extra); mitk::DataNode::Pointer d2y = mitk::DataNode::New(); d2y->SetProperty("name", mitk::StringProperty::New("d2y")); ds->Add(d2y, extra); MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1y") == d1y) && (ds->GetNamedNode("d2y") == d2y) && (ds->GetSources(d1y)->Size() == 1) // extra should be source of d1y && (ds->GetSources(d2y)->Size() == 1) // extra should be source of d2y && (ds->GetDerivations(extra)->Size() == 2) // d1y and d2y should be derived from extra , "add extra node"); ds->Remove(ds->GetDerivations(extra)); MITK_TEST_CONDITION((ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1y") == nullptr) // d1y should be nullptr now && (ds->GetNamedNode("d2y") == nullptr) // d2y should be nullptr now && (refCountbeforeDS == watcherD1y->GetReferenceCount()), "Checking removal of subset of two derived nodes from one parent node"); ds->Remove(extra); MITK_TEST_CONDITION((ds->GetNamedNode("extra") == nullptr), "Checking removal of a parent node"); extra = nullptr; } /* Checking GetGrouptags() */ { const std::set groupTags = ds->GetGroupTags(); MITK_TEST_CONDITION((groupTags.size() == 2) && (std::find(groupTags.begin(), groupTags.end(), "Resection Proposal 1") != groupTags.end()) && (std::find(groupTags.begin(), groupTags.end(), "Resection Proposal 2") != groupTags.end()), "Checking GetGrouptags()"); } /* Checking Event handling */ DSEventReceiver listener; try { ds->AddNodeEvent += mitk::MessageDelegate1(&listener, &DSEventReceiver::OnAdd); ds->RemoveNodeEvent += mitk::MessageDelegate1(&listener, &DSEventReceiver::OnRemove); mitk::DataNode::Pointer extra = mitk::DataNode::New(); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); ds->Add(extra); MITK_TEST_CONDITION(listener.m_NodeAdded == extra.GetPointer(), "Checking AddEvent"); ds->Remove(extra); MITK_TEST_CONDITION(listener.m_NodeRemoved == extra.GetPointer(), "Checking RemoveEvent"); /* RemoveListener */ ds->AddNodeEvent -= mitk::MessageDelegate1(&listener, &DSEventReceiver::OnAdd); ds->RemoveNodeEvent -= mitk::MessageDelegate1(&listener, &DSEventReceiver::OnRemove); listener.m_NodeAdded = nullptr; listener.m_NodeRemoved = nullptr; ds->Add(extra); ds->Remove(extra); MITK_TEST_CONDITION((listener.m_NodeRemoved == nullptr) && (listener.m_NodeAdded == nullptr), "Checking RemoveListener"); std::cout << "Pointer handling after event handling: " << std::flush; extra = nullptr; // delete reference to the node. its memory should be freed now MITK_TEST_CONDITION(watcher->GetReferenceCount() == 0, "Pointer handling after event handling"); } catch (...) { /* cleanup */ ds->AddNodeEvent -= mitk::MessageDelegate1(&listener, &DSEventReceiver::OnAdd); ds->RemoveNodeEvent -= mitk::MessageDelegate1(&listener, &DSEventReceiver::OnRemove); MITK_TEST_FAILED_MSG(<< "Exception during object removal methods"); } // Checking ComputeBoundingGeometry3D method*/ const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetAll(); auto geometry = ds->ComputeBoundingGeometry3D(); MITK_TEST_CONDITION(geometry->CountTimeSteps() == 4, "Test for number or time steps with ComputeBoundingGeometry()"); mitk::TimeBounds timebounds = geometry->GetTimeBounds(); MITK_TEST_CONDITION((timebounds[0] == 0) && (timebounds[1] == 4), "Test for timebounds with ComputeBoundingGeometry()"); for (unsigned int i = 0; i < geometry->CountTimeSteps(); i++) { mitk::BaseGeometry::Pointer subGeometry = geometry->GetGeometryForTimeStep(i); mitk::TimeBounds bounds = geometry->GetTimeBounds(i); MITK_TEST_CONDITION((bounds[0] == i) && (bounds[1] == i + 1), "Test for timebounds of geometry at different time steps with ComputeBoundingGeometry()"); } geometry = ds->ComputeBoundingGeometry3D(all); MITK_TEST_CONDITION(geometry->CountTimeSteps() == 4, "Test for number or time steps with ComputeBoundingGeometry(allNodes)"); timebounds = geometry->GetTimeBounds(); MITK_TEST_CONDITION((timebounds[0] == 0) && (timebounds[1] == 4), "Test for timebounds with ComputeBoundingGeometry(allNodes)"); for (unsigned int i = 0; i < geometry->CountTimeSteps(); i++) { mitk::BaseGeometry::Pointer subGeometry = geometry->GetGeometryForTimeStep(i); mitk::TimeBounds bounds = geometry->GetTimeBounds(i); MITK_TEST_CONDITION((bounds[0] == i) && (bounds[1] == i + 1), "Test for timebounds of geometry at different time steps with ComputeBoundingGeometry()"); } // test for thread safety of DataStorage try { mitk::StandaloneDataStorage::Pointer standaloneDataStorage = mitk::StandaloneDataStorage::New(); ItkDeleteEventListener listener(standaloneDataStorage); { mitk::DataNode::Pointer emptyNode = mitk::DataNode::New(); mitk::DataNode *pEmptyNode = emptyNode; listener.SetNode(emptyNode); standaloneDataStorage->Add(emptyNode); emptyNode = nullptr; // emptyNode is still alive because standaloneDataStorage // owns it standaloneDataStorage->Remove(pEmptyNode); // this should not freeze the whole thing } } catch (...) { MITK_TEST_FAILED_MSG(<< "Exception during testing DataStorage thread safe"); } /* Clear DataStorage */ ds->Remove(ds->GetAll()); MITK_TEST_CONDITION(ds->GetAll()->Size() == 0, "Checking Clear DataStorage"); } diff --git a/Modules/Core/test/mitkExceptionTest.cpp b/Modules/Core/test/mitkExceptionTest.cpp index bd8c597b82..3b21794216 100644 --- a/Modules/Core/test/mitkExceptionTest.cpp +++ b/Modules/Core/test/mitkExceptionTest.cpp @@ -1,318 +1,318 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkExceptionMacro.h" #include "mitkTestingMacros.h" #include #include #include class SpecializedTestException : public mitk::Exception { public: mitkExceptionClassMacro(SpecializedTestException, mitk::Exception); }; class ExceptionTestClass : public itk::Object { public: mitkClassMacroItkParent(ExceptionTestClass, itk::Object); itkFactorylessNewMacro(Self) itkCloneMacro(Self) void throwExceptionManually() // this method is ONLY to test the constructor and no code example // normally exceptions should only be thrown by using the exception macro! { throw mitk::Exception("test.cpp", 155, "", ""); } void throwSpecializedExceptionManually() // this method is ONLY to test the constructor and no code example // normally exceptions should only be thrown by using the exception macro! { throw SpecializedTestException("test.cpp", 155, "", ""); } void throwExceptionManually(std::string message1, std::string message2) // this method is ONLY to test methods of mitk::Exception and no code example // normally exceptions should only be thrown by using the exception macro! { throw mitk::Exception("testfile.cpp", 155, message1.c_str(), "") << message2; } void throwExceptionWithThrowMacro() { mitkThrow() << "TEST EXCEPION THROWING WITH mitkThrow()"; } void throwExceptionWithThrowMacro(std::string message) { mitkThrow() << message.c_str(); } void throwSpecializedExceptionWithThrowMacro(std::string message) { mitkThrowException(mitk::Exception) << message; } void throwSpecializedExceptionWithThrowMacro2(std::string message) { mitkThrowException(SpecializedTestException) << message; } void reThrowExceptionWithReThrowMacro(std::string messageThrow, std::string messageReThrow) { try { throwExceptionWithThrowMacro(messageThrow); } catch (mitk::Exception &e) { mitkReThrow(e) << messageReThrow; } } static void TestExceptionConstructor() { bool exceptionThrown = false; ExceptionTestClass::Pointer myExceptionTestObject = ExceptionTestClass::New(); try { myExceptionTestObject->throwExceptionManually(); } - catch (mitk::Exception) + catch (const mitk::Exception &) { exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown, "Testing constructor of mitkException"); exceptionThrown = false; try { myExceptionTestObject->throwSpecializedExceptionManually(); } - catch (SpecializedTestException) + catch (const SpecializedTestException &) { exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown, "Testing constructor specialized exception (deriving from mitkException)"); } static void TestExceptionMessageStream() { //##### this method is ONLY to test the streaming operators of the exceptions and //##### NO code example. Please do not instantiate exceptions by yourself in normal code! //##### Normally exceptions should only be thrown by using the exception macro! mitk::Exception myException = mitk::Exception("testfile.cpp", 111, "testmessage"); myException << " and additional stream"; MITK_TEST_CONDITION_REQUIRED(myException.GetDescription() == std::string("testmessage and additional stream"), "Testing mitkException message stream (adding std::string)"); myException.SetDescription("testmessage2"); myException << ' ' << 'a' << 'n' << 'd' << ' ' << 'c' << 'h' << 'a' << 'r' << 's'; MITK_TEST_CONDITION_REQUIRED(myException.GetDescription() == std::string("testmessage2 and chars"), "Testing mitkException message stream (adding single chars)"); myException.SetDescription("testmessage3"); myException << myException; // adding the object itself makes no sense but should work MITK_TEST_CONDITION_REQUIRED(myException.GetDescription() != std::string(""), "Testing mitkException message stream (adding object)"); SpecializedTestException mySpecializedException = SpecializedTestException("testfile.cpp", 111, "testmessage", "test"); mySpecializedException << " and additional stream"; MITK_TEST_CONDITION_REQUIRED( mySpecializedException.GetDescription() == std::string("testmessage and additional stream"), "Testing specialized exception message stream (adding std::string)"); } static void TestExceptionMessageStreamThrowing() { bool exceptionThrown = false; ExceptionTestClass::Pointer myExceptionTestObject = ExceptionTestClass::New(); std::string thrownMessage = ""; try { myExceptionTestObject->throwExceptionManually("message1", " and message2"); } - catch (mitk::Exception &e) + catch (const mitk::Exception &e) { thrownMessage = e.GetDescription(); exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown && (thrownMessage == std::string("message1 and message2")), "Testing throwing and streaming of mitk::Exception together.") } static void TestMitkThrowMacro() { bool exceptionThrown = false; ExceptionTestClass::Pointer myExceptionTestObject = ExceptionTestClass::New(); // case 1: test throwing try { myExceptionTestObject->throwExceptionWithThrowMacro(); } - catch (mitk::Exception) + catch (const mitk::Exception &) { exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown, "Testing mitkThrow()"); // case 2: test message text exceptionThrown = false; std::string messageText = ""; try { myExceptionTestObject->throwExceptionWithThrowMacro("test123"); } - catch (mitk::Exception &e) + catch (const mitk::Exception &e) { exceptionThrown = true; messageText = e.GetDescription(); } MITK_TEST_CONDITION_REQUIRED((exceptionThrown && (messageText == "test123")), "Testing message test of mitkThrow()"); // case 3: specialized exception / command mitkThrow(mitk::Exception) exceptionThrown = false; messageText = ""; try { myExceptionTestObject->throwSpecializedExceptionWithThrowMacro("test123"); } - catch (mitk::Exception &e) + catch (const mitk::Exception &e) { exceptionThrown = true; messageText = e.GetDescription(); } MITK_TEST_CONDITION_REQUIRED(exceptionThrown && messageText == "test123", "Testing special exception with mitkThrow(mitk::Exception)"); // case 4: specialized exception / command mitkThrow(mitk::SpecializedException) exceptionThrown = false; messageText = ""; try { myExceptionTestObject->throwSpecializedExceptionWithThrowMacro2("test123"); } - catch (SpecializedTestException &e) + catch (const SpecializedTestException &e) { exceptionThrown = true; messageText = e.GetDescription(); } MITK_TEST_CONDITION_REQUIRED(exceptionThrown && messageText == "test123", "Testing special exception with mitkThrow(mitk::SpecializedException)"); } static void TestRethrowInformation() // this method is ONLY to test methods of mitk::Exception and no code example // normally exceptions should only be instantiated and thrown by using the exception macros! { // first: testing rethrow information methods, when no information is stored // case 1.1: method GetNumberOfRethrows() mitk::Exception e = mitk::Exception("test.cpp", 155, "", ""); MITK_TEST_CONDITION_REQUIRED(e.GetNumberOfRethrows() == 0, "Testing GetNumberOfRethrows() with empty rethrow information"); // case 1.2: GetRethrowData() with negative number { std::string file = "invalid"; int line = -1; std::string message = "invalid"; e.GetRethrowData(-1, file, line, message); MITK_TEST_CONDITION_REQUIRED(((file == "") && (line == 0) && (message == "")), "Testing GetRethrowData() with invalid rethrow number (negative)."); } // case 1.3: GetRethrowData() with number 0 { std::string file = "invalid"; int line = -1; std::string message = "invalid"; e.GetRethrowData(0, file, line, message); MITK_TEST_CONDITION_REQUIRED(((file == "") && (line == 0) && (message == "")), "Testing GetRethrowData() with non-existing rethrow number (0)."); } // case 1.4: GetRethrowData() with number 1 { std::string file = "invalid"; int line = -1; std::string message = "invalid"; e.GetRethrowData(1, file, line, message); MITK_TEST_CONDITION_REQUIRED(((file == "") && (line == 0) && (message == "")), "Testing GetRethrowData() with non-existing rethrow number (1)."); } // second: add rethrow data e.AddRethrowData("test2.cpp", 10, "Rethrow one"); MITK_TEST_CONDITION_REQUIRED(e.GetNumberOfRethrows() == 1, "Testing adding of rethrow data."); e.AddRethrowData("test3.cpp", 15, "Rethrow two"); MITK_TEST_CONDITION_REQUIRED(e.GetNumberOfRethrows() == 2, "Testing adding of more rethrow data."); // third: test if this rethrow data was stored properly { std::string file = "invalid"; int line = -1; std::string message = "invalid"; e.GetRethrowData(0, file, line, message); MITK_TEST_CONDITION_REQUIRED(((file == "test2.cpp") && (line == 10) && (message == "Rethrow one")), "Testing stored information of first rethrow."); } { std::string file = "invalid"; int line = -1; std::string message = "invalid"; e.GetRethrowData(1, file, line, message); MITK_TEST_CONDITION_REQUIRED(((file == "test3.cpp") && (line == 15) && (message == "Rethrow two")), "Testing stored information of second rethrow."); } } static void TestRethrowMacro() { bool exceptionThrown = false; std::string message = ""; ExceptionTestClass::Pointer myExceptionTestObject = ExceptionTestClass::New(); // case 1: test throwing try { myExceptionTestObject->reThrowExceptionWithReThrowMacro("Test original message.", "Test rethrow message."); } - catch (mitk::Exception &e) + catch (const mitk::Exception &e) { message = e.GetDescription(); exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown, "Testing mitkReThrow()"); MITK_TEST_CONDITION_REQUIRED(message == "Test original message.Test rethrow message.", "Testing message/descriprion after rethrow.") } }; int mitkExceptionTest(int /*argc*/, char * /*argv*/ []) { MITK_TEST_BEGIN("MITKException"); ExceptionTestClass::TestExceptionConstructor(); ExceptionTestClass::TestExceptionMessageStream(); ExceptionTestClass::TestExceptionMessageStreamThrowing(); ExceptionTestClass::TestMitkThrowMacro(); ExceptionTestClass::TestRethrowInformation(); ExceptionTestClass::TestRethrowMacro(); MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkImageSliceSelectorTest.cpp b/Modules/Core/test/mitkImageSliceSelectorTest.cpp index 37f9954b43..f0099ec45b 100644 --- a/Modules/Core/test/mitkImageSliceSelectorTest.cpp +++ b/Modules/Core/test/mitkImageSliceSelectorTest.cpp @@ -1,211 +1,211 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include int mitkImageSliceSelectorTest(int argc, char *argv[]) { int slice_nr = 1; std::cout << "Loading file: "; if (argc == 0) { std::cout << "no file specified [FAILED]" << std::endl; return EXIT_FAILURE; } mitk::Image::Pointer image; try { image = mitk::IOUtil::Load(argv[1]); } catch (const mitk::Exception &) { std::cout << "file not an image - test will not be applied [PASSED]" << std::endl; std::cout << "[TEST DONE]" << std::endl; return EXIT_SUCCESS; } catch (itk::ExceptionObject &ex) { std::cout << "Exception: " << ex << "[FAILED]" << std::endl; return EXIT_FAILURE; } if (image->GetDimension(2) < 2) slice_nr = 0; // Take a slice mitk::ImageSliceSelector::Pointer slice = mitk::ImageSliceSelector::New(); slice->SetInput(image); slice->SetSliceNr(slice_nr); slice->Update(); std::cout << "Testing IsInitialized(): "; if (slice->GetOutput()->IsInitialized() == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing IsSliceSet(): "; if (slice->GetOutput()->IsSliceSet(0) == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; /* deactivated because IpPic is not available any more (see bug 16662) if(itksys::SystemTools::LowerCase(itksys::SystemTools::GetFilenameExtension(argv[1])).find(".pic")!=std::string::npos) { std::cout << "Testing whether the slice is identical with a slice loaded by mitkIpPicGetSlice:"; mitkIpPicDescriptor *picslice = mitkIpPicGetSlice(argv[1], nullptr, (image->GetDimension(2)-1-slice_nr)+1); int i, size = _mitkIpPicSize(picslice); char * p1 = (char*)slice->GetPic()->data; char * p2 = (char*)picslice->data; //picslice->info->write_protect=mitkIpFalse; //mitkIpPicPut("C:\\1aaaaIPPIC.pic", picslice); //mitkIpPicPut("C:\\1aaaaSEL.pic", slice->GetPic()); for(i=0; iSetInput(image); //the output size of this filter is smaller than the of the input!! cyl2cart->SetTargetXSize( 64 ); //Use the same slice-selector again, this time to take a slice of the filtered image //which is smaller than the one of the old input!! slice->SetInput(cyl2cart->GetOutput()); slice->SetSliceNr(1); //The requested region is still the old one, //therefore the following results in most ITK versions //in an exception! slice->Update(); //If no exception occured, check that the requested region is now //the one of the smaller image if(cyl2cart->GetOutput()->GetLargestPossibleRegion().GetSize()[0]!=64) { std::cout<<"Part 1 [FAILED]"<GetOutput()->GetDimensions()[0]!=64) || (cyl2cart->GetOutput()->GetDimensions()[1]!=64)) { std::cout<<"Part 1b [FAILED]"<ResetPipeline(); } */ try { slice->UpdateLargestPossibleRegion(); } - catch (itk::ExceptionObject) + catch (const itk::ExceptionObject &) { std::cout << "Part 2 [FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "Part 2 [PASSED]" << std::endl; std::cout << "Testing IsInitialized(): "; if (slice->GetOutput()->IsInitialized() == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing IsSliceSet(): "; if (slice->GetOutput()->IsSliceSet(0) == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; if (image->GetDimension(3) > 1) { int time = image->GetDimension(3) - 1; std::cout << "Testing 3D+t: Setting time to " << time << ": "; slice->SetTimeNr(time); if (slice->GetTimeNr() != time) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing 3D+t: Updating slice: "; slice->Update(); if (slice->GetOutput()->IsInitialized() == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing 3D+t: IsSliceSet(): "; if (slice->GetOutput()->IsSliceSet(0) == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing 3D+t: First slice in reader available: "; if (image->IsSliceSet(0, time) == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; } std::cout << "[TEST DONE]" << std::endl; return EXIT_SUCCESS; } diff --git a/Modules/CppMicroServices/core/src/util/usThreads_p.h b/Modules/CppMicroServices/core/src/util/usThreads_p.h index 8de2cc3beb..7f87fc4fbe 100644 --- a/Modules/CppMicroServices/core/src/util/usThreads_p.h +++ b/Modules/CppMicroServices/core/src/util/usThreads_p.h @@ -1,329 +1,329 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USTHREADINGMODEL_H #define USTHREADINGMODEL_H #include #ifdef US_ENABLE_THREADING_SUPPORT // Atomic compiler intrinsics #if defined(US_PLATFORM_APPLE) // OSAtomic.h optimizations only used in 10.5 and later, deprecated in 10.12 #include #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 && MAC_OS_X_VERSION_MAX_ALLOWED < 101200 #include #define US_ATOMIC_OPTIMIZATION_APPLE #endif #elif defined(__GLIBCPP__) || defined(__GLIBCXX__) #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) # include #else # include #endif #define US_ATOMIC_OPTIMIZATION_GNUC #endif // Mutex support #ifdef US_PLATFORM_WINDOWS #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifndef NOMINMAX #define NOMINMAX #endif #include #define US_THREADS_MUTEX(x) HANDLE (x); #define US_THREADS_MUTEX_INIT(x) #define US_THREADS_MUTEX_CTOR(x) : x(::CreateMutex(nullptr, FALSE, nullptr)) #define US_THREADS_MUTEX_DELETE(x) ::CloseHandle (x) #define US_THREADS_MUTEX_LOCK(x) ::WaitForSingleObject (x, INFINITE) #define US_THREADS_MUTEX_UNLOCK(x) ::ReleaseMutex (x) #define US_THREADS_LONG LONG #define US_ATOMIC_OPTIMIZATION #define US_ATOMIC_INCREMENT(x) IntType n = InterlockedIncrement(x) #define US_ATOMIC_DECREMENT(x) IntType n = InterlockedDecrement(x) #define US_ATOMIC_ASSIGN(l, r) InterlockedExchange(l, r) #elif defined(US_PLATFORM_POSIX) #include - #define US_THREADS_MUTEX(x) pthread_mutex_t (x); + #define US_THREADS_MUTEX(x) pthread_mutex_t x; #define US_THREADS_MUTEX_INIT(x) ::pthread_mutex_init(&x, 0) #define US_THREADS_MUTEX_CTOR(x) : x() #define US_THREADS_MUTEX_DELETE(x) ::pthread_mutex_destroy (&x) #define US_THREADS_MUTEX_LOCK(x) ::pthread_mutex_lock (&x) #define US_THREADS_MUTEX_UNLOCK(x) ::pthread_mutex_unlock (&x) #define US_ATOMIC_OPTIMIZATION #if defined(US_ATOMIC_OPTIMIZATION_APPLE) #if defined (__LP64__) && __LP64__ #define US_THREADS_LONG volatile int64_t #define US_ATOMIC_INCREMENT(x) IntType n = OSAtomicIncrement64Barrier(x) #define US_ATOMIC_DECREMENT(x) IntType n = OSAtomicDecrement64Barrier(x) #define US_ATOMIC_ASSIGN(l, v) OSAtomicCompareAndSwap64Barrier(*l, v, l) #else #define US_THREADS_LONG volatile int32_t #define US_ATOMIC_INCREMENT(x) IntType n = OSAtomicIncrement32Barrier(x) #define US_ATOMIC_DECREMENT(x) IntType n = OSAtomicDecrement32Barrier(x) #define US_ATOMIC_ASSIGN(l, v) OSAtomicCompareAndSwap32Barrier(*l, v, l) #endif #elif defined(US_ATOMIC_OPTIMIZATION_GNUC) #define US_THREADS_LONG _Atomic_word #define US_ATOMIC_INCREMENT(x) IntType n = __sync_add_and_fetch(x, 1) #define US_ATOMIC_DECREMENT(x) IntType n = __sync_add_and_fetch(x, -1) #define US_ATOMIC_ASSIGN(l, v) __sync_val_compare_and_swap(l, *l, v) #else #define US_THREADS_LONG long #undef US_ATOMIC_OPTIMIZATION #define US_ATOMIC_INCREMENT(x) m_AtomicMtx.Lock(); \ IntType n = ++(*x); \ m_AtomicMtx.Unlock() #define US_ATOMIC_DECREMENT(x) m_AtomicMtx.Lock(); \ IntType n = --(*x); \ m_AtomicMtx.Unlock() #define US_ATOMIC_ASSIGN(l, v) m_AtomicMtx.Lock(); \ *l = v; \ m_AtomicMtx.Unlock() #endif #endif #else // single threaded #define US_THREADS_MUTEX(x) #define US_THREADS_MUTEX_INIT(x) #define US_THREADS_MUTEX_CTOR(x) #define US_THREADS_MUTEX_DELETE(x) #define US_THREADS_MUTEX_LOCK(x) #define US_THREADS_MUTEX_UNLOCK(x) #define US_THREADS_LONG int #define US_ATOMIC_INCREMENT(x) IntType n = ++(*x); #define US_ATOMIC_DECREMENT(x) IntType n = --(*x); #define US_ATOMIC_ASSIGN(l, r) *l = r; #endif US_BEGIN_NAMESPACE class Mutex { public: Mutex() US_THREADS_MUTEX_CTOR(m_Mtx) { US_THREADS_MUTEX_INIT(m_Mtx); } ~Mutex() { US_THREADS_MUTEX_DELETE(m_Mtx); } void Lock() { US_THREADS_MUTEX_LOCK(m_Mtx); } void Unlock() { US_THREADS_MUTEX_UNLOCK(m_Mtx); } private: template friend class WaitCondition; // Copy-constructor not implemented. Mutex(const Mutex &); // Copy-assignement operator not implemented. Mutex & operator = (const Mutex &); US_THREADS_MUTEX(m_Mtx) }; class MutexLock { public: typedef Mutex MutexType; MutexLock(MutexType& mtx) : m_Mtx(&mtx) { m_Mtx->Lock(); } ~MutexLock() { m_Mtx->Unlock(); } private: MutexType* m_Mtx; // purposely not implemented MutexLock(const MutexLock&); MutexLock& operator=(const MutexLock&); }; class AtomicCounter { public: typedef US_THREADS_LONG IntType; AtomicCounter(int value = 0) : m_Counter(value) {} IntType AtomicIncrement() const { US_ATOMIC_INCREMENT(&m_Counter); return n; } IntType AtomicIncrement(volatile IntType& lval) const { US_ATOMIC_INCREMENT(&lval); return n; } IntType AtomicDecrement() const { US_ATOMIC_DECREMENT(&m_Counter); return n; } IntType AtomicDecrement(volatile IntType& lval) const { US_ATOMIC_DECREMENT(&lval); return n; } void AtomicAssign(volatile IntType& lval) const { US_ATOMIC_ASSIGN(&lval, m_Counter); } void AtomicAssign(volatile IntType& lval, const IntType val) const { US_ATOMIC_ASSIGN(&lval, val); } mutable IntType m_Counter; private: #if !defined(US_ATOMIC_OPTIMIZATION) mutable Mutex m_AtomicMtx; #endif }; class MutexLockingStrategy { public: MutexLockingStrategy() #ifdef US_ENABLE_THREADING_SUPPORT : m_Mtx() #endif {} MutexLockingStrategy(const MutexLockingStrategy&) #ifdef US_ENABLE_THREADING_SUPPORT : m_Mtx() #endif {} class Lock; friend class Lock; class Lock { public: #ifdef US_ENABLE_THREADING_SUPPORT // Lock object explicit Lock(const MutexLockingStrategy& host) : m_Host(host) { m_Host.m_Mtx.Lock(); } // Lock object explicit Lock(const MutexLockingStrategy* host) : m_Host(*host) { m_Host.m_Mtx.Lock(); } // Unlock object ~Lock() { m_Host.m_Mtx.Unlock(); } #else explicit Lock(const MutexLockingStrategy&) {} explicit Lock(const MutexLockingStrategy*) {} #endif private: // private by design Lock(); Lock(const Lock&); Lock& operator=(const Lock&); #ifdef US_ENABLE_THREADING_SUPPORT const MutexLockingStrategy& m_Host; #endif }; protected: #ifdef US_ENABLE_THREADING_SUPPORT mutable Mutex m_Mtx; #endif }; class NoLockingStrategy { }; US_END_NAMESPACE #include US_BEGIN_NAMESPACE template class WaitConditionStrategy = NoWaitCondition > class MultiThreaded : public LockingStrategy, public WaitConditionStrategy > { friend class WaitConditionStrategy >; }; US_END_NAMESPACE #endif // USTHREADINGMODEL_H diff --git a/Modules/CppMicroServices/core/test/usModuleTest.cpp b/Modules/CppMicroServices/core/test/usModuleTest.cpp index 583cd175d6..1eab5159c3 100644 --- a/Modules/CppMicroServices/core/test/usModuleTest.cpp +++ b/Modules/CppMicroServices/core/test/usModuleTest.cpp @@ -1,350 +1,350 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include #include #include #include #include "usTestUtilModuleListener.h" #include "usTestDriverActivator.h" #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; static const char PATH_SEPARATOR = '\\'; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; static const char PATH_SEPARATOR = '/'; #endif // Check that the executable's activator was loaded and called void frame01() { US_TEST_CONDITION_REQUIRED(TestDriverActivator::LoadCalled(), "ModuleActivator::Load() called for executable") } // Verify that the same member function pointers registered as listeners // with different receivers works. void frame02a() { ModuleContext* mc = GetModuleContext(); TestModuleListener listener1; TestModuleListener listener2; try { mc->RemoveModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->AddModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->RemoveModuleListener(&listener2, &TestModuleListener::ModuleChanged); mc->AddModuleListener(&listener2, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_FAILED_MSG( << "module listener registration failed " << ise.what() << " : frameSL02a:FAIL" ); } SharedLibrary target(LIB_PATH, "TestModuleA"); #ifdef US_BUILD_SHARED_LIBS // Start the test target try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in frameSL02a:FAIL" ); } #endif Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != nullptr, "Test for existing module TestModuleA") std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleA)); #endif std::vector seEvts; US_TEST_CONDITION(listener1.CheckListenerEvents(pEvts, seEvts), "Check first module listener") US_TEST_CONDITION(listener2.CheckListenerEvents(pEvts, seEvts), "Check second module listener") mc->RemoveModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->RemoveModuleListener(&listener2, &TestModuleListener::ModuleChanged); target.Unload(); } // Verify information from the ModuleInfo struct void frame005a(ModuleContext* mc) { Module* m = mc->GetModule(); // check expected headers US_TEST_CONDITION("main" == m->GetName(), "Test module name") US_TEST_CONDITION(ModuleVersion(0,1,0) == m->GetVersion(), "Test test driver module version") US_TEST_CONDITION(ModuleVersion(CppMicroServices_MAJOR_VERSION, CppMicroServices_MINOR_VERSION, CppMicroServices_PATCH_VERSION) == ModuleRegistry::GetModule(1)->GetVersion(), "Test CppMicroServices version") } // Get context id, location and status of the module void frame010a(ModuleContext* mc) { Module* m = mc->GetModule(); long int contextid = m->GetModuleId(); US_DEBUG << "CONTEXT ID:" << contextid; std::string location = m->GetLocation(); US_DEBUG << "LOCATION:" << location; US_TEST_CONDITION(!location.empty(), "Test for non-empty module location") US_TEST_CONDITION(m->IsLoaded(), "Test for loaded flag") US_TEST_CONDITION(ModuleSettings::GetStoragePath().empty(), "Test for empty base storage path") US_TEST_CONDITION(m->GetModuleContext()->GetDataFile("").empty(), "Test for empty data path") US_TEST_CONDITION(m->GetModuleContext()->GetDataFile("bla").empty(), "Test for empty data file path") } //---------------------------------------------------------------------------- //Test result of GetService(ServiceReference()). Should throw std::invalid_argument void frame018a(ModuleContext* mc) { try { mc->GetService(ServiceReferenceU()); US_DEBUG << "Got service object, expected std::invalid_argument exception"; US_TEST_FAILED_MSG(<< "Got service object, excpected std::invalid_argument exception") } catch (const std::invalid_argument& ) {} catch (...) { US_TEST_FAILED_MSG(<< "Got wrong exception, expected std::invalid_argument") } } // Load libA and check that it exists and that the service it registers exists, // also check that the expected events occur and that the storage paths are correct void frame020a(ModuleContext* mc, TestModuleListener& listener, #ifdef US_BUILD_SHARED_LIBS SharedLibrary& libA) { try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } #else SharedLibrary& /*libA*/) { #endif ModuleSettings::SetStoragePath(std::string("/tmp") + PATH_SEPARATOR); US_TEST_CONDITION(ModuleSettings::GetStoragePath() == "/tmp", "Test for valid base storage path") Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != nullptr, "Test for existing module TestModuleA") US_TEST_CONDITION(moduleA->GetName() == "TestModuleA", "Test module name") std::cout << moduleA->GetModuleContext()->GetDataFile("") << std::endl; std::stringstream ss; ss << moduleA->GetModuleId(); const std::string baseStoragePath = std::string("/tmp") + PATH_SEPARATOR + ss.str() + "_TestModuleA" + PATH_SEPARATOR; US_TEST_CONDITION(moduleA->GetModuleContext()->GetDataFile("") == baseStoragePath, "Test for valid data path") US_TEST_CONDITION(moduleA->GetModuleContext()->GetDataFile("bla") == baseStoragePath + "bla", "Test for valid data file path") // Check if libA registered the expected service try { ServiceReferenceU sr1 = mc->GetServiceReference("us::TestModuleAService"); InterfaceMap o1 = mc->GetService(sr1); US_TEST_CONDITION(!o1.empty(), "Test if service object found"); try { US_TEST_CONDITION(mc->UngetService(sr1), "Test if Service UnGet returns true"); } - catch (const std::logic_error le) + catch (const std::logic_error& le) { US_TEST_FAILED_MSG(<< "UnGetService exception: " << le.what()) } // check the listeners for events std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleA)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, sr1)); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } catch (const ServiceException& /*se*/) { US_TEST_FAILED_MSG(<< "test module, expected service not found"); } US_TEST_CONDITION(moduleA->IsLoaded() == true, "Test if loaded correctly"); } // Unload libA and check for correct events void frame030b(ModuleContext* mc, TestModuleListener& listener, SharedLibrary& libA) { Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != nullptr, "Test for non-null module") ServiceReferenceU sr1 = mc->GetServiceReference("us::TestModuleAService"); US_TEST_CONDITION(sr1, "Test for valid service reference") try { libA.Unload(); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleA->IsLoaded() == false, "Test for unloaded state") #endif } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "UnLoad module exception: " << e.what()) } std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleA)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, sr1)); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } struct LocalListener { void ServiceChanged(const ServiceEvent) {} }; // Add a service listener with a broken LDAP filter to Get an exception void frame045a(ModuleContext* mc) { LocalListener sListen1; std::string brokenFilter = "A broken LDAP filter"; try { mc->AddServiceListener(&sListen1, &LocalListener::ServiceChanged, brokenFilter); } catch (const std::invalid_argument& /*ia*/) { //assertEquals("InvalidSyntaxException.GetFilter should be same as input string", brokenFilter, ise.GetFilter()); } catch (...) { US_TEST_FAILED_MSG(<< "test module, wrong exception on broken LDAP filter:"); } } } // end unnamed namespace int usModuleTest(int /*argc*/, char* /*argv*/[]) { //US_TEST_BEGIN("ModuleTest"); std::vector modules = ModuleRegistry::GetModules(); for (std::vector::iterator iter = modules.begin(), iterEnd = modules.end(); iter != iterEnd; ++iter) { std::cout << "----- " << (*iter)->GetName() << std::endl; } frame01(); frame02a(); ModuleContext* mc = GetModuleContext(); TestModuleListener listener; try { mc->AddModuleListener(&listener, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); throw; } try { mc->AddServiceListener(&listener, &TestModuleListener::ServiceChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); throw; } frame005a(mc); frame010a(mc); frame018a(mc); SharedLibrary libA(LIB_PATH, "TestModuleA"); frame020a(mc, listener, libA); frame030b(mc, listener, libA); frame045a(mc); mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); mc->RemoveServiceListener(&listener, &TestModuleListener::ServiceChanged); //US_TEST_END() return 0; } diff --git a/Modules/CppMicroServices/core/test/usStaticModuleTest.cpp b/Modules/CppMicroServices/core/test/usStaticModuleTest.cpp index 049606c4b9..8b6994f189 100644 --- a/Modules/CppMicroServices/core/test/usStaticModuleTest.cpp +++ b/Modules/CppMicroServices/core/test/usStaticModuleTest.cpp @@ -1,183 +1,183 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include #include #include #include "usTestUtilModuleListener.h" #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif // Load libTestModuleB and check that it exists and that the service it registers exists, // also check that the expected events occur void frame020a(ModuleContext* mc, TestModuleListener& listener, #ifdef US_BUILD_SHARED_LIBS SharedLibrary& libB) { try { libB.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } #else SharedLibrary& /*libB*/) { #endif Module* moduleB = ModuleRegistry::GetModule("TestModuleB"); US_TEST_CONDITION_REQUIRED(moduleB != nullptr, "Test for existing module TestModuleB") Module* moduleImportedByB = ModuleRegistry::GetModule("TestModuleImportedByB"); US_TEST_CONDITION_REQUIRED(moduleImportedByB != nullptr, "Test for existing module TestModuleImportedByB") US_TEST_CONDITION(moduleB->GetName() == "TestModuleB", "Test module name") // Check if libB registered the expected service try { std::vector refs = mc->GetServiceReferences("us::TestModuleBService"); US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Test that both the service from the shared and imported library are regsitered"); InterfaceMap o1 = mc->GetService(refs.front()); US_TEST_CONDITION(!o1.empty(), "Test if first service object found"); InterfaceMap o2 = mc->GetService(refs.back()); US_TEST_CONDITION(!o2.empty(), "Test if second service object found"); try { US_TEST_CONDITION(mc->UngetService(refs.front()), "Test if Service UnGet for first service returns true"); US_TEST_CONDITION(mc->UngetService(refs.back()), "Test if Service UnGet for second service returns true"); } - catch (const std::logic_error le) + catch (const std::logic_error &le) { US_TEST_FAILED_MSG(<< "UnGetService exception: " << le.what()) } // check the listeners for events std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleB)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleB)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleImportedByB)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleImportedByB)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, refs.back())); seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, refs.front())); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } catch (const ServiceException& /*se*/) { US_TEST_FAILED_MSG(<< "test module, expected service not found"); } #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleB->IsLoaded() == true, "Test if loaded correctly"); #endif } // Unload libB and check for correct events void frame030b(ModuleContext* mc, TestModuleListener& listener, SharedLibrary& libB) { Module* moduleB = ModuleRegistry::GetModule("TestModuleB"); US_TEST_CONDITION_REQUIRED(moduleB != nullptr, "Test for non-null module") Module* moduleImportedByB = ModuleRegistry::GetModule("TestModuleImportedByB"); US_TEST_CONDITION_REQUIRED(moduleImportedByB != nullptr, "Test for non-null module") std::vector refs = mc->GetServiceReferences("us::TestModuleBService"); US_TEST_CONDITION(refs.front(), "Test for first valid service reference") US_TEST_CONDITION(refs.back(), "Test for second valid service reference") try { libB.Unload(); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleB->IsLoaded() == false, "Test for unloaded state") #endif } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "UnLoad module exception: " << e.what()) } std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleImportedByB)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleImportedByB)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleB)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleB)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, refs.front())); seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, refs.back())); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } } // end unnamed namespace int usStaticModuleTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("StaticModuleTest"); ModuleContext* mc = GetModuleContext(); TestModuleListener listener; ModuleListenerRegistrationHelper ml(mc, &listener, &TestModuleListener::ModuleChanged); ServiceListenerRegistrationHelper sl(mc, &listener, &TestModuleListener::ServiceChanged); SharedLibrary libB(LIB_PATH, "TestModuleB"); frame020a(mc, listener, libB); frame030b(mc, listener, libB); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usTestingMacros.h b/Modules/CppMicroServices/core/test/usTestingMacros.h index b7a2b2d04b..b8ce72e9a1 100644 --- a/Modules/CppMicroServices/core/test/usTestingMacros.h +++ b/Modules/CppMicroServices/core/test/usTestingMacros.h @@ -1,138 +1,138 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USTESTINGMACROS_H_ #define USTESTINGMACROS_H_ #include #include #include #include #include "usTestManager.h" US_BEGIN_NAMESPACE /** \brief Indicate a failed test. */ class TestFailedException : public std::exception { public: TestFailedException() {} }; US_END_NAMESPACE /** * * \brief Output some text without generating a terminating newline. * * */ #define US_TEST_OUTPUT_NO_ENDL(x) \ std::cout x << std::flush; /** \brief Output some text. */ #define US_TEST_OUTPUT(x) \ US_TEST_OUTPUT_NO_ENDL(x << "\n") /** \brief Do some general test preparations. Must be called first in the main test function. */ #define US_TEST_BEGIN(testName) \ std::string usTestName(#testName); \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().Initialize(); \ try { /** \brief Fail and finish test with message MSG */ #define US_TEST_FAILED_MSG(MSG) \ US_TEST_OUTPUT(MSG) \ throw US_PREPEND_NAMESPACE(TestFailedException)(); /** \brief Must be called last in the main test function. */ #define US_TEST_END() \ } catch (const US_PREPEND_NAMESPACE(TestFailedException)&) { \ US_TEST_OUTPUT(<< "Further test execution skipped.") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ } catch (const std::exception& ex) { \ US_TEST_OUTPUT(<< "Exception occured " << ex.what()) \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ } \ if (US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfFailedTests() > 0) { \ US_TEST_OUTPUT(<< usTestName << ": [DONE FAILED] , subtests passed: " << \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfPassedTests() << " failed: " << \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfFailedTests() ) \ return EXIT_FAILURE; \ } else { \ US_TEST_OUTPUT(<< usTestName << ": " \ << US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfPassedTests() \ << " tests [DONE PASSED]") \ return EXIT_SUCCESS; \ } #define US_TEST_CONDITION(COND,MSG) \ US_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ US_TEST_OUTPUT(<< " [FAILED]\n" << "In " << __FILE__ \ << ", line " << __LINE__ \ << ": " #COND " : [FAILED]") \ } else { \ US_TEST_OUTPUT(<< " [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } #define US_TEST_CONDITION_REQUIRED(COND,MSG) \ US_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ US_TEST_FAILED_MSG(<< " [FAILED]\n" << " +--> in " << __FILE__ \ << ", line " << __LINE__ \ << ", expression is false: \"" #COND "\"") \ } else { \ US_TEST_OUTPUT(<< " [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } /** * \brief Begin block which should be checked for exceptions * * This macro, together with US_TEST_FOR_EXCEPTION_END, can be used * to test whether a code block throws an expected exception. The test FAILS if the * exception is NOT thrown. */ #define US_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ try { #define US_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ US_TEST_OUTPUT( << "Expected an '" << #EXCEPTIONCLASS << "' exception. [FAILED]") \ } \ - catch (EXCEPTIONCLASS) { \ + catch (const EXCEPTIONCLASS &) { \ US_TEST_OUTPUT(<< "Caught an expected '" << #EXCEPTIONCLASS \ << "' exception. [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } /** * \brief Simplified version of US_TEST_FOR_EXCEPTION_BEGIN / END for * a single statement */ #define US_TEST_FOR_EXCEPTION(EXCEPTIONCLASS, STATEMENT) \ US_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ STATEMENT ; \ US_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) #endif // USTESTINGMACROS_H_ diff --git a/Modules/IGT/IO/mitkNavigationToolReader.cpp b/Modules/IGT/IO/mitkNavigationToolReader.cpp index 4587e31948..09d061ea50 100644 --- a/Modules/IGT/IO/mitkNavigationToolReader.cpp +++ b/Modules/IGT/IO/mitkNavigationToolReader.cpp @@ -1,282 +1,277 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //Poco headers #include #include //mitk headers #include "mitkNavigationToolReader.h" #include "mitkTrackingTypes.h" #include #include //All Tracking devices, which should be available by default #include "mitkNDIAuroraTypeInformation.h" #include "mitkNDIPolarisTypeInformation.h" #include "mitkVirtualTrackerTypeInformation.h" #include "mitkMicronTrackerTypeInformation.h" #include "mitkNPOptitrackTrackingTypeInformation.h" #include "mitkOpenIGTLinkTypeInformation.h" #include "mitkUnspecifiedTrackingTypeInformation.h" mitk::NavigationToolReader::NavigationToolReader() { m_ToolfilePath = mitk::IOUtil::GetTempPath() + Poco::Path::separator() + "IGT_Toolfiles" + Poco::Path::separator(); } mitk::NavigationToolReader::~NavigationToolReader() { } mitk::NavigationTool::Pointer mitk::NavigationToolReader::DoRead(std::string filename) { //decompress all files into a temporary directory std::ifstream file(filename.c_str(), std::ios::binary); if (!file.good()) { m_ErrorMessage = "Cannot open '" + filename + "' for reading"; return nullptr; } std::string tempDirectory = m_ToolfilePath + GetFileWithoutPath(filename); Poco::Zip::Decompress unzipper(file, Poco::Path(tempDirectory)); unzipper.decompressAllFiles(); //use SceneSerialization to load the DataStorage mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); mitk::DataStorage::Pointer loadedStorage = mySceneIO->LoadScene(tempDirectory + Poco::Path::separator() + GetFileWithoutPath(filename) + ".storage"); if (loadedStorage->GetAll()->size() == 0 || loadedStorage.IsNull()) { m_ErrorMessage = "Invalid file: cannot parse tool data."; return nullptr; } //convert the DataStorage back to a NavigationTool-Object mitk::DataNode::Pointer myNode = loadedStorage->GetAll()->ElementAt(0); mitk::NavigationTool::Pointer returnValue = ConvertDataNodeToNavigationTool(myNode, tempDirectory); //delete the data-storage file which is not needed any more. The toolfile must be left in the temporary directory becauses it is linked in the datatreenode of the tool std::remove((std::string(tempDirectory + Poco::Path::separator() + GetFileWithoutPath(filename) + ".storage")).c_str()); return returnValue; } mitk::NavigationTool::Pointer mitk::NavigationToolReader::ConvertDataNodeToNavigationTool(mitk::DataNode::Pointer node, std::string toolPath) { mitk::NavigationTool::Pointer returnValue = mitk::NavigationTool::New(); //DateTreeNode with Name and Surface returnValue->SetDataNode(node); //Identifier std::string identifier; node->GetStringProperty("identifier", identifier); returnValue->SetIdentifier(identifier); node->RemoveProperty("identifier"); //Serial Number std::string serial; node->GetStringProperty("serial number", serial); returnValue->SetSerialNumber(serial); node->RemoveProperty("serial number"); //Tracking Device mitk::TrackingDeviceType device_type; node->GetStringProperty("tracking device type", device_type); //For backward compability with old tool stroages (before 12/2015 device_type was an int value, now it is string) if (device_type.size() == 0) { /* This was the old enum. Numbers inserted for better readibility. Don't delete this if-case to allow loading of ols storages... enum TrackingDeviceType { 0 NDIPolaris, ///< Polaris: optical Tracker from NDI 1 NDIAurora, ///< Aurora: electromagnetic Tracker from NDI 2 ClaronMicron, ///< Micron Tracker: optical Tracker from Claron 3 IntuitiveDaVinci, ///< Intuitive Surgical: DaVinci Telemanipulator API Interface 4 AscensionMicroBird, ///< Ascension microBird / PCIBird family 5 VirtualTracker, ///< Virtual Tracking device class that produces random tracking coordinates 6 TrackingSystemNotSpecified, ///< entry for not specified or initialized tracking system 7 TrackingSystemInvalid, ///< entry for invalid state (mainly for testing) 8 NPOptitrack, ///< NaturalPoint: Optitrack optical Tracking System 9 OpenIGTLinkTrackingDeviceConnection ///< Device which is connected via open igt link }; */ int device_type_old; node->GetIntProperty("tracking device type", device_type_old); switch (device_type_old) { case 0:device_type = mitk::NDIPolarisTypeInformation::GetTrackingDeviceName(); break; case 1:device_type = mitk::NDIAuroraTypeInformation::GetTrackingDeviceName(); break; case 2:device_type = mitk::MicronTrackerTypeInformation::GetTrackingDeviceName(); break; case 3:device_type = "IntuitiveDaVinci"; break; case 4:device_type = "AscensionMicroBird"; break; case 5:device_type = mitk::VirtualTrackerTypeInformation::GetTrackingDeviceName(); break; case 6:device_type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); break; case 7:device_type = "TrackingSystemInvalid"; break; case 8:device_type = mitk::NPOptitrackTrackingTypeInformation::GetTrackingDeviceName(); break; case 9:device_type = mitk::OpenIGTLinkTypeInformation::GetTrackingDeviceName(); break; default: device_type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); break; //default... unknown... } } node->RemoveProperty("tracking device type"); returnValue->SetTrackingDeviceType(static_cast(device_type)); //Tool Type int type; node->GetIntProperty("tracking tool type", type); returnValue->SetType(static_cast(type)); node->RemoveProperty("tracking tool type"); //Calibration File Name std::string calibration_filename; node->GetStringProperty("toolfileName", calibration_filename); if (calibration_filename == "none") { returnValue->SetCalibrationFile("none"); } else { std::string calibration_filename_with_path = toolPath + Poco::Path::separator() + calibration_filename; returnValue->SetCalibrationFile(calibration_filename_with_path); } node->RemoveProperty("toolfileName"); //Tool Landmarks mitk::PointSet::Pointer ToolRegLandmarks = mitk::PointSet::New(); mitk::PointSet::Pointer ToolCalLandmarks = mitk::PointSet::New(); std::string RegLandmarksString; std::string CalLandmarksString; node->GetStringProperty("ToolRegistrationLandmarks", RegLandmarksString); node->GetStringProperty("ToolCalibrationLandmarks", CalLandmarksString); ToolRegLandmarks = ConvertStringToPointSet(RegLandmarksString); ToolCalLandmarks = ConvertStringToPointSet(CalLandmarksString); returnValue->SetToolLandmarks(ToolRegLandmarks); returnValue->SetToolControlPoints(ToolCalLandmarks); node->RemoveProperty("ToolRegistrationLandmarks"); node->RemoveProperty("ToolCalibrationLandmarks"); //Tool Tip std::string toolTipPositionString; std::string toolTipOrientationString; bool positionSet = node->GetStringProperty("ToolTipPosition", toolTipPositionString); bool orientationSet = node->GetStringProperty("ToolAxisOrientation", toolTipOrientationString); if (positionSet && orientationSet) //only define tooltip if it is set { returnValue->SetToolTipPosition(ConvertStringToPoint(toolTipPositionString)); returnValue->SetToolAxisOrientation(ConvertStringToQuaternion(toolTipOrientationString)); } else if (positionSet != orientationSet) { MITK_WARN << "Tooltip definition incomplete: position and orientation have to be set! Skipping tooltip definition."; } node->RemoveProperty("ToolTipPosition"); node->RemoveProperty("ToolAxisOrientation"); - //Tool Axis - std::string ToolAxisString; - node->GetStringProperty("ToolAxis", ToolAxisString); - returnValue->SetToolAxis(ConvertStringToPoint(ToolAxisString)); - return returnValue; } std::string mitk::NavigationToolReader::GetFileWithoutPath(std::string FileWithPath) { Poco::Path myFile(FileWithPath.c_str()); return myFile.getFileName(); } mitk::PointSet::Pointer mitk::NavigationToolReader::ConvertStringToPointSet(std::string string) { mitk::PointSet::Pointer returnValue = mitk::PointSet::New(); std::string pointSeperator = "|"; std::string valueSeperator = ";"; std::vector points; split(string, pointSeperator, points); for (unsigned int i = 0; i < points.size(); i++) { std::vector values; split(points.at(i), valueSeperator, values); if (values.size() == 4) { double index = atof(values.at(0).c_str()); mitk::Point3D point; point[0] = atof(values.at(1).c_str()); point[1] = atof(values.at(2).c_str()); point[2] = atof(values.at(3).c_str()); returnValue->SetPoint(index, point); } } return returnValue; } mitk::Point3D mitk::NavigationToolReader::ConvertStringToPoint(std::string string) { std::string valueSeperator = ";"; std::vector values; split(string, valueSeperator, values); mitk::Point3D point; if (values.size() == 3) { point[0] = atof(values.at(0).c_str()); point[1] = atof(values.at(1).c_str()); point[2] = atof(values.at(2).c_str()); } return point; } mitk::Quaternion mitk::NavigationToolReader::ConvertStringToQuaternion(std::string string) { std::string valueSeperator = ";"; std::vector values; split(string, valueSeperator, values); mitk::Quaternion quat = mitk::Quaternion(0, 0, 0, 1); if (values.size() == 4) { quat = mitk::Quaternion(atof(values.at(0).c_str()), atof(values.at(1).c_str()), atof(values.at(2).c_str()), atof(values.at(3).c_str())); } return quat; } void mitk::NavigationToolReader::split(std::string& text, std::string& separators, std::vector& words) { int n = text.length(); int start, stop; start = text.find_first_not_of(separators); while ((start >= 0) && (start < n)) { stop = text.find_first_of(separators, start); if ((stop < 0) || (stop > n)) stop = n; words.push_back(text.substr(start, stop - start)); start = text.find_first_not_of(separators, stop + 1); } } diff --git a/Modules/IGT/IO/mitkNavigationToolWriter.cpp b/Modules/IGT/IO/mitkNavigationToolWriter.cpp index d4ffeb0134..9e8b1ad615 100644 --- a/Modules/IGT/IO/mitkNavigationToolWriter.cpp +++ b/Modules/IGT/IO/mitkNavigationToolWriter.cpp @@ -1,173 +1,169 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //Poco headers #include #include //mitk headers #include "mitkNavigationToolWriter.h" #include #include #include #include #include //std headers #include mitk::NavigationToolWriter::NavigationToolWriter() { } mitk::NavigationToolWriter::~NavigationToolWriter() { } bool mitk::NavigationToolWriter::DoWrite(std::string FileName,mitk::NavigationTool::Pointer Tool) { //some initial validation checks... if ( Tool.IsNull()) { m_ErrorMessage = "Cannot write a navigation tool containing invalid tool data, aborting!"; MITK_ERROR << m_ErrorMessage; return false; } // Workaround for a problem: the geometry might be modified if the tool is tracked. If this // modified geometry is saved the surface representation is moved by this offset. To avoid // this bug, the geometry is set to identity for the saving progress and restored later. mitk::BaseGeometry::Pointer geometryBackup; if ( Tool->GetDataNode().IsNotNull() && (Tool->GetDataNode()->GetData()!=nullptr) && (Tool->GetDataNode()->GetData()->GetGeometry()!=nullptr) ) { geometryBackup = Tool->GetDataNode()->GetData()->GetGeometry()->Clone(); Tool->GetDataNode()->GetData()->GetGeometry()->SetIdentity(); } else {MITK_WARN << "Saving a tool with invalid data node, proceeding but errors might occure!";} //convert whole data to a mitk::DataStorage mitk::StandaloneDataStorage::Pointer saveStorage = mitk::StandaloneDataStorage::New(); mitk::DataNode::Pointer thisTool = ConvertToDataNode(Tool); saveStorage->Add(thisTool); //use SceneSerialization to save the DataStorage std::string DataStorageFileName = mitk::IOUtil::CreateTemporaryDirectory() + Poco::Path::separator() + GetFileWithoutPath(FileName) + ".storage"; mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); mySceneIO->SaveScene(saveStorage->GetAll(),saveStorage,DataStorageFileName); //now put the DataStorage and the Toolfile in a ZIP-file std::ofstream file( FileName.c_str(), std::ios::binary | std::ios::out); if (!file.good()) { m_ErrorMessage = "Could not open a zip file for writing: '" + FileName + "'"; MITK_ERROR << m_ErrorMessage; return false; } else { Poco::Zip::Compress zipper( file, true ); zipper.addFile(DataStorageFileName,GetFileWithoutPath(DataStorageFileName)); if (Tool->GetCalibrationFile()!="none") zipper.addFile(Tool->GetCalibrationFile(),GetFileWithoutPath(Tool->GetCalibrationFile())); zipper.close(); } //delete the data storage std::remove(DataStorageFileName.c_str()); //restore original geometry if (geometryBackup.IsNotNull()) {Tool->GetDataNode()->GetData()->SetGeometry(geometryBackup);} return true; } mitk::DataNode::Pointer mitk::NavigationToolWriter::ConvertToDataNode(mitk::NavigationTool::Pointer Tool) { mitk::DataNode::Pointer thisTool = Tool->GetDataNode(); //Name if (Tool->GetDataNode().IsNull()) { thisTool = mitk::DataNode::New(); thisTool->SetName("none"); } //Identifier - thisTool->AddProperty("identifier",mitk::StringProperty::New(Tool->GetIdentifier().c_str())); + thisTool->AddProperty("identifier",mitk::StringProperty::New(Tool->GetIdentifier().c_str()), NULL, true); //Serial Number - thisTool->AddProperty("serial number",mitk::StringProperty::New(Tool->GetSerialNumber().c_str())); + thisTool->AddProperty("serial number",mitk::StringProperty::New(Tool->GetSerialNumber().c_str()), NULL, true); //Tracking Device - thisTool->AddProperty("tracking device type",mitk::StringProperty::New(Tool->GetTrackingDeviceType())); + thisTool->AddProperty("tracking device type",mitk::StringProperty::New(Tool->GetTrackingDeviceType()), NULL, true); //Tool Type - thisTool->AddProperty("tracking tool type",mitk::IntProperty::New(Tool->GetType())); + thisTool->AddProperty("tracking tool type",mitk::IntProperty::New(Tool->GetType()), NULL, true); //Calibration File Name - thisTool->AddProperty("toolfileName",mitk::StringProperty::New(GetFileWithoutPath(Tool->GetCalibrationFile()))); + thisTool->AddProperty("toolfileName",mitk::StringProperty::New(GetFileWithoutPath(Tool->GetCalibrationFile())), NULL, true); //Tool Landmarks - thisTool->AddProperty("ToolRegistrationLandmarks",mitk::StringProperty::New(ConvertPointSetToString(Tool->GetToolLandmarks()))); - thisTool->AddProperty("ToolCalibrationLandmarks",mitk::StringProperty::New(ConvertPointSetToString(Tool->GetToolControlPoints()))); + thisTool->AddProperty("ToolRegistrationLandmarks",mitk::StringProperty::New(ConvertPointSetToString(Tool->GetToolLandmarks())), NULL, true); + thisTool->AddProperty("ToolCalibrationLandmarks",mitk::StringProperty::New(ConvertPointSetToString(Tool->GetToolControlPoints())), NULL, true); //Tool Tip if (Tool->IsToolTipSet()) { - thisTool->AddProperty("ToolTipPosition",mitk::StringProperty::New(ConvertPointToString(Tool->GetToolTipPosition()))); - thisTool->AddProperty("ToolAxisOrientation",mitk::StringProperty::New(ConvertQuaternionToString(Tool->GetToolAxisOrientation()))); + thisTool->AddProperty("ToolTipPosition",mitk::StringProperty::New(ConvertPointToString(Tool->GetToolTipPosition())), NULL, true); + thisTool->AddProperty("ToolAxisOrientation",mitk::StringProperty::New(ConvertQuaternionToString(Tool->GetToolAxisOrientation())), NULL, true); } - //Tool Axis - thisTool->AddProperty("ToolAxis", mitk::StringProperty::New(ConvertPointToString(Tool->GetToolAxis()))); - //Material is not needed, to avoid errors in scene serialization we have to do this: thisTool->RemoveProperty("material"); - return thisTool; } std::string mitk::NavigationToolWriter::GetFileWithoutPath(std::string FileWithPath) { Poco::Path myFile(FileWithPath.c_str()); return myFile.getFileName(); } std::string mitk::NavigationToolWriter::ConvertPointSetToString(mitk::PointSet::Pointer pointSet) { std::stringstream returnValue; mitk::PointSet::PointDataIterator it; for ( it = pointSet->GetPointSet()->GetPointData()->Begin();it != pointSet->GetPointSet()->GetPointData()->End();it++ ) { mitk::Point3D thisPoint = pointSet->GetPoint(it->Index()); returnValue << it->Index() << ";" << ConvertPointToString(thisPoint) << "|"; } return returnValue.str(); } std::string mitk::NavigationToolWriter::ConvertPointToString(mitk::Point3D point) { std::stringstream returnValue; returnValue << point[0] << ";" << point[1] << ";" << point[2]; return returnValue.str(); } std::string mitk::NavigationToolWriter::ConvertQuaternionToString(mitk::Quaternion quat) { std::stringstream returnValue; returnValue << quat.x() << ";" << quat.y() << ";" << quat.z() << ";" << quat.r(); return returnValue.str(); } diff --git a/Modules/IGT/Testing/mitkNavigationDataTest.cpp b/Modules/IGT/Testing/mitkNavigationDataTest.cpp index 798a1f1c73..8f1ee9bd87 100644 --- a/Modules/IGT/Testing/mitkNavigationDataTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataTest.cpp @@ -1,624 +1,624 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkNavigationData.h" #include "mitkVector.h" #include #include using namespace mitk; /** * helper function which checks if the non position / orientation / covariance related members are all set to certain values */ static bool AreBasicNavigationMembersEqual(const NavigationData::Pointer nd, const bool dataValid, const NavigationData::TimeStampType timeStamp, const std::string name) { bool result = true; result = result && (nd->IsDataValid() == dataValid); result = result && (mitk::Equal(nd->GetIGTTimeStamp(), timeStamp)); result = result && (0 == name.compare(nd->GetName())); return result; } /** * helper function which checks if the basic members, meaning the members not related to position / orientation / covariance * are the same for two NavigationData objects. */ static bool AreBasicNavigationMembersEqual(const NavigationData::Pointer nd1, const NavigationData::Pointer nd2) { return AreBasicNavigationMembersEqual(nd1, nd2->IsDataValid(), nd2->GetIGTTimeStamp(), nd2->GetName()); } /** * Test if the NavigationData object nd has the correct settings for covariance matrix specific members. * * @param nd * @param hasPosition the desired value for the hasPosition member * @param hasOrientation the desired value for the hasOrientation member * @param covMatrix the covariance matrix nd should have * @return */ static bool AreCovarianceNavigationMembersEqual(const NavigationData::Pointer nd, bool hasPosition, bool hasOrientation, NavigationData::CovarianceMatrixType covMatrix) { bool result = true; result = result && (nd->GetHasPosition() == hasPosition); result = result && (nd->GetHasOrientation() == hasOrientation); result = result && (mitk::MatrixEqualElementWise(nd->GetCovErrorMatrix(), covMatrix)); return result; } /** * Checks if the covariance related members of the two NavigationData objects are the same * * @see AreCovarianceNavigationMembersEqual * * @param nd1 * @param nd2 * @return */ static bool AreCovarianceNavigationMembersEqual(const NavigationData::Pointer nd1, const NavigationData::Pointer nd2) { return AreCovarianceNavigationMembersEqual(nd1, nd2->GetHasPosition(), nd2->GetHasOrientation(), nd2->GetCovErrorMatrix()); } /** * Creates a fully set NavigationData object for testing purposes. * * @return a smartpointer to the object */ static mitk::NavigationData::Pointer GetTestData() { mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType p; mitk::FillVector3D(p, 44.4, 55.5, 66.66); nd->SetPosition(p); mitk::NavigationData::OrientationType o(1.0, 2.0, 3.0, 4.0); nd->SetOrientation(o); nd->SetDataValid(true); nd->SetIGTTimeStamp(100.111); nd->SetHasPosition(false); nd->SetHasOrientation(false); mitk::NavigationData::CovarianceMatrixType m; m.Fill(17.17); m(2, 2) = 1000.01; nd->SetCovErrorMatrix(m); nd->SetName("my NavigationData"); nd->SetPositionAccuracy(100.0); nd->SetOrientationAccuracy(10.0); return nd; } static void TestInstatiation() { // Test instantiation of NavigationData mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); MITK_TEST_CONDITION(nd.IsNotNull(),"Test instatiation"); } static void TestGetterSetter() { mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType p; mitk::FillVector3D(p, 44.4, 55.5, 66.66); nd->SetPosition(p); MITK_TEST_CONDITION(nd->GetPosition() == p, "Set-/GetPosition()"); mitk::NavigationData::OrientationType o(1.0, 2.0, 3.0, 4.0); nd->SetOrientation(o); MITK_TEST_CONDITION(nd->GetOrientation() == o, "Set-/GetOrientation()"); nd->SetDataValid(true); MITK_TEST_CONDITION(nd->IsDataValid() == true, "Set-/IsDataValid()"); nd->SetIGTTimeStamp(100.111); MITK_TEST_CONDITION(mitk::Equal(nd->GetIGTTimeStamp(), 100.111), "Set-/GetIGTTimeStamp()"); nd->SetHasPosition(false); MITK_TEST_CONDITION(nd->GetHasPosition() == false, "Set-/GetHasPosition()"); nd->SetHasOrientation(false); MITK_TEST_CONDITION(nd->GetHasOrientation() == false, "Set-/GetHasOrientation()"); mitk::NavigationData::CovarianceMatrixType m; m.Fill(17.17); m(2, 2) = 1000.01; nd->SetCovErrorMatrix(m); MITK_TEST_CONDITION(nd->GetCovErrorMatrix() == m, "Set-/GetCovErrorMatrix()"); nd->SetName("my NavigationData"); MITK_TEST_CONDITION(std::string(nd->GetName()) == "my NavigationData", "Set-/GetName()"); nd->SetPositionAccuracy(100.0); mitk::NavigationData::CovarianceMatrixType result = nd->GetCovErrorMatrix(); MITK_TEST_CONDITION(mitk::Equal(result(0, 0), 10000.0) && mitk::Equal(result(1, 1), 10000.0) && mitk::Equal(result(2, 2), 10000.0), "SetPositionAccuracy()"); nd->SetOrientationAccuracy(10.0); mitk::NavigationData::CovarianceMatrixType result2 = nd->GetCovErrorMatrix(); MITK_TEST_CONDITION(mitk::Equal(result2(3, 3), 100.0) && mitk::Equal(result2(4, 4), 100.0) && mitk::Equal(result2(5, 5), 100.0), "SetOrientationAccuracy()"); } static void TestGraft() { //create test data mitk::NavigationData::Pointer nd = GetTestData(); mitk::NavigationData::Pointer graftedCopy = mitk::NavigationData::New(); graftedCopy->Graft(nd); bool graftIsEqual = (nd->GetPosition() == graftedCopy->GetPosition()) && (nd->GetOrientation() == graftedCopy->GetOrientation()) && AreCovarianceNavigationMembersEqual(nd, graftedCopy) && AreBasicNavigationMembersEqual(nd, graftedCopy); MITK_TEST_CONDITION(graftIsEqual, "Graft() produces equal NavigationData object"); } static void TestPrintSelf() { mitk::NavigationData::Pointer nd = GetTestData(); itk::Indent myIndent = itk::Indent(); MITK_TEST_OUTPUT(<<"Testing method PrintSelf(), method output will follow:"); bool success = true; try { nd->PrintSelf(std::cout,myIndent); } catch(...) { success = false; } MITK_TEST_CONDITION(success, "Testing method PrintSelf()."); } static void TestWrongInputs() { mitk::NavigationData::Pointer nd = GetTestData(); // Test CopyInformation bool success = false; try { nd->CopyInformation(nullptr); } catch(itk::ExceptionObject e) { success = true; } MITK_TEST_CONDITION(success, "Testing wrong input for method CopyInformation."); // Test Graft success = false; try { nd->Graft(nullptr); } catch(itk::ExceptionObject e) { success = true; } MITK_TEST_CONDITION(success, "Testing wrong input for method Graft."); } static mitk::Quaternion quaternion; static mitk::Quaternion quaternion_realistic; static mitk::Vector3D offsetVector; static mitk::Point3D offsetPoint; static mitk::Matrix3D rotation; static mitk::Quaternion quaternion2; static mitk::Vector3D offsetVector2; static mitk::Point3D offsetPoint2; static mitk::Matrix3D rotation2; static mitk::Point3D point; /** * Helper method setting up data required for tests (like points which shall be transformed by the NavigationData). */ static void SetupNaviDataTests() { // set rotation matrix to /* * 0 -1 0 * 1 0 0 * 0 0 1 */ rotation.Fill(0); rotation[0][1] = -1; rotation[1][0] = 1; rotation[2][2] = 1; // set quaternion to quaternion equivalent // values calculated with javascript at // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ quaternion = mitk::Quaternion(0, 0, 0.7071067811865475, 0.7071067811865476); // a more realistic quaternion from real tracking data quaternion_realistic = mitk::Quaternion(-0.57747,0.225593,0.366371,0.693933); // set offset to some value. Some tests need vectors, offers points. double offsetArray[3] = {1.0,2.0,3.123456}; offsetVector = offsetArray; offsetPoint = offsetArray; /***** Second set of data for compose tests ****/ // set rotation2 matrix to /* * 1 0 0 * 0 0 -1 * 0 1 0 */ rotation2.Fill(0); rotation2[0][0] = 1; rotation2[1][2] = -1; rotation2[2][1] = 1; quaternion2 = mitk::Quaternion(0.7071067811865475, 0, 0, 0.7071067811865476); mitk::ScalarType offsetArray2[3] = {1, 0, 0}; offsetVector2 = offsetArray2; offsetPoint2 = offsetArray2; /***** Create a point to be transformed *****/ mitk::ScalarType pointArray[] = {1.0, 3.0, 5.0}; point = pointArray; } /** * Helper method, which creates a NavigationData object using the data created in SetupNaviDataTests() */ static mitk::NavigationData::Pointer CreateNavidata(mitk::Quaternion quaternion, mitk::Point3D offset) { mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(); navigationData->SetOrientation(quaternion); navigationData->SetPosition(offset); return navigationData; } /** * Helper method which creates an affine transformation only composed by a rotation and a translation (no scalings and the likes). * * @param rotationMatrix * @param offset * @return */ static mitk::AffineTransform3D::Pointer CreateAffineTransform(mitk::Matrix3D rotationMatrix, mitk::Vector3D offset) { mitk::AffineTransform3D::Pointer affineTransform3D = mitk::AffineTransform3D::New(); affineTransform3D->SetOffset(offset); affineTransform3D->SetMatrix(rotationMatrix); return affineTransform3D; } /** * Test if NavigationData::GetInverse returns the correct inverse */ /*static void TestInverse() { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::NavigationData::Pointer ndInverse = nd->GetInverse(); // calculate expected inverted position vector: b2 = -A2b1 // for -A2b1 we need vnl_vectors. vnl_vector_fixed b1; for (int i = 0; i < 3; ++i) { b1[i] = nd->GetPosition()[i]; } vnl_vector_fixed b2; b2 = -(ndInverse->GetOrientation().rotate(b1)); // now copy result back into our mitk::Point3D mitk::Point3D invertedPosition; for (int i = 0; i < 3; ++i) { invertedPosition[i] = b2[i]; } MITK_TEST_CONDITION(mitk::Equal(nd->GetOrientation().inverse(), ndInverse->GetOrientation()),"Testing GetInverse: orientation inverted"); MITK_TEST_CONDITION(mitk::Equal(invertedPosition, ndInverse->GetPosition()), "Testing GetInverse: position inverted"); bool otherFlagsOk = AreBasicNavigationMembersEqual(nd, ndInverse) && AreCovarianceNavigationMembersEqual(ndInverse, false, false, nd->GetCovErrorMatrix()); // covariance update mechanism not yet implemented, thus validities are set to false. MITK_TEST_CONDITION(otherFlagsOk, "Testing GetInverse: other flags are same"); //######################################################################################## //################### Second test with more realistic quaternion ######################### //######################################################################################## //just copy data to be real sure that it is not overwritten during the test mitk::Quaternion referenceQuaternion; referenceQuaternion[0] = quaternion_realistic[0]; referenceQuaternion[1] = quaternion_realistic[1]; referenceQuaternion[2] = quaternion_realistic[2]; referenceQuaternion[3] = quaternion_realistic[3]; mitk::Point3D referencePoint; referencePoint[0] = offsetPoint[0]; referencePoint[1] = offsetPoint[1]; referencePoint[2] = offsetPoint[2]; referencePoint[3] = offsetPoint[3]; mitk::NavigationData::Pointer nd2 = CreateNavidata(quaternion_realistic, offsetPoint); mitk::NavigationData::Pointer ndInverse2 = nd2->GetInverse(); MITK_TEST_CONDITION(mitk::Equal(nd2->GetOrientation(),referenceQuaternion),"Testing if the method GetInverse() modifies the data which should never happen!"); MITK_TEST_CONDITION(mitk::Equal(ndInverse2->GetOrientation(),referenceQuaternion.inverse()),"Testing if the Qrientation was inverted correctly with the realistic quaternion"); }*/ /** * Test if the original orientation and position are retained after inverting two times. */ static void TestDoubleInverse() { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::NavigationData::Pointer ndDoubleInverse = nd->GetInverse()->GetInverse(); MITK_TEST_CONDITION(mitk::Equal(nd->GetOrientation(), ndDoubleInverse->GetOrientation()),"Testing GetInverse double application: orientation preserved"); MITK_TEST_CONDITION(mitk::Equal(nd->GetPosition(), ndDoubleInverse->GetPosition()), "Testing GetInverse double application: position preserved"); } /** * Tests if NavigationData::GetInverse throws an error if the NavigationData has no inverse * (e.g. after it is initialized, no rotation is stored -> the transformation cannot be inverted). */ static void TestInverseError() { // initialize empty NavigationData (quaternion is zeroed) mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::Quaternion quaternion; quaternion.fill(0); nd->SetOrientation(quaternion); - MITK_TEST_FOR_EXCEPTION(mitk::Exception&, nd->GetInverse()); + MITK_TEST_FOR_EXCEPTION(mitk::Exception, nd->GetInverse()); } /** * Tests if NavigationData::TransformPoint works. */ static void TestTransform() { SetupNaviDataTests(); mitk::NavigationData::Pointer navigationData = CreateNavidata(quaternion, offsetPoint); point = navigationData->TransformPoint(point); mitk::ScalarType resultingPointArray[] = {-2, 3, 8.123456}; mitk::Point3D resultingPoint = resultingPointArray; MITK_TEST_CONDITION(mitk::Equal(resultingPoint, point), "Testing point transformation"); } /** * Tests if the construction of a NavigationData object from an * affine transformation which is only composed of a rotation and translation works. */ static void TestAffineConstructor() { SetupNaviDataTests(); mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(affineTransform3D); MITK_TEST_CONDITION(AreBasicNavigationMembersEqual(navigationData, true, 0.0, ""), "Testing affine constructor: dataValid, timeStamp and name have been initialized to default values"); NavigationData::CovarianceMatrixType covMatrix; // empty covariance matrix MITK_TEST_CONDITION(AreCovarianceNavigationMembersEqual(navigationData, true, true, covMatrix), "Testing affine constructor: covariance matrix values have been correctly initialized"); // TODO: discuss with Alfred // why this is the desired initialization of the covariance information. MITK_TEST_CONDITION(mitk::Equal(navigationData->GetPosition(), offsetPoint), "Testing affine constructor: offset"); MITK_TEST_CONDITION(mitk::Equal(navigationData->GetOrientation(), quaternion), "Testing affine constructor: quaternion"); } /** * Tests if the construction of a NavigationData object throws an error when constructing from an * affine transformation which is orthogonal. */ static void TestAffineConstructorErrorTransposedNotInverse() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[1][0] = 2; // this matrix has determinant = 1 (triangular matrix with ones in diagonal) but transposed != inverse mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); - MITK_TEST_FOR_EXCEPTION(mitk::Exception&, mitk::NavigationData::New(affineTransform3D)); + MITK_TEST_FOR_EXCEPTION(mitk::Exception, mitk::NavigationData::New(affineTransform3D)); } /** * Tests if the construction of a NavigationData object throws an error when constructing from an * affine transformation which is not normal. */ static void TestAffineConstructorErrorDeterminantNonEqualOne() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[0][0] = 2; // determinant for diagonal matrices is product of diagonal elements => det = 2 mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); - MITK_TEST_FOR_EXCEPTION(mitk::Exception&, mitk::NavigationData::New(affineTransform3D)); + MITK_TEST_FOR_EXCEPTION(mitk::Exception, mitk::NavigationData::New(affineTransform3D)); } /** * Tests if the error suppression mechanism works if a NavigationData object is created from a * invalid affine transformation (one that is not only rotation and translation). */ static void TestAffineConstructorErrorCheckingFalse() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[0][0] = 2; // determinant for diagonal matrices is product of diagonal elements => det = 2 mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); bool exceptionSuppressed = true; try { mitk::NavigationData::New(affineTransform3D, false); } catch (mitk::Exception&) { exceptionSuppressed = false; } MITK_TEST_CONDITION(exceptionSuppressed, "Test affine constructor: exception can be suppressed.") } /** * Test if NavigationData::GetAffineTransform3D() returns the correct affine transformation. */ static void TestAffineGetter() { SetupNaviDataTests(); mitk::NavigationData::Pointer navigationData = CreateNavidata(quaternion, offsetPoint); mitk::AffineTransform3D::Pointer affineTransform = navigationData->GetAffineTransform3D(); MITK_TEST_CONDITION(mitk::Equal(affineTransform->GetOffset(), offsetVector), "Testing AffineTransform3D getter: offset"); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(affineTransform->GetMatrix(), rotation), "Testing AffineTransform3D getter: rotation"); } /** * This test tests the complete chain from affineTransform -> NavigationData -> affineTransform */ static void TestAffineToNaviDataToAffine() { SetupNaviDataTests(); mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); // there and back again: affineTransform -> NavigationData -> affineTransform mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(affineTransform3D); mitk::AffineTransform3D::Pointer affineTransform3D_2; affineTransform3D_2 = navigationData->GetAffineTransform3D(); MITK_TEST_CONDITION(mitk::Equal(affineTransform3D->GetOffset(), affineTransform3D_2->GetOffset()), "Testing affine -> navidata -> affine chain: offset"); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(affineTransform3D->GetMatrix(), affineTransform3D_2->GetMatrix()), "Testing affine -> navidata -> affine chain: rotation"); } static void TestCompose(bool pre = false) { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::AffineTransform3D::Pointer at = CreateAffineTransform(rotation, offsetVector); // second transform for composition mitk::NavigationData::Pointer nd2 = CreateNavidata(quaternion2, offsetPoint2); mitk::AffineTransform3D::Pointer at2 = CreateAffineTransform(rotation2, offsetVector2); // save point for affinetransform mitk::Point3D point2 = point; nd->Compose(nd2, pre); point = nd->TransformPoint(point); at->Compose(at2, pre); point2 = at->TransformPoint(point2); MITK_TEST_CONDITION(mitk::Equal(point, point2), "Compose pre = " << pre << ": composition works "); bool covarianceValidityReset = !nd->GetHasOrientation() && !nd->GetHasPosition(); MITK_TEST_CONDITION(covarianceValidityReset, "Compose pre = " << pre << ": covariance validities reset because not implemented yet."); } static void TestReverseCompose() { TestCompose(true); } /** * Tests the clone method. */ static void TestClone() { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::NavigationData::Pointer myClone = nd->Clone(); MITK_TEST_CONDITION(mitk::Equal(*nd,*myClone,mitk::eps,true), "Test if clone is equal to original object."); //change clone, original object should not change mitk::Point3D myPoint; mitk::FillVector3D(myPoint,121,32132,433); myClone->SetPosition(myPoint); MITK_TEST_CONDITION(!mitk::Equal(*nd,*myClone), "Test if clone could be modified without changing the original object."); } /** * This function is testing the Class mitk::NavigationData. For most tests we would need the MicronTracker hardware, so only a few * simple tests, which can run without the hardware are implemented yet (2009, January, 23rd). As soon as there is a working * concept to test the tracking classes which are very close to the hardware on all systems more tests are needed here. */ int mitkNavigationDataTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationData"); TestInstatiation(); TestGetterSetter(); TestGraft(); TestPrintSelf(); TestWrongInputs(); TestAffineConstructor(); TestAffineConstructorErrorDeterminantNonEqualOne(); TestAffineConstructorErrorTransposedNotInverse(); TestAffineConstructorErrorCheckingFalse(); TestAffineGetter(); TestAffineToNaviDataToAffine(); TestTransform(); //TestInverse(); Fails under MAC, see bug 18306 TestDoubleInverse(); TestInverseError(); TestCompose(); TestReverseCompose(); TestClone(); MITK_TEST_END(); } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp index 984a97a282..7e65448aeb 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp @@ -1,438 +1,440 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkIGTLDeviceSetupConnectionWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include +#include + const std::string QmitkIGTLDeviceSetupConnectionWidget::VIEW_ID = "org.mitk.views.igtldevicesetupconnectionwidget"; QmitkIGTLDeviceSetupConnectionWidget::QmitkIGTLDeviceSetupConnectionWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false) { m_Controls = nullptr; this->m_IGTLDevice = nullptr; CreateQtPartControl(this); m_NumSentFramesSinceLastUpdate = 0; m_NumReceivedFramesSinceLastUpdate = 0; } QmitkIGTLDeviceSetupConnectionWidget::~QmitkIGTLDeviceSetupConnectionWidget() { this->RemoveObserver(); } void QmitkIGTLDeviceSetupConnectionWidget::RemoveObserver() { if (this->m_IGTLDevice.IsNotNull()) { this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_MessageSentObserverTag); this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } } void QmitkIGTLDeviceSetupConnectionWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceSetupConnectionWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } // set the validator for the ip edit box (values must be between 0 and 255 and // there are four of them, seperated with a point QRegExpValidator *v = new QRegExpValidator(this); QRegExp rx("((1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})\\.){3,3}(1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})"); v->setRegExp(rx); m_Controls->editIP->setValidator(v); // set the validator for the port edit box (values must be between 1 and 65535) m_Controls->editPort->setValidator(new QIntValidator(1, 65535, this)); m_FPSCalculationTimer.start(1000); //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceSetupConnectionWidget::CreateConnections() { if (m_Controls) { // connect the widget items with the methods connect(m_Controls->butConnect, SIGNAL(clicked()), this, SLOT(OnConnect())); connect(m_Controls->editPort, SIGNAL(editingFinished()), this, SLOT(OnPortChanged())); connect(m_Controls->editIP, SIGNAL(editingFinished()), this, SLOT(OnHostnameChanged())); connect(m_Controls->bufferInMsgCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnBufferIncomingMessages(int))); connect(m_Controls->bufferOutMsgCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnBufferOutgoingMessages(int))); connect(&m_FPSCalculationTimer, SIGNAL(timeout()), this, SLOT(OnUpdateFPSLabel())); connect(m_Controls->logMessageDetailsCheckBox, SIGNAL(clicked()), this, SLOT(OnLogMessageDetailsCheckBoxClicked())); } //this is used for thread seperation, otherwise the worker thread would change the ui elements //which would cause an exception connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceSetupConnectionWidget::OnDeviceStateChanged() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::AdaptGUIToState() { //check the validity of the device if (this->m_IGTLDevice.IsNull()) { return; } //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); switch (state) { case mitk::IGTLDevice::Setup: if (!m_IsClient) { m_Controls->butConnect->setText("Go Online"); this->m_Controls->editIP->setEnabled(false); } else { m_Controls->butConnect->setText("Connect"); this->m_Controls->editIP->setEnabled(true); } this->m_Controls->editPort->setEnabled(true); this->m_Controls->logMessageStatusCheckBox->setChecked(false); this->m_Controls->logMessageDetailsCheckBox->setChecked(false); this->m_Controls->logMessageStatusCheckBox->setEnabled(false); this->m_Controls->logMessageDetailsCheckBox->setEnabled(false); this->m_Controls->bufferInMsgCheckBox->setEnabled(false); this->m_Controls->bufferOutMsgCheckBox->setEnabled(false); this->m_Controls->butConnect->setEnabled(true); this->m_Controls->fpsInLabel->setEnabled(false); this->m_Controls->fpsOutLabel->setEnabled(false); this->m_Controls->fpsInDescrLabel->setEnabled(false); this->m_Controls->fpsOutDescrLabel->setEnabled(false); if( this->m_IGTLDevice.IsNotNull() ) { this->m_IGTLDevice->SetLogMessages(false); } break; case mitk::IGTLDevice::Ready: if (m_IsClient) { this->m_Controls->butConnect->setText("Disconnect"); } else { this->m_Controls->butConnect->setText("Go Offline"); } this->m_Controls->editIP->setEnabled(false); this->m_Controls->editPort->setEnabled(false); this->m_Controls->logMessageStatusCheckBox->setEnabled(true); this->m_Controls->logMessageDetailsCheckBox->setEnabled(true); this->m_Controls->bufferInMsgCheckBox->setEnabled(true); this->m_Controls->bufferOutMsgCheckBox->setEnabled(true); this->m_Controls->butConnect->setEnabled(true); this->m_Controls->fpsInLabel->setEnabled(true); this->m_Controls->fpsOutLabel->setEnabled(true); this->m_Controls->fpsInDescrLabel->setEnabled(true); this->m_Controls->fpsOutDescrLabel->setEnabled(true); break; case mitk::IGTLDevice::Running: if (m_IsClient) { this->m_Controls->butConnect->setText("Disconnect"); } else { this->m_Controls->butConnect->setText("Go Offline"); } this->m_Controls->editIP->setEnabled(false); this->m_Controls->editPort->setEnabled(false); this->m_Controls->logMessageStatusCheckBox->setEnabled(true); this->m_Controls->logMessageDetailsCheckBox->setEnabled(true); this->m_Controls->bufferInMsgCheckBox->setEnabled(true); this->m_Controls->bufferOutMsgCheckBox->setEnabled(true); this->m_Controls->butConnect->setEnabled(true); this->m_Controls->fpsInLabel->setEnabled(true); this->m_Controls->fpsOutLabel->setEnabled(true); this->m_Controls->fpsInDescrLabel->setEnabled(true); this->m_Controls->fpsOutDescrLabel->setEnabled(true); break; default: mitkThrow() << "Invalid Device State"; break; } } void QmitkIGTLDeviceSetupConnectionWidget::Initialize( mitk::IGTLDevice::Pointer device) { //reset the GUI DisableSourceControls(); //reset the observers this->RemoveObserver(); if (device.IsNotNull()) { this->m_IGTLDevice = device; //check if the device is a server or a client if (dynamic_cast( this->m_IGTLDevice.GetPointer()) == nullptr) { m_IsClient = false; } else { m_IsClient = true; } this->AdaptGUIToState(); typedef itk::SimpleMemberCommand< QmitkIGTLDeviceSetupConnectionWidget > CurCommandType; CurCommandType::Pointer messageSentCommand = CurCommandType::New(); messageSentCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnMessageSent); this->m_MessageSentObserverTag = this->m_IGTLDevice->AddObserver( mitk::MessageSentEvent(), messageSentCommand); CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); messageReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived); this->m_MessageReceivedObserverTag = this->m_IGTLDevice->AddObserver( mitk::MessageReceivedEvent(), messageReceivedCommand); CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); commandReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnCommandReceived); this->m_CommandReceivedObserverTag = this->m_IGTLDevice->AddObserver( mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnLostConnection); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnNewConnection); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnDeviceStateChanged); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); OnBufferIncomingMessages(m_Controls->bufferInMsgCheckBox->isChecked()); OnBufferOutgoingMessages(m_Controls->bufferOutMsgCheckBox->isChecked()); } else { m_IGTLDevice = nullptr; } } void QmitkIGTLDeviceSetupConnectionWidget::DisableSourceControls() { m_Controls->editIP->setEnabled(false); m_Controls->editPort->setEnabled(false); m_Controls->butConnect->setEnabled(false); m_Controls->bufferInMsgCheckBox->setEnabled(false); m_Controls->bufferOutMsgCheckBox->setEnabled(false); this->m_Controls->logMessageStatusCheckBox->setChecked(false); this->m_Controls->logMessageDetailsCheckBox->setChecked(false); this->m_Controls->logMessageStatusCheckBox->setEnabled(false); this->m_Controls->logMessageDetailsCheckBox->setEnabled(false); if( this->m_IGTLDevice.IsNotNull() ) { this->m_IGTLDevice->SetLogMessages(false); } } void QmitkIGTLDeviceSetupConnectionWidget::OnConnect() { if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Setup) { QString port = m_Controls->editPort->text(); m_IGTLDevice->SetPortNumber(port.toInt()); std::string hostname = m_Controls->editIP->text().toStdString(); m_IGTLDevice->SetHostname(hostname); //connect with the other OpenIGTLink device => changes the state from Setup //to Ready if (m_IGTLDevice->OpenConnection()) { //starts the communication thread => changes the state from Ready to //Running if (m_IGTLDevice->StartCommunication()) { if (this->m_IsClient) { MITK_INFO("IGTLDeviceSourceManagementWidget") << "Successfully connected to " << hostname << " on port " << port.toStdString(); } } else { MITK_ERROR("QmitkIGTLDeviceSetupConnectionWidget") << "Could not start a communication with the" "server because the client is in the wrong state"; } } else { MITK_ERROR("QmitkIGTLDeviceSetupConnectionWidget") << "Could not connect to the server. " "Please check the hostname and port."; } } else if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Ready || m_IGTLDevice->GetState() == mitk::IGTLDevice::Running) { m_IGTLDevice->CloseConnection(); MITK_INFO("QmitkIGTLDeviceSetupConnectionWidget") << "Closed connection"; } else { mitkThrow() << "Invalid state of IGTLDevice"; } this->AdaptGUIToState(); } void QmitkIGTLDeviceSetupConnectionWidget::OnPortChanged() { } void QmitkIGTLDeviceSetupConnectionWidget::OnHostnameChanged() { } void QmitkIGTLDeviceSetupConnectionWidget::OnLostConnection() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::OnNewConnection() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived() { if( this->m_Controls->logMessageStatusCheckBox->isChecked() ) { MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a message."; } m_NumReceivedFramesSinceLastUpdate++; } void QmitkIGTLDeviceSetupConnectionWidget::OnMessageSent() { if( this->m_Controls->logMessageStatusCheckBox->isChecked() ) { MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Sent a message."; } m_NumSentFramesSinceLastUpdate++; } void QmitkIGTLDeviceSetupConnectionWidget::OnCommandReceived() { if( this->m_Controls->logMessageStatusCheckBox->isChecked() ) { MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a command."; } } void QmitkIGTLDeviceSetupConnectionWidget::OnBufferIncomingMessages(int state) { if (this->m_IGTLDevice.IsNotNull()) { this->m_IGTLDevice->EnableNoBufferingMode( this->m_IGTLDevice->GetMessageQueue(), (bool)state); } } void QmitkIGTLDeviceSetupConnectionWidget::OnBufferOutgoingMessages(int state) { if (this->m_IGTLDevice.IsNotNull()) { this->m_IGTLDevice->EnableNoBufferingMode( this->m_IGTLDevice->GetMessageQueue(), (bool)state); } } void QmitkIGTLDeviceSetupConnectionWidget::OnUpdateFPSLabel() { double fpsIn = m_NumReceivedFramesSinceLastUpdate / 1.0; double fpsOut = m_NumSentFramesSinceLastUpdate / 1.0; this->m_Controls->fpsInLabel->setText(QString::number(fpsIn)); this->m_Controls->fpsOutLabel->setText(QString::number(fpsOut)); m_NumReceivedFramesSinceLastUpdate = 0; m_NumSentFramesSinceLastUpdate = 0; } void QmitkIGTLDeviceSetupConnectionWidget::OnLogMessageDetailsCheckBoxClicked() { if( this->m_IGTLDevice.IsNull() ) { MITK_WARN << "Logging information not passed down to Message Provider."; return; } else { this->m_IGTLDevice->SetLogMessages( this->m_Controls->logMessageDetailsCheckBox->isChecked() ); } } diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticComposedVolumeTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticComposedVolumeTest.cpp index 65cc609884..f15b86cbcb 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacousticComposedVolumeTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticComposedVolumeTest.cpp @@ -1,148 +1,148 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "mitkPAComposedVolume.h" #include "mitkIOUtil.h" #include "mitkImageReadAccessor.h" #include class mitkPhotoacousticComposedVolumeTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticComposedVolumeTestSuite); MITK_TEST(TestCreateAndDestructComposedVolume); MITK_TEST(TestAccessInvalidFluenceComponent); MITK_TEST(TestAccessInvalidFluenceComponentIndex); MITK_TEST(TestAddMultiplePairs); MITK_TEST(TestSortFunctionality); MITK_TEST(TestAccessInvalidFluenceComponentForYOffset); CPPUNIT_TEST_SUITE_END(); private: mitk::pa::ComposedVolume::Pointer m_ComposedVolume; mitk::pa::TissueGeneratorParameters::Pointer m_DefaultParameters; mitk::pa::InSilicoTissueVolume::Pointer m_InSilicoTissueVolume; public: void setUp() override { m_DefaultParameters = mitk::pa::TissueGeneratorParameters::New(); m_DefaultParameters->SetXDim(5); m_DefaultParameters->SetYDim(5); m_DefaultParameters->SetZDim(5); m_InSilicoTissueVolume = mitk::pa::InSilicoTissueVolume::New(m_DefaultParameters); m_ComposedVolume = mitk::pa::ComposedVolume::New(m_InSilicoTissueVolume); } mitk::pa::FluenceYOffsetPair::Pointer createFluenceYOffsetPair(double value, double yOffset) { auto* data = new double[125]; for (int i = 0; i < 125; ++i) data[i] = value; mitk::pa::Volume::Pointer volume = mitk::pa::Volume::New(data, 5, 5, 5); return mitk::pa::FluenceYOffsetPair::New(volume, yOffset); } void TestCreateAndDestructComposedVolume() { CPPUNIT_ASSERT(m_ComposedVolume->GetNumberOfFluenceComponents() == 0); } void TestAccessInvalidFluenceComponent() { bool caughtException = false; try { m_ComposedVolume->GetFluenceValue(0, 0, 0, 0); } - catch (mitk::Exception e) + catch (const mitk::Exception &) { caughtException = true; } CPPUNIT_ASSERT(caughtException); } void TestAddMultiplePairs() { m_ComposedVolume->AddSlice(createFluenceYOffsetPair(0, 0)); CPPUNIT_ASSERT(m_ComposedVolume->GetNumberOfFluenceComponents() == 1); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(1, 1)); CPPUNIT_ASSERT(m_ComposedVolume->GetNumberOfFluenceComponents() == 2); } void TestSortFunctionality() { m_ComposedVolume->AddSlice(createFluenceYOffsetPair(2, 2)); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(-1, -1)); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(1, 1)); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(0, 0)); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(-2, -2)); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(0, 0, 2, 0) == 2); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(1, 0, 2, 0) == -1); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(2, 0, 2, 0) == 1); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(3, 0, 2, 0) == 0); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(4, 0, 2, 0) == -2); m_ComposedVolume->Sort(); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(0, 0, 2, 0) == -2); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(1, 0, 2, 0) == -1); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(2, 0, 2, 0) == 0); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(3, 0, 2, 0) == 1); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(4, 0, 2, 0) == 2); } void TestAccessInvalidFluenceComponentIndex() { #ifdef _DEBUG m_ComposedVolume->AddSlice(createFluenceYOffsetPair(0, 0)); bool caughtException = false; try { double unusedValue = m_ComposedVolume->GetFluenceValue(0, 1, 2, 300); unusedValue = 0; } - catch (mitk::Exception e) + catch (const mitk::Exception e) { caughtException = true; } CPPUNIT_ASSERT(caughtException); #endif } void TestAccessInvalidFluenceComponentForYOffset() { bool caughtException = false; try { m_ComposedVolume->GetYOffsetForFluenceComponentInPixels(0); } - catch (mitk::Exception e) + catch (const mitk::Exception &) { caughtException = true; } CPPUNIT_ASSERT(caughtException); } void tearDown() override { m_ComposedVolume = nullptr; } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticComposedVolume) diff --git a/Modules/Segmentation/Algorithms/mitkCorrectorAlgorithm.cpp b/Modules/Segmentation/Algorithms/mitkCorrectorAlgorithm.cpp index 81583cbeff..e2a14ce668 100644 --- a/Modules/Segmentation/Algorithms/mitkCorrectorAlgorithm.cpp +++ b/Modules/Segmentation/Algorithms/mitkCorrectorAlgorithm.cpp @@ -1,490 +1,490 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCorrectorAlgorithm.h" #include "mitkContourUtils.h" #include "mitkITKImageImport.h" #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" #include "mitkImageDataItem.h" #include #include "itkCastImageFilter.h" #include "itkImageDuplicator.h" #include "itkImageRegionIterator.h" mitk::CorrectorAlgorithm::CorrectorAlgorithm() : ImageToImageFilter(), m_FillColor(1), m_EraseColor(0) { } mitk::CorrectorAlgorithm::~CorrectorAlgorithm() { } template void ConvertBackToCorrectPixelType( itk::Image *, mitk::Image::Pointer target, itk::Image::Pointer segmentationPixelTypeImage) { typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::CastImageFilter CastImageFilterType; typename CastImageFilterType::Pointer castImageFilter = CastImageFilterType::New(); castImageFilter->SetInput(segmentationPixelTypeImage); castImageFilter->Update(); typename OutputImageType::Pointer tempItkImage = castImageFilter->GetOutput(); tempItkImage->DisconnectPipeline(); mitk::CastToMitkImage(tempItkImage, target); } void mitk::CorrectorAlgorithm::GenerateData() { Image::Pointer inputImage = ImageToImageFilter::GetInput(0); if (inputImage.IsNull() || inputImage->GetDimension() != 2) { itkExceptionMacro("CorrectorAlgorithm needs a 2D image as input."); } if (m_Contour.IsNull()) { itkExceptionMacro("CorrectorAlgorithm needs a Contour object as input."); } // copy the input (since m_WorkingImage will be changed later) m_WorkingImage = inputImage; TimeGeometry::Pointer originalGeometry = nullptr; if (inputImage->GetTimeGeometry()) { originalGeometry = inputImage->GetTimeGeometry()->Clone(); m_WorkingImage->SetTimeGeometry(originalGeometry); } else { itkExceptionMacro("Original image does not have a 'Time sliced geometry'! Cannot copy."); } Image::Pointer temporarySlice; // Convert to DefaultSegmentationDataType (because TobiasHeimannCorrectionAlgorithm relys on that data type) { itk::Image::Pointer correctPixelTypeImage; CastToItkImage(m_WorkingImage, correctPixelTypeImage); assert(correctPixelTypeImage.IsNotNull()); // possible bug in CastToItkImage ? // direction maxtrix is wrong/broken/not working after CastToItkImage, leading to a failed assertion in // mitk/Core/DataStructures/mitkSlicedGeometry3D.cpp, 479: // virtual void mitk::SlicedGeometry3D::SetSpacing(const mitk::Vector3D&): Assertion `aSpacing[0]>0 && aSpacing[1]>0 // && aSpacing[2]>0' failed // solution here: we overwrite it with an unity matrix itk::Image::DirectionType imageDirection; imageDirection.SetIdentity(); // correctPixelTypeImage->SetDirection(imageDirection); temporarySlice = this->GetOutput(); // temporarySlice = ImportItkImage( correctPixelTypeImage ); // m_FillColor = 1; m_EraseColor = 0; ImprovedHeimannCorrectionAlgorithm(correctPixelTypeImage); // this is suboptimal, needs to be kept synchronous to DefaultSegmentationDataType if (inputImage->GetChannelDescriptor().GetPixelType().GetComponentType() == itk::ImageIOBase::USHORT) { // the cast at the beginning did not copy the data CastToMitkImage(correctPixelTypeImage, temporarySlice); } else { // it did copy the data and cast the pixel type AccessByItk_n(m_WorkingImage, ConvertBackToCorrectPixelType, (temporarySlice, correctPixelTypeImage)); } } temporarySlice->SetTimeGeometry(originalGeometry); } template itk::Index<2> mitk::CorrectorAlgorithm::ensureIndexInImage(ScalarType i0, ScalarType i1) { itk::Index<2> toReturn; itk::Size<5> size = m_WorkingImage->GetLargestPossibleRegion().GetSize(); toReturn[0] = std::min((ScalarType)(size[0] - 1), std::max((ScalarType)0.0, i0)); toReturn[1] = std::min((ScalarType)(size[1] - 1), std::max((ScalarType)0.0, i1)); return toReturn; } bool mitk::CorrectorAlgorithm::ImprovedHeimannCorrectionAlgorithm( itk::Image::Pointer pic) { /*! Some documentation (not by the original author) TobiasHeimannCorrectionAlgorithm will be called, when the user has finished drawing a freehand line. There should be different results, depending on the line's properties: 1. Without any prior segmentation, the start point and the end point of the drawn line will be connected to a contour and the area enclosed by the contour will be marked as segmentation. 2. When the whole line is inside a segmentation, start and end point will be connected to a contour and the area of this contour will be subtracted from the segmentation. 3. When the line starts inside a segmentation and ends outside with only a single transition from segmentation to no-segmentation, nothing will happen. 4. When there are multiple transitions between inside-segmentation and outside-segmentation, the line will be divided in so called segments. Each segment is either fully inside or fully outside a segmentation. When it is inside a segmentation, its enclosed area will be subtracted from the segmentation. When the segment is outside a segmentation, its enclosed area it will be added to the segmentation. The algorithm is described in full length in Tobias Heimann's diploma thesis (MBI Technical Report 145, p. 37 - 40). */ ContourModel::Pointer projectedContour = mitk::ContourModelUtils::ProjectContourTo2DSlice(m_WorkingImage, m_Contour, true, false); if (projectedContour.IsNull() || projectedContour->GetNumberOfVertices() < 2) return false; // Read the first point of the contour auto contourIter = projectedContour->Begin(); if (contourIter == projectedContour->End()) return false; itk::Index<2> previousIndex; previousIndex = ensureIndexInImage((*contourIter)->Coordinates[0], (*contourIter)->Coordinates[1]); ++contourIter; int currentColor = (pic->GetPixel(previousIndex) == m_FillColor); TSegData currentSegment; int countOfSegments = 1; bool firstSegment = true; auto contourEnd = projectedContour->End(); for (; contourIter != contourEnd; ++contourIter) { // Get current point itk::Index<2> currentIndex; currentIndex = ensureIndexInImage((*contourIter)->Coordinates[0] + 0.5, (*contourIter)->Coordinates[1] + 0.5); // Calculate length and slope double slopeX = currentIndex[0] - previousIndex[0]; double slopeY = currentIndex[1] - previousIndex[1]; double length = std::sqrt(slopeX * slopeX + slopeY * slopeY); double deltaX = slopeX / length; double deltaY = slopeY / length; for (double i = 0; i <= length && length > 0; i += 1) { itk::Index<2> temporaryIndex; temporaryIndex = ensureIndexInImage(previousIndex[0] + deltaX * i, previousIndex[1] + deltaY * i); if (!pic->GetLargestPossibleRegion().IsInside(temporaryIndex)) continue; if ((pic->GetPixel(temporaryIndex) == m_FillColor) != currentColor) { currentSegment.points.push_back(temporaryIndex); if (!firstSegment) { ModifySegment(currentSegment, pic); } else { firstSegment = false; } currentSegment = TSegData(); ++countOfSegments; currentColor = (pic->GetPixel(temporaryIndex) == m_FillColor); } currentSegment.points.push_back(temporaryIndex); } previousIndex = currentIndex; } return true; } void mitk::CorrectorAlgorithm::ColorSegment( const mitk::CorrectorAlgorithm::TSegData &segment, itk::Image::Pointer pic) { int colorMode = (pic->GetPixel(segment.points[0]) == m_FillColor); int color = 0; if (colorMode) color = m_EraseColor; else color = m_FillColor; std::vector>::const_iterator indexIterator; std::vector>::const_iterator indexEnd; indexIterator = segment.points.begin(); indexEnd = segment.points.end(); for (; indexIterator != indexEnd; ++indexIterator) { pic->SetPixel(*indexIterator, color); } } itk::Image::Pointer mitk::CorrectorAlgorithm::CloneImage( itk::Image::Pointer pic) { typedef itk::Image ItkImageType; typedef itk::ImageDuplicator DuplicatorType; DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage(pic); duplicator->Update(); return duplicator->GetOutput(); } itk::Index<2> mitk::CorrectorAlgorithm::GetFirstPoint( const mitk::CorrectorAlgorithm::TSegData &segment, itk::Image::Pointer pic) { int colorMode = (pic->GetPixel(segment.points[0]) == m_FillColor); std::vector>::const_iterator indexIterator; std::vector>::const_iterator indexEnd; indexIterator = segment.points.begin(); indexEnd = segment.points.end(); itk::Index<2> index; for (; indexIterator != indexEnd; ++indexIterator) { for (int xOffset = -1; xOffset < 2; ++xOffset) { for (int yOffset = -1; yOffset < 2; ++yOffset) { index = ensureIndexInImage((*indexIterator)[0] - xOffset, (*indexIterator)[1] - yOffset); if ((pic->GetPixel(index) == m_FillColor) != colorMode) { return index; } } } } mitkThrow() << "No Starting point is found next to the curve."; } std::vector> mitk::CorrectorAlgorithm::FindSeedPoints( const mitk::CorrectorAlgorithm::TSegData &segment, itk::Image::Pointer pic) { typedef itk::Image::Pointer ItkImagePointerType; std::vector> seedPoints; try { itk::Index<2> firstPoint = GetFirstPoint(segment, pic); seedPoints.push_back(firstPoint); } - catch (mitk::Exception e) + catch (const mitk::Exception&) { return seedPoints; } if (segment.points.size() < 4) return seedPoints; std::vector>::const_iterator indexIterator; std::vector>::const_iterator indexEnd; indexIterator = segment.points.begin(); indexEnd = segment.points.end(); ItkImagePointerType listOfPoints = CloneImage(pic); listOfPoints->FillBuffer(0); listOfPoints->SetPixel(seedPoints[0], 1); for (; indexIterator != indexEnd; ++indexIterator) { listOfPoints->SetPixel(*indexIterator, 2); } indexIterator = segment.points.begin(); indexIterator++; indexIterator++; indexEnd--; indexEnd--; for (; indexIterator != indexEnd; ++indexIterator) { bool pointFound = true; while (pointFound) { pointFound = false; itk::Index<2> index; itk::Index<2> index2; for (int xOffset = -1; xOffset < 2; ++xOffset) { for (int yOffset = -1; yOffset < 2; ++yOffset) { index = ensureIndexInImage((*indexIterator)[0] - xOffset, (*indexIterator)[1] - yOffset); index2 = index; if (listOfPoints->GetPixel(index2) > 0) continue; index[0] = index[0] - 1; index = ensureIndexInImage(index[0], index[1]); if (listOfPoints->GetPixel(index) == 1) { pointFound = true; seedPoints.push_back(index2); listOfPoints->SetPixel(index2, 1); continue; } index[0] = index[0] + 2; index = ensureIndexInImage(index[0], index[1]); if (listOfPoints->GetPixel(index) == 1) { pointFound = true; seedPoints.push_back(index2); listOfPoints->SetPixel(index2, 1); continue; } index[0] = index[0] - 1; index[1] = index[1] - 1; index = ensureIndexInImage(index[0], index[1]); if (listOfPoints->GetPixel(index) == 1) { pointFound = true; seedPoints.push_back(index2); listOfPoints->SetPixel(index2, 1); continue; } index[1] = index[1] + 2; index = ensureIndexInImage(index[0], index[1]); if (listOfPoints->GetPixel(index) == 1) { pointFound = true; seedPoints.push_back(index2); listOfPoints->SetPixel(index2, 1); continue; } } } } } return seedPoints; } int mitk::CorrectorAlgorithm::FillRegion( const std::vector> &seedPoints, itk::Image::Pointer pic) { int numberOfPixel = 0; int mode = (pic->GetPixel(seedPoints[0]) == m_FillColor); int drawColor = m_FillColor; if (mode) { drawColor = m_EraseColor; } std::vector> workPoints; workPoints = seedPoints; // workPoints.push_back(seedPoints[0]); while (workPoints.size() > 0) { itk::Index<2> currentIndex = workPoints.back(); workPoints.pop_back(); if ((pic->GetPixel(currentIndex) == m_FillColor) == mode) ++numberOfPixel; pic->SetPixel(currentIndex, drawColor); currentIndex = ensureIndexInImage(currentIndex[0] - 1, currentIndex[1]); if (pic->GetLargestPossibleRegion().IsInside(currentIndex) && (pic->GetPixel(currentIndex) == m_FillColor) == mode) workPoints.push_back(currentIndex); currentIndex = ensureIndexInImage(currentIndex[0] + 2, currentIndex[1]); if (pic->GetLargestPossibleRegion().IsInside(currentIndex) && (pic->GetPixel(currentIndex) == m_FillColor) == mode) workPoints.push_back(currentIndex); currentIndex = ensureIndexInImage(currentIndex[0] - 1, currentIndex[1] - 1); if (pic->GetLargestPossibleRegion().IsInside(currentIndex) && (pic->GetPixel(currentIndex) == m_FillColor) == mode) workPoints.push_back(currentIndex); currentIndex = ensureIndexInImage(currentIndex[0], currentIndex[1] + 2); if (pic->GetLargestPossibleRegion().IsInside(currentIndex) && (pic->GetPixel(currentIndex) == m_FillColor) == mode) workPoints.push_back(currentIndex); } return numberOfPixel; } void mitk::CorrectorAlgorithm::OverwriteImage( itk::Image::Pointer source, itk::Image::Pointer target) { typedef itk::Image ItkImageType; typedef itk::ImageRegionIterator ImageIteratorType; ImageIteratorType sourceIter(source, source->GetLargestPossibleRegion()); ImageIteratorType targetIter(target, target->GetLargestPossibleRegion()); while (!sourceIter.IsAtEnd()) { targetIter.Set(sourceIter.Get()); ++sourceIter; ++targetIter; } } bool mitk::CorrectorAlgorithm::ModifySegment(const TSegData &segment, itk::Image::Pointer pic) { typedef itk::Image::Pointer ItkImagePointerType; ItkImagePointerType firstSideImage = CloneImage(pic); ColorSegment(segment, firstSideImage); ItkImagePointerType secondSideImage = CloneImage(firstSideImage); std::vector> seedPoints = FindSeedPoints(segment, firstSideImage); if (seedPoints.size() < 1) return false; int firstSidePixel = FillRegion(seedPoints, firstSideImage); std::vector> secondSeedPoints = FindSeedPoints(segment, firstSideImage); if (secondSeedPoints.size() < 1) return false; int secondSidePixel = FillRegion(secondSeedPoints, secondSideImage); if (firstSidePixel < secondSidePixel) { OverwriteImage(firstSideImage, pic); } else { OverwriteImage(secondSideImage, pic); } return true; } diff --git a/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp index 5b19b33362..129e2dba29 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp @@ -1,1311 +1,1307 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkLabelSetWidget.h" // mitk #include #include #include #include #include #include #include #include #include #include #include // Qmitk #include #include #include // Qt #include #include #include #include #include #include #include #include #include // itk #include // todo: // berry //#include QmitkLabelSetWidget::QmitkLabelSetWidget(QWidget *parent) : QWidget(parent), m_DataStorage(nullptr), m_Completer(nullptr), m_ToolManager(nullptr) { m_Controls.setupUi(this); m_ColorSequenceRainbow.GoToBegin(); m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(m_ToolManager); m_Controls.m_LabelSearchBox->setAlwaysShowClearIcon(true); m_Controls.m_LabelSearchBox->setShowSearchIcon(true); QStringList completionList; completionList << ""; m_Completer = new QCompleter(completionList, this); m_Completer->setCaseSensitivity(Qt::CaseInsensitive); m_Controls.m_LabelSearchBox->setCompleter(m_Completer); connect(m_Controls.m_LabelSearchBox, SIGNAL(returnPressed()), this, SLOT(OnSearchLabel())); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(labelListModified(const QStringList&)), this, SLOT( // OnLabelListModified(const QStringList&)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(mergeLabel(int)), this, SLOT( OnMergeLabel(int)) ); QStringListModel *completeModel = static_cast(m_Completer->model()); completeModel->setStringList(GetLabelStringList()); m_Controls.m_LabelSearchBox->setEnabled(false); m_Controls.m_lblCaption->setText(""); InitializeTableWidget(); } QmitkLabelSetWidget::~QmitkLabelSetWidget() { } void QmitkLabelSetWidget::OnTableViewContextMenuRequested(const QPoint& /*pos*/) { int pixelValue = GetPixelValueOfSelectedItem(); QMenu *menu = new QMenu(m_Controls.m_LabelSetTableWidget); if (m_Controls.m_LabelSetTableWidget->selectedItems().size() > 1) { QAction *mergeAction = new QAction(QIcon(":/Qmitk/MergeLabels.png"), "Merge selection on current label", this); mergeAction->setEnabled(true); QObject::connect(mergeAction, SIGNAL(triggered(bool)), this, SLOT(OnMergeLabels(bool))); menu->addAction(mergeAction); QAction *removeLabelsAction = new QAction(QIcon(":/Qmitk/RemoveLabel.png"), "Remove selected labels", this); removeLabelsAction->setEnabled(true); QObject::connect(removeLabelsAction, SIGNAL(triggered(bool)), this, SLOT(OnRemoveLabels(bool))); menu->addAction(removeLabelsAction); QAction *eraseLabelsAction = new QAction(QIcon(":/Qmitk/EraseLabel.png"), "Erase selected labels", this); eraseLabelsAction->setEnabled(true); QObject::connect(eraseLabelsAction, SIGNAL(triggered(bool)), this, SLOT(OnEraseLabels(bool))); menu->addAction(eraseLabelsAction); QAction *combineAndCreateSurfaceAction = new QAction(QIcon(":/Qmitk/CreateSurface.png"), "Combine and create a surface", this); combineAndCreateSurfaceAction->setEnabled(true); QObject::connect( combineAndCreateSurfaceAction, SIGNAL(triggered(bool)), this, SLOT(OnCombineAndCreateSurface(bool))); // menu->addAction(combineAndCreateSurfaceAction); Not implemented QAction *createMasksAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create a mask for each selected label", this); createMasksAction->setEnabled(true); QObject::connect(createMasksAction, SIGNAL(triggered(bool)), this, SLOT(OnCreateMasks(bool))); // menu->addAction(createMasksAction); Not implemented QAction *combineAndCreateMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Combine and create a mask", this); combineAndCreateMaskAction->setEnabled(true); QObject::connect(combineAndCreateMaskAction, SIGNAL(triggered(bool)), this, SLOT(OnCombineAndCreateMask(bool))); // menu->addAction(combineAndCreateMaskAction); Not implemented } else { QAction *renameAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "Rename...", this); renameAction->setEnabled(true); QObject::connect(renameAction, SIGNAL(triggered(bool)), this, SLOT(OnRenameLabel(bool))); menu->addAction(renameAction); QAction *removeAction = new QAction(QIcon(":/Qmitk/RemoveLabel.png"), "Remove...", this); removeAction->setEnabled(true); QObject::connect(removeAction, SIGNAL(triggered(bool)), this, SLOT(OnRemoveLabel(bool))); menu->addAction(removeAction); QAction *eraseAction = new QAction(QIcon(":/Qmitk/EraseLabel.png"), "Erase...", this); eraseAction->setEnabled(true); QObject::connect(eraseAction, SIGNAL(triggered(bool)), this, SLOT(OnEraseLabel(bool))); menu->addAction(eraseAction); QAction *mergeAction = new QAction(QIcon(":/Qmitk/MergeLabels.png"), "Merge...", this); mergeAction->setEnabled(true); QObject::connect(mergeAction, SIGNAL(triggered(bool)), this, SLOT(OnMergeLabel(bool))); menu->addAction(mergeAction); QAction *randomColorAction = new QAction(QIcon(":/Qmitk/RandomColor.png"), "Random color", this); randomColorAction->setEnabled(true); QObject::connect(randomColorAction, SIGNAL(triggered(bool)), this, SLOT(OnRandomColor(bool))); menu->addAction(randomColorAction); QAction *viewOnlyAction = new QAction(QIcon(":/Qmitk/visible.png"), "View only", this); viewOnlyAction->setEnabled(true); QObject::connect(viewOnlyAction, SIGNAL(triggered(bool)), this, SLOT(OnSetOnlyActiveLabelVisible(bool))); menu->addAction(viewOnlyAction); QAction *viewAllAction = new QAction(QIcon(":/Qmitk/visible.png"), "View all", this); viewAllAction->setEnabled(true); QObject::connect(viewAllAction, SIGNAL(triggered(bool)), this, SLOT(OnSetAllLabelsVisible(bool))); menu->addAction(viewAllAction); QAction *hideAllAction = new QAction(QIcon(":/Qmitk/invisible.png"), "Hide all", this); hideAllAction->setEnabled(true); QObject::connect(hideAllAction, SIGNAL(triggered(bool)), this, SLOT(OnSetAllLabelsInvisible(bool))); menu->addAction(hideAllAction); QAction *lockAllAction = new QAction(QIcon(":/Qmitk/lock.png"), "Lock all", this); lockAllAction->setEnabled(true); QObject::connect(lockAllAction, SIGNAL(triggered(bool)), this, SLOT(OnLockAllLabels(bool))); menu->addAction(lockAllAction); QAction *unlockAllAction = new QAction(QIcon(":/Qmitk/unlock.png"), "Unlock all", this); unlockAllAction->setEnabled(true); QObject::connect(unlockAllAction, SIGNAL(triggered(bool)), this, SLOT(OnUnlockAllLabels(bool))); menu->addAction(unlockAllAction); QAction *createSurfaceAction = new QAction(QIcon(":/Qmitk/CreateSurface.png"), "Create surface", this); createSurfaceAction->setEnabled(true); createSurfaceAction->setMenu(new QMenu()); QAction *tmp1 = createSurfaceAction->menu()->addAction(QString("Detailed")); QAction *tmp2 = createSurfaceAction->menu()->addAction(QString("Smoothed")); QObject::connect(tmp1, SIGNAL(triggered(bool)), this, SLOT(OnCreateDetailedSurface(bool))); QObject::connect(tmp2, SIGNAL(triggered(bool)), this, SLOT(OnCreateSmoothedSurface(bool))); menu->addAction(createSurfaceAction); QAction *createMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create mask", this); createMaskAction->setEnabled(true); QObject::connect(createMaskAction, SIGNAL(triggered(bool)), this, SLOT(OnCreateMask(bool))); menu->addAction(createMaskAction); QAction *createCroppedMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create cropped mask", this); createCroppedMaskAction->setEnabled(true); QObject::connect(createCroppedMaskAction, SIGNAL(triggered(bool)), this, SLOT(OnCreateCroppedMask(bool))); // QAction* importAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "Import...", this ); // importAction->setEnabled(true); // QObject::connect( importAction, SIGNAL( triggered(bool) ), this, SLOT( OnImportSegmentationSession(bool) ) ); // menu->addAction(importAction); menu->addAction(createCroppedMaskAction); QSlider *opacitySlider = new QSlider; opacitySlider->setMinimum(0); opacitySlider->setMaximum(100); opacitySlider->setOrientation(Qt::Horizontal); QObject::connect(opacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OnOpacityChanged(int))); QLabel *_OpacityLabel = new QLabel("Opacity: "); QVBoxLayout *_OpacityWidgetLayout = new QVBoxLayout; _OpacityWidgetLayout->setContentsMargins(4, 4, 4, 4); _OpacityWidgetLayout->addWidget(_OpacityLabel); _OpacityWidgetLayout->addWidget(opacitySlider); QWidget *_OpacityWidget = new QWidget; _OpacityWidget->setLayout(_OpacityWidgetLayout); QWidgetAction *OpacityAction = new QWidgetAction(this); OpacityAction->setDefaultWidget(_OpacityWidget); // QObject::connect( m_OpacityAction, SIGNAL( changed() ), this, SLOT( OpacityActionChanged() ) ); opacitySlider->setValue(static_cast(GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetOpacity() * 100)); menu->addAction(OpacityAction); } menu->popup(QCursor::pos()); } void QmitkLabelSetWidget::OnUnlockAllLabels(bool /*value*/) { GetWorkingImage()->GetActiveLabelSet()->SetAllLabelsLocked(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnLockAllLabels(bool /*value*/) { GetWorkingImage()->GetActiveLabelSet()->SetAllLabelsLocked(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnSetAllLabelsVisible(bool /*value*/) { GetWorkingImage()->GetActiveLabelSet()->SetAllLabelsVisible(true); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnSetAllLabelsInvisible(bool /*value*/) { GetWorkingImage()->GetActiveLabelSet()->SetAllLabelsVisible(false); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnSetOnlyActiveLabelVisible(bool /*value*/) { mitk::LabelSetImage* workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); workingImage->GetActiveLabelSet()->SetAllLabelsVisible(false); workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->SetVisible(true); workingImage->GetActiveLabelSet()->UpdateLookupTable(pixelValue); this->WaitCursorOn(); const mitk::Point3D &pos = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetCenterOfMassCoordinates(); this->WaitCursorOff(); if (pos.GetVnlVector().max_value() > 0.0) { emit goToLabel(pos); } UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnMergeLabel(bool /*value*/) { QmitkSearchLabelDialog dialog(this); dialog.setWindowTitle("Select a second label.."); dialog.SetLabelSuggestionList(GetLabelStringList()); int dialogReturnValue = dialog.exec(); if (dialogReturnValue == QDialog::Rejected) return; int sourcePixelValue = -1; for (int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); i++) { if (dialog.GetLabelSetWidgetTableCompleteWord() == QString(m_Controls.m_LabelSetTableWidget->item(i, 0)->text())) sourcePixelValue = m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt(); } if (sourcePixelValue == -1) { MITK_INFO << "unknown label"; return; } int pixelValue = GetPixelValueOfSelectedItem(); GetWorkingImage()->MergeLabel(pixelValue, sourcePixelValue, GetWorkingImage()->GetActiveLayer()); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnEraseLabel(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to erase the contents of label \""; question.append(QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question(this, "Erase label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); GetWorkingImage()->EraseLabel(pixelValue); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnRemoveLabel(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to remove label \""; question.append(QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question(this, "Remove label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); GetWorkingImage()->GetActiveLabelSet()->RemoveLabel(pixelValue); GetWorkingImage()->EraseLabel(pixelValue); this->WaitCursorOff(); } ResetAllTableWidgetItems(); } void QmitkLabelSetWidget::OnRenameLabel(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QmitkNewSegmentationDialog dialog(this); dialog.setWindowTitle("Rename Label"); dialog.SetSuggestionList(m_OrganColors); dialog.SetColor(GetWorkingImage()->GetActiveLabelSet()->GetLabel(pixelValue)->GetColor()); dialog.SetSegmentationName(QString::fromStdString(GetWorkingImage()->GetActiveLabelSet()->GetLabel(pixelValue)->GetName())); if (dialog.exec() == QDialog::Rejected) { return; } QString segmentationName = dialog.GetSegmentationName(); if (segmentationName.isEmpty()) { segmentationName = "Unnamed"; } GetWorkingImage()->GetActiveLabelSet()->RenameLabel(pixelValue, segmentationName.toStdString(), dialog.GetColor()); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnCombineAndCreateMask(bool /*value*/) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ...to do... // } void QmitkLabelSetWidget::OnCreateMasks(bool /*value*/) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ..to do.. // } void QmitkLabelSetWidget::OnCombineAndCreateSurface(bool /*value*/) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ..to do.. // } void QmitkLabelSetWidget::OnEraseLabels(bool /*value*/) { QString question = "Do you really want to erase the selected labels?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Erase selected labels", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if (ranges.isEmpty()) return; std::vector VectorOfLablePixelValues; foreach (QTableWidgetSelectionRange a, ranges) for (int i = a.topRow(); i <= a.bottomRow(); i++) VectorOfLablePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt()); this->WaitCursorOn(); GetWorkingImage()->EraseLabels(VectorOfLablePixelValues, GetWorkingImage()->GetActiveLayer()); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnRemoveLabels(bool /*value*/) { QString question = "Do you really want to remove selected labels?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Remove selected labels", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if (ranges.isEmpty()) { return; } std::vector VectorOfLablePixelValues; foreach(QTableWidgetSelectionRange a, ranges) { for (int i = a.topRow(); i <= a.bottomRow(); ++i) { VectorOfLablePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt()); } } this->WaitCursorOn(); GetWorkingImage()->RemoveLabels(VectorOfLablePixelValues, GetWorkingImage()->GetActiveLayer()); this->WaitCursorOff(); } ResetAllTableWidgetItems(); } void QmitkLabelSetWidget::OnMergeLabels(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to merge selected labels into \""; question.append(QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Merge selected label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if (ranges.isEmpty()) { return; } std::vector vectorOfSourcePixelValues; foreach(QTableWidgetSelectionRange a, ranges) { for (int i = a.topRow(); i <= a.bottomRow(); ++i) { vectorOfSourcePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt()); } } this->WaitCursorOn(); GetWorkingImage()->MergeLabels(pixelValue, vectorOfSourcePixelValues, GetWorkingImage()->GetActiveLayer()); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnLockedButtonClicked() { int row = -1; for(int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); ++i) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i, LOCKED_COL)) { row = i; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { int pixelValue = m_Controls.m_LabelSetTableWidget->item(row, 0)->data(Qt::UserRole).toInt(); GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->SetLocked(!GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetLocked()); } } void QmitkLabelSetWidget::OnVisibleButtonClicked() { int row = -1; for(int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); ++i) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i, VISIBLE_COL)) { row = i; break; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { QTableWidgetItem *item = m_Controls.m_LabelSetTableWidget->item(row, 0); int pixelValue = item->data(Qt::UserRole).toInt(); GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->SetVisible(!GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetVisible()); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } } void QmitkLabelSetWidget::OnColorButtonClicked() { int row = -1; for(int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); ++i) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i, COLOR_COL)) { row = i; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { int pixelValue = m_Controls.m_LabelSetTableWidget->item(row, 0)->data(Qt::UserRole).toInt(); const mitk::Color &color = GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetColor(); QColor initial(color.GetRed() * 255, color.GetGreen() * 255, color.GetBlue() * 255); QColor qcolor = QColorDialog::getColor(initial, nullptr, QString("Change color")); if (!qcolor.isValid()) { return; } QPushButton *button = static_cast(m_Controls.m_LabelSetTableWidget->cellWidget(row, COLOR_COL)); if (!button) { return; } button->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(qcolor.red())); styleSheet.append(","); styleSheet.append(QString::number(qcolor.green())); styleSheet.append(","); styleSheet.append(QString::number(qcolor.blue())); styleSheet.append(")"); button->setStyleSheet(styleSheet); mitk::Color newColor; newColor.SetRed(qcolor.red() / 255.0); newColor.SetGreen(qcolor.green() / 255.0); newColor.SetBlue(qcolor.blue() / 255.0); GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->SetColor(newColor); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } } void QmitkLabelSetWidget::OnRandomColor(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->SetColor(m_ColorSequenceRainbow.GetNextColor()); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::SetOrganColors(const QStringList &organColors) { m_OrganColors = organColors; } void QmitkLabelSetWidget::OnActiveLabelChanged(int pixelValue) { mitk::LabelSetImage *workingImage = GetWorkingImage(); assert(workingImage); workingImage->GetActiveLabelSet()->SetActiveLabel(pixelValue); // MITK_INFO << "Active Label set to << " << pixelValue; mitk::SurfaceBasedInterpolationController *interpolator = mitk::SurfaceBasedInterpolationController::GetInstance(); if (interpolator) { interpolator->SetActiveLabel(pixelValue); } workingImage->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnItemClicked(QTableWidgetItem *item) { if (!item) return; int pixelValue = item->data(Qt::UserRole).toInt(); QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if (!ranges.empty() && ranges.back().rowCount() == 1) { SelectLabelByPixelValue(pixelValue); OnActiveLabelChanged(pixelValue); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnItemDoubleClicked(QTableWidgetItem *item) { if (!item) return; int pixelValue = item->data(Qt::UserRole).toInt(); // OnItemClicked(item); <<-- Double click first call OnItemClicked WaitCursorOn(); mitk::LabelSetImage* workingImage = GetWorkingImage(); workingImage->UpdateCenterOfMass(pixelValue, workingImage->GetActiveLayer()); const mitk::Point3D &pos = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetCenterOfMassCoordinates(); WaitCursorOff(); if (pos.GetVnlVector().max_value() > 0.0) { emit goToLabel(pos); } workingImage->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::SelectLabelByPixelValue(mitk::Label::PixelType pixelValue) { // MITK_INFO << "QmitkLabelSetWidget::SelectLabelByPixelValue " << pixelValue; if (!GetWorkingImage()->ExistLabel(pixelValue)) return; for (int row = 0; row < m_Controls.m_LabelSetTableWidget->rowCount(); row++) { if (m_Controls.m_LabelSetTableWidget->item(row, 0)->data(Qt::UserRole).toInt() == pixelValue) { m_Controls.m_LabelSetTableWidget->clearSelection(); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.m_LabelSetTableWidget->selectRow(row); m_Controls.m_LabelSetTableWidget->scrollToItem(m_Controls.m_LabelSetTableWidget->item(row, 0)); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); // SelectTableWidgetItem(m_Controls.m_LabelSetTableWidget->item(i,0)); // emit resetView(); // GetWorkingImage()->Modified(); return; } } } void QmitkLabelSetWidget::InsertTableWidgetItem(mitk::Label *label) { const mitk::Color &color = label->GetColor(); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0] * 255)); styleSheet.append(","); styleSheet.append(QString::number(color[1] * 255)); styleSheet.append(","); styleSheet.append(QString::number(color[2] * 255)); styleSheet.append(")"); QTableWidget* tableWidget = m_Controls.m_LabelSetTableWidget; int colWidth = (tableWidget->columnWidth(NAME_COL) < 180) ? 180 : tableWidget->columnWidth(NAME_COL) - 2; QString text = fontMetrics().elidedText(label->GetName().c_str(), Qt::ElideMiddle, colWidth); QTableWidgetItem *nameItem = new QTableWidgetItem(text); nameItem->setTextAlignment(Qt::AlignCenter | Qt::AlignLeft); // ---!--- // IMPORTANT: ADD PIXELVALUE TO TABLEWIDGETITEM.DATA nameItem->setData(Qt::UserRole, QVariant(label->GetValue())); // ---!--- QPushButton *pbColor = new QPushButton(tableWidget); pbColor->setFixedSize(24, 24); pbColor->setCheckable(false); pbColor->setAutoFillBackground(true); pbColor->setToolTip("Change label color"); pbColor->setStyleSheet(styleSheet); connect(pbColor, SIGNAL(clicked()), this, SLOT(OnColorButtonClicked())); QPushButton *pbLocked = new QPushButton(tableWidget); pbLocked->setFixedSize(24, 24); QIcon *iconLocked = new QIcon(); iconLocked->addFile(QString::fromUtf8(":/Qmitk/lock.png"), QSize(), QIcon::Normal, QIcon::Off); iconLocked->addFile(QString::fromUtf8(":/Qmitk/unlock.png"), QSize(), QIcon::Normal, QIcon::On); pbLocked->setIcon(*iconLocked); pbLocked->setIconSize(QSize(24, 24)); pbLocked->setCheckable(true); pbLocked->setToolTip("Lock/unlock label"); pbLocked->setChecked(!label->GetLocked()); connect(pbLocked, SIGNAL(clicked()), this, SLOT(OnLockedButtonClicked())); QPushButton *pbVisible = new QPushButton(tableWidget); pbVisible->setFixedSize(24, 24); pbVisible->setAutoRepeat(false); QIcon *iconVisible = new QIcon(); iconVisible->addFile(QString::fromUtf8(":/Qmitk/visible.png"), QSize(), QIcon::Normal, QIcon::Off); iconVisible->addFile(QString::fromUtf8(":/Qmitk/invisible.png"), QSize(), QIcon::Normal, QIcon::On); pbVisible->setIcon(*iconVisible); pbVisible->setIconSize(QSize(24, 24)); pbVisible->setCheckable(true); pbVisible->setToolTip("Show/hide label"); pbVisible->setChecked(!label->GetVisible()); connect(pbVisible, SIGNAL(clicked()), this, SLOT(OnVisibleButtonClicked())); int row = tableWidget->rowCount(); tableWidget->insertRow(row); tableWidget->setRowHeight(row, 24); tableWidget->setItem(row, 0, nameItem); tableWidget->setCellWidget(row, 1, pbLocked); tableWidget->setCellWidget(row, 2, pbColor); tableWidget->setCellWidget(row, 3, pbVisible); tableWidget->selectRow(row); // m_LabelSetImage->SetActiveLabel(label->GetPixelValue()); // m_ToolManager->WorkingDataModified.Send(); // emit activeLabelChanged(label->GetPixelValue()); if (row == 0) { tableWidget->hideRow(row); // hide exterior label } } void QmitkLabelSetWidget::UpdateAllTableWidgetItems() { mitk::LabelSetImage *workingImage = GetWorkingImage(); if (!workingImage) return; // add all labels QTableWidget* tableWidget = m_Controls.m_LabelSetTableWidget; m_LabelStringList.clear(); for(int i = 0 ; i < tableWidget->rowCount(); ++i) { UpdateTableWidgetItem(tableWidget->item(i, 0)); m_LabelStringList.append(tableWidget->item(i, 0)->text()); } OnLabelListModified(m_LabelStringList); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::UpdateTableWidgetItem(QTableWidgetItem *item) { mitk::LabelSetImage *workingImage = GetWorkingImage(); mitk::Label *label = workingImage->GetLabel(item->data(Qt::UserRole).toInt(), workingImage->GetActiveLayer()); const mitk::Color &color = label->GetColor(); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0] * 255)); styleSheet.append(","); styleSheet.append(QString::number(color[1] * 255)); styleSheet.append(","); styleSheet.append(QString::number(color[2] * 255)); styleSheet.append(")"); QTableWidget *tableWidget = m_Controls.m_LabelSetTableWidget; int colWidth = (tableWidget->columnWidth(NAME_COL) < 180) ? 180 : tableWidget->columnWidth(NAME_COL) - 2; QString text = fontMetrics().elidedText(label->GetName().c_str(), Qt::ElideMiddle, colWidth); item->setText(text); QPushButton *pbLocked = dynamic_cast(tableWidget->cellWidget(item->row(), 1)); pbLocked->setChecked(!label->GetLocked()); QPushButton *pbColor = dynamic_cast(tableWidget->cellWidget(item->row(), 2)); pbColor->setStyleSheet(styleSheet); QPushButton *pbVisible = dynamic_cast(tableWidget->cellWidget(item->row(), 3)); pbVisible->setChecked(!label->GetVisible()); if (item->row() == 0) { tableWidget->hideRow(item->row()); // hide exterior label } } void QmitkLabelSetWidget::ResetAllTableWidgetItems() { QTableWidget *tableWidget = m_Controls.m_LabelSetTableWidget; // remove all rows while (tableWidget->rowCount()) { tableWidget->removeRow(0); } mitk::LabelSetImage *workingImage = GetWorkingImage(); if (!workingImage) return; // add all labels m_LabelStringList.clear(); mitk::LabelSet::LabelContainerConstIteratorType it = workingImage->GetActiveLabelSet()->IteratorConstBegin(); mitk::LabelSet::LabelContainerConstIteratorType end = workingImage->GetActiveLabelSet()->IteratorConstEnd(); int pixelValue = -1; while (it != end) { InsertTableWidgetItem(it->second); if (workingImage->GetActiveLabel() == it->second) // get active pixelValue = it->first; m_LabelStringList.append(QString(it->second->GetName().c_str())); it++; } SelectLabelByPixelValue(pixelValue); OnLabelListModified(m_LabelStringList); std::stringstream captionText; captionText << "Number of labels: " << workingImage->GetNumberOfLabels(workingImage->GetActiveLayer()) - 1; m_Controls.m_lblCaption->setText(captionText.str().c_str()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } int QmitkLabelSetWidget::GetPixelValueOfSelectedItem() { if (m_Controls.m_LabelSetTableWidget->currentItem()) { return m_Controls.m_LabelSetTableWidget->currentItem()->data(Qt::UserRole).toInt(); } return -1; } QStringList &QmitkLabelSetWidget::GetLabelStringList() { return m_LabelStringList; } void QmitkLabelSetWidget::InitializeTableWidget() { QTableWidget *tableWidged = m_Controls.m_LabelSetTableWidget; tableWidged->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); tableWidged->setTabKeyNavigation(false); tableWidged->setAlternatingRowColors(false); tableWidged->setFocusPolicy(Qt::NoFocus); tableWidged->setColumnCount(4); tableWidged->resizeColumnToContents(NAME_COL); tableWidged->setColumnWidth(LOCKED_COL, 25); tableWidged->setColumnWidth(COLOR_COL, 25); tableWidged->setColumnWidth(VISIBLE_COL, 25); -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) tableWidged->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); -#else - tableWidged->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); -#endif tableWidged->setContextMenuPolicy(Qt::CustomContextMenu); tableWidged->horizontalHeader()->hide(); tableWidged->setSortingEnabled(false); tableWidged->verticalHeader()->hide(); tableWidged->setEditTriggers(QAbstractItemView::NoEditTriggers); tableWidged->setSelectionMode(QAbstractItemView::ExtendedSelection); tableWidged->setSelectionBehavior(QAbstractItemView::SelectRows); connect(tableWidged, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(OnItemClicked(QTableWidgetItem *))); connect( tableWidged, SIGNAL(itemDoubleClicked(QTableWidgetItem *)), this, SLOT(OnItemDoubleClicked(QTableWidgetItem *))); connect(tableWidged, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(OnTableViewContextMenuRequested(const QPoint &))); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(activeLabelChanged(int)), this, SLOT(OnActiveLabelChanged(int)) // ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(importSegmentation()), this, SLOT( OnImportSegmentation()) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(importLabeledImage()), this, SLOT( OnImportLabeledImage()) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(renameLabel(int, const mitk::Color&, const std::string&)), this, // SLOT(OnRenameLabel(int, const mitk::Color&, const std::string&)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createSurface(int, bool)), this, SLOT(OnCreateSurface(int, bool)) // ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(toggleOutline(bool)), this, SLOT(OnToggleOutline(bool)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(goToLabel(const mitk::Point3D&)), this, SIGNAL(goToLabel(const // mitk::Point3D&)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(combineAndCreateSurface( const QList& // )), // this, SLOT(OnCombineAndCreateSurface( const QList&)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createMask(int)), this, SLOT(OnCreateMask(int)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createCroppedMask(int)), this, SLOT(OnCreateCroppedMask(int)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(combineAndCreateMask( const QList& // )), // this, SLOT(OnCombineAndCreateMask( const QList&)) ); } void QmitkLabelSetWidget::OnOpacityChanged(int value) { int pixelValue = GetPixelValueOfSelectedItem(); float opacity = static_cast(value) / 100.0f; GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->SetOpacity(opacity); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } void QmitkLabelSetWidget::setEnabled(bool enabled) { QWidget::setEnabled(enabled); UpdateControls(); } void QmitkLabelSetWidget::SetDataStorage(mitk::DataStorage *storage) { m_DataStorage = storage; } void QmitkLabelSetWidget::OnSearchLabel() { std::string text = m_Controls.m_LabelSearchBox->text().toStdString(); int pixelValue = -1; int row = -1; for(int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); ++i) { if( m_Controls.m_LabelSetTableWidget->item(i, 0)->text().toStdString().compare(text) == 0) { pixelValue = m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt(); row = i; break; } } if (pixelValue == -1) { return; } GetWorkingImage()->GetActiveLabelSet()->SetActiveLabel(pixelValue); QTableWidgetItem *nameItem = m_Controls.m_LabelSetTableWidget->item(row, NAME_COL); if (!nameItem) { return; } m_Controls.m_LabelSetTableWidget->clearSelection(); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.m_LabelSetTableWidget->selectRow(row); m_Controls.m_LabelSetTableWidget->scrollToItem(nameItem); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); GetWorkingImage()->GetActiveLabelSet()->SetActiveLabel(pixelValue); this->WaitCursorOn(); mitk::Point3D pos = GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetCenterOfMassCoordinates(); m_ToolManager->WorkingDataChanged(); if (pos.GetVnlVector().max_value() > 0.0) { emit goToLabel(pos); } else { GetWorkingImage()->UpdateCenterOfMass(pixelValue, GetWorkingImage()->GetActiveLayer()); mitk::Point3D pos = GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetCenterOfMassCoordinates(); emit goToLabel(pos); } this->WaitCursorOff(); } void QmitkLabelSetWidget::OnLabelListModified(const QStringList &list) { QStringListModel *completeModel = static_cast(m_Completer->model()); completeModel->setStringList(list); } mitk::LabelSetImage *QmitkLabelSetWidget::GetWorkingImage() { mitk::DataNode *workingNode = GetWorkingNode(); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); return workingImage; } mitk::DataNode *QmitkLabelSetWidget::GetWorkingNode() { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); return workingNode; } void QmitkLabelSetWidget::UpdateControls() { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); bool hasWorkingData = (workingNode != nullptr); m_Controls.m_LabelSetTableWidget->setEnabled(hasWorkingData); m_Controls.m_LabelSearchBox->setEnabled(hasWorkingData); if (!hasWorkingData) return; QStringListModel *completeModel = static_cast(m_Completer->model()); completeModel->setStringList(GetLabelStringList()); } void QmitkLabelSetWidget::OnCreateCroppedMask(bool) { m_ToolManager->ActivateTool(-1); mitk::LabelSetImage *workingImage = GetWorkingImage(); mitk::Image::Pointer maskImage; int pixelValue = GetPixelValueOfSelectedItem(); try { this->WaitCursorOn(); mitk::AutoCropImageFilter::Pointer cropFilter = mitk::AutoCropImageFilter::New(); cropFilter->SetInput(workingImage->CreateLabelMask(pixelValue)); cropFilter->SetBackgroundValue(0); cropFilter->SetMarginFactor(1.15); cropFilter->Update(); maskImage = cropFilter->GetOutput(); this->WaitCursorOff(); } catch (mitk::Exception &e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } if (maskImage.IsNull()) { QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } mitk::DataNode::Pointer maskNode = mitk::DataNode::New(); std::string name = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetName(); name += "-mask"; maskNode->SetName(name); maskNode->SetData(maskImage); maskNode->SetBoolProperty("binary", true); maskNode->SetBoolProperty("outline binary", true); maskNode->SetBoolProperty("outline binary shadow", true); maskNode->SetFloatProperty("outline width", 2.0); maskNode->SetColor(workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetColor()); maskNode->SetOpacity(1.0); m_DataStorage->Add(maskNode, GetWorkingNode()); } void QmitkLabelSetWidget::OnCreateMask(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::LabelSetImage *workingImage = GetWorkingImage(); mitk::Image::Pointer maskImage; int pixelValue = GetPixelValueOfSelectedItem(); try { this->WaitCursorOn(); maskImage = workingImage->CreateLabelMask(pixelValue); this->WaitCursorOff(); } catch (mitk::Exception &e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } if (maskImage.IsNull()) { QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } mitk::DataNode::Pointer maskNode = mitk::DataNode::New(); std::string name = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetName(); name += "-mask"; maskNode->SetName(name); maskNode->SetData(maskImage); maskNode->SetBoolProperty("binary", true); maskNode->SetBoolProperty("outline binary", true); maskNode->SetBoolProperty("outline binary shadow", true); maskNode->SetFloatProperty("outline width", 2.0); maskNode->SetColor(workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetColor()); maskNode->SetOpacity(1.0); m_DataStorage->Add(maskNode, GetWorkingNode()); } void QmitkLabelSetWidget::OnToggleOutline(bool value) { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); workingNode->SetBoolProperty("labelset.contour.active", value); workingNode->GetData()->Modified(); // fixme: workaround to force data-type rendering (and not only property-type) mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnCreateSmoothedSurface(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::DataNode::Pointer workingNode = GetWorkingNode(); mitk::LabelSetImage *workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); mitk::LabelSetImageToSurfaceThreadedFilter::Pointer surfaceFilter = mitk::LabelSetImageToSurfaceThreadedFilter::New(); itk::SimpleMemberCommand::Pointer successCommand = itk::SimpleMemberCommand::New(); successCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ResultAvailable(), successCommand); itk::SimpleMemberCommand::Pointer errorCommand = itk::SimpleMemberCommand::New(); errorCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ProcessingError(), errorCommand); mitk::DataNode::Pointer groupNode = workingNode; surfaceFilter->SetPointerParameter("Group node", groupNode); surfaceFilter->SetPointerParameter("Input", workingImage); surfaceFilter->SetParameter("RequestedLabel", pixelValue); surfaceFilter->SetParameter("Smooth", true); surfaceFilter->SetDataStorage(*m_DataStorage); mitk::StatusBar::GetInstance()->DisplayText("Surface creation is running in background..."); try { surfaceFilter->StartAlgorithm(); } catch (mitk::Exception &e) { MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Surface", "Could not create a surface mesh out of the selected label. See error log for details.\n"); } } void QmitkLabelSetWidget::OnCreateDetailedSurface(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::DataNode::Pointer workingNode = GetWorkingNode(); mitk::LabelSetImage *workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); mitk::LabelSetImageToSurfaceThreadedFilter::Pointer surfaceFilter = mitk::LabelSetImageToSurfaceThreadedFilter::New(); itk::SimpleMemberCommand::Pointer successCommand = itk::SimpleMemberCommand::New(); successCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ResultAvailable(), successCommand); itk::SimpleMemberCommand::Pointer errorCommand = itk::SimpleMemberCommand::New(); errorCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ProcessingError(), errorCommand); mitk::DataNode::Pointer groupNode = workingNode; surfaceFilter->SetPointerParameter("Group node", groupNode); surfaceFilter->SetPointerParameter("Input", workingImage); surfaceFilter->SetParameter("RequestedLabel", pixelValue); surfaceFilter->SetParameter("Smooth", false); surfaceFilter->SetDataStorage(*m_DataStorage); mitk::StatusBar::GetInstance()->DisplayText("Surface creation is running in background..."); try { surfaceFilter->StartAlgorithm(); } catch (mitk::Exception &e) { MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Surface", "Could not create a surface mesh out of the selected label. See error log for details.\n"); } } void QmitkLabelSetWidget::OnImportLabeledImage() { /* m_ToolManager->ActivateTool(-1); mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); assert(referenceNode); // Ask the user for a list of files to open QStringList fileNames = QFileDialog::getOpenFileNames( this, "Open Image", m_LastFileOpenPath, mitk::CoreObjectFactory::GetInstance()->GetFileExtensions()); if (fileNames.empty()) return; try { this->WaitCursorOn(); mitk::Image::Pointer image = mitk::IOUtil::Load( fileNames.front().toStdString() ); if (image.IsNull()) { this->WaitCursorOff(); QMessageBox::information(this, "Import Labeled Image", "Could not load the selected segmentation.\n"); return; } mitk::LabelSetImage::Pointer newImage = mitk::LabelSetImage::New(); newImage->InitializeByLabeledImage(image); this->WaitCursorOff(); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); std::string newName = referenceNode->GetName(); newName += "-labels"; newNode->SetName(newName); newNode->SetData(newImage); m_DataStorage->Add(newNode, referenceNode); } catch (mitk::Exception & e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Import Labeled Image", "Could not load the selected segmentation. See error log for details.\n"); return; } this->UpdateControls(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); */ } void QmitkLabelSetWidget::OnImportSegmentation() { /* m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast( workingNode->GetData() ); assert(workingImage); std::string fileExtensions("Segmentation files (*.lset);;"); QString qfileName = QFileDialog::getOpenFileName(this, "Import Segmentation", m_LastFileOpenPath, fileExtensions.c_str() ); if (qfileName.isEmpty() ) return; mitk::NrrdLabelSetImageReader::Pointer reader = mitk::NrrdLabelSetImageReader::New(); reader->SetFileName(qfileName.toLatin1()); try { this->WaitCursorOn(); reader->Update(); mitk::LabelSetImage::Pointer newImage = reader->GetOutput(); workingImage->Concatenate(newImage); this->WaitCursorOff(); } catch ( mitk::Exception& e ) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Import Segmentation", "Could not import the selected segmentation session.\n See error log for details.\n"); } */ mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::WaitCursorOn() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } void QmitkLabelSetWidget::WaitCursorOff() { this->RestoreOverrideCursor(); } void QmitkLabelSetWidget::RestoreOverrideCursor() { QApplication::restoreOverrideCursor(); } void QmitkLabelSetWidget::OnThreadedCalculationDone() { mitk::StatusBar::GetInstance()->Clear(); } diff --git a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp index 293eee4487..cbc7025dbb 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp @@ -1,1356 +1,1356 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkSlicesInterpolator.h" #include "QmitkSelectableGLWidget.h" #include "QmitkStdMultiWidget.h" #include "mitkApplyDiffImageOperation.h" #include "mitkColorProperty.h" #include "mitkCoreObjectFactory.h" #include "mitkDiffImageApplier.h" #include "mitkInteractionConst.h" #include "mitkLevelWindowProperty.h" #include "mitkOperationEvent.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkProgressBar.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkSegTool2D.h" #include "mitkSliceNavigationController.h" #include "mitkSurfaceToImageFilter.h" #include "mitkToolManager.h" #include "mitkUndoController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) float SURFACE_COLOR_RGB[3] = {0.49f, 1.0f, 0.16f}; const std::map QmitkSlicesInterpolator::createActionToSliceDimension() { std::map actionToSliceDimension; foreach (mitk::SliceNavigationController *slicer, m_ControllerToDeleteObserverTag.keys()) { actionToSliceDimension[new QAction(QString::fromStdString(slicer->GetViewDirectionAsString()), nullptr)] = slicer; } return actionToSliceDimension; } QmitkSlicesInterpolator::QmitkSlicesInterpolator(QWidget *parent, const char * /*name*/) : QWidget(parent), // ACTION_TO_SLICEDIMENSION( createActionToSliceDimension() ), m_Interpolator(mitk::SegmentationInterpolationController::New()), m_SurfaceInterpolator(mitk::SurfaceInterpolationController::GetInstance()), m_ToolManager(nullptr), m_Initialized(false), m_LastSNC(nullptr), m_LastSliceIndex(0), m_2DInterpolationEnabled(false), m_3DInterpolationEnabled(false), m_FirstRun(true) { m_GroupBoxEnableExclusiveInterpolationMode = new QGroupBox("Interpolation", this); QVBoxLayout *vboxLayout = new QVBoxLayout(m_GroupBoxEnableExclusiveInterpolationMode); m_EdgeDetector = mitk::FeatureBasedEdgeDetectionFilter::New(); m_PointScorer = mitk::PointCloudScoringFilter::New(); m_CmbInterpolation = new QComboBox(m_GroupBoxEnableExclusiveInterpolationMode); m_CmbInterpolation->addItem("Disabled"); m_CmbInterpolation->addItem("2-Dimensional"); m_CmbInterpolation->addItem("3-Dimensional"); vboxLayout->addWidget(m_CmbInterpolation); m_BtnApply2D = new QPushButton("Confirm for single slice", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApply2D); m_BtnApplyForAllSlices2D = new QPushButton("Confirm for all slices", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApplyForAllSlices2D); m_BtnApply3D = new QPushButton("Confirm", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApply3D); m_BtnSuggestPlane = new QPushButton("Suggest a plane", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnSuggestPlane); m_BtnReinit3DInterpolation = new QPushButton("Reinit Interpolation", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnReinit3DInterpolation); m_ChkShowPositionNodes = new QCheckBox("Show Position Nodes", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_ChkShowPositionNodes); this->HideAllInterpolationControls(); connect(m_CmbInterpolation, SIGNAL(currentIndexChanged(int)), this, SLOT(OnInterpolationMethodChanged(int))); connect(m_BtnApply2D, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked())); connect(m_BtnApplyForAllSlices2D, SIGNAL(clicked()), this, SLOT(OnAcceptAllInterpolationsClicked())); connect(m_BtnApply3D, SIGNAL(clicked()), this, SLOT(OnAccept3DInterpolationClicked())); connect(m_BtnSuggestPlane, SIGNAL(clicked()), this, SLOT(OnSuggestPlaneClicked())); connect(m_BtnReinit3DInterpolation, SIGNAL(clicked()), this, SLOT(OnReinit3DInterpolation())); connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SLOT(OnShowMarkers(bool))); connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SIGNAL(SignalShowMarkerNodes(bool))); QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(m_GroupBoxEnableExclusiveInterpolationMode); this->setLayout(layout); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnInterpolationInfoChanged); InterpolationInfoChangedObserverTag = m_Interpolator->AddObserver(itk::ModifiedEvent(), command); itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged); SurfaceInterpolationInfoChangedObserverTag = m_SurfaceInterpolator->AddObserver(itk::ModifiedEvent(), command2); // feedback node and its visualization properties m_FeedbackNode = mitk::DataNode::New(); mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties(m_FeedbackNode); m_FeedbackNode->SetProperty("binary", mitk::BoolProperty::New(true)); m_FeedbackNode->SetProperty("outline binary", mitk::BoolProperty::New(true)); m_FeedbackNode->SetProperty("color", mitk::ColorProperty::New(255.0, 255.0, 0.0)); m_FeedbackNode->SetProperty("texture interpolation", mitk::BoolProperty::New(false)); m_FeedbackNode->SetProperty("layer", mitk::IntProperty::New(20)); m_FeedbackNode->SetProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(0, 1))); m_FeedbackNode->SetProperty("name", mitk::StringProperty::New("Interpolation feedback")); m_FeedbackNode->SetProperty("opacity", mitk::FloatProperty::New(0.8)); m_FeedbackNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_InterpolatedSurfaceNode = mitk::DataNode::New(); m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); m_InterpolatedSurfaceNode->SetProperty("name", mitk::StringProperty::New("Surface Interpolation feedback")); m_InterpolatedSurfaceNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); m_InterpolatedSurfaceNode->SetProperty("line width", mitk::FloatProperty::New(4.0f)); m_InterpolatedSurfaceNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_InterpolatedSurfaceNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_InterpolatedSurfaceNode->SetVisibility(false); m_3DContourNode = mitk::DataNode::New(); m_3DContourNode->SetProperty("color", mitk::ColorProperty::New(0.0, 0.0, 0.0)); m_3DContourNode->SetProperty("hidden object", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty("name", mitk::StringProperty::New("Drawn Contours")); m_3DContourNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); m_3DContourNode->SetProperty("material.wireframeLineWidth", mitk::FloatProperty::New(2.0f)); m_3DContourNode->SetProperty("3DContourContainer", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_3DContourNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); m_3DContourNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))); m_3DContourNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))); m_3DContourNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); QWidget::setContentsMargins(0, 0, 0, 0); if (QWidget::layout() != nullptr) { QWidget::layout()->setContentsMargins(0, 0, 0, 0); } // For running 3D Interpolation in background // create a QFuture and a QFutureWatcher connect(&m_Watcher, SIGNAL(started()), this, SLOT(StartUpdateInterpolationTimer())); connect(&m_Watcher, SIGNAL(finished()), this, SLOT(OnSurfaceInterpolationFinished())); connect(&m_Watcher, SIGNAL(finished()), this, SLOT(StopUpdateInterpolationTimer())); m_Timer = new QTimer(this); connect(m_Timer, SIGNAL(timeout()), this, SLOT(ChangeSurfaceColor())); } void QmitkSlicesInterpolator::SetDataStorage(mitk::DataStorage::Pointer storage) { if (m_DataStorage == storage) { return; } if (m_DataStorage.IsNotNull()) { m_DataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkSlicesInterpolator::NodeRemoved) ); } m_DataStorage = storage; m_SurfaceInterpolator->SetDataStorage(storage); if (m_DataStorage.IsNotNull()) { m_DataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkSlicesInterpolator::NodeRemoved) ); } } mitk::DataStorage *QmitkSlicesInterpolator::GetDataStorage() { if (m_DataStorage.IsNotNull()) { return m_DataStorage; } else { return nullptr; } } void QmitkSlicesInterpolator::Initialize(mitk::ToolManager *toolManager, const QList &controllers) { Q_ASSERT(!controllers.empty()); if (m_Initialized) { // remove old observers Uninitialize(); } m_ToolManager = toolManager; if (m_ToolManager) { // set enabled only if a segmentation is selected mitk::DataNode *node = m_ToolManager->GetWorkingData(0); QWidget::setEnabled(node != nullptr); // react whenever the set of selected segmentation changes m_ToolManager->WorkingDataChanged += mitk::MessageDelegate(this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified); // connect to the slice navigation controller. after each change, call the interpolator foreach (mitk::SliceNavigationController *slicer, controllers) { // Has to be initialized m_LastSNC = slicer; m_TimeStep.insert(slicer, slicer->GetTime()->GetPos()); itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSliceNavigationControllerDeleted); m_ControllerToDeleteObserverTag.insert(slicer, slicer->AddObserver(itk::DeleteEvent(), deleteCommand)); itk::MemberCommand::Pointer timeChangedCommand = itk::MemberCommand::New(); timeChangedCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnTimeChanged); m_ControllerToTimeObserverTag.insert( slicer, slicer->AddObserver(mitk::SliceNavigationController::TimeGeometryEvent(nullptr, 0), timeChangedCommand)); itk::MemberCommand::Pointer sliceChangedCommand = itk::MemberCommand::New(); sliceChangedCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSliceChanged); m_ControllerToSliceObserverTag.insert( slicer, slicer->AddObserver(mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), sliceChangedCommand)); } ACTION_TO_SLICEDIMENSION = createActionToSliceDimension(); } m_Initialized = true; } void QmitkSlicesInterpolator::Uninitialize() { if (m_ToolManager.IsNotNull()) { m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate(this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified); } foreach (mitk::SliceNavigationController *slicer, m_ControllerToSliceObserverTag.keys()) { slicer->RemoveObserver(m_ControllerToDeleteObserverTag.take(slicer)); slicer->RemoveObserver(m_ControllerToTimeObserverTag.take(slicer)); slicer->RemoveObserver(m_ControllerToSliceObserverTag.take(slicer)); } ACTION_TO_SLICEDIMENSION.clear(); m_ToolManager = nullptr; m_Initialized = false; } QmitkSlicesInterpolator::~QmitkSlicesInterpolator() { if (m_Initialized) { // remove old observers Uninitialize(); } WaitForFutures(); if (m_DataStorage.IsNotNull()) { m_DataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkSlicesInterpolator::NodeRemoved) ); if (m_DataStorage->Exists(m_3DContourNode)) m_DataStorage->Remove(m_3DContourNode); if (m_DataStorage->Exists(m_InterpolatedSurfaceNode)) m_DataStorage->Remove(m_InterpolatedSurfaceNode); } // remove observer m_Interpolator->RemoveObserver(InterpolationInfoChangedObserverTag); m_SurfaceInterpolator->RemoveObserver(SurfaceInterpolationInfoChangedObserverTag); delete m_Timer; } /** External enableization... */ void QmitkSlicesInterpolator::setEnabled(bool enable) { QWidget::setEnabled(enable); // Set the gui elements of the different interpolation modi enabled if (enable) { if (m_2DInterpolationEnabled) { this->Show2DInterpolationControls(true); m_Interpolator->Activate2DInterpolation(true); } else if (m_3DInterpolationEnabled) { this->Show3DInterpolationControls(true); this->Show3DInterpolationResult(true); } } // Set all gui elements of the interpolation disabled else { this->HideAllInterpolationControls(); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::On2DInterpolationEnabled(bool status) { OnInterpolationActivated(status); m_Interpolator->Activate2DInterpolation(status); } void QmitkSlicesInterpolator::On3DInterpolationEnabled(bool status) { On3DInterpolationActivated(status); } void QmitkSlicesInterpolator::OnInterpolationDisabled(bool status) { if (status) { OnInterpolationActivated(!status); On3DInterpolationActivated(!status); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::HideAllInterpolationControls() { this->Show2DInterpolationControls(false); this->Show3DInterpolationControls(false); } void QmitkSlicesInterpolator::Show2DInterpolationControls(bool show) { m_BtnApply2D->setVisible(show); m_BtnApplyForAllSlices2D->setVisible(show); } void QmitkSlicesInterpolator::Show3DInterpolationControls(bool show) { m_BtnApply3D->setVisible(show); m_BtnSuggestPlane->setVisible(show); m_ChkShowPositionNodes->setVisible(show); m_BtnReinit3DInterpolation->setVisible(show); } void QmitkSlicesInterpolator::OnInterpolationMethodChanged(int index) { switch (index) { case 0: // Disabled m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation"); this->HideAllInterpolationControls(); this->OnInterpolationActivated(false); this->On3DInterpolationActivated(false); this->Show3DInterpolationResult(false); m_Interpolator->Activate2DInterpolation(false); break; case 1: // 2D m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)"); this->HideAllInterpolationControls(); this->Show2DInterpolationControls(true); this->OnInterpolationActivated(true); this->On3DInterpolationActivated(false); m_Interpolator->Activate2DInterpolation(true); break; case 2: // 3D m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)"); this->HideAllInterpolationControls(); this->Show3DInterpolationControls(true); this->OnInterpolationActivated(false); this->On3DInterpolationActivated(true); m_Interpolator->Activate2DInterpolation(false); break; default: MITK_ERROR << "Unknown interpolation method!"; m_CmbInterpolation->setCurrentIndex(0); break; } } void QmitkSlicesInterpolator::OnShowMarkers(bool state) { mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = m_DataStorage->GetSubset(mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { it->Value()->SetProperty("helper object", mitk::BoolProperty::New(!state)); } } void QmitkSlicesInterpolator::OnToolManagerWorkingDataModified() { if (m_ToolManager->GetWorkingData(0) != nullptr) { m_Segmentation = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); m_BtnReinit3DInterpolation->setEnabled(true); } else { // If no workingdata is set, remove the interpolation feedback this->GetDataStorage()->Remove(m_FeedbackNode); m_FeedbackNode->SetData(nullptr); this->GetDataStorage()->Remove(m_3DContourNode); m_3DContourNode->SetData(nullptr); this->GetDataStorage()->Remove(m_InterpolatedSurfaceNode); m_InterpolatedSurfaceNode->SetData(nullptr); m_BtnReinit3DInterpolation->setEnabled(false); return; } // Updating the current selected segmentation for the 3D interpolation SetCurrentContourListID(); if (m_2DInterpolationEnabled) { OnInterpolationActivated(true); // re-initialize if needed } this->CheckSupportedImageDimension(); } void QmitkSlicesInterpolator::OnToolManagerReferenceDataModified() { } void QmitkSlicesInterpolator::OnTimeChanged(itk::Object *sender, const itk::EventObject &e) { // Check if we really have a GeometryTimeEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController *slicer = dynamic_cast(sender); Q_ASSERT(slicer); m_TimeStep[slicer] = slicer->GetTime()->GetPos(); m_SurfaceInterpolator->SetCurrentTimeStep(slicer->GetTime()->GetPos()); if (m_LastSNC == slicer) { slicer->SendSlice(); // will trigger a new interpolation } } void QmitkSlicesInterpolator::OnSliceChanged(itk::Object *sender, const itk::EventObject &e) { // Check whether we really have a GeometrySliceEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController *slicer = dynamic_cast(sender); if (TranslateAndInterpolateChangedSlice(e, slicer)) { slicer->GetRenderer()->RequestUpdate(); } } bool QmitkSlicesInterpolator::TranslateAndInterpolateChangedSlice(const itk::EventObject &e, mitk::SliceNavigationController *slicer) { if (!m_2DInterpolationEnabled) return false; try { const mitk::SliceNavigationController::GeometrySliceEvent &event = dynamic_cast(e); mitk::TimeGeometry *tsg = event.GetTimeGeometry(); if (tsg && m_TimeStep.contains(slicer)) { mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast(tsg->GetGeometryForTimeStep(m_TimeStep[slicer]).GetPointer()); if (slicedGeometry) { m_LastSNC = slicer; mitk::PlaneGeometry *plane = dynamic_cast(slicedGeometry->GetPlaneGeometry(event.GetPos())); if (plane) Interpolate(plane, m_TimeStep[slicer], slicer); return true; } } } - catch (std::bad_cast) + catch (const std::bad_cast &) { return false; // so what } return false; } void QmitkSlicesInterpolator::Interpolate(mitk::PlaneGeometry *plane, unsigned int timeStep, mitk::SliceNavigationController *slicer) { if (m_ToolManager) { mitk::DataNode *node = m_ToolManager->GetWorkingData(0); if (node) { m_Segmentation = dynamic_cast(node->GetData()); if (m_Segmentation) { int clickedSliceDimension(-1); int clickedSliceIndex(-1); // calculate real slice position, i.e. slice of the image and not slice of the TimeSlicedGeometry mitk::SegTool2D::DetermineAffectedImageSlice(m_Segmentation, plane, clickedSliceDimension, clickedSliceIndex); mitk::Image::Pointer interpolation = m_Interpolator->Interpolate(clickedSliceDimension, clickedSliceIndex, plane, timeStep); m_FeedbackNode->SetData(interpolation); m_LastSNC = slicer; m_LastSliceIndex = clickedSliceIndex; } } } } void QmitkSlicesInterpolator::OnSurfaceInterpolationFinished() { mitk::Surface::Pointer interpolatedSurface = m_SurfaceInterpolator->GetInterpolationResult(); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); if (interpolatedSurface.IsNotNull() && workingNode && workingNode->IsVisible( mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) { m_BtnApply3D->setEnabled(true); m_BtnSuggestPlane->setEnabled(true); m_InterpolatedSurfaceNode->SetData(interpolatedSurface); m_3DContourNode->SetData(m_SurfaceInterpolator->GetContoursAsSurface()); this->Show3DInterpolationResult(true); if (!m_DataStorage->Exists(m_InterpolatedSurfaceNode)) { m_DataStorage->Add(m_InterpolatedSurfaceNode); } if (!m_DataStorage->Exists(m_3DContourNode)) { m_DataStorage->Add(m_3DContourNode, workingNode); } } else if (interpolatedSurface.IsNull()) { m_BtnApply3D->setEnabled(false); m_BtnSuggestPlane->setEnabled(false); if (m_DataStorage->Exists(m_InterpolatedSurfaceNode)) { this->Show3DInterpolationResult(false); } } m_BtnReinit3DInterpolation->setEnabled(true); foreach (mitk::SliceNavigationController *slicer, m_ControllerToTimeObserverTag.keys()) { slicer->GetRenderer()->RequestUpdate(); } } void QmitkSlicesInterpolator::OnAcceptInterpolationClicked() { if (m_Segmentation && m_FeedbackNode->GetData()) { // Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk // reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); // Set slice as input mitk::Image::Pointer slice = dynamic_cast(m_FeedbackNode->GetData()); reslice->SetInputSlice(slice->GetSliceData()->GetVtkImageAccessor(slice)->GetVtkImageData()); // set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput(m_Segmentation); unsigned int timestep = m_LastSNC->GetTime()->GetPos(); extractor->SetTimeStep(timestep); extractor->SetWorldGeometry(m_LastSNC->GetCurrentPlaneGeometry()); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry(m_Segmentation->GetTimeGeometry()->GetGeometryForTimeStep(timestep)); extractor->Modified(); extractor->Update(); // the image was modified within the pipeline, but not marked so m_Segmentation->Modified(); m_Segmentation->GetVtkImageData()->Modified(); m_FeedbackNode->SetData(nullptr); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::AcceptAllInterpolations(mitk::SliceNavigationController *slicer) { /* * What exactly is done here: * 1. We create an empty diff image for the current segmentation * 2. All interpolated slices are written into the diff image * 3. Then the diffimage is applied to the original segmentation */ if (m_Segmentation) { mitk::Image::Pointer image3D = m_Segmentation; unsigned int timeStep(slicer->GetTime()->GetPos()); if (m_Segmentation->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(m_Segmentation); timeSelector->SetTimeNr(timeStep); timeSelector->Update(); image3D = timeSelector->GetOutput(); } // create a empty diff image for the undo operation mitk::Image::Pointer diffImage = mitk::Image::New(); diffImage->Initialize(image3D); // Create scope for ImageWriteAccessor so that the accessor is destroyed // after the image is initialized. Otherwise later image access will lead to an error { mitk::ImageWriteAccessor imAccess(diffImage); // Set all pixels to zero mitk::PixelType pixelType(mitk::MakeScalarPixelType()); // For legacy purpose support former pixel type of segmentations (before multilabel) if (m_Segmentation->GetImageDescriptor()->GetChannelDescriptor().GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR) { pixelType = mitk::MakeScalarPixelType(); } memset(imAccess.GetData(), 0, (pixelType.GetBpe() >> 3) * diffImage->GetDimension(0) * diffImage->GetDimension(1) * diffImage->GetDimension(2)); } // Since we need to shift the plane it must be clone so that the original plane isn't altered mitk::PlaneGeometry::Pointer reslicePlane = slicer->GetCurrentPlaneGeometry()->Clone(); int sliceDimension(-1); int sliceIndex(-1); mitk::SegTool2D::DetermineAffectedImageSlice(m_Segmentation, reslicePlane, sliceDimension, sliceIndex); unsigned int zslices = m_Segmentation->GetDimension(sliceDimension); mitk::ProgressBar::GetInstance()->AddStepsToDo(zslices); mitk::Point3D origin = reslicePlane->GetOrigin(); unsigned int totalChangedSlices(0); for (unsigned int sliceIndex = 0; sliceIndex < zslices; ++sliceIndex) { // Transforming the current origin of the reslice plane // so that it matches the one of the next slice m_Segmentation->GetSlicedGeometry()->WorldToIndex(origin, origin); origin[sliceDimension] = sliceIndex; m_Segmentation->GetSlicedGeometry()->IndexToWorld(origin, origin); reslicePlane->SetOrigin(origin); // Set the slice as 'input' mitk::Image::Pointer interpolation = m_Interpolator->Interpolate(sliceDimension, sliceIndex, reslicePlane, timeStep); if (interpolation.IsNotNull()) // we don't check if interpolation is necessary/sensible - but m_Interpolator does { // Setting up the reslicing pipeline which allows us to write the interpolation results back into // the image volume vtkSmartPointer reslice = vtkSmartPointer::New(); // set overwrite mode to true to write back to the image volume reslice->SetInputSlice(interpolation->GetSliceData()->GetVtkImageAccessor(interpolation)->GetVtkImageData()); reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer diffslicewriter = mitk::ExtractSliceFilter::New(reslice); diffslicewriter->SetInput(diffImage); diffslicewriter->SetTimeStep(0); diffslicewriter->SetWorldGeometry(reslicePlane); diffslicewriter->SetVtkOutputRequest(true); diffslicewriter->SetResliceTransformByGeometry(diffImage->GetTimeGeometry()->GetGeometryForTimeStep(0)); diffslicewriter->Modified(); diffslicewriter->Update(); ++totalChangedSlices; } mitk::ProgressBar::GetInstance()->Progress(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (totalChangedSlices > 0) { // store undo stack items if (true) { // create do/undo operations mitk::ApplyDiffImageOperation *doOp = new mitk::ApplyDiffImageOperation(mitk::OpTEST, m_Segmentation, diffImage, timeStep); mitk::ApplyDiffImageOperation *undoOp = new mitk::ApplyDiffImageOperation(mitk::OpTEST, m_Segmentation, diffImage, timeStep); undoOp->SetFactor(-1.0); std::stringstream comment; comment << "Confirm all interpolations (" << totalChangedSlices << ")"; mitk::OperationEvent *undoStackItem = new mitk::OperationEvent(mitk::DiffImageApplier::GetInstanceForUndo(), doOp, undoOp, comment.str()); mitk::OperationEvent::IncCurrGroupEventId(); mitk::OperationEvent::IncCurrObjectEventId(); mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent(undoStackItem); // acutally apply the changes here to the original image mitk::DiffImageApplier::GetInstanceForUndo()->ExecuteOperation(doOp); } } m_FeedbackNode->SetData(nullptr); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::FinishInterpolation(mitk::SliceNavigationController *slicer) { // this redirect is for calling from outside if (slicer == nullptr) OnAcceptAllInterpolationsClicked(); else AcceptAllInterpolations(slicer); } void QmitkSlicesInterpolator::OnAcceptAllInterpolationsClicked() { QMenu orientationPopup(this); std::map::const_iterator it; for (it = ACTION_TO_SLICEDIMENSION.begin(); it != ACTION_TO_SLICEDIMENSION.end(); it++) orientationPopup.addAction(it->first); connect(&orientationPopup, SIGNAL(triggered(QAction *)), this, SLOT(OnAcceptAllPopupActivated(QAction *))); orientationPopup.exec(QCursor::pos()); } void QmitkSlicesInterpolator::OnAccept3DInterpolationClicked() { if (m_InterpolatedSurfaceNode.IsNotNull() && m_InterpolatedSurfaceNode->GetData()) { mitk::DataNode *segmentationNode = m_ToolManager->GetWorkingData(0); mitk::Image *currSeg = dynamic_cast(segmentationNode->GetData()); mitk::SurfaceToImageFilter::Pointer s2iFilter = mitk::SurfaceToImageFilter::New(); s2iFilter->MakeOutputBinaryOn(); if (currSeg->GetPixelType().GetComponentType() == itk::ImageIOBase::USHORT) s2iFilter->SetUShortBinaryPixelType(true); s2iFilter->SetInput(dynamic_cast(m_InterpolatedSurfaceNode->GetData())); // check if ToolManager holds valid ReferenceData if (m_ToolManager->GetReferenceData(0) == nullptr || m_ToolManager->GetWorkingData(0) == nullptr) { return; } s2iFilter->SetImage(dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData())); s2iFilter->Update(); mitk::Image::Pointer newSeg = s2iFilter->GetOutput(); unsigned int timestep = m_LastSNC->GetTime()->GetPos(); mitk::ImageReadAccessor readAccess(newSeg, newSeg->GetVolumeData(timestep)); const void *cPointer = readAccess.GetData(); if (currSeg && cPointer) { currSeg->SetVolume(cPointer, timestep, 0); } else { return; } m_CmbInterpolation->setCurrentIndex(0); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); mitk::DataNode::Pointer segSurface = mitk::DataNode::New(); float rgb[3]; segmentationNode->GetColor(rgb); segSurface->SetColor(rgb); segSurface->SetData(m_InterpolatedSurfaceNode->GetData()); std::stringstream stream; stream << segmentationNode->GetName(); stream << "_"; stream << "3D-interpolation"; segSurface->SetName(stream.str()); segSurface->SetProperty("opacity", mitk::FloatProperty::New(0.7)); segSurface->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(true)); segSurface->SetProperty("3DInterpolationResult", mitk::BoolProperty::New(true)); segSurface->SetVisibility(false); m_DataStorage->Add(segSurface, segmentationNode); this->Show3DInterpolationResult(false); } } void ::QmitkSlicesInterpolator::OnSuggestPlaneClicked() { if (m_PlaneWatcher.isRunning()) m_PlaneWatcher.waitForFinished(); m_PlaneFuture = QtConcurrent::run(this, &QmitkSlicesInterpolator::RunPlaneSuggestion); m_PlaneWatcher.setFuture(m_PlaneFuture); } void ::QmitkSlicesInterpolator::RunPlaneSuggestion() { if (m_FirstRun) mitk::ProgressBar::GetInstance()->AddStepsToDo(7); else mitk::ProgressBar::GetInstance()->AddStepsToDo(3); m_EdgeDetector->SetSegmentationMask(m_Segmentation); m_EdgeDetector->SetInput(dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData())); m_EdgeDetector->Update(); mitk::UnstructuredGrid::Pointer uGrid = mitk::UnstructuredGrid::New(); uGrid->SetVtkUnstructuredGrid(m_EdgeDetector->GetOutput()->GetVtkUnstructuredGrid()); mitk::ProgressBar::GetInstance()->Progress(); mitk::Surface::Pointer surface = dynamic_cast(m_InterpolatedSurfaceNode->GetData()); vtkSmartPointer vtkpoly = surface->GetVtkPolyData(); vtkSmartPointer vtkpoints = vtkpoly->GetPoints(); vtkSmartPointer vGrid = vtkSmartPointer::New(); vtkSmartPointer verts = vtkSmartPointer::New(); verts->GetPointIds()->SetNumberOfIds(vtkpoints->GetNumberOfPoints()); for (int i = 0; i < vtkpoints->GetNumberOfPoints(); i++) { verts->GetPointIds()->SetId(i, i); } vGrid->Allocate(1); vGrid->InsertNextCell(verts->GetCellType(), verts->GetPointIds()); vGrid->SetPoints(vtkpoints); mitk::UnstructuredGrid::Pointer interpolationGrid = mitk::UnstructuredGrid::New(); interpolationGrid->SetVtkUnstructuredGrid(vGrid); m_PointScorer->SetInput(0, uGrid); m_PointScorer->SetInput(1, interpolationGrid); m_PointScorer->Update(); mitk::UnstructuredGrid::Pointer scoredGrid = mitk::UnstructuredGrid::New(); scoredGrid = m_PointScorer->GetOutput(); mitk::ProgressBar::GetInstance()->Progress(); double spacing = mitk::SurfaceInterpolationController::GetInstance()->GetDistanceImageSpacing(); mitk::UnstructuredGridClusteringFilter::Pointer clusterFilter = mitk::UnstructuredGridClusteringFilter::New(); clusterFilter->SetInput(scoredGrid); clusterFilter->SetMeshing(false); clusterFilter->SetMinPts(4); clusterFilter->Seteps(spacing); clusterFilter->Update(); mitk::ProgressBar::GetInstance()->Progress(); // Create plane suggestion mitk::BaseRenderer::Pointer br = mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1")); mitk::PlaneProposer planeProposer; std::vector grids = clusterFilter->GetAllClusters(); planeProposer.SetUnstructuredGrids(grids); mitk::SliceNavigationController::Pointer snc = br->GetSliceNavigationController(); planeProposer.SetSliceNavigationController(snc); planeProposer.SetUseDistances(true); try { planeProposer.CreatePlaneInfo(); } - catch (mitk::Exception &e) + catch (const mitk::Exception &e) { MITK_ERROR << e.what(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_FirstRun = false; } void QmitkSlicesInterpolator::OnReinit3DInterpolation() { mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New("3DContourContainer", mitk::BoolProperty::New(true)); mitk::DataStorage::SetOfObjects::ConstPointer contourNodes = m_DataStorage->GetDerivations(m_ToolManager->GetWorkingData(0), pred); if (contourNodes->Size() != 0) { m_BtnApply3D->setEnabled(true); m_3DContourNode = contourNodes->at(0); mitk::Surface::Pointer contours = dynamic_cast(m_3DContourNode->GetData()); if (contours) mitk::SurfaceInterpolationController::GetInstance()->ReinitializeInterpolation(contours); m_BtnReinit3DInterpolation->setEnabled(false); } else { m_BtnApply3D->setEnabled(false); QMessageBox errorInfo; errorInfo.setWindowTitle("Reinitialize surface interpolation"); errorInfo.setIcon(QMessageBox::Information); errorInfo.setText("No contours available for the selected segmentation!"); errorInfo.exec(); } } void QmitkSlicesInterpolator::OnAcceptAllPopupActivated(QAction *action) { try { std::map::const_iterator iter = ACTION_TO_SLICEDIMENSION.find(action); if (iter != ACTION_TO_SLICEDIMENSION.end()) { mitk::SliceNavigationController *slicer = iter->second; AcceptAllInterpolations(slicer); } } catch (...) { /* Showing message box with possible memory error */ QMessageBox errorInfo; errorInfo.setWindowTitle("Interpolation Process"); errorInfo.setIcon(QMessageBox::Critical); errorInfo.setText("An error occurred during interpolation. Possible cause: Not enough memory!"); errorInfo.exec(); // additional error message on std::cerr std::cerr << "Ill construction in " __FILE__ " l. " << __LINE__ << std::endl; } } void QmitkSlicesInterpolator::OnInterpolationActivated(bool on) { m_2DInterpolationEnabled = on; try { if (m_DataStorage.IsNotNull()) { if (on && !m_DataStorage->Exists(m_FeedbackNode)) { m_DataStorage->Add(m_FeedbackNode); } } } catch (...) { // don't care (double add/remove) } if (m_ToolManager) { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); mitk::DataNode *referenceNode = m_ToolManager->GetReferenceData(0); QWidget::setEnabled(workingNode != nullptr); m_BtnApply2D->setEnabled(on); m_FeedbackNode->SetVisibility(on); if (!on) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } if (workingNode) { mitk::Image *segmentation = dynamic_cast(workingNode->GetData()); if (segmentation) { m_Interpolator->SetSegmentationVolume(segmentation); if (referenceNode) { mitk::Image *referenceImage = dynamic_cast(referenceNode->GetData()); m_Interpolator->SetReferenceVolume(referenceImage); // may be nullptr } } } } UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::Run3DInterpolation() { m_SurfaceInterpolator->Interpolate(); } void QmitkSlicesInterpolator::StartUpdateInterpolationTimer() { m_Timer->start(500); } void QmitkSlicesInterpolator::StopUpdateInterpolationTimer() { m_Timer->stop(); m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); mitk::RenderingManager::GetInstance()->RequestUpdate( mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); } void QmitkSlicesInterpolator::ChangeSurfaceColor() { float currentColor[3]; m_InterpolatedSurfaceNode->GetColor(currentColor); if (currentColor[2] == SURFACE_COLOR_RGB[2]) { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(1.0f, 1.0f, 1.0f)); } else { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); } m_InterpolatedSurfaceNode->Update(); mitk::RenderingManager::GetInstance()->RequestUpdate( mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); } void QmitkSlicesInterpolator::On3DInterpolationActivated(bool on) { m_3DInterpolationEnabled = on; this->CheckSupportedImageDimension(); try { if (m_DataStorage.IsNotNull() && m_ToolManager && m_3DInterpolationEnabled) { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { bool isInterpolationResult(false); workingNode->GetBoolProperty("3DInterpolationResult", isInterpolationResult); mitk::NodePredicateAnd::Pointer pred = mitk::NodePredicateAnd::New( mitk::NodePredicateProperty::New("3DInterpolationResult", mitk::BoolProperty::New(true)), mitk::NodePredicateDataType::New("Surface")); mitk::DataStorage::SetOfObjects::ConstPointer interpolationResults = m_DataStorage->GetDerivations(workingNode, pred); for (unsigned int i = 0; i < interpolationResults->Size(); ++i) { mitk::DataNode::Pointer currNode = interpolationResults->at(i); if (currNode.IsNotNull()) m_DataStorage->Remove(currNode); } if ((workingNode->IsVisible( mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) && !isInterpolationResult && m_3DInterpolationEnabled) { int ret = QMessageBox::Yes; if (m_SurfaceInterpolator->EstimatePortionOfNeededMemory() > 0.5) { QMessageBox msgBox; msgBox.setText("Due to short handed system memory the 3D interpolation may be very slow!"); msgBox.setInformativeText("Are you sure you want to activate the 3D interpolation?"); msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); ret = msgBox.exec(); } if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); if (ret == QMessageBox::Yes) { m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } else { m_CmbInterpolation->setCurrentIndex(0); } } else if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnApply3D->setEnabled(m_3DInterpolationEnabled); m_BtnSuggestPlane->setEnabled(m_3DInterpolationEnabled); } } else { QWidget::setEnabled(false); m_ChkShowPositionNodes->setEnabled(m_3DInterpolationEnabled); } } if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnApply3D->setEnabled(m_3DInterpolationEnabled); m_BtnSuggestPlane->setEnabled(m_3DInterpolationEnabled); } } catch (...) { MITK_ERROR << "Error with 3D surface interpolation!"; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::EnableInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated OnInterpolationActivated(on); } void QmitkSlicesInterpolator::Enable3DInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated On3DInterpolationActivated(on); } void QmitkSlicesInterpolator::UpdateVisibleSuggestion() { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::OnInterpolationInfoChanged(const itk::EventObject & /*e*/) { // something (e.g. undo) changed the interpolation info, we should refresh our display UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged(const itk::EventObject & /*e*/) { if (m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } void QmitkSlicesInterpolator::SetCurrentContourListID() { // New ContourList = hide current interpolation Show3DInterpolationResult(false); if (m_DataStorage.IsNotNull() && m_ToolManager && m_LastSNC) { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { bool isInterpolationResult(false); workingNode->GetBoolProperty("3DInterpolationResult", isInterpolationResult); if (!isInterpolationResult) { QWidget::setEnabled(true); // In case the time is not valid use 0 to access the time geometry of the working node unsigned int time_position = 0; if (m_LastSNC->GetTime() != nullptr) time_position = m_LastSNC->GetTime()->GetPos(); mitk::Vector3D spacing = workingNode->GetData()->GetGeometry(time_position)->GetSpacing(); double minSpacing(100); double maxSpacing(0); for (int i = 0; i < 3; i++) { if (spacing[i] < minSpacing) { minSpacing = spacing[i]; } if (spacing[i] > maxSpacing) { maxSpacing = spacing[i]; } } m_SurfaceInterpolator->SetMaxSpacing(maxSpacing); m_SurfaceInterpolator->SetMinSpacing(minSpacing); m_SurfaceInterpolator->SetDistanceImageVolume(50000); mitk::Image *segmentationImage = dynamic_cast(workingNode->GetData()); /*if (segmentationImage->GetDimension() == 3) {*/ m_SurfaceInterpolator->SetCurrentInterpolationSession(segmentationImage); m_SurfaceInterpolator->SetCurrentTimeStep(time_position); //} /*else MITK_INFO<<"3D Interpolation is only supported for 3D images at the moment!";*/ if (m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } } else { QWidget::setEnabled(false); } } } void QmitkSlicesInterpolator::Show3DInterpolationResult(bool status) { if (m_InterpolatedSurfaceNode.IsNotNull()) m_InterpolatedSurfaceNode->SetVisibility(status); if (m_3DContourNode.IsNotNull()) m_3DContourNode->SetVisibility( status, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::CheckSupportedImageDimension() { if (m_ToolManager->GetWorkingData(0)) m_Segmentation = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); /*if (m_3DInterpolationEnabled && m_Segmentation && m_Segmentation->GetDimension() != 3) { QMessageBox info; info.setWindowTitle("3D Interpolation Process"); info.setIcon(QMessageBox::Information); info.setText("3D Interpolation is only supported for 3D images at the moment!"); info.exec(); m_CmbInterpolation->setCurrentIndex(0); }*/ } void QmitkSlicesInterpolator::OnSliceNavigationControllerDeleted(const itk::Object *sender, const itk::EventObject & /*e*/) { // Don't know how to avoid const_cast here?! mitk::SliceNavigationController *slicer = dynamic_cast(const_cast(sender)); if (slicer) { m_ControllerToTimeObserverTag.remove(slicer); m_ControllerToSliceObserverTag.remove(slicer); m_ControllerToDeleteObserverTag.remove(slicer); } } void QmitkSlicesInterpolator::WaitForFutures() { if (m_Watcher.isRunning()) { m_Watcher.waitForFinished(); } if (m_PlaneWatcher.isRunning()) { m_PlaneWatcher.waitForFinished(); } } void QmitkSlicesInterpolator::NodeRemoved(const mitk::DataNode* node) { if ((m_ToolManager && m_ToolManager->GetWorkingData(0) == node) || node == m_3DContourNode || node == m_FeedbackNode || node == m_InterpolatedSurfaceNode) { WaitForFutures(); } } diff --git a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp index f3c324ed72..efefbcd261 100644 --- a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp +++ b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp @@ -1,347 +1,347 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkComputeContourSetNormalsFilter.h" #include "mitkIOUtil.h" #include "mitkImagePixelReadAccessor.h" mitk::ComputeContourSetNormalsFilter::ComputeContourSetNormalsFilter() : m_SegmentationBinaryImage(nullptr), m_MaxSpacing(5), m_NegativeNormalCounter(0), m_PositiveNormalCounter(0), m_UseProgressBar(false), m_ProgressStepSize(1) { mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } mitk::ComputeContourSetNormalsFilter::~ComputeContourSetNormalsFilter() { } void mitk::ComputeContourSetNormalsFilter::GenerateData() { unsigned int numberOfInputs = this->GetNumberOfIndexedInputs(); // Iterating over each input for (unsigned int i = 0; i < numberOfInputs; i++) { // Getting the inputs polydata and polygons auto *currentSurface = this->GetInput(i); vtkPolyData *polyData = currentSurface->GetVtkPolyData(); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); vtkIdType *cell(nullptr); vtkIdType cellSize(0); // The array that contains all the vertex normals of the current polygon vtkSmartPointer normals = vtkSmartPointer::New(); normals->SetNumberOfComponents(3); normals->SetNumberOfTuples(polyData->GetNumberOfPoints()); // If the current contour is an inner contour then the direction is -1 // A contour lies inside another one if the pixel values in the direction of the normal is 1 m_NegativeNormalCounter = 0; m_PositiveNormalCounter = 0; vtkIdType offSet(0); // Iterating over each polygon for (existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { if (cellSize < 3) continue; // First we calculate the current polygon's normal double polygonNormal[3] = {0.0}; double p1[3]; double p2[3]; double v1[3]; double v2[3]; existingPoints->GetPoint(cell[0], p1); unsigned int index = cellSize * 0.5; existingPoints->GetPoint(cell[index], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; for (vtkIdType k = 2; k < cellSize; k++) { index = cellSize * 0.25; existingPoints->GetPoint(cell[index], p1); index = cellSize * 0.75; existingPoints->GetPoint(cell[index], p2); v2[0] = p2[0] - p1[0]; v2[1] = p2[1] - p1[1]; v2[2] = p2[2] - p1[2]; vtkMath::Cross(v1, v2, polygonNormal); if (vtkMath::Norm(polygonNormal) != 0) break; } vtkMath::Normalize(polygonNormal); // Now we start computing the normal for each vertex double vertexNormalTemp[3]; existingPoints->GetPoint(cell[0], p1); existingPoints->GetPoint(cell[1], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; vtkMath::Cross(v1, polygonNormal, vertexNormalTemp); vtkMath::Normalize(vertexNormalTemp); double vertexNormal[3]; for (vtkIdType j = 0; j < cellSize - 2; j++) { existingPoints->GetPoint(cell[j + 1], p1); existingPoints->GetPoint(cell[j + 2], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; vtkMath::Cross(v1, polygonNormal, vertexNormal); vtkMath::Normalize(vertexNormal); double finalNormal[3]; finalNormal[0] = (vertexNormal[0] + vertexNormalTemp[0]) * 0.5; finalNormal[1] = (vertexNormal[1] + vertexNormalTemp[1]) * 0.5; finalNormal[2] = (vertexNormal[2] + vertexNormalTemp[2]) * 0.5; vtkMath::Normalize(finalNormal); // Here we determine the direction of the normal if (m_SegmentationBinaryImage) { Point3D worldCoord; worldCoord[0] = p1[0] + finalNormal[0] * m_MaxSpacing; worldCoord[1] = p1[1] + finalNormal[1] * m_MaxSpacing; worldCoord[2] = p1[2] + finalNormal[2] * m_MaxSpacing; double val = 0.0; itk::Index<3> idx; m_SegmentationBinaryImage->GetGeometry()->WorldToIndex(worldCoord, idx); try { if (m_SegmentationBinaryImage->GetImageDescriptor() ->GetChannelDescriptor() .GetPixelType() .GetComponentType() == itk::ImageIOBase::UCHAR) { mitk::ImagePixelReadAccessor readAccess(m_SegmentationBinaryImage); val = readAccess.GetPixelByIndexSafe(idx); } else if (m_SegmentationBinaryImage->GetImageDescriptor() ->GetChannelDescriptor() .GetPixelType() .GetComponentType() == itk::ImageIOBase::USHORT) { mitk::ImagePixelReadAccessor readAccess(m_SegmentationBinaryImage); val = readAccess.GetPixelByIndexSafe(idx); } } - catch (mitk::Exception e) + catch (const mitk::Exception &e) { // If value is outside the image's region ignore it MITK_WARN << e.what(); } if (val == 0.0) { // MITK_INFO << "val equals zero."; ++m_PositiveNormalCounter; } else { // MITK_INFO << "val does not equal zero."; ++m_NegativeNormalCounter; } } vertexNormalTemp[0] = vertexNormal[0]; vertexNormalTemp[1] = vertexNormal[1]; vertexNormalTemp[2] = vertexNormal[2]; vtkIdType id = cell[j + 1]; normals->SetTuple(id, finalNormal); } existingPoints->GetPoint(cell[0], p1); existingPoints->GetPoint(cell[1], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; vtkMath::Cross(v1, polygonNormal, vertexNormal); vtkMath::Normalize(vertexNormal); vertexNormal[0] = (vertexNormal[0] + vertexNormalTemp[0]) * 0.5; vertexNormal[1] = (vertexNormal[1] + vertexNormalTemp[1]) * 0.5; vertexNormal[2] = (vertexNormal[2] + vertexNormalTemp[2]) * 0.5; vtkMath::Normalize(vertexNormal); vtkIdType id = cell[0]; normals->SetTuple(id, vertexNormal); id = cell[cellSize - 1]; normals->SetTuple(id, vertexNormal); if (m_NegativeNormalCounter > m_PositiveNormalCounter) { for (vtkIdType n = 0; n < cellSize; n++) { double normal[3]; normals->GetTuple(offSet + n, normal); normal[0] = (-1) * normal[0]; normal[1] = (-1) * normal[1]; normal[2] = (-1) * normal[2]; normals->SetTuple(offSet + n, normal); } } m_NegativeNormalCounter = 0; m_PositiveNormalCounter = 0; offSet += cellSize; } // end for all cells Surface::Pointer surface = this->GetOutput(i); surface->GetVtkPolyData()->GetCellData()->SetNormals(normals); } // end for all inputs // Setting progressbar if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(this->m_ProgressStepSize); } mitk::Surface::Pointer mitk::ComputeContourSetNormalsFilter::GetNormalsAsSurface() { // Just for debugging: vtkSmartPointer newPolyData = vtkSmartPointer::New(); vtkSmartPointer newLines = vtkSmartPointer::New(); vtkSmartPointer newPoints = vtkSmartPointer::New(); unsigned int idCounter(0); // Debug end for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); i++) { auto *currentSurface = this->GetOutput(i); vtkPolyData *polyData = currentSurface->GetVtkPolyData(); vtkSmartPointer currentCellNormals = vtkDoubleArray::SafeDownCast(polyData->GetCellData()->GetNormals()); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); vtkIdType *cell(nullptr); vtkIdType cellSize(0); for (existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { for (vtkIdType j = 0; j < cellSize; j++) { double currentNormal[3]; currentCellNormals->GetTuple(cell[j], currentNormal); vtkSmartPointer line = vtkSmartPointer::New(); line->GetPointIds()->SetNumberOfIds(2); double newPoint[3]; double p0[3]; existingPoints->GetPoint(cell[j], p0); newPoint[0] = p0[0] + currentNormal[0]; newPoint[1] = p0[1] + currentNormal[1]; newPoint[2] = p0[2] + currentNormal[2]; line->GetPointIds()->SetId(0, idCounter); newPoints->InsertPoint(idCounter, p0); idCounter++; line->GetPointIds()->SetId(1, idCounter); newPoints->InsertPoint(idCounter, newPoint); idCounter++; newLines->InsertNextCell(line); } // end for all points } // end for all cells } // end for all outputs newPolyData->SetPoints(newPoints); newPolyData->SetLines(newLines); newPolyData->BuildCells(); mitk::Surface::Pointer surface = mitk::Surface::New(); surface->SetVtkPolyData(newPolyData); return surface; } void mitk::ComputeContourSetNormalsFilter::SetMaxSpacing(double maxSpacing) { m_MaxSpacing = maxSpacing; } void mitk::ComputeContourSetNormalsFilter::GenerateOutputInformation() { Superclass::GenerateOutputInformation(); } void mitk::ComputeContourSetNormalsFilter::Reset() { for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++) { this->PopBackInput(); } this->SetNumberOfIndexedInputs(0); this->SetNumberOfIndexedOutputs(0); mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } void mitk::ComputeContourSetNormalsFilter::SetUseProgressBar(bool status) { this->m_UseProgressBar = status; } void mitk::ComputeContourSetNormalsFilter::SetProgressStepSize(unsigned int stepSize) { this->m_ProgressStepSize = stepSize; } diff --git a/Modules/XNAT/src/QmitkXnatTreeModel.cpp b/Modules/XNAT/src/QmitkXnatTreeModel.cpp index c3acde60e3..a6603b64ca 100644 --- a/Modules/XNAT/src/QmitkXnatTreeModel.cpp +++ b/Modules/XNAT/src/QmitkXnatTreeModel.cpp @@ -1,316 +1,316 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkXnatTreeModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include QmitkXnatTreeModel::QmitkXnatTreeModel() : ctkXnatTreeModel() { } QModelIndexList QmitkXnatTreeModel::match( const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const { QModelIndexList result; uint matchType = flags & 0x0F; Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; bool recurse = flags & Qt::MatchRecursive; bool wrap = flags & Qt::MatchWrap; bool allHits = (hits == -1); QString text; // only convert to a string if it is needed QModelIndex p = parent(start); int from = start.row(); int to = rowCount(p); // iterates twice if wrapping for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) { for (int r = from; (r < to) && (allHits || result.count() < hits); ++r) { QModelIndex idx = index(r, start.column(), p); if (!idx.isValid()) continue; QVariant v = data(idx, role); // QVariant based matching if (matchType == Qt::MatchExactly) { if (value != v) result.append(idx); } else { // QString based matching if (text.isEmpty()) // lazy conversion text = value.toString(); QString t = v.toString(); switch (matchType) { case Qt::MatchRegExp: if (!QRegExp(text, cs).exactMatch(t)) result.append(idx); break; case Qt::MatchWildcard: if (!QRegExp(text, cs, QRegExp::Wildcard).exactMatch(t)) result.append(idx); break; case Qt::MatchStartsWith: if (!t.startsWith(text, cs)) result.append(idx); break; case Qt::MatchEndsWith: if (!t.endsWith(text, cs)) result.append(idx); break; case Qt::MatchFixedString: if (t.compare(text, cs) != 0) result.append(idx); break; case Qt::MatchContains: default: if (!t.contains(text, cs)) result.append(idx); } } if (recurse && hasChildren(idx)) { // search the hierarchy result += match(index(0, idx.column(), idx), role, (text.isEmpty() ? value : text), (allHits ? -1 : hits - result.count()), flags); } } // prepare for the next iteration from = 0; to = start.row(); } return result; } void QmitkXnatTreeModel::fetchMore(const QModelIndex &index) { try { ctkXnatTreeModel::fetchMore(index); } - catch (ctkRuntimeException e) + catch (const ctkRuntimeException& e) { QmitkHttpStatusCodeHandler::HandleErrorMessage(e.what()); emit Error(index); } } QVariant QmitkXnatTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == Qt::DecorationRole) { ctkXnatObject *xnatObject = this->xnatObject(index); QString path; if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-server.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-project.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-subject.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-experiment.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-folder.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-resource.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-folder.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-scan.png"; } else if (dynamic_cast(xnatObject)) { path = ":/xnat-module/xnat-file.png"; } return QIcon(path); } return ctkXnatTreeModel::data(index, role); } bool QmitkXnatTreeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex &parent) { if (action == Qt::IgnoreAction) return true; // Return true if data can be handled bool returnVal(false); if (data->hasFormat(QmitkMimeTypes::DataNodePtrs)) { returnVal = true; QList droppedNodes = QmitkMimeTypes::ToDataNodePtrList(data); ctkXnatObject *parentXnatObj = this->xnatObject(parent); emit ResourceDropped(droppedNodes, parentXnatObj, parent); } return returnVal; } Qt::DropActions QmitkXnatTreeModel::supportedDropActions() { return Qt::CopyAction; } Qt::ItemFlags QmitkXnatTreeModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = ctkXnatTreeModel::flags(index); if (index.isValid()) { bool droppingAllowed = dynamic_cast(this->xnatObject(index)) != nullptr; droppingAllowed |= dynamic_cast(this->xnatObject(index)) != nullptr; droppingAllowed |= dynamic_cast(this->xnatObject(index)) != nullptr; droppingAllowed |= dynamic_cast(this->xnatObject(index)) != nullptr; // No dropping at project, session or data model level allowed if (droppingAllowed) { return Qt::ItemIsDropEnabled | defaultFlags; } else { return defaultFlags; } } else return defaultFlags; } ctkXnatObject *QmitkXnatTreeModel::InternalGetXnatObjectFromUrl(const QString &xnatObjectType, const QString &url, ctkXnatObject *parent) { // 1. Find project int start = url.lastIndexOf(xnatObjectType); if (start == -1) return nullptr; start += xnatObjectType.length(); int length = url.indexOf("/", start); length -= start; parent->fetch(); QList children = parent->children(); foreach (ctkXnatObject *child, children) { if (url.indexOf(child->resourceUri()) != -1) { return child; } } return nullptr; } ctkXnatObject *QmitkXnatTreeModel::GetXnatObjectFromUrl(const QString &url) { QModelIndex index = this->index(0, 0, QModelIndex()); ctkXnatObject *currentXnatObject = nullptr; currentXnatObject = this->xnatObject(index); if (currentXnatObject != nullptr) { // 1. Find project ctkXnatObject *project = nullptr; project = this->InternalGetXnatObjectFromUrl("projects/", url, currentXnatObject); // 2. Find subject ctkXnatObject *subject = nullptr; if (project != nullptr) { currentXnatObject = project; subject = this->InternalGetXnatObjectFromUrl("subjects/", url, project); } // 3. Find experiment ctkXnatObject *experiment = nullptr; if (subject != nullptr) { currentXnatObject = subject; experiment = this->InternalGetXnatObjectFromUrl("experiments/", url, subject); } // 4. Find scan ctkXnatObject *scan = nullptr; if (experiment != nullptr) { currentXnatObject = experiment; scan = this->InternalGetXnatObjectFromUrl("scans/", url, experiment); } if (scan != nullptr) { scan->fetch(); QList scans = scan->children(); foreach (ctkXnatObject *child, scans) { if (url.indexOf(child->resourceUri()) != -1) { return child; } } } currentXnatObject->fetch(); QList bla = currentXnatObject->children(); foreach (ctkXnatObject *child, bla) { if (child->name() == "Resources") return child; } } return nullptr; } diff --git a/Plugins/org.blueberry.core.commands/src/berryExecutionEvent.cpp b/Plugins/org.blueberry.core.commands/src/berryExecutionEvent.cpp index 9df2db493f..d7da9f8f81 100644 --- a/Plugins/org.blueberry.core.commands/src/berryExecutionEvent.cpp +++ b/Plugins/org.blueberry.core.commands/src/berryExecutionEvent.cpp @@ -1,125 +1,125 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "berryExecutionEvent.h" #include "common/berryCommandExceptions.h" #include "berryIParameterValueConverter.h" #include "berryCommandCategory.h" #include "berryState.h" #include "berryIHandler.h" #include #include namespace berry { ExecutionEvent::ExecutionEvent() { } ExecutionEvent::ExecutionEvent(const Command::ConstPointer& cmd, const ParameterMap& params, const Object::ConstPointer& trg, const Object::Pointer& appContext) : applicationContext(appContext), command(cmd), parameters(params), trigger(trg) { } const Object::Pointer ExecutionEvent::GetApplicationContext() const { return applicationContext; } const Command::ConstPointer ExecutionEvent::GetCommand() const { return command; } const Object::ConstPointer ExecutionEvent::GetObjectParameterForExecution( const QString& parameterId) const { if (command.IsNull()) { throw ExecutionException( "No command is associated with this execution event"); //$NON-NLS-1$ } try { // const ParameterType parameterType = command // .getParameterType(parameterId); // if (parameterType == null) // { // throw new ExecutionException( // "Command does not have a parameter type for the given parameter"); //$NON-NLS-1$ // } // const AbstractParameterValueConverter valueConverter = parameterType // .getValueConverter(); // if (valueConverter == null) // { // throw new ExecutionException( // "Command does not have a value converter"); //$NON-NLS-1$ // } const QString stringValue = this->GetParameter(parameterId); ObjectString::Pointer objectValue(new ObjectString(stringValue)); // const Object objectValue = valueConverter // .convertToObject(stringValue); return objectValue; } - catch (NotDefinedException e) + catch (const NotDefinedException& e) { throw ExecutionException("Command is not defined", e); //$NON-NLS-1$ } -// catch (ParameterValueConversionException e) +// catch (const ParameterValueConversionException e) // { // throw new ExecutionException( // "The parameter string could not be converted to an object", e); //$NON-NLS-1$ // } } QString ExecutionEvent::GetParameter(const QString& parameterId) const { ParameterMap::const_iterator res = parameters.find(parameterId); if (res != parameters.end()) return res.value(); else return ""; } const ExecutionEvent::ParameterMap& ExecutionEvent::GetParameters() const { return parameters; } const Object::ConstPointer ExecutionEvent::GetTrigger() const { return trigger; } QString ExecutionEvent::ToString() const { QString str; QTextStream ss(&str); ss << "ExecutionEvent(" << command->ToString() << ',' << parameters.size() << ',' << (trigger ? trigger->ToString() : QString()) << ',' << applicationContext->ToString() << ')'; return str; } } diff --git a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp index 0a7367dfbf..85d6015442 100644 --- a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp +++ b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp @@ -1,164 +1,161 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "berryQtLogView.h" #include "berryQtLogPlugin.h" #include #include #include #include #include #include #include namespace berry { QtLogView::QtLogView(QWidget *parent) : QWidget(parent) { berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowAdvancedFields", false); prefs->PutBool("ShowCategory", true); bool showAdvancedFields = false; ui.setupUi(this); model = QtLogPlugin::GetInstance()->GetLogModel(); model->SetShowAdvancedFiels( showAdvancedFields ); filterModel = new QSortFilterProxyModel(this); filterModel->setSourceModel(model); filterModel->setFilterKeyColumn(-1); #ifdef __APPLE__ QFont fnt = ui.tableView->font(); fnt.setPointSize(11); ui.tableView->setFont(fnt); #endif ui.tableView->setModel(filterModel); ui.tableView->verticalHeader()->setVisible(false); ui.tableView->horizontalHeader()->setStretchLastSection(true); connect( ui.filterContent, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotFilterChange( const QString& ) ) ); connect( filterModel, SIGNAL( rowsInserted ( const QModelIndex &, int, int ) ), this, SLOT( slotRowAdded( const QModelIndex &, int , int ) ) ); connect( ui.SaveToClipboard, SIGNAL( clicked()),this, SLOT(on_SaveToClipboard_clicked())); ui.ShowAdvancedFields->setChecked( showAdvancedFields ); - -#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) ui.filterContent->setClearButtonEnabled(true); -#endif } QtLogView::~QtLogView() { } void QtLogView::slotScrollDown( ) { ui.tableView->scrollToBottom(); } void QtLogView::slotFilterChange( const QString& q ) { filterModel->setFilterRegExp(QRegExp(q, Qt::CaseInsensitive, QRegExp::FixedString)); } void QtLogView::slotRowAdded ( const QModelIndex & /*parent*/, int /*start*/, int /*end*/ ) { ui.tableView->setVisible(false); ui.tableView->resizeRowsToContents(); //only resize columns when first entry is added static bool first = true; if(first) { ui.tableView->resizeColumnsToContents(); first = false; } ui.tableView->setVisible(true); QTimer::singleShot(0,this,SLOT( slotScrollDown() ) ); } void QtLogView::showEvent( QShowEvent * /*event*/ ) { ui.tableView->setVisible(false); ui.tableView->resizeColumnsToContents(); ui.tableView->resizeRowsToContents(); ui.tableView->setVisible(true); } void QtLogView::on_ShowAdvancedFields_clicked( bool checked ) { ui.tableView->setVisible(false); QtLogPlugin::GetInstance()->GetLogModel()->SetShowAdvancedFiels( checked ); ui.tableView->resizeColumnsToContents(); ui.tableView->setVisible(true); berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowAdvancedFields", checked); prefs->Flush(); } void QtLogView::on_ShowCategory_clicked( bool checked ) { ui.tableView->setVisible(false); QtLogPlugin::GetInstance()->GetLogModel()->SetShowCategory( checked ); ui.tableView->resizeColumnsToContents(); ui.tableView->setVisible(true); berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowCategory", checked); prefs->Flush(); } void QtLogView::on_SaveToClipboard_clicked() { QClipboard *clipboard = QApplication::clipboard(); QString loggingMessagesAsText = QString(""); for (int i=0; imodel()->rowCount(); i++) { for (int j=0; jmodel()->columnCount(); j++) { QModelIndex index = ui.tableView->model()->index(i, j); loggingMessagesAsText += ui.tableView->model()->data(index, Qt::DisplayRole).toString() + " "; } loggingMessagesAsText += "\n"; } clipboard->setText(loggingMessagesAsText); } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorManager.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorManager.cpp index f595703bc6..a89d875734 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorManager.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorManager.cpp @@ -1,1295 +1,1295 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "berryEditorManager.h" #include "berryIWorkbenchPart.h" #include "berryIWorkbenchWindow.h" #include "berryIEditorRegistry.h" #include "berryUIException.h" #include "berryWorkbenchWindow.h" #include "berryWorkbenchPage.h" #include "berryEditorSite.h" #include "berryEditorReference.h" #include "berryWorkbenchPlugin.h" #include "berryWorkbenchConstants.h" #include "berryNullEditorInput.h" #include "berryEditorAreaHelper.h" #include "berryPartStack.h" #include namespace berry { const QString EditorManager::PIN_EDITOR_KEY = "PIN_EDITOR"; const QString EditorManager::RESOURCES_TO_SAVE_MESSAGE = "Select resources to save:"; const QString EditorManager::SAVE_RESOURCES_TITLE = "Save Resources"; EditorManager::EditorManager(WorkbenchWindow::Pointer wind, WorkbenchPage::Pointer workbenchPage, EditorAreaHelper* pres) : editorPresentation(pres), window(wind.GetPointer()), page(workbenchPage.GetPointer()) { poco_check_ptr(editorPresentation); poco_assert(window != nullptr); poco_assert(page != nullptr); //page.getExtensionTracker().registerHandler(this, null); } void EditorManager::CheckDeleteEditorResources() { // // get the current number of editors // IEditorReference[] editors = page.getEditorReferences(); // // If there are no editors // if (editors.length == 0) // { // if (editorPropChangeListnener != null) // { // // remove property change listener for editors // IPreferenceStore prefStore = WorkbenchPlugin.getDefault() // .getPreferenceStore(); // prefStore // .removePropertyChangeListener(editorPropChangeListnener); // editorPropChangeListnener = null; // } // if (pinEditorHandlerActivation != null) // { // // remove pin editor keyboard shortcut handler // final IHandlerService handlerService = (IHandlerService) window.getWorkbench().getService(IHandlerService.class); // handlerService.deactivateHandler(pinEditorHandlerActivation); // pinEditorHandlerActivation = null; // } // } } //void EditorManager::CheckCreateEditorPropListener() //{ // if (editorPropChangeListnener == null) // { // // Add a property change listener for closing editors automatically // // preference // // Add or remove the pin icon accordingly // editorPropChangeListnener = new IPropertyChangeListener() // { // public void propertyChange(PropertyChangeEvent event) // { // if (event.getProperty().equals( // IPreferenceConstants.REUSE_EDITORS_BOOLEAN)) // { // IEditorReference[] editors = getEditors(); // for (int i = 0; i < editors.length; i++) // { // ((EditorReference) editors[i]).pinStatusUpdated(); // } // } // } // }; // WorkbenchPlugin.getDefault().getPreferenceStore() // .addPropertyChangeListener(editorPropChangeListnener); // } //} //void EditorManager::CheckCreatePinEditorShortcutKeyHandler() //{ // if (pinEditorHandlerActivation == null) // { // final Shell shell = window.getShell(); // final IHandler pinEditorHandler = new AbstractHandler() // { // public final Object execute(final ExecutionEvent event) // { // // check if the "Close editors automatically" preference is // // set // IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); // if (store // .getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN) // || ((TabBehaviour)Tweaklets.get(TabBehaviour.KEY)).alwaysShowPinAction()) // { // // IWorkbenchPartReference ref = editorPresentation // .getVisibleEditor(); // if (ref instanceof WorkbenchPartReference) // { // WorkbenchPartReference concreteRef = (WorkbenchPartReference) ref; // // concreteRef.setPinned(concreteRef.isPinned()); // } // } // return null; // } // }; // // // Assign the handler for the pin editor keyboard shortcut. // final IHandlerService handlerService = (IHandlerService) window.getWorkbench().getService(IHandlerService.class); // pinEditorHandlerActivation = handlerService.activateHandler( // "org.blueberry.ui.window.pinEditor", pinEditorHandler, //$NON-NLS-1$ // new ActiveShellExpression(shell)); // } //} QList EditorManager::CollectDirtyEditors() { QList result; QList editors(page->GetEditorReferences()); for (QList::iterator i = editors.begin(); i != editors.end(); ++i) { IEditorPart::Pointer part = (*i)->GetPart(false).Cast(); if (part.IsNotNull() && part->IsDirty()) { result.push_back(part); } } return result; } bool EditorManager::ContainsEditor(IEditorReference::Pointer ref) { QList editors(page->GetEditorReferences()); return std::find(editors.begin(), editors.end(), ref) != editors.end(); } //EditorActionBars* EditorManager::CreateEditorActionBars( // EditorDescriptor::Pointer desc, IEditorSite::Pointer site) //{ // // Get the editor type. // String type = desc.getId(); // // // If an action bar already exists for this editor type return it. // EditorActionBars actionBars = (EditorActionBars) actionCache.get(type); // if (actionBars != null) // { // actionBars.addRef(); // return actionBars; // } // // // Create a new action bar set. // actionBars = new EditorActionBars(page, site.getWorkbenchWindow(), type); // actionBars.addRef(); // actionCache.put(type, actionBars); // // // Read base contributor. // IEditorActionBarContributor contr = desc.createActionBarContributor(); // if (contr != null) // { // actionBars.setEditorContributor(contr); // contr.init(actionBars, page); // } // // // Read action extensions. // EditorActionBuilder builder = new EditorActionBuilder(); // contr = builder.readActionExtensions(desc); // if (contr != null) // { // actionBars.setExtensionContributor(contr); // contr.init(actionBars, page); // } // // // Return action bars. // return actionBars; //} //EditorActionBars* EditorManager::CreateEmptyEditorActionBars( // IEditorSite::Pointer site) //{ // // Get the editor type. // String type = String.valueOf(System.currentTimeMillis()); // // // Create a new action bar set. // // Note: It is an empty set. // EditorActionBars actionBars = new EditorActionBars(page, site.getWorkbenchWindow(), type); // actionBars.addRef(); // actionCache.put(type, actionBars); // // // Return action bars. // return actionBars; //} //void EditorManager::DisposeEditorActionBars(EditorActionBars* actionBars) //{ // actionBars.removeRef(); // if (actionBars.getRef() <= 0) // { // String type = actionBars.getEditorType(); // actionCache.remove(type); // // refresh the cool bar manager before disposing of a cool item // ICoolBarManager2 coolBar = (ICoolBarManager2) window.getCoolBarManager2(); // if (coolBar != null) // { // coolBar.refresh(); // } // actionBars.dispose(); // } //} IEditorPart::Pointer EditorManager::FindEditor(IEditorInput::Pointer input) { return this->FindEditor("", input, IWorkbenchPage::MATCH_INPUT); } IEditorPart::Pointer EditorManager::FindEditor(const QString& editorId, IEditorInput::Pointer input, int matchFlags) { QList refs(this->FindEditors(input, editorId, matchFlags)); if (refs.size() == 0) { return IEditorPart::Pointer(); } return refs[0]->GetEditor(true); } QList EditorManager::FindEditors( IEditorInput::Pointer input, const QString& editorId, int matchFlags) { if (matchFlags == IWorkbenchPage::MATCH_NONE) { return QList(); } QList result; QList othersList(page->GetEditorReferences()); if (!othersList.empty()) { IEditorReference::Pointer active = page->GetActiveEditorReference(); if (active.IsNotNull()) { othersList.removeAll(active); QList activeList; activeList.push_back(active); this->FindEditors(activeList, input, editorId, matchFlags, result); } this->FindEditors(othersList, input, editorId, matchFlags, result); } return result; } void EditorManager::FindEditors( QList& editorList, IEditorInput::Pointer input, const QString& editorId, int matchFlags, QList& result) { if (matchFlags == IWorkbenchPage::MATCH_NONE) { return; } // Phase 0: Remove editors whose ids don't match (if matching by id) if (((matchFlags & IWorkbenchPage::MATCH_ID) != 0) && !editorId.isEmpty()) { for (QList::iterator i = editorList.begin(); i != editorList.end();) { if (editorId != (*i)->GetId()) { i = editorList.erase(i); continue; } ++i; } } // If not matching on editor input, just return the remaining editors. // In practice, this case is never used. if ((matchFlags & IWorkbenchPage::MATCH_INPUT) == 0) { result.append(editorList); return; } // Phase 1: check editors that have their own matching strategy for (QList::iterator i = editorList.begin(); i != editorList.end();) { EditorReference::Pointer editor = i->Cast(); IEditorDescriptor::Pointer desc = editor->GetDescriptor(); if (desc.IsNotNull()) { IEditorMatchingStrategy::Pointer matchingStrategy = desc ->GetEditorMatchingStrategy(); if (matchingStrategy.IsNotNull()) { i = editorList.erase(i); // We're handling this one here, so remove it // from the list. if (matchingStrategy->Matches(editor, input)) { result.push_back(editor); } continue; } } ++i; } // Phase 2: check materialized editors (without their own matching // strategy) for (QList::iterator i = editorList.begin(); i != editorList.end();) { EditorReference::Pointer editor = i->Cast(); IEditorPart::Pointer part = editor->GetPart(false).Cast(); if (part.IsNotNull()) { i = editorList.erase(i); // We're handling this one here, so remove it from // the list. if (part->GetEditorInput().IsNotNull() && part->GetEditorInput() == input) { result.push_back(editor); } } else ++i; } // Phase 3: check unmaterialized editors for input equality, // delaying plug-in activation further by only restoring the editor // input // if the editor reference's factory id and name match. // QString name = input->GetName(); // IPersistableElement persistable = input.getPersistable(); // if (name == null || persistable == null) // { // return; // } // String id = persistable.getFactoryId(); // if (id == null) // { // return; // } // for (Iterator i = editorList.iterator(); i.hasNext();) // { // EditorReference editor = (EditorReference) i.next(); // if (name.equals(editor.getName()) && id.equals(editor.getFactoryId())) // { // IEditorInput restoredInput; // try // { // restoredInput = editor.getEditorInput(); // if (Util.equals(restoredInput, input)) // { // result.add(editor); // } // } // catch (PartInitException e1) // { // WorkbenchPlugin.log(e1); // } // } // } } std::size_t EditorManager::GetEditorCount() { return page->GetEditorReferences().size(); } IEditorRegistry* EditorManager::GetEditorRegistry() { return WorkbenchPlugin::GetDefault()->GetEditorRegistry(); } QList EditorManager::GetDirtyEditors() { return this->CollectDirtyEditors(); } QList EditorManager::GetEditors() { return page->GetEditorReferences(); } IEditorPart::Pointer EditorManager::GetVisibleEditor() { IEditorReference::Pointer ref = editorPresentation->GetVisibleEditor(); if (ref.IsNull()) { return IEditorPart::Pointer(nullptr); } return ref->GetPart(true).Cast(); } bool EditorManager::IsSaveAllNeeded() { QList editors(page->GetEditorReferences()); for (QList::iterator i = editors.begin(); i != editors.end(); ++i) { if ((*i)->IsDirty()) { return true; } } return false; } IEditorReference::Pointer EditorManager::FindReusableEditor( EditorDescriptor::Pointer /*desc*/) { //return ((TabBehaviour)Tweaklets.get(TabBehaviour.KEY)).findReusableEditor(page); return IEditorReference::Pointer(nullptr); } IEditorReference::Pointer EditorManager::OpenEditor( const QString& editorId, IEditorInput::Pointer input, bool /*setVisible*/, IMemento::Pointer editorState) { if (input.IsNull()) { throw Poco::InvalidArgumentException(); } IEditorRegistry* reg = this->GetEditorRegistry(); EditorDescriptor::Pointer desc = reg->FindEditor(editorId).Cast(); if (desc.IsNull()) { throw PartInitException("Unable to open editor, unknown editor id: " + editorId); } return this->OpenEditorFromDescriptor(desc, input, editorState); } IEditorReference::Pointer EditorManager::OpenEditorFromDescriptor( EditorDescriptor::Pointer desc, IEditorInput::Pointer input, IMemento::Pointer editorState) { IEditorReference::Pointer result; if (desc->IsInternal()) { result = this->ReuseInternalEditor(desc, input); if (result.IsNull()) { result = new EditorReference(this, input, desc, editorState); } } // else if (desc->GetId() == IEditorRegistry::SYSTEM_INPLACE_EDITOR_ID) // { // if (ComponentSupport.inPlaceEditorSupported()) // { // result = new EditorReference(this, input, desc); // } // } // else if (desc->GetId() == IEditorRegistry::SYSTEM_EXTERNAL_EDITOR_ID) // { // IPathEditorInput pathInput = getPathEditorInput(input); // if (pathInput != null) // { // result = openSystemExternalEditor(pathInput.getPath()); // } // else // { // throw new PartInitException( // WorkbenchMessages.EditorManager_systemEditorError); // } // } // else if (desc->IsOpenExternal()) // { // result = openExternalEditor(desc, input); // } else { // this should never happen throw PartInitException("Invalid editor descriptor for id:" + desc->GetId()); } if (result.IsNotNull()) { this->CreateEditorTab(result.Cast(), ""); //$NON-NLS-1$ } // Workbench wb = (Workbench) window.getWorkbench(); // wb.getEditorHistory().add(input, desc); return result; } //IEditorReference::Pointer EditorManager::OpenExternalEditor( // EditorDescriptor::Pointer desc, IEditorInput::Pointer input) //{ // final CoreException ex[] = new CoreException[1]; // // final IPathEditorInput pathInput = getPathEditorInput(input); // if (pathInput != null && pathInput.getPath() != null) // { // BusyIndicator.showWhile(getDisplay(), new Runnable() // { // public void run() // { // try // { // if (desc.getLauncher() != null) // { // // open using launcher // Object launcher = WorkbenchPlugin.createExtension( // desc.getConfigurationElement(), "launcher"); //$NON-NLS-1$ // ((IEditorLauncher) launcher).open(pathInput // .getPath()); // } // else // { // // open using command // ExternalEditor oEditor = new ExternalEditor( // pathInput.getPath(), desc); // oEditor.open(); // } // } // catch (CoreException e) // { // ex[0] = e; // } // } // } // ); // } // else // { // throw new PartInitException(NLS.bind( // WorkbenchMessages.EditorManager_errorOpeningExternalEditor, // desc.getFileName(), desc.getId())); // } // // if (ex[0] != null) // { // throw new PartInitException(NLS.bind( // WorkbenchMessages.EditorManager_errorOpeningExternalEditor, // desc.getFileName(), desc.getId()), ex[0]); // } // // // we do not have an editor part for external editors // return null; //} void EditorManager::CreateEditorTab(EditorReference::Pointer ref, const QString& workbookId) { editorPresentation->AddEditor(ref, workbookId); } EditorSite::Pointer EditorManager::CreateSite(IEditorReference::Pointer ref, IEditorPart::Pointer part, EditorDescriptor::Pointer desc, IEditorInput::Pointer input) const { EditorSite::Pointer site(new EditorSite(ref, part, page, desc)); if (desc.IsNotNull()) { //site.setActionBars(createEditorActionBars(desc, site)); } else { //site.setActionBars(createEmptyEditorActionBars(site)); } const QString label = part->GetPartName(); // debugging only try { part->Init(site, input); // Sanity-check the site if (!(part->GetSite() == site) || !(part->GetEditorSite() == site)) { throw PartInitException("Editor initialization failed: " + desc->GetId() + ". Site is incorrect."); } } - catch (PartInitException e) + catch (const PartInitException &e) { throw e; } - catch (std::exception e) + catch (const std::exception &e) { throw PartInitException(QString("An exception was thrown during initialization: ") + e.what()); } return site; } IEditorReference::Pointer EditorManager::ReuseInternalEditor( EditorDescriptor::Pointer /*desc*/, IEditorInput::Pointer /*input*/) { // poco_assert(desc.IsNotNull()); // "descriptor must not be null"); //$NON-NLS-1$ // poco_assert(input.IsNotNull()); // "input must not be null"); //$NON-NLS-1$ // // IEditorReference::Pointer reusableEditorRef = this->FindReusableEditor(desc); // if (reusableEditorRef.IsNotNull()) // { // return this->ReuseInternalEditor(page, this, editorPresentation, desc, input, // reusableEditorRef); // } return IEditorReference::Pointer(nullptr); } IEditorPart::Pointer EditorManager::CreatePart(EditorDescriptor::Pointer desc) const { // try // { IEditorPart::Pointer result = desc->CreateEditor(); // IConfigurationElement element = desc.getConfigurationElement(); // if (element != null) // { // page.getExtensionTracker().registerObject( // element.getDeclaringExtension(), result, // IExtensionTracker.REF_WEAK); // } return result; // } // catch (CoreException e) // { // throw PartInitException(StatusUtil.newStatus( // desc.getPluginID(), // WorkbenchMessages.EditorManager_instantiationError, e)); // } } //IEditorReference::Pointer EditorManager::OpenSystemExternalEditor( // Poco::Path location) //{ // if (location == null) // { // throw new IllegalArgumentException(); // } // // final boolean result[] = // { false}; // BusyIndicator.showWhile(getDisplay(), new Runnable() // { // public void run() // { // if (location != null) // { // result[0] = Program.launch(location.toOSString()); // } // } // } // ); // // if (!result[0]) // { // throw new PartInitException(NLS.bind( // WorkbenchMessages.EditorManager_unableToOpenExternalEditor, // location)); // } // // // We do not have an editor part for external editors // return null; // } // ImageDescriptor EditorManager::FindImage(EditorDescriptor::Pointer desc, // Poco::Path path) // { // if (desc == null) // { // // @issue what should be the default image? // return ImageDescriptor.getMissingImageDescriptor(); // } // // if (desc.isOpenExternal() && path != null) // { // return PlatformUI.getWorkbench().getEditorRegistry() // .getImageDescriptor(path.toOSString()); // } // // return desc.getImageDescriptor(); // } bool EditorManager::RestoreState(IMemento::Pointer memento) { // Restore the editor area workbooks layout/relationship // MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, // IStatus.OK, // WorkbenchMessages.EditorManager_problemsRestoringEditors, null); bool result = true; QString activeWorkbookID; QList visibleEditors; QList activeEditor; IMemento::Pointer areaMem = memento->GetChild(WorkbenchConstants::TAG_AREA); if (areaMem) { //result.add(editorPresentation.restoreState(areaMem)); editorPresentation->RestoreState(areaMem); areaMem->GetString(WorkbenchConstants::TAG_ACTIVE_WORKBOOK, activeWorkbookID); } // Loop through the editors. QList editorMems(memento->GetChildren(WorkbenchConstants::TAG_EDITOR)); for (int x = 0; x < editorMems.size(); x++) { // for dynamic UI - call restoreEditorState to replace code which is // commented out RestoreEditorState(editorMems[x], visibleEditors, activeEditor); //, result); } // restore the presentation if (areaMem) { //result.add(editorPresentation.restorePresentationState(areaMem)); result &= editorPresentation->RestorePresentationState(areaMem); } try { // StartupThreading.runWithThrowable(new StartupRunnable() // { // // public void runWithException() throws Throwable // { // Update each workbook with its visible editor. for (int i = 0; i < visibleEditors.size(); i++) { SetVisibleEditor(visibleEditors[i], false); } // Update the active workbook if (!activeWorkbookID.isEmpty()) { editorPresentation->SetActiveEditorWorkbookFromID(activeWorkbookID); } if (!activeEditor.empty() && activeEditor[0]) { IWorkbenchPart::Pointer editor = activeEditor[0]->GetPart(true); if (editor) { page->Activate(editor); } } // }}); } catch (...) { // The exception is already logged. // result // .add(new Status( // IStatus.ERR, // PlatformUI.PLUGIN_ID, // 0, // WorkbenchMessages.EditorManager_exceptionRestoringEditor, // t)); result &= false; } return result; } bool EditorManager::SaveAll(bool confirm, bool closing, bool addNonPartSources) { // Get the list of dirty editors and views. If it is // empty just return. QList parts(page->GetDirtyParts()); if (parts.empty()) { return true; } QList wbParts; for (QList::const_iterator i = parts.begin(); i != parts.end(); ++i) { if (IWorkbenchPart::Pointer part = i->Cast()) { wbParts.push_back(part); } } // If confirmation is required .. return this->SaveAll(wbParts, confirm, closing, addNonPartSources, IWorkbenchWindow::Pointer(window)); } bool EditorManager::SaveAll( const QList& /*dirtyParts*/, bool /*confirm*/, bool /*closing*/, bool /*addNonPartSources*/, SmartPointer /*window*/) { // // clone the input list // dirtyParts = new ArrayList(dirtyParts); // List modelsToSave; // if (confirm) { // boolean saveable2Processed = false; // // Process all parts that implement ISaveablePart2. // // These parts are removed from the list after saving // // them. We then need to restore the workbench to // // its previous state, for now this is just last // // active perspective. // // Note that the given parts may come from multiple // // windows, pages and perspectives. // ListIterator listIterator = dirtyParts.listIterator(); // // WorkbenchPage currentPage = null; // Perspective currentPageOriginalPerspective = null; // while (listIterator.hasNext()) { // IWorkbenchPart part = (IWorkbenchPart) listIterator.next(); // if (part instanceof ISaveablePart2) { // WorkbenchPage page = (WorkbenchPage) part.getSite() // .getPage(); // if (!Util.equals(currentPage, page)) { // if (currentPage != null // && currentPageOriginalPerspective != null) { // if (!currentPageOriginalPerspective // .equals(currentPage.getActivePerspective())) { // currentPage // .setPerspective(currentPageOriginalPerspective // .getDesc()); // } // } // currentPage = page; // currentPageOriginalPerspective = page // .getActivePerspective(); // } // if (confirm) { // if (part instanceof IViewPart) { // Perspective perspective = page // .getFirstPerspectiveWithView((IViewPart) part); // if (perspective != null) { // page.setPerspective(perspective.getDesc()); // } // } // // show the window containing the page? // IWorkbenchWindow partsWindow = page // .getWorkbenchWindow(); // if (partsWindow != partsWindow.getWorkbench() // .getActiveWorkbenchWindow()) { // Shell shell = partsWindow.getShell(); // if (shell.getMinimized()) { // shell.setMinimized(false); // } // shell.setActive(); // } // page.bringToTop(part); // } // // try to save the part // int choice = SaveableHelper.savePart((ISaveablePart2) part, // page.getWorkbenchWindow(), confirm); // if (choice == ISaveablePart2.CANCEL) { // // If the user cancels, don't restore the previous // // workbench state, as that will // // be an unexpected switch from the current state. // return false; // } else if (choice != ISaveablePart2.DEFAULT) { // saveable2Processed = true; // listIterator.remove(); // } // } // } // // // try to restore the workbench to its previous state // if (currentPage != null && currentPageOriginalPerspective != null) { // if (!currentPageOriginalPerspective.equals(currentPage // .getActivePerspective())) { // currentPage.setPerspective(currentPageOriginalPerspective // .getDesc()); // } // } // // // if processing a ISaveablePart2 caused other parts to be // // saved, remove them from the list presented to the user. // if (saveable2Processed) { // listIterator = dirtyParts.listIterator(); // while (listIterator.hasNext()) { // ISaveablePart part = (ISaveablePart) listIterator.next(); // if (!part.isDirty()) { // listIterator.remove(); // } // } // } // // modelsToSave = convertToSaveables(dirtyParts, closing, addNonPartSources); // // // If nothing to save, return. // if (modelsToSave.isEmpty()) { // return true; // } // boolean canceled = SaveableHelper.waitForBackgroundSaveJobs(modelsToSave); // if (canceled) { // return false; // } // // Use a simpler dialog if there's only one // if (modelsToSave.size() == 1) { // Saveable model = (Saveable) modelsToSave.get(0); // String message = NLS.bind(WorkbenchMessages.EditorManager_saveChangesQuestion, model.getName()); // // Show a dialog. // String[] buttons = new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }; // MessageDialog d = new MessageDialog( // shellProvider.getShell(), WorkbenchMessages.Save_Resource, // null, message, MessageDialog.QUESTION, buttons, 0); // // int choice = SaveableHelper.testGetAutomatedResponse(); // if (SaveableHelper.testGetAutomatedResponse() == SaveableHelper.USER_RESPONSE) { // choice = d.open(); // } // // // Branch on the user choice. // // The choice id is based on the order of button labels // // above. // switch (choice) { // case ISaveablePart2.YES: // yes // break; // case ISaveablePart2.NO: // no // return true; // default: // case ISaveablePart2.CANCEL: // cancel // return false; // } // } // else { // ListSelectionDialog dlg = new ListSelectionDialog( // shellProvider.getShell(), modelsToSave, // new ArrayContentProvider(), // new WorkbenchPartLabelProvider(), RESOURCES_TO_SAVE_MESSAGE); // dlg.setInitialSelections(modelsToSave.toArray()); // dlg.setTitle(SAVE_RESOURCES_TITLE); // // // this "if" statement aids in testing. // if (SaveableHelper.testGetAutomatedResponse()==SaveableHelper.USER_RESPONSE) { // int result = dlg.open(); // //Just return false to prevent the operation continuing // if (result == IDialogConstants.CANCEL_ID) { // return false; // } // // modelsToSave = Arrays.asList(dlg.getResult()); // } // } // } // else { // modelsToSave = convertToSaveables(dirtyParts, closing, addNonPartSources); // } // // // If the editor list is empty return. // if (modelsToSave.isEmpty()) { // return true; // } // // // Create save block. // final List finalModels = modelsToSave; // IRunnableWithProgress progressOp = new IRunnableWithProgress() { // public void run(IProgressMonitor monitor) { // IProgressMonitor monitorWrap = new EventLoopProgressMonitor( // monitor); // monitorWrap.beginTask("", finalModels.size()); //$NON-NLS-1$ // for (Iterator i = finalModels.iterator(); i.hasNext();) { // Saveable model = (Saveable) i.next(); // // handle case where this model got saved as a result of saving another // if (!model.isDirty()) { // monitor.worked(1); // continue; // } // SaveableHelper.doSaveModel(model, new SubProgressMonitor(monitorWrap, 1), shellProvider, closing || confirm); // if (monitorWrap.isCanceled()) { // break; // } // } // monitorWrap.done(); // } // }; // // // Do the save. // return SaveableHelper.runProgressMonitorOperation( // WorkbenchMessages.Save_All, progressOp, runnableContext, shellProvider); return true; } bool EditorManager::SavePart(ISaveablePart::Pointer /*saveable*/, IWorkbenchPart::Pointer /*part*/, bool /*confirm*/) { //TODO EditorManager save part (SaveableHelper) //return SaveableHelper.savePart(saveable, part, window, confirm); return true; } bool EditorManager::SaveState(const IMemento::Pointer memento) { // final MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, // IStatus.OK, // WorkbenchMessages.EditorManager_problemsSavingEditors, null); bool result = true; // Save the editor area workbooks layout/relationship IMemento::Pointer editorAreaMem = memento->CreateChild(WorkbenchConstants::TAG_AREA); //result.add(editorPresentation.saveState(editorAreaMem)); result &= editorPresentation->SaveState(editorAreaMem); // Save the active workbook id editorAreaMem->PutString(WorkbenchConstants::TAG_ACTIVE_WORKBOOK, editorPresentation->GetActiveEditorWorkbookID()); // Get each workbook QList workbooks(editorPresentation->GetWorkbooks()); for (QList::iterator iter = workbooks.begin(); iter != workbooks.end(); ++iter) { PartStack::Pointer workbook = *iter; // Use the list of editors found in EditorStack; fix for 24091 QList editorPanes(workbook->GetChildren()); for (QList::iterator i = editorPanes.begin(); i != editorPanes.end(); ++i) { // Save each open editor. EditorReference::Pointer editorReference = i->Cast()->GetPartReference().Cast(); IEditorPart::Pointer editor = editorReference->GetEditor(false); if (!editor) { if (editorReference->GetMemento()) { IMemento::Pointer editorMem = memento ->CreateChild(WorkbenchConstants::TAG_EDITOR); editorMem->PutMemento(editorReference->GetMemento()); } continue; } // for dynamic UI - add the next line to replace the subsequent // code which is commented out SaveEditorState(memento, editorReference); //, result); } } return result; } bool EditorManager::SetVisibleEditor(IEditorReference::Pointer newEd, bool setFocus) { return editorPresentation->SetVisibleEditor(newEd, setFocus); } IPathEditorInput::Pointer EditorManager::GetPathEditorInput( IEditorInput::Pointer input) { if (input.Cast().IsNotNull()) { return input.Cast(); } // return (IPathEditorInput) // Util.getAdapter(input, IPathEditorInput.class); return IPathEditorInput::Pointer(nullptr); } void EditorManager::RestoreEditorState(IMemento::Pointer /*editorMem*/, QList& /*visibleEditors*/, QList& /*activeEditor*/) { // MultiStatus result) { //TODO Restore editor state // String strFocus = editorMem.getString(IWorkbenchConstants.TAG_FOCUS); // boolean visibleEditor = "true".equals(strFocus); //$NON-NLS-1$ // EditorReference::Pointer e = new EditorReference(this, editorMem); // // try // { // StartupThreading.runWithPartInitExceptions(new StartupRunnable () // { // // public void runWithException() throws Throwable // { // createEditorTab(e, workbookID); // }}); // // } // catch (PartInitException ex) // { // result.add(ex.getStatus()); // } // // String strActivePart = editorMem // .getString(IWorkbenchConstants.TAG_ACTIVE_PART); // if ("true".equals(strActivePart)) // { //$NON-NLS-1$ // activeEditor[0] = e; // } // // String strFocus = editorMem.getString(IWorkbenchConstants.TAG_FOCUS); // boolean visibleEditor = "true".equals(strFocus); //$NON-NLS-1$ // if (visibleEditor) // { // visibleEditors.add(e); // } } void EditorManager::SaveEditorState(IMemento::Pointer /*mem*/, IEditorReference::Pointer /*ed*/) { //TODO Save editor state // final EditorReference editorRef = (EditorReference) ed; // final IEditorPart editor = ed.getEditor(false); // final IMemento memento = mem; // final MultiStatus result = res; // if (!(editor.getEditorSite() instanceof EditorSite)) // { // return; // } // final EditorSite site = (EditorSite) editor.getEditorSite(); // if (site.getPane() instanceof MultiEditorInnerPane) // { // return; // } // // SafeRunner.run(new SafeRunnable() // { // public void run() // { // // Get the input. // IEditorInput input = editor.getEditorInput(); // if (!input.exists()) // { // return; // } // IPersistableElement persistable = input.getPersistable(); // if (persistable == null) // { // return; // } // // // Save editor. // IMemento editorMem = memento // .createChild(IWorkbenchConstants.TAG_EDITOR); // editorMem.putString(IWorkbenchConstants.TAG_TITLE, editorRef // .getTitle()); // editorMem.putString(IWorkbenchConstants.TAG_NAME, editorRef // .getName()); // editorMem.putString(IWorkbenchConstants.TAG_ID, editorRef // .getId()); // editorMem.putString(IWorkbenchConstants.TAG_TOOLTIP, editorRef // .getTitleToolTip()); // // editorMem.putString(IWorkbenchConstants.TAG_PART_NAME, // editorRef.getPartName()); // // if (editor instanceof IWorkbenchPart3) // { // Map properties = ((IWorkbenchPart3) editor) // .getPartProperties(); // if (!properties.isEmpty()) // { // IMemento propBag = editorMem // .createChild(IWorkbenchConstants.TAG_PROPERTIES); // Iterator i = properties.entrySet().iterator(); // while (i.hasNext()) // { // Map.Entry entry = (Map.Entry) i.next(); // IMemento p = propBag.createChild( // IWorkbenchConstants.TAG_PROPERTY, // (String) entry.getKey()); // p.putTextData((String) entry.getValue()); // } // } // } // // if (editorRef.isPinned()) // { // editorMem.putString(IWorkbenchConstants.TAG_PINNED, "true"); //$NON-NLS-1$ // } // // EditorPane editorPane = (EditorPane) ((EditorSite) editor // .getEditorSite()).getPane(); // editorMem.putString(IWorkbenchConstants.TAG_WORKBOOK, // editorPane.getWorkbook().getID()); // // if (editor == page.getActivePart()) // { // editorMem.putString(IWorkbenchConstants.TAG_ACTIVE_PART, // "true"); //$NON-NLS-1$ // } // // if (editorPane == editorPane.getWorkbook().getSelection()) // { // editorMem.putString(IWorkbenchConstants.TAG_FOCUS, "true"); //$NON-NLS-1$ // } // // if (input instanceof IPathEditorInput) // { // IPath path = ((IPathEditorInput) input).getPath(); // if (path != null) // { // editorMem.putString(IWorkbenchConstants.TAG_PATH, path // .toString()); // } // } // // // Save input. // IMemento inputMem = editorMem // .createChild(IWorkbenchConstants.TAG_INPUT); // inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID, // persistable.getFactoryId()); // persistable.saveState(inputMem); // // // any editors that want to persist state // if (editor instanceof IPersistableEditor) // { // IMemento editorState = editorMem // .createChild(IWorkbenchConstants.TAG_EDITOR_STATE); // ((IPersistableEditor) editor).saveState(editorState); // } // } // // public void handleException(Throwable e) // { // result // .add(new Status( // IStatus.ERR, // PlatformUI.PLUGIN_ID, // 0, // NLS // .bind( // WorkbenchMessages.EditorManager_unableToSaveEditor, // editorRef.getTitle()), e)); // } // } // ); } IMemento::Pointer EditorManager::GetMemento(IEditorReference::Pointer e) { if (e.Cast().IsNotNull()) { return e.Cast()->GetMemento(); } return IMemento::Pointer(nullptr); } IEditorReference::Pointer EditorManager::OpenEmptyTab() { IEditorInput::Pointer input(new NullEditorInput()); EditorDescriptor::Pointer desc = (dynamic_cast(this->GetEditorRegistry())) ->FindEditor(EditorRegistry::EMPTY_EDITOR_ID).Cast(); EditorReference::Pointer result(new EditorReference(this, input, desc)); try { this->CreateEditorTab(result, ""); return result; } catch (const PartInitException& e) { // StatusManager.getManager().handle( // StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH, e)); BERRY_ERROR << e.what() << std::endl; } return IEditorReference::Pointer(nullptr); } bool EditorManager::UseIPersistableEditor() { // IPreferenceStore store = WorkbenchPlugin.getDefault() // .getPreferenceStore(); // return store.getBoolean(IPreferenceConstants.USE_IPERSISTABLE_EDITORS); return false; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorReference.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorReference.cpp index 2a6a4069e8..91e70a7209 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryEditorReference.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryEditorReference.cpp @@ -1,572 +1,572 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "tweaklets/berryWorkbenchPageTweaklet.h" #include "berryEditorReference.h" #include "berryEditorManager.h" #include "berryEditorDescriptor.h" #include "berryEditorRegistry.h" #include "berryEditorSite.h" #include "berryEditorAreaHelper.h" #include "berryWorkbenchPlugin.h" #include "berryWorkbenchPage.h" #include "berryNullEditorInput.h" #include "berryPartTester.h" #include "berryPlatformUI.h" #include "berryIWorkbenchPartConstants.h" namespace berry { EditorReference::EditorReference(EditorManager* man, IEditorInput::Pointer input, EditorDescriptor::Pointer desc, IMemento::Pointer editorState) : manager(man), expectingInputChange(false), reportedMalfunctioningEditor(false) { this->InitListenersAndHandlers(); restoredInput = input; this->editorState = editorState; this->Init(desc->GetId(), "", desc->GetImageDescriptor(), desc->GetLabel(), ""); } EditorReference::EditorReference(EditorManager* man, IMemento::Pointer memento) : manager(man), expectingInputChange(false), reportedMalfunctioningEditor(false) { this->InitListenersAndHandlers(); this->editorMemento = memento; if (manager->UseIPersistableEditor()) { //editorState = editorMemento->GetChild(WorkbenchConstants::TAG_EDITOR_STATE); } else { editorState = nullptr; } // String id = memento.getString(IWorkbenchConstants.TAG_ID); // String title = memento.getString(IWorkbenchConstants.TAG_TITLE); // String tooltip = Util.safeString(memento // .getString(IWorkbenchConstants.TAG_TOOLTIP)); // String partName = memento // .getString(IWorkbenchConstants.TAG_PART_NAME); // // IMemento propBag = memento.getChild(IWorkbenchConstants.TAG_PROPERTIES); // if (propBag != null) // { // IMemento[] props = propBag // .getChildren(IWorkbenchConstants.TAG_PROPERTY); // for (int i = 0; i < props.length; i++) // { // propertyCache.put(props[i].getID(), props[i].getTextData()); // } // } // For compatibility set the part name to the title if not found // if (partName.empty()) // { // partName = title; // } // Get the editor descriptor. // EditorDescriptor::Pointer desc; // if (id != null) // { // desc = getDescriptor(id); // } // // desc may be null if id is null or desc is not found, but findImage below handles this // String location = memento.getString(IWorkbenchConstants.TAG_PATH); // IPath path = location == null ? null : new Path(location); // ImageDescriptor iDesc = this.manager.findImage(desc, path); // // this.name = memento.getString(IWorkbenchConstants.TAG_NAME); // if (this.name == null) // { // this.name = title; // } // setPinned("true".equals(memento.getString(IWorkbenchConstants.TAG_PINNED))); //$NON-NLS-1$ // // IMemento inputMem = memento.getChild(IWorkbenchConstants.TAG_INPUT); // if (inputMem != null) // { // this.factoryId = inputMem // .getString(IWorkbenchConstants.TAG_FACTORY_ID); // } // // init(id, title, tooltip, iDesc, partName, ""); //$NON-NLS-1$ } EditorDescriptor::Pointer EditorReference::GetDescriptor() { return this->GetDescriptor(this->GetId()); } EditorDescriptor::Pointer EditorReference::GetDescriptor(const QString& id) { EditorDescriptor::Pointer desc; IEditorRegistry* reg = WorkbenchPlugin::GetDefault()->GetEditorRegistry(); desc = reg->FindEditor(id).Cast (); return desc; } void EditorReference::InitListenersAndHandlers() { // Create a property change listener to track the "close editors automatically" // preference and show/remove the pin icon on editors // Only 1 listener will be created in the EditorManager when necessary //this->manager->CheckCreateEditorPropListener(); // Create a keyboard shortcut handler for pinning editors // Only 1 handler will be created in the EditorManager when necessary //this->manager->CheckCreatePinEditorShortcutKeyHandler(); } PartPane::Pointer EditorReference::CreatePane() { PartPane::Pointer pane( new PartPane(IWorkbenchPartReference::Pointer(this), this->manager->page)); return pane; //return Tweaklets::Get(WorkbenchTweaklet::KEY)->CreateEditorPane(this, // this->manager->page); } void EditorReference::PinStatusUpdated() { //firePropertyChange(IWorkbenchPart.PROP_TITLE); } QString EditorReference::GetFactoryId() { // IEditorPart editor = getEditor(false); // if (editor != null) // { // IPersistableElement persistable = editor.getEditorInput() // .getPersistable(); // if (persistable != null) // { // return persistable.getFactoryId(); // } // return null; // } // return factoryId; return ""; } QString EditorReference::ComputePartName() const { return WorkbenchPartReference::ComputePartName(); } QString EditorReference::GetName() { if (part.IsNotNull()) { return this->GetEditor(false)->GetEditorInput()->GetName(); } return name; } IEditorPart::Pointer EditorReference::GetEditor(bool restore) { return this->GetPart(restore).Cast (); } void EditorReference::SetName(const QString& name) { this->name = name; } IMemento::Pointer EditorReference::GetMemento() { return editorMemento; } IWorkbenchPage::Pointer EditorReference::GetPage() const { return IWorkbenchPage::Pointer(this->manager->page); } IEditorInput::Pointer EditorReference::GetEditorInput() { IEditorPart::Pointer part = this->GetEditor(false); if (part.IsNotNull()) { return part->GetEditorInput(); } return this->GetRestoredInput(); } IEditorInput::Pointer EditorReference::GetRestoredInput() { if (restoredInput.IsNotNull()) { return restoredInput; } // Get the input factory. // IMemento::Pointer editorMem = this->GetMemento(); // if (editorMem == null) // { // throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_no_persisted_state, getId(), getName())); // } // IMemento inputMem = editorMem // .getChild(IWorkbenchConstants.TAG_INPUT); // String factoryID = null; // if (inputMem != null) // { // factoryID = inputMem // .getString(IWorkbenchConstants.TAG_FACTORY_ID); // } // if (factoryID == null) // { // throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_no_input_factory_ID, getId(), getName())); // } // IAdaptable input = null; // String label = null; // debugging only // if (UIStats.isDebugging(UIStats.CREATE_PART_INPUT)) // { // label = getName() != null ? getName() : factoryID; // } // try // { // UIStats.start(UIStats.CREATE_PART_INPUT, label); // IElementFactory factory = PlatformUI.getWorkbench() // .getElementFactory(factoryID); // if (factory == null) // { // throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_bad_element_factory, new Object[] // { factoryID, getId(), getName()})); // } // // // Get the input element. // input = factory.createElement(inputMem); // if (input == null) // { // throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_create_element_returned_null, new Object[] // { factoryID, getId(), getName()})); // } // }finally // { // UIStats.end(UIStats.CREATE_PART_INPUT, input, label); // } // if (!(input instanceof IEditorInput)) // { // throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_wrong_createElement_result, new Object[] // { factoryID, getId(), getName()})); // } // restoredInput = (IEditorInput) input; return restoredInput; } IWorkbenchPart::Pointer EditorReference::CreatePart() { if (EditorRegistry::EMPTY_EDITOR_ID == this->GetId()) { return this->GetEmptyEditor(this->GetDescriptor()); } IWorkbenchPart::Pointer result; // Try to restore the editor -- this does the real work of restoring the editor // try { result = this->CreatePartHelper().Cast (); - } catch (PartInitException e) + } catch (const PartInitException &e) { // If unable to create the part, create an error part instead // and pass the error to the status handling facility // IStatus originalStatus = exception.getStatus(); // IStatus logStatus = StatusUtil.newStatus(originalStatus, // NLS.bind("Unable to create editor ID {0}: {1}", //$NON-NLS-1$ // getId(), originalStatus.getMessage())); // IStatus displayStatus = StatusUtil.newStatus(originalStatus, // NLS.bind(WorkbenchMessages.EditorManager_unableToCreateEditor, // originalStatus.getMessage())); WorkbenchPlugin::Log(QString("Unable to create editor ID ") + this->GetId() + ": " + e.what()); // Pass the error to the status handling facility //StatusManager.getManager().handle(logStatus); EditorDescriptor::Pointer descr = this->GetDescriptor(); QString label = this->GetId(); if (descr.IsNotNull()) label = descr->GetLabel(); IEditorPart::Pointer part = Tweaklets::Get(WorkbenchPageTweaklet::KEY)->CreateErrorEditorPart(label, e.what()); if (part.IsNotNull()) { IEditorInput::Pointer input; try { input = this->GetEditorInput(); - } catch (PartInitException e1) + } catch (const PartInitException&) { input = new NullEditorInput(EditorReference::Pointer(this)); } PartPane::Pointer pane = this->GetPane(); pane->CreateControl( manager->page->GetEditorPresentation()->GetLayoutPart()->GetControl()); EditorSite::Pointer site( new EditorSite(IEditorReference::Pointer(this), part, manager->page, descr)); //site.setActionBars(new EditorActionBars(manager.page, site.getWorkbenchWindow(), getId())); part->Init(site, input); try { part->CreatePartControl(pane->GetControl()); } catch (...) { //content.dispose(); //StatusUtil.handleStatus(e, StatusManager.SHOW // | StatusManager.LOG); WorkbenchPlugin::Log("Error creating editor"); return IWorkbenchPart::Pointer(nullptr); } result = part.Cast (); } } return result; } void EditorReference::PropertyChanged(Object::Pointer source, int propId) { // Detect badly behaved editors that don't fire PROP_INPUT events // when they're supposed to. This branch is only needed to handle // malfunctioning editors. if (propId == IWorkbenchPartConstants::PROP_INPUT) { expectingInputChange = false; } WorkbenchPartReference::PropertyChanged(source, propId); } bool EditorReference::SetInput(IEditorInput::Pointer input) { if (part.IsNotNull()) { if (part.Cast ().IsNotNull()) { IReusableEditor::Pointer editor = part.Cast (); expectingInputChange = true; editor->SetInput(input); // If the editor never fired a PROP_INPUT event, log the fact that we've discovered // a buggy editor and fire the event for free. Firing the event for free isn't required // and cannot be relied on (it only works if the input change was triggered by this // method, and there are definitely other cases where events will still be lost), // but older versions of the workbench did this so we fire it here in the spirit // of playing nice. if (expectingInputChange) { // Log the fact that this editor is broken this->ReportMalfunction( "Editor is not firing a PROP_INPUT event in response to IReusableEditor.setInput(...)"); //$NON-NLS-1$ // Fire the property for free (can't be relied on since there are other ways the input // can change, but we do it here to be consistent with older versions of the workbench) FirePropertyChange(IWorkbenchPartConstants::PROP_INPUT); } return editor->GetEditorInput() == input; } // Can't change the input if the editor already exists and isn't an IReusableEditor return false; } // Changing the input is trivial and always succeeds if the editor doesn't exist yet if (input != restoredInput) { restoredInput = input; //firePropertyChange(IWorkbenchPartConstants.PROP_INPUT); } return true; } void EditorReference::ReportMalfunction(const QString& string) { if (!reportedMalfunctioningEditor) { reportedMalfunctioningEditor = true; QString errorMessage = "Problem detected with part " + this->GetId(); //$NON-NLS-1$ if (part.IsNotNull()) { errorMessage.append("(class = ").append(part->GetClassName()).append( ")"); //$NON-NLS-1$ //$NON-NLS-2$ } errorMessage += ": " + string; //$NON-NLS-1$ //StatusManager.getManager().handle(StatusUtil.newStatus(getDescriptor().getPluginId(), errorMessage, null)); BERRY_ERROR << errorMessage << std::endl; } } IEditorPart::Pointer EditorReference::CreatePartHelper() { EditorSite::Pointer site; IEditorPart::Pointer part; try { IEditorInput::Pointer editorInput = this->GetEditorInput(); // Get the editor descriptor. QString editorID = this->GetId(); EditorDescriptor::Pointer desc = this->GetDescriptor(); if (desc.IsNull()) { throw PartInitException("No editor descriptor for id " + editorID); } if (desc->IsInternal()) { // Create an editor instance. part = manager->CreatePart(desc); this->CreatePartProperties(part); } // else if (desc->GetId() == IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID) // { // // part = ComponentSupport.getSystemInPlaceEditor(); // // if (part == null) // { // throw new PartInitException(WorkbenchMessages.EditorManager_no_in_place_support); // } // } else { throw PartInitException("Invalid editor descriptor for id " + editorID); } // Create a pane for this part PartPane::Pointer pane = this->GetPane(); pane->CreateControl(manager->page->GetEditorPresentation()->GetLayoutPart()->GetControl()); // Link everything up to the part reference (the part reference itself should not have // been modified until this point) site = manager->CreateSite(IEditorReference::Pointer(this), part, desc, editorInput); // if there is saved state that's appropriate, pass it on if (/*part instanceof IPersistableEditor &&*/editorState.IsNotNull()) { //part->RestoreState(editorState); } // Remember the site and the action bars (now that we've created them, we'll need to dispose // them if an exception occurs) //actionBars = (EditorActionBars) site.getActionBars(); part->CreatePartControl(pane->GetControl()); // The editor should now be fully created. Exercise its public interface, and sanity-check // it wherever possible. If it's going to throw exceptions or behave badly, it's much better // that it does so now while we can still cancel creation of the part. PartTester::TestEditor(part); return part; - } catch (std::exception e) + } catch (const std::exception &e) { throw PartInitException(e.what()); } } IEditorPart::Pointer EditorReference::GetEmptyEditor( EditorDescriptor::Pointer descr) { IEditorPart::Pointer part = Tweaklets::Get(WorkbenchPageTweaklet::KEY)->CreateErrorEditorPart("(Empty)", ""); IEditorInput::Pointer input; try { input = this->GetEditorInput(); - } catch (PartInitException e1) + } catch (const PartInitException&) { input = new NullEditorInput(EditorReference::Pointer(this)); } PartPane::Pointer pane = this->GetPane(); pane->CreateControl( manager->page->GetEditorPresentation()->GetLayoutPart()->GetControl()); EditorSite::Pointer site(new EditorSite(IEditorReference::Pointer(this), part, manager->page, descr)); //site.setActionBars(new EditorActionBars(manager.page, site.getWorkbenchWindow(), getId())); part->Init(site, input); try { part->CreatePartControl(pane->GetControl()); - } catch (std::exception e) + } catch (const std::exception &e) { //StatusManager.getManager().handle( // StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH, e)); BERRY_ERROR << e.what() << std::endl; return IEditorPart::Pointer(nullptr); } this->part = part.Cast (); // Add a dispose listener to the part. This dispose listener does nothing but log an exception // if the part's widgets get disposed unexpectedly. The workbench part reference is the only // object that should dispose this control, and it will remove the listener before it does so. this->RefreshFromPart(); //this->ReleaseReferences(); if (this->GetPage().Cast ()->GetActiveEditorReference() != this) { //fireInternalPropertyChange(INTERNAL_PROPERTY_OPENED); } return part; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryViewRegistryReader.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryViewRegistryReader.cpp index 39f44724bb..e2aabe5e09 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryViewRegistryReader.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryViewRegistryReader.cpp @@ -1,113 +1,113 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "berryViewRegistryReader.h" #include "berryViewRegistry.h" #include "berryWorkbenchRegistryConstants.h" #include "berryWorkbenchPlugin.h" #include "berryPlatformUI.h" namespace berry { QString ViewRegistryReader::GENERAL_VIEW_ID = "org.blueberry.ui"; ViewRegistryReader::ViewRegistryReader() : RegistryReader() { } void ViewRegistryReader::ReadViews(IExtensionRegistry* in, ViewRegistry* out) { // this does not seem to really ever be throwing an the exception viewRegistry = out; this->ReadRegistry(in, PlatformUI::PLUGIN_ID(), WorkbenchRegistryConstants::PL_VIEWS); } void ViewRegistryReader::ReadCategory(const IConfigurationElement::Pointer& element) { try { Category::Pointer cat(new Category(element)); viewRegistry->Add(cat); } - catch (CoreException e) + catch (const CoreException &e) { // log an error since its not safe to show a dialog here WorkbenchPlugin::Log( "Unable to create view category.", e); } } bool ViewRegistryReader::ReadElement(const SmartPointer &element) { QString elementName = element->GetName(); if (elementName == WorkbenchRegistryConstants::TAG_VIEW) { this->ReadView(element); return true; } if (elementName == WorkbenchRegistryConstants::TAG_CATEGORY) { this->ReadCategory(element); this->ReadElementChildren(element); return true; } if (elementName == WorkbenchRegistryConstants::TAG_STICKYVIEW) { this->ReadSticky(element); return true; } return false; } void ViewRegistryReader::ReadSticky(const SmartPointer &element) { try { viewRegistry->Add(StickyViewDescriptor::Pointer(new StickyViewDescriptor(element))); } - catch (CoreException& e) + catch (const CoreException& e) { //TODO IStatus // log an error since its not safe to open a dialog here // WorkbenchPlugin.log( // "Unable to create sticky view descriptor.", e.getStatus());//$NON-NLS-1$ WorkbenchPlugin::Log("Unable to create sticky view descriptor.", e); } } void ViewRegistryReader::ReadView(const SmartPointer &element) { try { ViewDescriptor::Pointer desc(new ViewDescriptor(element)); viewRegistry->Add(desc); } - catch (CoreException e) + catch (const CoreException &e) { // log an error since its not safe to open a dialog here WorkbenchPlugin::Log( "Unable to create view descriptor.", e);//$NON-NLS-1$ } } } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTNavigationToolCalibration.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTNavigationToolCalibration.cpp index 7b05ed2277..3205d28f18 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTNavigationToolCalibration.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTNavigationToolCalibration.cpp @@ -1,755 +1,756 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include // Blueberry #include #include // Qmitk #include "QmitkIGTNavigationToolCalibration.h" // mitk #include #include #include #include #include #include #include // Qt #include #include //vtk #include const std::string QmitkIGTNavigationToolCalibration::VIEW_ID = "org.mitk.views.igtnavigationtoolcalibration"; QmitkIGTNavigationToolCalibration::QmitkIGTNavigationToolCalibration() { m_ToolTransformationWidget = new QmitkInteractiveTransformationWidget(); } QmitkIGTNavigationToolCalibration::~QmitkIGTNavigationToolCalibration() { //The following code is required due to a bug in the point list widget. //If this is removed, MITK crashes when closing the view: m_Controls.m_RegistrationLandmarkWidget->SetPointSetNode(nullptr); m_Controls.m_CalibrationLandmarkWidget->SetPointSetNode(nullptr); //clean up data storage this->GetDataStorage()->Remove(m_ToolTipPointPreview); delete m_ToolTransformationWidget; } void QmitkIGTNavigationToolCalibration::SetFocus() { } void QmitkIGTNavigationToolCalibration::OnToolCalibrationMethodChanged(int index) { //if pivot calibration (3) or manual(0) is chosen only calibration pointer is needed if (index == 0 || index == 3) { if (!CheckInitialization(false)) { return; } } else{ if (!CheckInitialization()) { return; } } UpdateManualToolTipCalibrationView(); m_Controls.m_CalibrationMethodsWidget->setCurrentIndex(index); m_IndexCurrentCalibrationMethod = index; } void QmitkIGTNavigationToolCalibration::CreateQtPartControl(QWidget *parent) { m_TrackingTimer = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.m_SetToolToCalibrate, SIGNAL(clicked()), this, SLOT(SetToolToCalibrate())); connect(m_Controls.m_SetPointer, SIGNAL(clicked()), this, SLOT(SetCalibrationPointer())); connect(m_TrackingTimer, SIGNAL(timeout()), this, SLOT(UpdateTrackingTimer())); connect(m_Controls.m_AddLandmark, SIGNAL(clicked()), this, SLOT(AddLandmark())); connect(m_Controls.m_SaveCalibratedTool, SIGNAL(clicked()), this, SLOT(SaveCalibratedTool())); connect(m_Controls.m_AddPivotPose, SIGNAL(clicked()), this, SLOT(OnAddPivotPose())); connect(m_Controls.m_ComputePivot, SIGNAL(clicked()), this, SLOT(OnComputePivot())); connect(m_Controls.m_UseComputedPivotPoint, SIGNAL(clicked()), this, SLOT(OnUseComputedPivotPoint())); connect(m_Controls.m_StartEditTooltipManually, SIGNAL(clicked()), this, SLOT(OnStartManualToolTipCalibration())); connect(m_Controls.m_GetPositions, SIGNAL(clicked()), this, SLOT(OnGetPositions())); connect(m_Controls.m_ToolAxis_X, SIGNAL(valueChanged(double)), this, SLOT(OnToolAxisSpinboxChanged())); connect(m_Controls.m_ToolAxis_Y, SIGNAL(valueChanged(double)), this, SLOT(OnToolAxisSpinboxChanged())); connect(m_Controls.m_ToolAxis_Z, SIGNAL(valueChanged(double)), this, SLOT(OnToolAxisSpinboxChanged())); connect(m_Controls.m_CalibrateToolAxis, SIGNAL(clicked()), this, SLOT(OnCalibrateToolAxis())); connect((QObject*)(m_ToolTransformationWidget), SIGNAL(EditToolTipFinished(mitk::AffineTransform3D::Pointer)), this, SLOT(OnManualEditToolTipFinished(mitk::AffineTransform3D::Pointer))); connect(m_Controls.m_CalibrationMethodComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnToolCalibrationMethodChanged(int))); connect((QObject*)(m_Controls.m_RunCalibrationButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnRunSingleRefToolCalibrationClicked())); connect((QObject*)(m_Controls.m_CollectNavigationDataButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnLoginSingleRefToolNavigationDataClicked())); connect((QObject*)(m_Controls.m_SetNewToolTipPosButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnSetNewToolTipPosButtonClicked())); m_IDToolToCalibrate = -1; m_IDCalibrationPointer = -1; m_IndexCurrentCalibrationMethod = -1; m_OnLoginSingleRefToolNavigationDataClicked = false; m_NumberOfNavigationDataCounter = 0; m_NumberOfNavigationData = -1; //for pivot calibration m_OnAddPivotPoseClicked = false; PivotCount = 0; m_PivotPoses = std::vector(); m_CalibrationLandmarks = mitk::PointSet::New(); m_CalibrationLandmarksNode = mitk::DataNode::New(); m_CalibrationLandmarksNode->SetData(m_CalibrationLandmarks); m_Controls.m_CalibrationLandmarkWidget->SetPointSetNode(m_CalibrationLandmarksNode); m_RegistrationLandmarks = mitk::PointSet::New(); m_RegistrationLandmarksNode = mitk::DataNode::New(); m_RegistrationLandmarksNode->SetData(m_RegistrationLandmarks); m_Controls.m_RegistrationLandmarkWidget->SetPointSetNode(m_RegistrationLandmarksNode); m_ToolSurfaceInToolCoordinatesDataNode = mitk::DataNode::New(); m_ToolSurfaceInToolCoordinatesDataNode->SetName("ToolSurface(ToolCoordinates)"); m_LoggedNavigationDataDifferences = std::vector< mitk::NavigationData::Pointer >(); } void QmitkIGTNavigationToolCalibration::OnRunSingleRefToolCalibrationClicked() { if (!CheckInitialization()) { return; } mitk::NavigationData::Pointer ToolTipTransform = mitk::NavigationData::New(); if (m_Controls.m_CalibratePosition->isChecked()) { //1: Compute mean translational offset vector m_ResultOffsetVector.Fill(0); for (std::vector::iterator vecIter = m_LoggedNavigationDataOffsets.begin(); vecIter != m_LoggedNavigationDataOffsets.end(); vecIter++) { m_ResultOffsetVector[0] = m_ResultOffsetVector[0] + (*vecIter)[0]; m_ResultOffsetVector[1] = m_ResultOffsetVector[1] + (*vecIter)[1]; m_ResultOffsetVector[2] = m_ResultOffsetVector[2] + (*vecIter)[2]; } m_ResultOffsetVector[0] = m_ResultOffsetVector[0] / m_LoggedNavigationDataOffsets.size(); m_ResultOffsetVector[1] = m_ResultOffsetVector[1] / m_LoggedNavigationDataOffsets.size(); m_ResultOffsetVector[2] = m_ResultOffsetVector[2] / m_LoggedNavigationDataOffsets.size(); this->m_Controls.m_ResultOfCalibration->setText( QString("x: ") + QString(QString::number(m_ResultOffsetVector[0], 103, 3)) + QString("; y: ") + (QString::number(m_ResultOffsetVector[1], 103, 3)) + QString("; z: ") + (QString::number(m_ResultOffsetVector[2], 103, 3))); ToolTipTransform->SetPosition(m_ResultOffsetVector); } if (m_Controls.m_CalibrateOrientation->isChecked()) { //2: Compute mean orientation mitk::Quaternion meanOrientation; std::vector allOrientations = std::vector (); for (std::size_t i = 0; i < m_LoggedNavigationDataDifferences.size(); i++) { allOrientations.push_back(m_LoggedNavigationDataDifferences.at(i)->GetOrientation()); } meanOrientation = mitk::QuaternionAveraging::CalcAverage(allOrientations); this->m_Controls.m_ResultOfCalibrationOrientation->setText( QString("qx: ") + QString(QString::number(meanOrientation.x(), 103, 3)) + QString("; qy: ") + (QString::number(meanOrientation.y(), 103, 3)) + QString("; qz: ") + (QString::number(meanOrientation.z(), 103, 3)) + QString("; qr: ") + (QString::number(meanOrientation.r(), 103, 3))); ToolTipTransform->SetOrientation(meanOrientation); } MITK_INFO << "Computed calibration: "; MITK_INFO << "Translation Vector: " << ToolTipTransform->GetPosition(); MITK_INFO << "Quaternion: (" << ToolTipTransform->GetOrientation() << ")"; MITK_INFO << "Euler Angles [rad]: (" << ToolTipTransform->GetOrientation().rotation_euler_angles() << ")"; MITK_INFO << "Matrix:"; vnl_matrix_fixed rotMatrix = ToolTipTransform->GetOrientation().rotation_matrix_transpose(); MITK_INFO << rotMatrix[0][0] << " " << rotMatrix[0][1] << " " << rotMatrix[0][2] << std::endl; MITK_INFO << rotMatrix[1][0] << " " << rotMatrix[1][1] << " " << rotMatrix[1][2] << std::endl; MITK_INFO << rotMatrix[2][0] << " " << rotMatrix[2][1] << " " << rotMatrix[2][2] << std::endl; //3: write everything into the final tool tip transform and save it as member (it will be written to the tool later on) mitk::NavigationData::Pointer ToolTipInTrackingCoordinates = mitk::NavigationData::New(); ToolTipInTrackingCoordinates->Compose(ToolTipTransform); ToolTipInTrackingCoordinates->Compose(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); ShowToolTipPreview(ToolTipInTrackingCoordinates); m_Controls.m_SetNewToolTipPosButton->setEnabled(true); m_ComputedToolTipTransformation = ToolTipTransform; } void QmitkIGTNavigationToolCalibration::OnLoginSingleRefToolNavigationDataClicked() { if (!CheckInitialization()) { return; } //reset old data m_LoggedNavigationDataOffsets.clear(); m_LoggedNavigationDataDifferences.clear(); m_OnLoginSingleRefToolNavigationDataClicked = true; m_Controls.m_CollectNavigationDataButton->setEnabled(false); m_NumberOfNavigationData = m_Controls.m_NumberOfNavigationDataToCollect->value(); MITK_INFO << "Collecting " << m_NumberOfNavigationData << " NavigationData ... " << endl; } void QmitkIGTNavigationToolCalibration::LoginSingleRefToolNavigationData() { if (!CheckInitialization()) { return; } if (m_NumberOfNavigationDataCounter < m_NumberOfNavigationData) { //update label text QString labelText = "Collecting Data: " + QString::number(m_NumberOfNavigationDataCounter); m_Controls.m_CollectionStatus->setText(labelText); mitk::NavigationData::Pointer referenceTool = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer); mitk::NavigationData::Pointer toolToCalibrate = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); //compute difference: // differenceND = toolToCalibrate^-1 * referenceTool mitk::NavigationData::Pointer differenceND = mitk::NavigationData::New(); differenceND->Compose(referenceTool); differenceND->Compose(toolToCalibrate->GetInverse()); //inverse mode... if (m_Controls.m_InvertQuaternions->isChecked()) { // negate identity matrix to directly show parameters that will set up in NDI 6D Software Architect differenceND = differenceND->GetInverse(); } //save difference in member m_LoggedNavigationDataOffsets.push_back(differenceND->GetPosition()); m_LoggedNavigationDataDifferences.push_back(differenceND); m_NumberOfNavigationDataCounter++; } if (m_NumberOfNavigationDataCounter == m_NumberOfNavigationData) { m_NumberOfNavigationDataCounter = 0; m_OnLoginSingleRefToolNavigationDataClicked = false; m_Controls.m_CollectNavigationDataButton->setEnabled(true); m_Controls.m_RunCalibrationButton->setEnabled(true); MITK_INFO << "Collecting " << m_NumberOfNavigationData << " NavigationData ... Finished" << endl; QString labelText = "Collected " + QString::number(m_NumberOfNavigationData) + " data samples!"; m_Controls.m_CollectionStatus->setText(labelText); } } void QmitkIGTNavigationToolCalibration::OnSetNewToolTipPosButtonClicked() { ApplyToolTipTransform(m_ComputedToolTipTransformation); RemoveToolTipPreview(); } void QmitkIGTNavigationToolCalibration::ClearOldPivot() { mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(); this->ApplyToolTipTransform(tempND); UpdateManualToolTipCalibrationView(); //m_ManualToolTipEditWidget->hide(); //TODO this->GetDataStorage()->Remove(m_ToolSurfaceInToolCoordinatesDataNode); } void QmitkIGTNavigationToolCalibration::OnAddPivotPose() { ClearOldPivot(); //When the collect Poses Button is Clicked m_OnAddPivotPoseClicked = true; m_NumberOfNavigationData = m_Controls.m_PosesToCollect->value(); } void QmitkIGTNavigationToolCalibration::AddPivotPose() { //Save the poses to be used in computation if (PivotCount < m_NumberOfNavigationData) { mitk::NavigationData::Pointer currentPose = mitk::NavigationData::New(); currentPose->Graft(m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_IDToolToCalibrate)); m_PivotPoses.push_back(currentPose); m_Controls.m_PoseNumber->setText(QString::number(m_PivotPoses.size())); PivotCount++; } if (PivotCount == m_NumberOfNavigationData) { m_OnAddPivotPoseClicked = false; } } void QmitkIGTNavigationToolCalibration::OnComputePivot() { mitk::PivotCalibration::Pointer myPivotCalibration = mitk::PivotCalibration::New(); for (std::size_t i = 0; i < this->m_PivotPoses.size(); i++) { myPivotCalibration->AddNavigationData(m_PivotPoses.at(i)); } QString resultString; if (myPivotCalibration->ComputePivotResult()) { mitk::NavigationData::Pointer markerTransformationTrackingCoordinates = m_PivotPoses.at(0); //Get computed pivot transfromation in tool coordinates mitk::NavigationData::Pointer ToolTipToTool = mitk::NavigationData::New(); ToolTipToTool->SetPosition(myPivotCalibration->GetResultPivotPoint()); ToolTipToTool->SetOrientation(mitk::Quaternion(0,0,0,1)); mitk::NavigationData::Pointer TrackerToTool = mitk::NavigationData::New(); TrackerToTool->SetOrientation(markerTransformationTrackingCoordinates->GetOrientation()); TrackerToTool->SetPosition(markerTransformationTrackingCoordinates->GetPosition()); TrackerToTool->Compose(ToolTipToTool); // Compute pivot point in relation to marker transformation for preview mitk::NavigationData::Pointer ToolTipToTracker = mitk::NavigationData::New(); ToolTipToTracker->Compose(ToolTipToTool); ToolTipToTracker->Compose(markerTransformationTrackingCoordinates); //add the preview node to the data storage ShowToolTipPreview(ToolTipToTracker); //parse result string resultString = QString("Pivot computation succeeded!\n") + QString("RMS Error: ") + QString::number(myPivotCalibration->GetResultRMSError()) + QString("\n") + QString("Pivot Point: ") + QString::number(myPivotCalibration->GetResultPivotPoint()[0]) + ";" + QString::number(myPivotCalibration->GetResultPivotPoint()[1]) + ";" + QString::number(myPivotCalibration->GetResultPivotPoint()[2]) + QString("\n"); //finally: save results to member variable m_ComputedToolTipTransformation = ToolTipToTool; //enable button to use the computed point with the tool m_Controls.m_UseComputedPivotPoint->setEnabled(true); } else { resultString = "Pivot computation failed!"; } MITK_INFO << resultString.toStdString().c_str(); m_Controls.m_ResultText->setText(resultString); } void QmitkIGTNavigationToolCalibration::UpdatePivotCount() { PivotCount = 0; while (!m_PivotPoses.empty()) { m_PivotPoses.pop_back(); } m_Controls.m_PoseNumber->setText(QString::number(PivotCount)); } void QmitkIGTNavigationToolCalibration::OnUseComputedPivotPoint() { RemoveToolTipPreview(); QString resultString = QString("Pivoted tool tip transformation was written to the tool ") + m_ToolToCalibrate->GetToolName().c_str(); ApplyToolTipTransform(m_ComputedToolTipTransformation, resultString.toStdString()); m_Controls.m_ResultText->setText(resultString); UpdatePivotCount(); } void QmitkIGTNavigationToolCalibration::ApplyToolTipTransform(mitk::NavigationData::Pointer ToolTipTransformInToolCoordinates, std::string message) { if (!CheckInitialization(false)) { return; } //Update tool in tool storage m_ToolToCalibrate->SetToolTipPosition(ToolTipTransformInToolCoordinates->GetPosition()); m_ToolToCalibrate->SetToolAxisOrientation(ToolTipTransformInToolCoordinates->GetOrientation()); //And also update tracking device, so the transform is directly used mitk::TrackingDeviceSource::Pointer trackingDeviceSource; try { trackingDeviceSource = dynamic_cast(m_NavigationDataSourceOfToolToCalibrate.GetPointer()); mitk::TrackingTool::Pointer TrackingToolToCalibrate = trackingDeviceSource->GetTrackingDevice()->GetTool(m_IDToolToCalibrate); TrackingToolToCalibrate->SetToolTipPosition(ToolTipTransformInToolCoordinates->GetPosition(), ToolTipTransformInToolCoordinates->GetOrientation()); } catch (std::exception& e) { MITK_ERROR << "Error while trying to set the tool tip to the running tracking device. Aborting! (" << e.what() << ")"; } MITK_INFO << message; } void QmitkIGTNavigationToolCalibration::ShowToolTipPreview(mitk::NavigationData::Pointer ToolTipInTrackingCoordinates) { if(m_ToolTipPointPreview.IsNull()) { m_ToolTipPointPreview = mitk::DataNode::New(); m_ToolTipPointPreview->SetName("Modified Tool Tip Preview"); mitk::Color blue; blue.SetBlue(1); m_ToolTipPointPreview->SetColor(blue); mitk::Surface::Pointer mySphere = mitk::Surface::New(); vtkSmartPointer vtkData = vtkSmartPointer::New(); vtkData->SetRadius(3.0f); vtkData->SetCenter(0.0, 0.0, 0.0); vtkData->Update(); mySphere->SetVtkPolyData(vtkData->GetOutput()); m_ToolTipPointPreview->SetData(mySphere); this->GetDataStorage()->Add(m_ToolTipPointPreview); } m_ToolTipPointPreview->GetData()->GetGeometry()->SetIndexToWorldTransform(ToolTipInTrackingCoordinates->GetAffineTransform3D()); } void QmitkIGTNavigationToolCalibration::RemoveToolTipPreview() { this->GetDataStorage()->Remove(m_ToolTipPointPreview.GetPointer()); } void QmitkIGTNavigationToolCalibration::UpdateManualToolTipCalibrationView() { if (m_ToolToCalibrate.IsNull()) { return; } //parse human readable transformation data and display it std::stringstream translation; std::stringstream orientation; translation << m_ToolToCalibrate->GetToolTipPosition(); orientation << "Quaternion: (" << m_ToolToCalibrate->GetToolAxisOrientation() << ")" << std::endl; orientation << std::endl; orientation << "Euler Angles [rad]: (" << m_ToolToCalibrate->GetToolAxisOrientation().rotation_euler_angles() << ")" << std::endl; orientation << std::endl; orientation << "Matrix:" << std::endl; vnl_matrix_fixed rotMatrix = m_ToolToCalibrate->GetToolAxisOrientation().rotation_matrix_transpose(); orientation << rotMatrix[0][0] << " " << rotMatrix[0][1] << " " << rotMatrix[0][2] << std::endl; orientation << rotMatrix[1][0] << " " << rotMatrix[1][1] << " " << rotMatrix[1][2] << std::endl; orientation << rotMatrix[2][0] << " " << rotMatrix[2][1] << " " << rotMatrix[2][2] << std::endl; m_Controls.m_ManualCurrentTranslation->setText(translation.str().c_str()); m_Controls.m_ManualCurrentOrientation->setPlainText(orientation.str().c_str()); } void QmitkIGTNavigationToolCalibration::OnStartManualToolTipCalibration() { if (!CheckInitialization(false)) { return; } m_ToolTransformationWidget->SetToolToEdit(m_ToolToCalibrate); m_ToolTransformationWidget->SetDefaultOffset(m_ToolToCalibrate->GetToolTipPosition()); m_ToolTransformationWidget->SetDefaultRotation(m_ToolToCalibrate->GetToolAxisOrientation()); m_ToolTransformationWidget->open(); } void QmitkIGTNavigationToolCalibration::OnManualEditToolTipFinished(mitk::AffineTransform3D::Pointer toolTip) { //This function is called, when the toolTipEdit view is closed. //if user pressed cancle, nullptr is returned. Do nothing. Else, set values. if (toolTip) { mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(toolTip);//Convert to Navigation data for simple transversion to quaternion QString resultString = QString("Manual edited values are written to ") + m_ToolToCalibrate->GetToolName().c_str(); ApplyToolTipTransform(tempND, resultString.toStdString()); m_Controls.m_ResultText->setText(resultString); + m_ComputedToolTipTransformation = tempND; } UpdateManualToolTipCalibrationView(); } void QmitkIGTNavigationToolCalibration::OnGetPositions() { if (!CheckInitialization(true)) { return; } //Navigation Data from Tool which should be calibrated if (!m_AxisCalibration_ToolToCalibrate) m_AxisCalibration_ToolToCalibrate = mitk::NavigationData::New(); m_AxisCalibration_ToolToCalibrate->Graft(m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_IDToolToCalibrate)); //Navigation Data from calibration pointer tool if (!m_AxisCalibration_NavDataCalibratingTool) m_AxisCalibration_NavDataCalibratingTool = mitk::NavigationData::New(); m_AxisCalibration_NavDataCalibratingTool->Graft(m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_IDCalibrationPointer)); MITK_DEBUG << "Positions for tool axis calibration:"; MITK_DEBUG << " ToolTip: " << m_AxisCalibration_ToolToCalibrate->GetPosition() << ","; MITK_DEBUG << " Rotation: \n" << m_AxisCalibration_ToolToCalibrate->GetRotationMatrix(); MITK_DEBUG << " End of the tool: " << m_AxisCalibration_NavDataCalibratingTool->GetPosition(); QString _label = "Position recorded: " + QString::number(m_AxisCalibration_NavDataCalibratingTool->GetPosition()[0], 'f', 1) + ", " + QString::number(m_AxisCalibration_NavDataCalibratingTool->GetPosition()[1], 'f', 1) + ", " + QString::number(m_AxisCalibration_NavDataCalibratingTool->GetPosition()[2], 'f', 1); m_Controls.m_ToolAxisPositionLabel->setText(_label); } void QmitkIGTNavigationToolCalibration::OnCalibrateToolAxis() { if (!m_ComputedToolTipTransformation) { MITK_ERROR << "Please compute tool tip first."; QMessageBox::information(NULL, "Error", "Please compute / specifiy tool tip first"); return; } if (!m_AxisCalibration_ToolToCalibrate || !m_AxisCalibration_NavDataCalibratingTool) { MITK_ERROR << "Please record position first."; QMessageBox::information(NULL, "Error", "Please record position first"); return; } //Calculate the tool tip //here is an explanation, what is happening here: /* The axis is equal to the (tool tip) minus the (end of the tool) in tool coordinates of the tool which should be calibrated. The tool tip is defined as the origin of the tool coordinate system. The end of the tool is recorded by the calibration pointer's position and is transformed into the coordinate system of the tool to be calibrated Normalize it. */ //m_CalibratedToolAxis = -m_AxisCalibration_ToolToCalibrate->TransformPoint(m_AxisCalibration_NavDataCalibratingTool->GetPosition()).GetVectorFromOrigin(); m_CalibratedToolAxis = -m_AxisCalibration_ToolToCalibrate->GetInverse()->TransformPoint(m_AxisCalibration_NavDataCalibratingTool->GetPosition()).GetVectorFromOrigin(); MITK_DEBUG << "Tool Endpoint in Tool coordinates: " << m_CalibratedToolAxis; m_CalibratedToolAxis.Normalize(); MITK_DEBUG << "Tool Axis: " << m_CalibratedToolAxis; m_ToolToCalibrate->SetToolAxis(m_CalibratedToolAxis); // Update TrackingTool m_ComputedToolTipTransformation->SetPosition(m_ToolToCalibrate->GetToolTipPosition()); m_ComputedToolTipTransformation->SetOrientation(m_ToolToCalibrate->GetToolAxisOrientation()); ApplyToolTipTransform(m_ComputedToolTipTransformation); //Update GUI QString calibratedToolAxisString = "Tool Axis: " + QString::number(m_CalibratedToolAxis.GetElement(0), 'f', 3) + ", " + QString::number(m_CalibratedToolAxis.GetElement(1), 'f', 3) + ", " + QString::number(m_CalibratedToolAxis.GetElement(2), 'f', 3); m_Controls.m_ToolAxisCalibrationLabel->setText(calibratedToolAxisString); //Block QT signals, we don't want to emit SpinboxChanged on the first value to overwrite the next ones m_Controls.m_ToolAxis_X->blockSignals(true); m_Controls.m_ToolAxis_Y->blockSignals(true); m_Controls.m_ToolAxis_Z->blockSignals(true); m_Controls.m_ToolAxis_X->setValue(m_CalibratedToolAxis[0]); m_Controls.m_ToolAxis_Y->setValue(m_CalibratedToolAxis[1]); m_Controls.m_ToolAxis_Z->setValue(m_CalibratedToolAxis[2]); m_Controls.m_ToolAxis_X->blockSignals(false); m_Controls.m_ToolAxis_Y->blockSignals(false); m_Controls.m_ToolAxis_Z->blockSignals(false); } void QmitkIGTNavigationToolCalibration::OnToolAxisSpinboxChanged() { m_CalibratedToolAxis.SetElement(0, m_Controls.m_ToolAxis_X->value()); m_CalibratedToolAxis.SetElement(1, m_Controls.m_ToolAxis_Y->value()); m_CalibratedToolAxis.SetElement(2, m_Controls.m_ToolAxis_Z->value()); m_ToolToCalibrate->SetToolAxis(m_CalibratedToolAxis); // Update TrackingTool if (m_ComputedToolTipTransformation.IsNull()) { m_ComputedToolTipTransformation = mitk::NavigationData::New(); } m_ComputedToolTipTransformation->SetPosition(m_ToolToCalibrate->GetToolTipPosition()); m_ComputedToolTipTransformation->SetOrientation(m_ToolToCalibrate->GetToolAxisOrientation()); ApplyToolTipTransform(m_ComputedToolTipTransformation); MITK_INFO << "Tool axis changed to " << m_CalibratedToolAxis; } void QmitkIGTNavigationToolCalibration::SetToolToCalibrate() { m_IDToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedToolID(); if (m_IDToolToCalibrate == -1) //no valid tool to calibrate { m_Controls.m_CalToolLabel->setText(""); m_Controls.m_StatusWidgetToolToCalibrate->RemoveStatusLabels(); m_TrackingTimer->stop(); } else { m_ToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedNavigationTool(); m_NavigationDataSourceOfToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource(); m_Controls.m_CalToolLabel->setText(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)->GetName()); //initialize widget m_Controls.m_StatusWidgetToolToCalibrate->RemoveStatusLabels(); m_Controls.m_StatusWidgetToolToCalibrate->SetShowPositions(true); m_Controls.m_StatusWidgetToolToCalibrate->SetTextAlignment(Qt::AlignLeft); m_Controls.m_StatusWidgetToolToCalibrate->AddNavigationData(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); m_Controls.m_StatusWidgetToolToCalibrate->ShowStatusLabels(); //initialize manual tool tip calibration view UpdateManualToolTipCalibrationView(); //save tool surface in tool coordinates for further editing mitk::Surface::Pointer ToolSurface = dynamic_cast(m_ToolToCalibrate->GetDataNode()->GetData())->Clone(); m_ToolSurfaceInToolCoordinatesDataNode->SetData(ToolSurface); m_ToolSurfaceInToolCoordinatesDataNode->GetData()->GetGeometry()->SetIdentity(); // update tool tip and rotation information for tool tip calibration tab UpdateManualToolTipCalibrationView(); // update tool axis information for tool axis calibration tab mitk::Point3D toolAxis = m_ToolToCalibrate->GetToolAxis(); m_CalibratedToolAxis[0] = toolAxis[0]; m_CalibratedToolAxis[1] = toolAxis[1]; m_CalibratedToolAxis[2] = toolAxis[2]; m_Controls.m_ToolAxis_X->blockSignals(true); m_Controls.m_ToolAxis_Y->blockSignals(true); m_Controls.m_ToolAxis_Z->blockSignals(true); m_Controls.m_ToolAxis_X->setValue(m_CalibratedToolAxis[0]); m_Controls.m_ToolAxis_Y->setValue(m_CalibratedToolAxis[1]); m_Controls.m_ToolAxis_Z->setValue(m_CalibratedToolAxis[2]); m_Controls.m_ToolAxis_X->blockSignals(false); m_Controls.m_ToolAxis_Y->blockSignals(false); m_Controls.m_ToolAxis_Z->blockSignals(false); //start updating timer for status widgets, etc. if (!m_TrackingTimer->isActive()) m_TrackingTimer->start(100); } } void QmitkIGTNavigationToolCalibration::SetCalibrationPointer() { m_IDCalibrationPointer = m_Controls.m_SelectionWidget->GetSelectedToolID(); if (m_IDCalibrationPointer == -1) { m_Controls.m_PointerLabel->setText(""); m_Controls.m_StatusWidgetCalibrationPointer->RemoveStatusLabels(); m_TrackingTimer->stop(); } else { m_NavigationDataSourceOfCalibrationPointer = m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource(); m_Controls.m_PointerLabel->setText(m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)->GetName()); //initialize widget m_Controls.m_StatusWidgetCalibrationPointer->RemoveStatusLabels(); m_Controls.m_StatusWidgetCalibrationPointer->SetShowPositions(true); m_Controls.m_StatusWidgetCalibrationPointer->SetTextAlignment(Qt::AlignLeft); m_Controls.m_StatusWidgetCalibrationPointer->AddNavigationData(m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)); m_Controls.m_StatusWidgetCalibrationPointer->ShowStatusLabels(); if (!m_TrackingTimer->isActive()) m_TrackingTimer->start(100); } } void QmitkIGTNavigationToolCalibration::UpdateOffsetCoordinates() { if (m_NavigationDataSourceOfCalibrationPointer.IsNull() || m_NavigationDataSourceOfToolToCalibrate.IsNull()) { return; } mitk::NavigationData::Pointer referenceToolND = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer); mitk::NavigationData::Pointer toolToCalibrateND = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); if (referenceToolND->IsDataValid() && toolToCalibrateND->IsDataValid()) { //computation: difference between both tools (in tool coordinates) //differenceND = toolToCalibrateND^-1 * referenceToolND mitk::NavigationData::Pointer differenceND = mitk::NavigationData::New(); differenceND->Compose(referenceToolND); differenceND->Compose(toolToCalibrateND->GetInverse()); //display this orientation in the UI m_Controls.m_OffsetCoordinates->setText( QString("x: ") + QString(QString::number(differenceND->GetPosition()[0], 103, 3)) + QString("; y: ") + (QString::number(differenceND->GetPosition()[1], 103, 3)) + QString("; z: ") + (QString::number(differenceND->GetPosition()[2], 103, 3))); m_Controls.m_OrientationOffsetCoordinates->setText( QString("qx: ") + QString(QString::number(differenceND->GetOrientation().x(), 103, 3)) + QString("; qy: ") + (QString::number(differenceND->GetOrientation().y(), 103, 3)) + QString("; qz: ") + (QString::number(differenceND->GetOrientation().z(), 103, 3)) + QString("; qr: ") + (QString::number(differenceND->GetOrientation().r(), 103, 3))); //also update preview if active if (m_ToolTipPointPreview.IsNotNull()) //NOT WORKING! TODO: fix or remove! { mitk::NavigationData::Pointer ToolTipTransform = mitk::NavigationData::New(); ToolTipTransform->SetPosition(m_ResultOffsetVector); mitk::NavigationData::Pointer ToolTipInTrackingCoordinates = mitk::NavigationData::New(); //maybe store as for better peformance... ToolTipInTrackingCoordinates->Compose(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); ToolTipInTrackingCoordinates->Compose(ToolTipTransform); m_ToolTipPointPreview->GetData()->GetGeometry()->SetIndexToWorldTransform(ToolTipInTrackingCoordinates->GetAffineTransform3D()); } } } void QmitkIGTNavigationToolCalibration::UpdateTrackingTimer() { m_Controls.m_StatusWidgetToolToCalibrate->Refresh(); m_Controls.m_StatusWidgetCalibrationPointer->Refresh(); if (m_OnLoginSingleRefToolNavigationDataClicked) LoginSingleRefToolNavigationData(); if (m_OnAddPivotPoseClicked) AddPivotPose(); // 1 == Single Reference Calibration Method if (m_IndexCurrentCalibrationMethod == 1) UpdateOffsetCoordinates(); } void QmitkIGTNavigationToolCalibration::AddLandmark() { if (!CheckInitialization()) { return; } mitk::NavigationData::Pointer navDataTool = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); mitk::Point3D landmark = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)->GetPosition(); //convert to itk transform itk::Vector translation; for (int k = 0; k < 3; k++) translation[k] = navDataTool->GetPosition()[k]; itk::Matrix rotation; for (int k = 0; k < 3; k++) for (int l = 0; l < 3; l++) rotation[k][l] = navDataTool->GetOrientation().rotation_matrix_transpose()[k][l]; rotation = rotation.GetTranspose(); itk::Vector landmarkItk; landmarkItk[0] = landmark[0]; landmarkItk[1] = landmark[1]; landmarkItk[2] = landmark[2]; //compute landmark in tool coordinates itk::Matrix rotationInverse; for (int k = 0; k < 3; k++) for (int l = 0; l < 3; l++) rotationInverse[k][l] = rotation.GetInverse()[k][l]; landmarkItk = rotationInverse * (landmarkItk - translation); //convert back and add landmark to pointset landmark[0] = landmarkItk[0]; landmark[1] = landmarkItk[1]; landmark[2] = landmarkItk[2]; m_RegistrationLandmarks->InsertPoint(m_RegistrationLandmarks->GetSize(), landmark); } void QmitkIGTNavigationToolCalibration::SaveCalibratedTool() { if (m_ToolToCalibrate.IsNotNull()) { mitk::NavigationTool::Pointer calibratedTool = m_ToolToCalibrate; calibratedTool->SetToolControlPoints(this->m_CalibrationLandmarks); calibratedTool->SetToolLandmarks(this->m_RegistrationLandmarks); mitk::NavigationToolWriter::Pointer myWriter = mitk::NavigationToolWriter::New(); std::string filename = QFileDialog::getSaveFileName(nullptr,tr("Save Navigation Tool"), "/", "*.IGTTool").toUtf8().data(); if (filename == "") return; if (myWriter->DoWrite(filename, calibratedTool)) MITK_INFO << "Saved calibrated tool to file " << filename; else MITK_WARN << "Can't write tool to file " << filename; } else { MITK_ERROR << "Did not find navigation tool storage of calibrated tool, aborting!"; } } bool QmitkIGTNavigationToolCalibration::CheckInitialization(bool CalibrationPointerRequired) { if ((m_IDToolToCalibrate == -1) || ((CalibrationPointerRequired) && (m_IDCalibrationPointer == -1) ) ) { QMessageBox msgBox; msgBox.setText("Tool to calibrate and/or calibration pointer not initialized, cannot proceed!"); msgBox.exec(); return false; } else { return true; } } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp index 5942405f0d..bcf8c0a50f 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp @@ -1,1287 +1,1266 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkImageStatisticsView.h" // Qt includes #include #include #include // berry includes #include // mitk includes #include #include #include #include #include #include #include #include // itk includes #include "itksys/SystemTools.hxx" #include "itkImageRegionConstIteratorWithIndex.h" #include //blueberry includes #include #include const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics"; const int QmitkImageStatisticsView::STAT_TABLE_BASE_HEIGHT = 180; QmitkImageStatisticsView::QmitkImageStatisticsView(QObject* /*parent*/, const char* /*name*/) : m_Controls( nullptr ), m_SelectedImage( nullptr ), m_SelectedImageMask( nullptr ), m_SelectedPlanarFigure( nullptr ), m_ImageObserverTag( -1 ), m_ImageMaskObserverTag( -1 ), m_PlanarFigureObserverTag( -1 ), m_TimeObserverTag( -1 ), m_CurrentStatisticsValid( false ), m_StatisticsUpdatePending( false ), m_DataNodeSelectionChanged ( false ), m_Visible(false) { this->m_CalculationThread = new QmitkImageStatisticsCalculationThread; } QmitkImageStatisticsView::~QmitkImageStatisticsView() { if ( m_SelectedImage != nullptr ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask != nullptr ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure != nullptr ) m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } delete this->m_CalculationThread; } void QmitkImageStatisticsView::CreateQtPartControl(QWidget *parent) { if (m_Controls == nullptr) { m_Controls = new Ui::QmitkImageStatisticsViewControls; m_Controls->setupUi(parent); CreateConnections(); m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_Controls->m_BinSizeFrame->setEnabled(false); - #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) - m_Controls->m_StatisticsWidgetStack->setVisible(false); - m_Controls->label_HistogramIsInvisibleWarning->setEnabled(true); - m_Controls->label_HistogramIsInvisibleWarning->setVisible(true); - m_Controls->label_HistogramIsInvisibleWarning->setText("Histogram is not visible because Qt 5.10 is required. You can use the button Copy to Clipboard below to retrieve values."); - m_Controls->groupBox_plot->setVisible(false); - #else - m_Controls->label_HistogramIsInvisibleWarning->setVisible(false); - #endif - } } void QmitkImageStatisticsView::OnPageSuccessfullyLoaded() { berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); QString styleName = m_StylePref->Get(berry::QtPreferences::QT_STYLE_NAME, ""); if (styleName == ":/org.blueberry.ui.qt/darkstyle.qss") { this->m_Controls->m_JSHistogram->SetTheme(QmitkChartWidget::ChartStyle::darkstyle); } else { this->m_Controls->m_JSHistogram->SetTheme(QmitkChartWidget::ChartStyle::lightstyle); } } void QmitkImageStatisticsView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(this->m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardHistogramButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_ButtonCopyStatisticsToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardStatisticsButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_IgnoreZerosCheckbox), SIGNAL(clicked()),(QObject*) this, SLOT(OnIgnoreZerosCheckboxClicked()) ); connect( (QObject*) this->m_CalculationThread, SIGNAL(finished()),this, SLOT( OnThreadedStatisticsCalculationEnds()),Qt::QueuedConnection); connect( (QObject*) this, SIGNAL(StatisticsUpdate()),this, SLOT( RequestStatisticsUpdate()), Qt::QueuedConnection); connect( (QObject*) this->m_Controls->m_StatisticsTable, SIGNAL(cellDoubleClicked(int,int)),this, SLOT( JumpToCoordinates(int,int)) ); connect((QObject*)(this->m_Controls->m_barRadioButton), SIGNAL(clicked()), (QObject*)(this), SLOT(OnBarRadioButtonSelected())); connect((QObject*)(this->m_Controls->m_lineRadioButton), SIGNAL(clicked()), (QObject*)(this), SLOT(OnLineRadioButtonSelected())); connect( (QObject*) (this->m_Controls->m_HistogramNBinsSpinbox), SIGNAL(editingFinished()), this, SLOT(OnHistogramNBinsCheckBoxValueChanged())); connect((QObject*)(this->m_Controls->m_UseDefaultNBinsCheckBox), SIGNAL(clicked()), (QObject*) this, SLOT(OnDefaultNBinsSpinBoxChanged())); connect((QObject*)(this->m_Controls->m_ShowSubchartCheckBox), SIGNAL(clicked()), (QObject*) this, SLOT(OnShowSubchartBoxChanged())); connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnPageSuccessfullyLoaded())); } } void QmitkImageStatisticsView::OnDefaultNBinsSpinBoxChanged() { if (this->m_Controls->m_UseDefaultNBinsCheckBox->isChecked()) { m_Controls->m_HistogramNBinsSpinbox->setValue(100); this->m_CalculationThread->SetHistogramNBins(m_Controls->m_HistogramNBinsSpinbox->value()); m_HistogramNBins = m_Controls->m_HistogramNBinsSpinbox->value(); } m_Controls->m_BinSizeFrame->setEnabled(!m_Controls->m_UseDefaultNBinsCheckBox->isChecked()); this->UpdateStatistics(); } void QmitkImageStatisticsView::OnShowSubchartBoxChanged() { bool showSubchart = this->m_Controls->m_ShowSubchartCheckBox->isChecked(); this->m_Controls->m_JSHistogram->Reload(showSubchart); } void QmitkImageStatisticsView::OnBarRadioButtonSelected() { this->m_Controls->m_JSHistogram->SetChartTypeForAllDataAndReload(QmitkChartWidget::ChartType::bar); } void QmitkImageStatisticsView::OnLineRadioButtonSelected() { this->m_Controls->m_JSHistogram->SetChartTypeForAllDataAndReload(QmitkChartWidget::ChartType::line); } void QmitkImageStatisticsView::PartClosed(const berry::IWorkbenchPartReference::Pointer& ) { } void QmitkImageStatisticsView::OnTimeChanged(const itk::EventObject& e) { if (this->m_SelectedDataNodes.isEmpty() || this->m_SelectedImage == nullptr) return; const mitk::SliceNavigationController::GeometryTimeEvent* timeEvent = dynamic_cast(&e); assert(timeEvent != nullptr); int timestep = timeEvent->GetPos(); if (this->m_SelectedImage->GetTimeSteps() > 1) { for (int x = 0; x < this->m_Controls->m_StatisticsTable->columnCount(); x++) { for (int y = 0; y < this->m_Controls->m_StatisticsTable->rowCount(); y++) { QTableWidgetItem* item = this->m_Controls->m_StatisticsTable->item(y, x); if (item == nullptr) break; if (x == timestep) { item->setBackgroundColor(Qt::yellow); } else { if (y % 2 == 0) item->setBackground(this->m_Controls->m_StatisticsTable->palette().base()); else item->setBackground(this->m_Controls->m_StatisticsTable->palette().alternateBase()); } } } this->m_Controls->m_StatisticsTable->viewport()->update(); } if ((this->m_SelectedImage->GetTimeSteps() == 1 && timestep == 0) || this->m_SelectedImage->GetTimeSteps() > 1) { - // display histogram for selected timestep - //bug in Qt thats leads to crash in debug builds. Fixed in Qt 5.10 - #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - m_Controls->m_JSHistogram->Clear(); - #endif + m_Controls->m_JSHistogram->Clear(); QmitkImageStatisticsCalculationThread::HistogramType::ConstPointer histogram = (QmitkImageStatisticsCalculationThread::HistogramType::ConstPointer)this->m_CalculationThread->GetTimeStepHistogram(timestep); if (histogram.IsNotNull()) { bool statisticsUpdateSuccessful = this->m_CalculationThread->GetStatisticsUpdateSuccessFlag(); if (statisticsUpdateSuccessful) { auto imageNameLabel = m_Controls->m_SelectedFeatureImageLabel->text().toStdString(); this->m_Controls->m_JSHistogram->AddData2D(ConvertHistogramToMap(histogram), imageNameLabel); if (this->m_Controls->m_lineRadioButton->isChecked()) { this->m_Controls->m_JSHistogram->SetChartType(imageNameLabel, QmitkChartWidget::ChartType::line); } else { this->m_Controls->m_JSHistogram->SetChartType(imageNameLabel, QmitkChartWidget::ChartType::bar); } this->m_Controls->m_JSHistogram->SetXAxisLabel("Grey value"); this->m_Controls->m_JSHistogram->SetYAxisLabel("Frequency"); this->m_Controls->m_JSHistogram->Show(this->m_Controls->m_ShowSubchartCheckBox->isChecked()); } } } } void QmitkImageStatisticsView::JumpToCoordinates(int row ,int col) { if(m_SelectedDataNodes.isEmpty()) { MITK_WARN("QmitkImageStatisticsView") << "No data node selected for statistics calculation." ; return; } mitk::Point3D world; if (row==5 && !m_WorldMinList.empty()) world = m_WorldMinList[col]; else if (row==4 && !m_WorldMaxList.empty()) world = m_WorldMaxList[col]; else return; mitk::IRenderWindowPart* part = this->GetRenderWindowPart(); if (part) { part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SelectSliceByPoint(world); mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), col); part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetGeometryTime(timeEvent); } } void QmitkImageStatisticsView::OnIgnoreZerosCheckboxClicked() { emit StatisticsUpdate(); } void QmitkImageStatisticsView::OnClipboardHistogramButtonClicked() { if (!m_CurrentStatisticsValid) { QApplication::clipboard()->clear(); } if (m_SelectedPlanarFigure == nullptr) { const unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); typedef mitk::ImageStatisticsCalculator::HistogramType HistogramType; const HistogramType *histogram = this->m_CalculationThread->GetTimeStepHistogram(t).GetPointer(); QString clipboard("Measurement \t Frequency\n"); for (HistogramType::ConstIterator it = histogram->Begin(); it != histogram->End(); ++it) { clipboard = clipboard.append("%L1 \t %L2\n") .arg(it.GetMeasurementVector()[0], 0, 'f', 2) .arg(it.GetFrequency()); } QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard); } //If a (non-closed) PlanarFigure is selected, display a line profile widget else if (m_SelectedPlanarFigure != nullptr) { QString clipboard("Pixel \t Intensity\n"); for (unsigned int i = 0; i < m_IntensityProfileList.size(); i++) { clipboard = clipboard.append("%L1 \t %L2\n").arg(QString::number(i)).arg(QString::number(m_IntensityProfileList.at(i))); } QApplication::clipboard()->setText(clipboard, QClipboard::Clipboard); } } void QmitkImageStatisticsView::OnClipboardStatisticsButtonClicked() { QLocale tempLocal; QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); if ( m_CurrentStatisticsValid && !( m_SelectedPlanarFigure != nullptr)) { const std::vector &statistics = this->m_CalculationThread->GetStatisticsData(); // Set time borders for for loop ;) unsigned int startT, endT; if(this->m_Controls->m_CheckBox4dCompleteTable->checkState()==Qt::CheckState::Unchecked) { startT = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()-> GetPos(); endT = startT+1; } else { startT = 0; endT = statistics.size(); } QVector< QVector > statisticsTable; QStringList headline{ "Timestep", "Mean", "Median", "StdDev", "RMS", "Max", "Min", "NumberOfVoxels", "Skewness", "Kurtosis", "Uniformity", "Entropy", "MPP", "UPP", "V [mm³]" }; for(int i=0;i row; row.append(headline.at(i)); statisticsTable.append(row); } // Fill Table for(unsigned int t=startT;tGetMean()) << QString::number(statistics[t]->GetMedian()) << QString::number(statistics[t]->GetStd()) << QString::number(statistics[t]->GetRMS()) << QString::number(statistics[t]->GetMax()) << QString::number(statistics[t]->GetMin()) << QString::number(statistics[t]->GetN()) << QString::number(statistics[t]->GetSkewness()) << QString::number(statistics[t]->GetKurtosis()) << QString::number(statistics[t]->GetUniformity()) << QString::number(statistics[t]->GetEntropy()) << QString::number(statistics[t]->GetMPP()) << QString::number(statistics[t]->GetUPP()) << QString::number(m_Controls->m_StatisticsTable->item(7, 0)->data(Qt::DisplayRole).toDouble()); for(int z=0;zsetText(clipboard, QClipboard::Clipboard); } else { QApplication::clipboard()->clear(); } QLocale::setDefault(tempLocal); } void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes ) { if (this->m_Visible) { this->SelectionChanged( nodes ); } else { this->m_DataNodeSelectionChanged = true; } } void QmitkImageStatisticsView::SelectionChanged(const QList &selectedNodes) { - //Clear Histogram if data node is deselected - //bug in Qt thats leads to crash in debug builds. Fixed in Qt 5.10 - #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) m_Controls->m_JSHistogram->Clear(); - #endif if( this->m_StatisticsUpdatePending ) { this->m_DataNodeSelectionChanged = true; return; // not ready for new data now! } if (selectedNodes.size() == this->m_SelectedDataNodes.size()) { int i = 0; for (; i < selectedNodes.size(); ++i) { if (selectedNodes.at(i) != this->m_SelectedDataNodes.at(i)) { break; } } // node selection did not change if (i == selectedNodes.size()) return; } //reset the feature image and image mask field m_Controls->m_SelectedFeatureImageLabel->setText("None"); m_Controls->m_SelectedMaskLabel->setText("None"); this->ReinitData(); if (selectedNodes.isEmpty()) { DisableHistogramGUIElements(); } else { EnableHistogramGUIElements(); ResetHistogramGUIElementsToDefault(); } if(selectedNodes.size() == 1 || selectedNodes.size() == 2) { bool isBinary = false; selectedNodes.value(0)->GetBoolProperty("binary",isBinary); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); isBinary |= isLabelSet->CheckNode(selectedNodes.value(0)); if(isBinary) { EnableHistogramGUIElements(); m_Controls->m_InfoLabel->setText(""); } for (int i= 0; i< selectedNodes.size(); ++i) { this->m_SelectedDataNodes.push_back(selectedNodes.at(i)); } this->m_DataNodeSelectionChanged = false; this->m_Controls->m_ErrorMessageLabel->setText( "" ); this->m_Controls->m_ErrorMessageLabel->hide(); emit StatisticsUpdate(); } else { this->m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::DisableHistogramGUIElements() { m_Controls->m_InfoLabel->setText(""); m_Controls->groupBox_histogram->setEnabled(false); m_Controls->groupBox_statistics->setEnabled(false); } void QmitkImageStatisticsView::ResetHistogramGUIElementsToDefault() { m_Controls->m_barRadioButton->setChecked(true); m_Controls->m_HistogramNBinsSpinbox->setValue(100); m_HistogramNBins = m_Controls->m_HistogramNBinsSpinbox->value(); m_Controls->m_UseDefaultNBinsCheckBox->setChecked(true); m_Controls->m_ShowSubchartCheckBox->setChecked(true); m_Controls->m_BinSizeFrame->setEnabled(false); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_HistogramNBinsSpinbox->setEnabled(true); this->m_CalculationThread->SetHistogramNBins(m_Controls->m_HistogramNBinsSpinbox->value()); } void QmitkImageStatisticsView::EnableHistogramGUIElements() { m_Controls->groupBox_histogram->setEnabled(true); m_Controls->groupBox_plot->setEnabled(true); m_Controls->groupBox_statistics->setEnabled(true); } void QmitkImageStatisticsView::ReinitData() { while( this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if(this->m_SelectedImage != nullptr) { this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag); this->m_SelectedImage = nullptr; } if(this->m_SelectedImageMask != nullptr) { this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag); this->m_SelectedImageMask = nullptr; } if(this->m_SelectedPlanarFigure != nullptr) { this->m_SelectedPlanarFigure->RemoveObserver( this->m_PlanarFigureObserverTag); this->m_SelectedPlanarFigure = nullptr; } this->m_SelectedDataNodes.clear(); this->m_StatisticsUpdatePending = false; m_Controls->m_ErrorMessageLabel->setText( "" ); m_Controls->m_ErrorMessageLabel->hide(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); } void QmitkImageStatisticsView::OnThreadedStatisticsCalculationEnds() { m_Controls->m_ErrorMessageLabel->setText(""); m_Controls->m_ErrorMessageLabel->hide(); this->WriteStatisticsToGUI(); } void QmitkImageStatisticsView::UpdateStatistics() { mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); if ( renderPart == nullptr ) { this->m_StatisticsUpdatePending = false; return; } m_WorldMinList.clear(); m_WorldMaxList.clear(); // classify selected nodes mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateOr::Pointer imagePredicate = mitk::NodePredicateOr::New(isImage, isLabelSet); std::string maskName; std::string maskType; std::string featureImageName; unsigned int maskDimension = 0; // reset data from last run ITKCommandType::Pointer changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::SelectedDataModified ); mitk::DataNode::Pointer planarFigureNode; for( int i= 0 ; i < this->m_SelectedDataNodes.size(); ++i) { mitk::PlanarFigure::Pointer planarFig = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); if( imagePredicate->CheckNode(this->m_SelectedDataNodes.at(i)) ) { bool isMask = false; this->m_SelectedDataNodes.at(i)->GetPropertyValue("binary", isMask); isMask |= isLabelSet->CheckNode(this->m_SelectedDataNodes.at(i)); if( this->m_SelectedImageMask == nullptr && isMask) { this->m_SelectedImageMask = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageMaskObserverTag = this->m_SelectedImageMask->AddObserver(itk::ModifiedEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; } else if( !isMask ) { if(this->m_SelectedImage == nullptr) { this->m_SelectedImage = static_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } featureImageName = this->m_SelectedDataNodes.at(i)->GetName(); } } else if (planarFig.IsNotNull()) { if(this->m_SelectedPlanarFigure == nullptr) { this->m_SelectedPlanarFigure = planarFig; this->m_PlanarFigureObserverTag = this->m_SelectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = this->m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; planarFigureNode = m_SelectedDataNodes.at(i); } } else { m_Controls->m_ErrorMessageLabel->setText("Invalid data node type!"); m_Controls->m_ErrorMessageLabel->show(); } } if(maskName == "") { maskName = "None"; maskType = ""; maskDimension = 0; } if(featureImageName == "") { featureImageName = "None"; } if (m_SelectedPlanarFigure != nullptr && m_SelectedImage == nullptr) { mitk::DataStorage::SetOfObjects::ConstPointer parentSet = this->GetDataStorage()->GetSources(planarFigureNode); for (unsigned int i=0; iSize(); i++) { mitk::DataNode::Pointer node = parentSet->ElementAt(i); if( imagePredicate->CheckNode(node) ) { bool isMask = false; node->GetPropertyValue("binary", isMask); isMask |= isLabelSet->CheckNode(node); if( !isMask ) { if(this->m_SelectedImage == nullptr) { this->m_SelectedImage = static_cast(node->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } } } } } unsigned int timeStep = renderPart->GetTimeNavigationController()->GetTime()->GetPos(); if ( m_SelectedImage != nullptr && m_SelectedImage->IsInitialized()) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { m_Controls->m_ErrorMessageLabel->setText( "Multi-component images not supported." ); m_Controls->m_ErrorMessageLabel->show(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); m_CurrentStatisticsValid = false; this->m_StatisticsUpdatePending = false; this->DisableHistogramGUIElements(); m_Controls->m_InfoLabel->setText(""); return; } std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); m_Controls->m_SelectedFeatureImageLabel->setText(featureImageName.c_str()); // check time step validity if(m_SelectedImage->GetDimension() <= 3 && timeStep > m_SelectedImage->GetDimension(3)-1) { timeStep = m_SelectedImage->GetDimension(3)-1; } // Add the used mask time step to the mask label so the user knows which mask time step was used // if the image time step is bigger than the total number of mask time steps (see // ImageStatisticsCalculator::ExtractImageAndMask) if (m_SelectedImageMask != nullptr) { unsigned int maskTimeStep = timeStep; if (maskTimeStep >= m_SelectedImageMask->GetTimeSteps()) { maskTimeStep = m_SelectedImageMask->GetTimeSteps() - 1; } m_Controls->m_SelectedMaskLabel->setText(m_Controls->m_SelectedMaskLabel->text() + QString(" (t=") + QString::number(maskTimeStep) + QString(")")); } // check if the segmentation mask is empty if (m_SelectedImageMask != nullptr) { auto maskStatistics = m_SelectedImageMask->GetStatistics(); mitk::ScalarType maskMaxValue = maskStatistics->GetScalarValueMax(0); if (m_SelectedImageMask->GetDimension() == 4) { for (unsigned int curTimestep = 1; curTimestep < m_SelectedImageMask->GetTimeSteps(); curTimestep++) { maskMaxValue = std::max(maskStatistics->GetScalarValueMax(curTimestep), maskMaxValue); } } bool segmentationIsEmpty = maskMaxValue == 0; if (segmentationIsEmpty) { m_Controls->m_ErrorMessageLabel->setText( "Empty segmentation mask selected..." ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; return; } } //// initialize thread and trigger it this->m_CalculationThread->SetIgnoreZeroValueVoxel( m_Controls->m_IgnoreZerosCheckbox->isChecked() ); this->m_CalculationThread->Initialize( m_SelectedImage, m_SelectedImageMask, m_SelectedPlanarFigure ); this->m_CalculationThread->SetTimeStep( timeStep ); m_Controls->m_ErrorMessageLabel->setText("Calculating statistics..."); m_Controls->m_ErrorMessageLabel->show(); try { // Compute statistics this->m_CalculationThread->start(); } catch ( const mitk::Exception& e) { m_Controls->m_ErrorMessageLabel->setText("" + QString(e.GetDescription()) + ""); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::runtime_error &e ) { // In case of exception, print error message on GUI m_Controls->m_ErrorMessageLabel->setText("" + QString(e.what()) + ""); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); // In case of exception, print error message on GUI m_Controls->m_ErrorMessageLabel->setText("" + QString(e.what()) + ""); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } } else { this->m_StatisticsUpdatePending = false; } } void QmitkImageStatisticsView::SelectedDataModified() { if( !m_StatisticsUpdatePending ) { emit StatisticsUpdate(); } } void QmitkImageStatisticsView::NodeRemoved(const mitk::DataNode *node) { while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if (node->GetData() == m_SelectedImage) { m_SelectedImage = nullptr; } } void QmitkImageStatisticsView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { if(this->m_DataNodeSelectionChanged) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->m_StatisticsUpdatePending = true; this->UpdateStatistics(); } } if (this->GetRenderWindowPart()) this->GetRenderWindowPart()->RequestUpdate(); } void QmitkImageStatisticsView::OnHistogramNBinsCheckBoxValueChanged() { if (static_cast(m_Controls->m_HistogramNBinsSpinbox->value()) != m_HistogramNBins) { m_HistogramNBins = m_Controls->m_HistogramNBinsSpinbox->value(); this->m_CalculationThread->SetHistogramNBins(m_Controls->m_HistogramNBinsSpinbox->value()); this->UpdateStatistics(); } } void QmitkImageStatisticsView::WriteStatisticsToGUI() { - //bug in Qt thats leads to crash in debug builds. Fixed in Qt 5.10 - #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) m_Controls->m_JSHistogram->Clear(); - #endif m_IntensityProfileList.clear(); //Disconnect OnLineRadioButtonSelected() to prevent reloading chart when radiobutton is checked programmatically disconnect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), 0, 0); connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnPageSuccessfullyLoaded())); m_Controls->m_InfoLabel->setText(""); if (m_DataNodeSelectionChanged) { this->m_StatisticsUpdatePending = false; this->RequestStatisticsUpdate(); return; // stop visualization of results and calculate statistics of new selection } if (this->m_CalculationThread->GetStatisticsUpdateSuccessFlag()) { if (this->m_CalculationThread->GetStatisticsChangedFlag()) { // Do not show any error messages m_Controls->m_ErrorMessageLabel->hide(); m_CurrentStatisticsValid = true; } if (m_SelectedImage != nullptr) { //all statistics are now computed also on planar figures (lines, paths...)! // If a (non-closed) PlanarFigure is selected, display a line profile widget if (m_SelectedPlanarFigure != nullptr && !m_SelectedPlanarFigure->IsClosed()) { // check whether PlanarFigure is initialized const mitk::PlaneGeometry *planarFigurePlaneGeometry = m_SelectedPlanarFigure->GetPlaneGeometry(); if (planarFigurePlaneGeometry != nullptr) { unsigned int timeStep = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); mitk::Image::Pointer image; if (this->m_CalculationThread->GetStatisticsImage()->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(this->m_CalculationThread->GetStatisticsImage()); timeSelector->SetTimeNr(timeStep); timeSelector->Update(); image = timeSelector->GetOutput(); } else { image = this->m_CalculationThread->GetStatisticsImage(); } mitk::IntensityProfile::ConstPointer intensityProfile = (mitk::IntensityProfile::ConstPointer)mitk::ComputeIntensityProfile(image, m_SelectedPlanarFigure); m_IntensityProfileList = ConvertIntensityProfileToVector(intensityProfile); auto lineDataLabel = "Intensity profile " + m_Controls->m_SelectedMaskLabel->text().toStdString(); m_Controls->m_JSHistogram->SetChartType(lineDataLabel, QmitkChartWidget::ChartType::line); m_Controls->m_JSHistogram->AddData1D(m_IntensityProfileList, lineDataLabel); m_Controls->m_JSHistogram->SetXAxisLabel("Distance"); m_Controls->m_JSHistogram->SetYAxisLabel("Intensity"); m_Controls->m_JSHistogram->Show(m_Controls->m_ShowSubchartCheckBox->isChecked()); m_Controls->m_lineRadioButton->setChecked(true); m_Controls->m_lineRadioButton->setEnabled(false); m_Controls->m_barRadioButton->setEnabled(false); m_Controls->m_HistogramNBinsSpinbox->setEnabled(false); m_Controls->m_BinSizeFrame->setEnabled(false); m_Controls->m_UseDefaultNBinsCheckBox->setEnabled(false); //Reconnect OnLineRadioButtonSelected() connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnLineRadioButtonSelected())); auto statisticsVector = this->m_CalculationThread->GetStatisticsData(); //only one entry (current timestep) this->FillLinearProfileStatisticsTableView(statisticsVector.front().GetPointer(), this->m_CalculationThread->GetStatisticsImage()); QString message("Only linegraph available for an intensity profile!"); if (this->m_CalculationThread->GetStatisticsImage()->GetDimension() == 4) { message += "Only current timestep displayed!"; } message += ""; m_Controls->m_InfoLabel->setText(message); m_CurrentStatisticsValid = true; } else { // Clear statistics, histogram, and GUI this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_CurrentStatisticsValid = false; m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_SelectedMaskLabel->setText("None"); this->m_StatisticsUpdatePending = false; m_Controls->m_InfoLabel->setText(""); return; } } else { m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); auto histogram = this->m_CalculationThread->GetTimeStepHistogram(this->m_CalculationThread->GetTimeStep()).GetPointer(); auto imageLabelName = m_Controls->m_SelectedFeatureImageLabel->text().toStdString(); m_Controls->m_JSHistogram->AddData2D(ConvertHistogramToMap(histogram), imageLabelName); m_Controls->m_JSHistogram->SetChartType(imageLabelName, QmitkChartWidget::ChartType::bar); this->m_Controls->m_JSHistogram->SetXAxisLabel("Gray value"); this->m_Controls->m_JSHistogram->SetYAxisLabel("Frequency"); m_Controls->m_UseDefaultNBinsCheckBox->setEnabled(true); m_Controls->m_JSHistogram->Show(this->m_Controls->m_ShowSubchartCheckBox->isChecked()); this->FillStatisticsTableView(this->m_CalculationThread->GetStatisticsData(), this->m_CalculationThread->GetStatisticsImage()); } m_CurrentStatisticsValid = true; } } else { m_Controls->m_SelectedMaskLabel->setText("None"); m_Controls->m_ErrorMessageLabel->setText(m_CalculationThread->GetLastErrorMessage().c_str()); m_Controls->m_ErrorMessageLabel->show(); // Clear statistics and histogram this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_CurrentStatisticsValid = false; } berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); this->m_StatisticsUpdatePending = false; } void QmitkImageStatisticsView::FillStatisticsTableView( const std::vector &statistics, const mitk::Image *image ) { this->m_Controls->m_StatisticsTable->setColumnCount(image->GetTimeSteps()); this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(image->GetTimeSteps() > 1); // Set Checkbox for complete copy of statistic table if(image->GetTimeSteps()>1) { this->m_Controls->m_CheckBox4dCompleteTable->setEnabled(true); } else { this->m_Controls->m_CheckBox4dCompleteTable->setEnabled(false); this->m_Controls->m_CheckBox4dCompleteTable->setChecked(false); } for (unsigned int t = 0; t < image->GetTimeSteps(); t++) { this->m_Controls->m_StatisticsTable->setHorizontalHeaderItem(t, new QTableWidgetItem(QString::number(t))); if (statistics.at(t)->GetMaxIndex().size()==3) { mitk::Point3D index, max, min; index[0] = statistics.at(t)->GetMaxIndex()[0]; index[1] = statistics.at(t)->GetMaxIndex()[1]; index[2] = statistics.at(t)->GetMaxIndex()[2]; m_SelectedImage->GetGeometry()->IndexToWorld(index, max); this->m_WorldMaxList.push_back(max); index[0] = statistics.at(t)->GetMinIndex()[0]; index[1] = statistics.at(t)->GetMinIndex()[1]; index[2] = statistics.at(t)->GetMinIndex()[2]; m_SelectedImage->GetGeometry()->IndexToWorld(index, min); this->m_WorldMinList.push_back(min); } auto statisticsVector = AssembleStatisticsIntoVector(statistics.at(t).GetPointer(), image); unsigned int count = 0; for (const auto& entry : statisticsVector) { auto item = new QTableWidgetItem(entry); this->m_Controls->m_StatisticsTable->setItem(count, t, item); count++; } } this->m_Controls->m_StatisticsTable->resizeColumnsToContents(); int height = STAT_TABLE_BASE_HEIGHT; if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height(); if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height(); this->m_Controls->m_StatisticsTable->setMinimumHeight(height); // make sure the current timestep's column is highlighted (and the correct histogram is displayed) unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()-> GetPos(); mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), t); this->OnTimeChanged(timeEvent); t = std::min(image->GetTimeSteps() - 1, t); // See bug 18340 /*QString hotspotMean; hotspotMean.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMean(), 0, 'f', decimals)); hotspotMean += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 7, t, new QTableWidgetItem( hotspotMean ) ); QString hotspotMax; hotspotMax.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMax(), 0, 'f', decimals)); hotspotMax += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 8, t, new QTableWidgetItem( hotspotMax ) ); QString hotspotMin; hotspotMin.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMin(), 0, 'f', decimals)); hotspotMin += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 9, t, new QTableWidgetItem( hotspotMin ) );*/ } std::vector QmitkImageStatisticsView::AssembleStatisticsIntoVector(mitk::ImageStatisticsCalculator::StatisticsContainer::ConstPointer statistics, mitk::Image::ConstPointer image, bool noVolumeDefined) const { std::vector result; unsigned int decimals = 2; //statistics of higher order should have 5 decimal places because they used to be very small unsigned int decimalsHigherOrderStatistics = 5; if (image->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE || image->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT) { decimals = 5; } result.push_back(GetFormattedString(statistics->GetMean(), decimals)); result.push_back(GetFormattedString(statistics->GetMedian(), decimals)); result.push_back(GetFormattedString(statistics->GetStd(), decimals)); result.push_back(GetFormattedString(statistics->GetRMS(), decimals)); result.push_back(GetFormattedString(statistics->GetMax(), decimals) + " " + GetFormattedIndex(statistics->GetMaxIndex())); result.push_back(GetFormattedString(statistics->GetMin(), decimals) + " " + GetFormattedIndex(statistics->GetMinIndex())); //to prevent large negative values of empty image statistics if (statistics->GetN() != std::numeric_limits::min()) { result.push_back(GetFormattedString(statistics->GetN(), 0)); const mitk::BaseGeometry *geometry = image->GetGeometry(); if (geometry != NULL && !noVolumeDefined) { const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); double volume = spacing[0] * spacing[1] * spacing[2] * static_cast(statistics->GetN()); result.push_back(GetFormattedString(volume, decimals)); } else { result.push_back("NA"); } } else { result.push_back("NA"); result.push_back("NA"); } result.push_back(GetFormattedString(statistics->GetSkewness(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetKurtosis(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetUniformity(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetEntropy(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetMPP(), decimals)); result.push_back(GetFormattedString(statistics->GetUPP(), decimalsHigherOrderStatistics)); return result; } void QmitkImageStatisticsView::FillLinearProfileStatisticsTableView(mitk::ImageStatisticsCalculator::StatisticsContainer::ConstPointer statistics, const mitk::Image *image) { this->m_Controls->m_StatisticsTable->setColumnCount(1); this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false); m_PlanarFigureStatistics = this->AssembleStatisticsIntoVector(statistics, image, true); for (unsigned int i = 0; i< m_PlanarFigureStatistics.size(); i++) { this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem(m_PlanarFigureStatistics[i] )); } this->m_Controls->m_StatisticsTable->resizeColumnsToContents(); int height = STAT_TABLE_BASE_HEIGHT; if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height(); if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height(); this->m_Controls->m_StatisticsTable->setMinimumHeight(height); } void QmitkImageStatisticsView::InvalidateStatisticsTableView() { this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false); this->m_Controls->m_StatisticsTable->setColumnCount(1); for ( int i = 0; i < this->m_Controls->m_StatisticsTable->rowCount(); ++i ) { { this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem( "NA" ) ); } } this->m_Controls->m_StatisticsTable->setMinimumHeight(STAT_TABLE_BASE_HEIGHT); } void QmitkImageStatisticsView::Activated() { } void QmitkImageStatisticsView::Deactivated() { } void QmitkImageStatisticsView::Visible() { m_Visible = true; mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart(); if (renderWindow) { itk::ReceptorMemberCommand::Pointer cmdTimeEvent = itk::ReceptorMemberCommand::New(); cmdTimeEvent->SetCallbackFunction(this, &QmitkImageStatisticsView::OnTimeChanged); // It is sufficient to add the observer to the axial render window since the GeometryTimeEvent // is always triggered by all views. m_TimeObserverTag = renderWindow->GetQmitkRenderWindow("axial")-> GetSliceNavigationController()-> AddObserver(mitk::SliceNavigationController::GeometryTimeEvent(nullptr, 0), cmdTimeEvent); } if (m_DataNodeSelectionChanged) { if (this->IsCurrentSelectionValid()) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->SelectionChanged(this->GetDataManagerSelection()); } m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::Hidden() { m_Visible = false; // The slice navigation controller observer is removed here instead of in the destructor. // If it was called in the destructor, the application would freeze because the view's // destructor gets called after the render windows have been destructed. if ( m_TimeObserverTag != 0 ) { mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart(); if (renderWindow) { renderWindow->GetQmitkRenderWindow("axial")->GetSliceNavigationController()-> RemoveObserver( m_TimeObserverTag ); } m_TimeObserverTag = 0; } } void QmitkImageStatisticsView::SetFocus() { } std::map QmitkImageStatisticsView::ConvertHistogramToMap(itk::Statistics::Histogram::ConstPointer histogram) const { std::map histogramMap; auto endIt = histogram->End(); auto it = histogram->Begin(); // generating Lists of measurement and frequencies for (; it != endIt; ++it) { double frequency = it.GetFrequency(); double measurement = it.GetMeasurementVector()[0]; histogramMap.emplace(measurement, frequency); } return histogramMap; } std::vector QmitkImageStatisticsView::ConvertIntensityProfileToVector(mitk::IntensityProfile::ConstPointer intensityProfile) const { std::vector intensityProfileList; auto end = intensityProfile->End(); for (auto it = intensityProfile->Begin(); it != end; ++it) { intensityProfileList.push_back(it.GetMeasurementVector()[0]); } return intensityProfileList; } QString QmitkImageStatisticsView::GetFormattedString(double value, unsigned int decimals) const { typedef mitk::ImageStatisticsCalculator::StatisticsContainer::RealType RealType; RealType maxVal = std::numeric_limits::max(); if (value == maxVal) { return QString("NA"); } else { return QString("%1").arg(value, 0, 'f', decimals); } } QString QmitkImageStatisticsView::GetFormattedIndex(const vnl_vector& vector) const { if (vector.empty()) { return QString(); } QString formattedIndex("("); for (const auto& entry : vector) { formattedIndex += QString::number(entry); formattedIndex += ","; } formattedIndex.chop(1); formattedIndex += ")"; return formattedIndex; } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui index ae99157bb2..7475b0623e 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui @@ -1,750 +1,649 @@ QmitkImageStatisticsViewControls true 0 0 548 812 Form 0 0 Qt::LeftToRight Feature Image: 0 0 None 0 0 Mask: 0 0 None -1 0 0 color: rgb(255, 0, 0); Error Message Qt::AutoText Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Ignore zero-valued voxels false Statistics 9 9 9 100 180 16777215 16777215 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded true QAbstractItemView::NoEditTriggers true true Qt::DotLine false 14 1 false false 80 true 80 false true true false 25 25 false false Mean Median StdDev RMS Max Min N V (mm³) Skewness Kurtosis Uniformity Entropy MPP UPP 0 0 0 0 0 0 Copy to Clipboard Qt::Horizontal QSizePolicy::Fixed 20 20 false copy complete table Qt::Horizontal 40 20 false 400 450 Histogram false - - - - false - - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - - - false 0 0 0 0 16777215 16777215 Plot 0 0 Barchart true 0 0 0 0 Linegraph Qt::Horizontal 40 20 Show Subchart true Use default #bins true QFrame::NoFrame QFrame::Raised 0 0 0 0 0 60 0 100 16777215 # bins: false Press enter to recalculate statistics with new bin size. 1 10000 100 0 0 0 0 0 0 0 0 0 0 0 0 Copy to Clipboard Qt::Horizontal 40 20 Qt::Vertical 20 40 QmitkChartWidget QWidget
QmitkChartWidget.h