diff --git a/.arcconfig b/.arcconfig
index 1b723c4095..79f83b948a 100644
--- a/.arcconfig
+++ b/.arcconfig
@@ -1,5 +1,6 @@
 {
-  "base": "git:merge-base(origin/master)",
+  "arc.land.onto.default": "develop",
+  "base": "git:merge-base(origin/develop)",
   "history.immutable": true,
   "phabricator.uri": "https://phabricator.mitk.org/"
 }
diff --git a/CMake/MITKDashboardScript.TEMPLATE.cmake b/CMake/MITKDashboardScript.TEMPLATE.cmake
index 663f15eb44..0d459014e1 100644
--- a/CMake/MITKDashboardScript.TEMPLATE.cmake
+++ b/CMake/MITKDashboardScript.TEMPLATE.cmake
@@ -1,146 +1,143 @@
 #
 # 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.14.5 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 16 2019")
 #set(CTEST_CMAKE_GENERATOR_PLATFORM "x64")
 #set(CTEST_DASHBOARD_ROOT "D:/dc")
 
 set(MITK_EXTENSIONS # "<repo>|<branch/tag/commit>|<src dir>"
 # "https://phabricator.mitk.org/source/mitk-projecttemplate.git|master|MITK-ProjectTemplate"
 # "https://phabricator.mitk.org/source/mitk-diffusion.git|master|MITK-Diffusion"
 )
 
 #
 # 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{PATH} "$ENV{PATH}")
 
 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")
+#set(GIT_BRANCH "develop")
 
 ##########################################
 # 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()
 
+if(NOT GIT_BRANCH)
+  set(GIT_BRANCH "master")
+endif()
+
 #
 # 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(url "https://raw.githubusercontent.com/MITK/MITK/${GIT_BRANCH}/CMake/MITKDashboardSetup.cmake")
 set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.setup)
 downloadFile("${url}" "${dest}")
 include(${dest})
diff --git a/CMake/MITKDashboardSetup.cmake b/CMake/MITKDashboardSetup.cmake
index eb41141d25..a1befe0885 100644
--- a/CMake/MITKDashboardSetup.cmake
+++ b/CMake/MITKDashboardSetup.cmake
@@ -1,145 +1,134 @@
 # This file is intended to be included at the end of a custom MITKDashboardScript.TEMPLATE.cmake file
 
 list(APPEND CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
 
 #
 # Automatically determined properties
 #
 set(MY_OPERATING_SYSTEM )
 
 if(UNIX)
-  # Download a utility script
-  # See T24757.
-  # if(IS_PHABRICATOR_URL)
-  #   set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH}/CMake/mitkDetectOS.sh?view=raw")
-  # else()
-    set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/mitkDetectOS.sh")
-  # endif()
+  set(url "https://raw.githubusercontent.com/MITK/MITK/${GIT_BRANCH}/CMake/mitkDetectOS.sh")
   set(dest "${CTEST_SCRIPT_DIRECTORY}/mitkDetectOS.sh")
   downloadFile("${url}" "${dest}")
   execute_process(COMMAND sh "${dest}"
   RESULT_VARIABLE _result OUTPUT_VARIABLE _out
   OUTPUT_STRIP_TRAILING_WHITESPACE)
 
   if(NOT _result)
     set(MY_OPERATING_SYSTEM "${_out}")
   endif()
 endif()
 
 if(NOT MY_OPERATING_SYSTEM)
   set(MY_OPERATING_SYSTEM "${CMAKE_HOST_SYSTEM}") # Windows 7, Linux-2.6.32, Darwin...
 endif()
 
 site_name(CTEST_SITE)
 
 if(NOT DEFINED MITK_USE_Qt5)
   set(MITK_USE_Qt5 1)
 endif()
 
 #
 # Project specific properties
 #
 if(NOT CTEST_BUILD_NAME)
   if(MITK_USE_Qt5)
      set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} ${CTEST_BUILD_CONFIGURATION}")
   else()
     set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} ${CTEST_BUILD_CONFIGURATION}")
   endif()
   set(CTEST_BUILD_NAME "${CTEST_BUILD_NAME}${CTEST_BUILD_NAME_SUFFIX}")
 endif()
 set(PROJECT_BUILD_DIR "MITK-build")
 
 set(CTEST_PATH "$ENV{PATH}")
 if(WIN32)
   if("${CTEST_CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64")
     set(CMAKE_LIBRARY_ARCHITECTURE x64)
   else()
     set(CMAKE_LIBRARY_ARCHITECTURE x86)
   endif()
   string(SUBSTRING "${MY_COMPILER}" 2 2 vc_version)
 
   set(OPENCV_BIN_DIR "${CTEST_BINARY_DIRECTORY}/ep/${CMAKE_LIBRARY_ARCHITECTURE}/vc${vc_version}/bin")
 
   set(BLUEBERRY_RUNTIME_DIR "${CTEST_BINARY_DIRECTORY}/MITK-build/bin/plugins/${CTEST_BUILD_CONFIGURATION}")
 
   set(PYTHON_BINARY_DIRS "${CTEST_BINARY_DIRECTORY}/ep/src/CTK-build/CMakeExternals/Install/bin")
   get_filename_component(_python_dir "${Python3_EXECUTABLE}" DIRECTORY)
   list(APPEND PYTHON_BINARY_DIRS "${_python_dir}")
 
   set(CTEST_PATH "${CTEST_PATH};${CTEST_BINARY_DIRECTORY}/ep/bin;${BLUEBERRY_RUNTIME_DIR};${OPENCV_BIN_DIR};${PYTHON_BINARY_DIRS}")
 endif()
 set(ENV{PATH} "${CTEST_PATH}")
 
 # If the dashscript doesn't define a GIT_REPOSITORY variable, let's define it here.
 if(NOT DEFINED GIT_REPOSITORY OR GIT_REPOSITORY STREQUAL "")
   set(GIT_REPOSITORY "https://phabricator.mitk.org/source/mitk.git")
 endif()
 
 #
 # Display build info
 #
 message("Site name: ${CTEST_SITE}")
 message("Build name: ${CTEST_BUILD_NAME}")
 message("Script Mode: ${SCRIPT_MODE}")
 message("Coverage: ${WITH_COVERAGE}, MemCheck: ${WITH_MEMCHECK}")
 
 #
 # Set initial cache options
 #
 if(CTEST_CMAKE_GENERATOR MATCHES ".*Makefiles.*")
   set(CTEST_USE_LAUNCHERS 1)
 else()
   set(CTEST_USE_LAUNCHERS 0)
 endif()
 set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} ${CTEST_USE_LAUNCHERS})
 
 if(NOT DEFINED MITK_BUILD_CONFIGURATION)
   set(MITK_BUILD_CONFIGURATION "All")
 endif()
 
 if(NOT DEFINED MITK_VTK_DEBUG_LEAKS)
   set(MITK_VTK_DEBUG_LEAKS 1)
 endif()
 
 set(INITIAL_CMAKECACHE_OPTIONS "
 SUPERBUILD_EXCLUDE_MITKBUILD_TARGET:BOOL=TRUE
 MITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION}
 MITK_VTK_DEBUG_LEAKS:BOOL=${MITK_VTK_DEBUG_LEAKS}
 ${ADDITIONAL_CMAKECACHE_OPTION}
 ")
 
 # Write a cache file for populating the MITK initial cache (not the superbuild cache).
 # This can be used to provide variables which are not passed through the
 # superbuild process to the MITK configure step)
 if(MITK_INITIAL_CACHE)
   set(mitk_cache_file "${CTEST_SCRIPT_DIRECTORY}/mitk_initial_cache.txt")
   file(WRITE "${mitk_cache_file}" "${MITK_INITIAL_CACHE}")
   set(INITIAL_CMAKECACHE_OPTIONS "${INITIAL_CMAKECACHE_OPTIONS}
 MITK_INITIAL_CACHE_FILE:INTERNAL=${mitk_cache_file}
 ")
 endif()
 
 if(MITK_EXTENSIONS)
   set(MITK_EXTENSION_DIRS "")
   foreach(extension ${MITK_EXTENSIONS})
     if(extension MATCHES "[^|]+\\|[^|]+\\|(.+)")
       if(MITK_EXTENSION_DIRS)
         set(MITK_EXTENSION_DIRS "${MITK_EXTENSION_DIRS};")
       endif()
       set(MITK_EXTENSION_DIRS "${MITK_EXTENSION_DIRS}${CTEST_DASHBOARD_ROOT}/${CMAKE_MATCH_1}")
     endif()
   endforeach()
 endif()
 
 #
 # Download and include dashboard driver script
 #
-if(IS_PHABRICATOR_URL)
-  string(REPLACE "/" "%252F" GIT_BRANCH_URL ${GIT_BRANCH})
-  set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH_URL}/CMake/MITKDashboardDriverScript.cmake?view=raw")
-else()
-  set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/MITKDashboardDriverScript.cmake")
-endif()
+set(url "https://raw.githubusercontent.com/MITK/MITK/${GIT_BRANCH}/CMake/MITKDashboardDriverScript.cmake")
 set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.driver)
 downloadFile("${url}" "${dest}")
 include(${dest})
diff --git a/CMake/mitkFunctionAddCustomModuleTest.cmake b/CMake/mitkFunctionAddCustomModuleTest.cmake
index 4659520d33..3c57b8cfd3 100644
--- a/CMake/mitkFunctionAddCustomModuleTest.cmake
+++ b/CMake/mitkFunctionAddCustomModuleTest.cmake
@@ -1,28 +1,28 @@
 #!
 #! \brief Add a custom test for MITK module
 #!
 #! \param test_name Unique identifier for the test
 #! \param test_function Name of the test function (the one with the argc,argv signature)
 #!
 #! Additional parameters will be passed as command line parameters to the test.
 #!
 function(mitkAddCustomModuleTest test_name test_function)
 
   if (BUILD_TESTING AND MODULE_IS_ENABLED)
     if(MITK_XVFB_TESTING)
-      set(xvfb_run "xvfb-run" "--auto-servernum")
+      set(xvfb_run ${MITK_XVFB_TESTING_COMMAND})
     else()
       set(xvfb_run )
     endif()
     add_test(NAME ${test_name} COMMAND ${xvfb_run} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${test_function} ${ARGN})
     set_property(TEST ${test_name} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK)
     mitkFunctionGetLibrarySearchPaths(MITK_RUNTIME_PATH_RELEASE release RELEASE)
     mitkFunctionGetLibrarySearchPaths(MITK_RUNTIME_PATH_DEBUG debug DEBUG)
     set(test_env_path ${MITK_RUNTIME_PATH_RELEASE} ${MITK_RUNTIME_PATH_DEBUG} $ENV{PATH})
     list(REMOVE_DUPLICATES test_env_path)
     string (REGEX REPLACE "\;" "\\\;" test_env_path "${test_env_path}")
     set_property(TEST ${test_name} PROPERTY ENVIRONMENT "PATH=${test_env_path}" APPEND)
     set_property(TEST ${test_name} PROPERTY SKIP_RETURN_CODE 77)
   endif()
 
 endfunction()
diff --git a/CMake/mitkFunctionCreateModule.cmake b/CMake/mitkFunctionCreateModule.cmake
index 5a4205ba7b..6e17f8a5ed 100644
--- a/CMake/mitkFunctionCreateModule.cmake
+++ b/CMake/mitkFunctionCreateModule.cmake
@@ -1,675 +1,677 @@
 ##################################################################
 #
 # 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 <moduleName> 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 <moduleName> 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 <arg>
 #! \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] <dir1>...]...
 #! \endverbatim
 #!        The default scope for include directories is PUBLIC.
 #! \param DEPENDS List of module dependencies:
 #!        \verbatim
 #! [[PUBLIC|PRIVATE|INTERFACE] <module1>...]...
 #! \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] <list>
       INTERNAL_INCLUDE_DIRS  # include dirs internal to this module (DEPRECATED)
       DEPENDS                # list of modules this module depends on: [PUBLIC|PRIVATE|INTERFACE] <list>
       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] <package-list>
       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] <list>
      )
 
   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()
       foreach(dep ${MODULE_DEPENDS})
           if(TARGET ${dep})
             get_target_property(AUTLOAD_DEP ${dep} MITK_AUTOLOAD_DIRECTORY)
             if (AUTLOAD_DEP)
               message(SEND_ERROR "Module \"${MODULE_NAME}\" has an invalid dependency on autoload module \"${dep}\". Check MITK_CREATE_MODULE usage for \"${MODULE_NAME}\".")
             endif()
           endif()
       endforeach(dep)
 
       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})
       set_property(TARGET ${_module_autoload_meta_target} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Autoload")
     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)
 	# this would turn on unused parameter warnings, but unfortunately MSVC cannot
 	# distinguish yet between internal and external headers so this would be triggered
 	# a lot by external code. There is support for it on the way so this line could be
 	# reactivated after https://gitlab.kitware.com/cmake/cmake/issues/17904 has been fixed.
         # mitkFunctionCheckCAndCXXCompilerFlags("/w34100" 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)
         mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-copy" module_c_flags module_cxx_flags)
         mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=cast-function-type" module_c_flags module_cxx_flags)
+        mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-declarations" module_c_flags module_cxx_flags)
+        mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=type-limits" 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)
       # INTERFACE_LIBRARY targets may only have whitelisted properties. The property "FOLDER" is not allowed.
       # set_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules")
     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_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Executables")
         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_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules")
         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 $<$<CONFIG:Debug>:${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 $<$<CONFIG:Release>:${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 $<$<CONFIG:Debug>:${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 $<$<CONFIG:Release>:${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/mitkMacroCreateModuleTests.cmake b/CMake/mitkMacroCreateModuleTests.cmake
index 9c6c81a7f3..a60564cac2 100644
--- a/CMake/mitkMacroCreateModuleTests.cmake
+++ b/CMake/mitkMacroCreateModuleTests.cmake
@@ -1,109 +1,109 @@
 #
 # Create tests and testdriver for this module
 #
 # Usage: MITK_CREATE_MODULE_TESTS( [EXTRA_DRIVER_INIT init_code]  )
 #
 # EXTRA_DRIVER_INIT is inserted as c++ code in the testdriver and will be executed before each test
 #
 macro(MITK_CREATE_MODULE_TESTS)
   cmake_parse_arguments(MODULE_TEST
                         "US_MODULE;NO_INIT" "EXTRA_DRIVER_INIT;EXTRA_DRIVER_INCLUDE" "EXTRA_DEPENDS;DEPENDS;PACKAGE_DEPENDS" ${ARGN})
 
   if(BUILD_TESTING AND MODULE_IS_ENABLED)
     include(files.cmake)
     include_directories(.)
 
     set(TESTDRIVER ${MODULE_NAME}TestDriver)
 
     set(MODULE_TEST_EXTRA_DRIVER_INIT "${MODULE_TEST_EXTRA_DRIVER_INIT}")
 
     if(MITK_XVFB_TESTING)
-      set(xvfb_run "xvfb-run" "--auto-servernum")
+      set(xvfb_run ${MITK_XVFB_TESTING_COMMAND})
     else()
       set(xvfb_run )
     endif()
 
     if(MODULE_TEST_US_MODULE)
       message(WARNING "The US_MODULE argument is deprecated and should be removed")
     endif()
 
     if(MODULE_TEST_US_MODULE AND MODULE_TEST_NO_INIT)
       message(WARNING "Conflicting arguments US_MODULE and NO_INIT: NO_INIT wins.")
     endif()
 
     set(_no_init)
     if(MODULE_TEST_NO_INIT)
       set(_no_init NO_INIT)
     endif()
 
     set(MITK_MODULE_NAME_REGEX_MATCH )
     set(MITK_MODULE_NAME_REGEX_NOT_MATCH )
 
     set(_testdriver_file_list ${CMAKE_CURRENT_BINARY_DIR}/testdriver_files.cmake)
     configure_file(${MITK_CMAKE_DIR}/mitkTestDriverFiles.cmake.in ${_testdriver_file_list} @ONLY)
     mitk_create_executable(${TESTDRIVER}
                            DEPENDS ${MODULE_NAME} ${MODULE_TEST_DEPENDS} ${MODULE_TEST_EXTRA_DEPENDS} MitkTestingHelper
                            PACKAGE_DEPENDS ${MODULE_TEST_PACKAGE_DEPENDS}
                            SUBPROJECTS ${MODULE_SUBPROJECTS}
                            FILES_CMAKE ${_testdriver_file_list}
                            NO_FEATURE_INFO
                            NO_BATCH_FILE
                            NO_INSTALL
                            ${_no_init})
     set_property(TARGET ${EXECUTABLE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Tests")
 
     #
     # Now tell CMake which tests should be run. This is done automatically
     # for all tests in ${KITNAME}_TESTS and ${KITNAME}_IMAGE_TESTS. The IMAGE_TESTS
     # are run for each image in the TESTIMAGES list.
     #
     include(files.cmake)
     foreach( test ${MODULE_TESTS} )
       get_filename_component(TName ${test} NAME_WE)
       add_test(NAME ${TName} COMMAND ${xvfb_run} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName})
       # Add labels for CDash subproject support
       if(MODULE_SUBPROJECTS)
         set_property(TEST ${TName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK)
       endif()
       mitkFunctionGetLibrarySearchPaths(MITK_RUNTIME_PATH_RELEASE release RELEASE)
       mitkFunctionGetLibrarySearchPaths(MITK_RUNTIME_PATH_DEBUG debug DEBUG)
       set(test_env_path ${MITK_RUNTIME_PATH_RELEASE} ${MITK_RUNTIME_PATH_DEBUG} $ENV{PATH})
       list(REMOVE_DUPLICATES test_env_path)
       string (REGEX REPLACE "\;" "\\\;" test_env_path "${test_env_path}")
       set_property(TEST ${TName} PROPERTY ENVIRONMENT "PATH=${test_env_path}" APPEND)
       set_property(TEST ${TName} PROPERTY SKIP_RETURN_CODE 77)
     endforeach()
 
     set(TEST_TYPES IMAGE SURFACE POINTSET) # add other file types here
 
     foreach(test_type ${TEST_TYPES})
        foreach(test_data ${MODULE_TEST${test_type}} ${ADDITIONAL_TEST_${test_type}})
          if(EXISTS ${test_data})
            set(TEST_DATA_FULL_PATH ${test_data})
           else()
              # todo: maybe search other paths as well
              # yes, please in mitk/Testing/Data, too
              set(TEST_DATA_FULL_PATH ${MITK_DATA_DIR}/${test_data})
           endif()
 
            if(EXISTS ${TEST_DATA_FULL_PATH})
              foreach( test ${MODULE_${test_type}_TESTS})
                get_filename_component(TName ${test} NAME_WE)
                get_filename_component(DName ${TEST_DATA_FULL_PATH} NAME)
                add_test(NAME ${TName}_${DName} COMMAND ${xvfb_run} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName} ${TEST_DATA_FULL_PATH})
                # Add labels for CDash subproject support
                if(MODULE_SUBPROJECTS)
                  set_property(TEST ${TName}_${DName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK)
                endif()
                set_property(TEST ${TName}_${DName} PROPERTY ENVIRONMENT "PATH=${test_env_path}" APPEND)
                set_property(TEST ${TName}_${DName} PROPERTY SKIP_RETURN_CODE 77)
              endforeach()
            else()
              message("!!!!! No such file: ${TEST_DATA_FULL_PATH} !!!!!")
            endif()
          endforeach()
     endforeach()
 
  endif()
 
 endmacro()
diff --git a/CMakeExternals/ITK.cmake b/CMakeExternals/ITK.cmake
index c958c56146..6217b38384 100644
--- a/CMakeExternals/ITK.cmake
+++ b/CMakeExternals/ITK.cmake
@@ -1,85 +1,85 @@
 #-----------------------------------------------------------------------------
 # 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
   # Added Module for Wavelets
     -DModule_IsotropicWavelets:BOOL=ON
   )
 
   if(CTEST_USE_LAUNCHERS)
     list(APPEND additional_cmake_args
       "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake"
     )
   endif()
 
   mitk_query_custom_ep_vars()
 
   ExternalProject_Add(${proj}
      LIST_SEPARATOR ${sep}
      UPDATE_COMMAND ""
-     # ITK 4.13.2 + GCC9 patch
-     URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/ITK_a092294.tar.gz
-     URL_MD5 5e3f39105917d992d5079be473994bc6
+     # ITK 4.13 release branch snapshot
+     URL https://github.com/InsightSoftwareConsortium/ITK/archive/e53d1d94.tar.gz
+     URL_MD5 977f77cb299cf3d722d13dd5408bcde5
      CMAKE_GENERATOR ${gen}
      CMAKE_GENERATOR_PLATFORM ${gen_platform}
      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}
        ${${proj}_CUSTOM_CMAKE_ARGS}
      CMAKE_CACHE_ARGS
        ${ep_common_cache_args}
        ${${proj}_CUSTOM_CMAKE_CACHE_ARGS}
      CMAKE_CACHE_DEFAULT_ARGS
        ${ep_common_cache_default_args}
        ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS}
      DEPENDS ${proj_DEPENDENCIES}
     )
 
   set(ITK_DIR ${ep_prefix})
   mitkFunctionInstallExternalCMakeProject(${proj})
 
 else()
 
   mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}")
 
 endif()
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0431e192ed..1ae49aa27d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,1473 +1,1481 @@
 set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.14.5)
 cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION})
 
 #-----------------------------------------------------------------------------
 # See https://cmake.org/cmake/help/v3.14/manual/cmake-policies.7.html for details
 #-----------------------------------------------------------------------------
 
 set(project_policies )
 foreach(policy ${project_policies})
   if(POLICY ${policy})
     cmake_policy(SET ${policy} NEW)
   endif()
 endforeach()
 
 #-----------------------------------------------------------------------------
 # 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 2018.04.99)
   include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR})
 endif()
 
 #-----------------------------------------------------------------------------
 # MITK Extension Feature
 #-----------------------------------------------------------------------------
 
 set(MITK_EXTENSION_DIRS "" CACHE STRING "")
 set(MITK_DIR_PLUS_EXTENSION_DIRS ${MITK_SOURCE_DIR} ${MITK_EXTENSION_DIRS})
 
 #-----------------------------------------------------------------------------
 # Update CMake module path
 #-----------------------------------------------------------------------------
 
 set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake)
 
 set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR})
 
 foreach(MITK_EXTENSION_DIR ${MITK_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)
 include(mitkFunctionAddLibrarySearchPaths)
 
 SUPPRESS_VC_DEPRECATED_WARNINGS()
 
 #-----------------------------------------------------------------------------
 # Set a default build type if none was specified
 #-----------------------------------------------------------------------------
 
 if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
   message(STATUS "Setting build type to 'Debug' as none was specified.")
   set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
 
   # Set the possible values of build type for cmake-gui
   set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
                STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
 endif()
 
 #-----------------------------------------------------------------------------
 # Check miminum macOS version
 #-----------------------------------------------------------------------------
 # The minimum supported macOS version is 10.13. If you use a version less than 10.13, there is no guarantee that the build still works.
 if(APPLE)
   exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE macos_version)
   if (macos_version VERSION_LESS "10.13")
     message(WARNING "Detected macOS version \"${macos_version}\" is not supported anymore. Minimum required macOS version is at least 10.13.")
   endif()
   if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.13)
     message(WARNING "Detected macOS deployment target \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" is not supported anymore. Minimum required macOS version is at least 10.13.")
   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 2017
   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)
 #-----------------------------------------------------------------------------
 
 # -----------------------------------------
 # General build options
 option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON)
 option(WITH_COVERAGE "Enable/Disable coverage" OFF)
 option(BUILD_TESTING "Test the project" ON)
 option(MITK_FAST_TESTING "Disable long-running tests like packaging" OFF)
 option(MITK_XVFB_TESTING "Execute test drivers through xvfb-run" OFF)
 
 option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF)
 option(MITK_BUILD_EXAMPLES "Build the MITK Examples" OFF)
 option(MITK_ENABLE_PIC_READER "Enable support for reading the DKFZ pic file format." ON)
 
 mark_as_advanced(
   MITK_XVFB_TESTING
   MITK_FAST_TESTING
   MITK_BUILD_ALL_APPS
   MITK_ENABLE_PIC_READER
 )
 
+#-----------------------------------------------------------------------------
+# Set UI testing flags
+#-----------------------------------------------------------------------------
+if(MITK_XVFB_TESTING)
+  set(MITK_XVFB_TESTING_COMMAND "xvfb-run" "--auto-servernum" CACHE STRING "Command and options to test through Xvfb")
+  mark_as_advanced(MITK_XVFB_TESTING_COMMAND)
+endif(MITK_XVFB_TESTING)
+
 # -----------------------------------------
 # Other options
 set(MITK_CUSTOM_REVISION_DESC "" CACHE STRING "Override MITK revision description")
 mark_as_advanced(MITK_CUSTOM_REVISION_DESC)
 
 set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "")
 
 include(CMakeExternals/ExternalProjectList.cmake)
 
 foreach(MITK_EXTENSION_DIR ${MITK_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
 
 option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON)
 option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF)
 option(MITK_USE_OpenMP "Use OpenMP" OFF)
 option(MITK_USE_Python3 "Use Python 3" OFF)
 
 #-----------------------------------------------------------------------------
 # Build configurations
 #-----------------------------------------------------------------------------
 
 set(_buildConfigs "Custom")
 
 file(GLOB _buildConfigFiles CMake/BuildConfigurations/*.cmake)
 
 foreach(_buildConfigFile ${_buildConfigFiles})
   get_filename_component(_buildConfigFile ${_buildConfigFile} NAME_WE)
   list(APPEND _buildConfigs ${_buildConfigFile})
 endforeach()
 
 foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS})
   file(GLOB _extBuildConfigFiles ${MITK_EXTENSION_DIR}/CMake/BuildConfigurations/*.cmake)
 
   foreach(_extBuildConfigFile ${_extBuildConfigFiles})
     get_filename_component(_extBuildConfigFile ${_extBuildConfigFile} NAME_WE)
     list(APPEND _buildConfigs ${_extBuildConfigFile})
   endforeach()
 
   list(REMOVE_DUPLICATES _buildConfigs)
 endforeach()
 
 set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations")
 set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs})
 
 mitkFunctionEnableBuildConfiguration()
 
 mitkFunctionCreateWhitelistPaths(MITK)
 mitkFunctionFindWhitelists(MITK)
 
 # -----------------------------------------
 # Qt version related variables
 
 option(MITK_USE_Qt5 "Use Qt 5 library" ON)
 
 if(MITK_USE_Qt5)
   set(MITK_QT5_MINIMUM_VERSION 5.12)
   set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets Xml XmlPatterns WebEngineWidgets UiTools Help LinguistTools)
   if(APPLE)
     list(APPEND MITK_QT5_COMPONENTS DBus)
   elseif(UNIX)
     list(APPEND MITK_QT5_COMPONENTS X11Extras)
   endif()
 
   # Hint at default install locations of Qt
   if(NOT Qt5_DIR)
     if(MSVC)
       set(_dir_candidates "C:/Qt")
 
       if(CMAKE_GENERATOR MATCHES "^Visual Studio [0-9]+ ([0-9]+)")
         set(_compilers "msvc${CMAKE_MATCH_1}")
       elseif(CMAKE_GENERATOR MATCHES "Ninja")
         include(mitkFunctionGetMSVCVersion)
         mitkFunctionGetMSVCVersion()
         if(VISUAL_STUDIO_PRODUCT_NAME MATCHES "^Visual Studio ([0-9]+)")
           set(_compilers "msvc${CMAKE_MATCH_1}")
         endif()
       endif()
 
       if(_compilers MATCHES "[0-9]+")
         if (CMAKE_MATCH_0 EQUAL 2019)
           list(APPEND _compilers "msvc2017") # Binary compatible to 2019
         endif()
       endif()
     else()
       set(_dir_candidates ~/Qt)
 
       if(APPLE)
         set(_compilers clang)
       else()
         list(APPEND _dir_candidates /opt/Qt)
         set(_compilers gcc)
       endif()
     endif()
 
     if(CMAKE_SIZEOF_VOID_P EQUAL 8)
       foreach(_compiler ${_compilers})
         list(APPEND _compilers64 "${_compiler}_64")
       endforeach()
       set(_compilers ${_compilers64})
     endif()
 
     foreach(_dir_candidate ${_dir_candidates})
       get_filename_component(_dir_candidate ${_dir_candidate} REALPATH)
       foreach(_compiler ${_compilers})
         set(_glob_expression "${_dir_candidate}/5.*/${_compiler}")
         file(GLOB _hints ${_glob_expression})
         list(SORT _hints)
         list(APPEND MITK_QT5_HINTS ${_hints})
       endforeach()
     endforeach()
   endif()
 
   find_package(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS} REQUIRED HINTS ${MITK_QT5_HINTS})
 
   if(${Qt5_VERSION} VERSION_GREATER_EQUAL 5.13)
     message(FATAL_ERROR "Qt version ${Qt5_VERSION_MAJOR}.${Qt5_VERSION_MINOR} is not yet supported. We recommend using the latest long-term support version 5.12.x.")
   endif()
 endif()
 
 # -----------------------------------------
 # 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")
 
 if(MITK_USE_cpprestsdk)
   find_package(OpenSSL QUIET)
   if(NOT OpenSSL_FOUND)
     set(openssl_message "Could not find OpenSSL (dependency of C++ REST SDK).\n")
     if(UNIX)
       if(APPLE)
         set(openssl_message "${openssl_message}Please install it using your favorite package management "
                             "system (i.e. Homebrew or MacPorts).\n")
       else()
         set(openssl_message "${openssl_message}Please install the dev package of OpenSSL (i.e. libssl-dev).\n")
       endif()
     else()
       set(openssl_message "${openssl_message}Please install Win32 OpenSSL:\n"
                           "  https://slproweb.com/products/Win32OpenSSL.html\n")
     endif()
     set(openssl_message "${openssl_message}If it still cannot be found, you can hint CMake to find OpenSSL by "
                         "adding/setting the OPENSSL_ROOT_DIR variable to the root directory of an "
                         "OpenSSL installation. Make sure to clear variables of partly found "
                         "versions of OpenSSL before, or they will be mixed up.")
     message(FATAL_ERROR ${openssl_message})
   endif()
 
   list(APPEND MITK_USE_Boost_LIBRARIES date_time regex system)
   if(UNIX)
     list(APPEND MITK_USE_Boost_LIBRARIES atomic chrono filesystem random thread)
   endif()
   list(REMOVE_DUPLICATES MITK_USE_Boost_LIBRARIES)
   set(MITK_USE_Boost_LIBRARIES ${MITK_USE_Boost_LIBRARIES} CACHE STRING "A semi-colon separated list of required Boost libraries" FORCE)
 endif()
 
 if(MITK_USE_Python3)
   set(MITK_USE_ZLIB ON CACHE BOOL "" FORCE)
 
   if(APPLE AND CMAKE_FRAMEWORK_PATH AND CMAKE_FRAMEWORK_PATH MATCHES "python3\\.?([0-9]+)")
     find_package(Python3 3.${CMAKE_MATCH_1} EXACT REQUIRED COMPONENTS Interpreter Development NumPy)
   else()
     find_package(Python3 REQUIRED COMPONENTS Interpreter Development NumPy)
   endif()
 
   if(WIN32)
     string(REPLACE "\\" "/" Python3_STDARCH "${Python3_STDARCH}")
     string(REPLACE "\\" "/" Python3_STDLIB "${Python3_STDLIB}")
     string(REPLACE "\\" "/" Python3_SITELIB "${Python3_SITELIB}")
   endif()
 endif()
 
 if(BUILD_TESTING AND NOT MITK_USE_CppUnit)
   message("> Forcing MITK_USE_CppUnit to ON because BUILD_TESTING=ON")
   set(MITK_USE_CppUnit ON CACHE BOOL "Use CppUnit for unit tests" FORCE)
 endif()
 
 if(MITK_USE_BLUEBERRY)
   option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF)
   mark_as_advanced(MITK_BUILD_ALL_PLUGINS)
 
   if(NOT MITK_USE_CTK)
     message("> Forcing MITK_USE_CTK to ON because of MITK_USE_BLUEBERRY")
     set(MITK_USE_CTK ON CACHE BOOL "Use CTK in MITK" FORCE)
   endif()
 endif()
 
 #-----------------------------------------------------------------------------
 # Pixel type multiplexing
 #-----------------------------------------------------------------------------
 
 # Customize the default pixel types for multiplex macros
 
 set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES
     "int, unsigned int, short, unsigned short, char, unsigned char"
     CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros")
 
 set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES
     "double, float"
     CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros")
 
 set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES
     "itk::RGBPixel<unsigned char>, itk::RGBAPixel<unsigned char>"
     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<unsigned char>, itk::RGBAPixel<unsigned char>"
     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-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
   )
 
 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}/CTestSubprojectList.cmake)
     set(MITK_CTEST_SUBPROJECTS "")
     include(${MITK_CMAKE_EXTENSION_DIR}/CTestSubprojectList.cmake)
     if(MITK_CTEST_SUBPROJECTS)
       list(APPEND CTEST_PROJECT_SUBPROJECTS ${MITK_CTEST_SUBPROJECTS})
     endif()
   endif()
 endforeach()
 
 # 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  ****************************
 #*****************************************************************************
 
 #-----------------------------------------------------------------------------
 # Organize MITK targets in folders
 #-----------------------------------------------------------------------------
 
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 set(MITK_ROOT_FOLDER "MITK" CACHE STRING "")
 mark_as_advanced(MITK_ROOT_FOLDER)
 
 #-----------------------------------------------------------------------------
 # CMake function(s) and macro(s)
 #-----------------------------------------------------------------------------
 
 include(WriteBasicConfigVersionFile)
 include(CheckCXXSourceCompiles)
 include(GenerateExportHeader)
 
 include(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(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 applications
 option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON)
 mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW)
 
 # 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 ON)
   endif()
 endif()
 
 if(NOT UNIX)
   set(MITK_WIN32_FORCE_STATIC "STATIC" CACHE INTERNAL "Use this variable to always build static libraries on non-unix platforms")
 endif()
 
 if(MITK_BUILD_ALL_PLUGINS)
   set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL")
 endif()
 
 # Configure pixel types used for ITK image access multiplexing
 mitkMacroConfigureItkPixelTypes()
 
 # Configure module naming conventions
 set(MITK_MODULE_NAME_REGEX_MATCH "^[A-Z].*$")
 set(MITK_MODULE_NAME_REGEX_NOT_MATCH "^[Mm][Ii][Tt][Kk].*$")
 set(MITK_DEFAULT_MODULE_NAME_PREFIX "Mitk")
 set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX})
 set(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME 1)
 
 #-----------------------------------------------------------------------------
 # Get MITK version info
 #-----------------------------------------------------------------------------
 
 mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK)
 mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK)
 
 # MITK_VERSION
 set(MITK_VERSION_STRING "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}")
 if(MITK_VERSION_PATCH STREQUAL "99")
   set(MITK_VERSION_STRING "${MITK_VERSION_STRING}-${MITK_REVISION_SHORTID}")
 endif()
 
 #-----------------------------------------------------------------------------
 # Installation preparation
 #
 # These should be set before any MITK install macros are used
 #-----------------------------------------------------------------------------
 
 # on macOS all BlueBerry plugins get copied into every
 # application bundle (.app directory) specified here
 if(MITK_USE_BLUEBERRY AND APPLE)
 
   foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS})
     set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications)
     get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE)
     if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake)
       set(MITK_APPS "")
       include(${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake)
       foreach(mitk_app ${MITK_APPS})
         # extract option_name
         string(REPLACE "^^" "\\;" target_info ${mitk_app})
         set(target_info_list ${target_info})
         list(GET target_info_list 1 option_name)
         list(GET target_info_list 0 app_name)
         # check if the application is enabled
         if(${option_name} OR MITK_BUILD_ALL_APPS)
           set(MACOSX_BUNDLE_NAMES ${MACOSX_BUNDLE_NAMES} Mitk${app_name})
         endif()
       endforeach()
     endif()
   endforeach()
 
 endif()
 
 #-----------------------------------------------------------------------------
 # Set coverage Flags
 #-----------------------------------------------------------------------------
 
 if(WITH_COVERAGE)
   if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
     set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG")
     set(COVERAGE_CXX_FLAGS ${coverage_flags})
     set(COVERAGE_C_FLAGS ${coverage_flags})
   endif()
 endif()
 
 #-----------------------------------------------------------------------------
 # MITK C/CXX Flags
 #-----------------------------------------------------------------------------
 
 set(MITK_C_FLAGS "${COVERAGE_C_FLAGS}")
 set(MITK_C_FLAGS_DEBUG )
 set(MITK_C_FLAGS_RELEASE )
 set(MITK_CXX_FLAGS "${COVERAGE_CXX_FLAGS} ${MITK_CXX14_FLAG}")
 set(MITK_CXX_FLAGS_DEBUG )
 set(MITK_CXX_FLAGS_RELEASE )
 
 set(MITK_EXE_LINKER_FLAGS )
 set(MITK_SHARED_LINKER_FLAGS )
 
 if(WIN32)
   set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -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
   mitkFunctionCheckCompilerFlags("/wd4251" MITK_CXX_FLAGS) # warning C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
 endif()
 
 if(APPLE)
   set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -DGL_SILENCE_DEPRECATION") # Apple deprecated OpenGL in macOS 10.14
 endif()
 
 if(NOT MSVC_VERSION)
   foreach(_flag
     -Wall
     -Wextra
     -Wpointer-arith
     -Winvalid-pch
     -Wcast-align
     -Wwrite-strings
     -Wno-error=gnu
     -Wno-error=unknown-pragmas
     # The strict-overflow warning is generated by ITK template code
     -Wno-error=strict-overflow
     -Woverloaded-virtual
     -Wstrict-null-sentinel
     #-Wold-style-cast
     #-Wsign-promo
     -Wno-error=deprecated-copy
     -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.68 1.68.0)
 
 # We need this later for a DCMTK workaround
 set(_dcmtk_dir_orig ${DCMTK_DIR})
 
 # This property is populated at the top half of this file
 get_property(MITK_EXTERNAL_PROJECTS GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS)
 foreach(ep ${MITK_EXTERNAL_PROJECTS})
   get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE)
   get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS)
   if(MITK_USE_${ep} AND _package)
     if(_components)
       find_package(${_package} COMPONENTS ${_components} REQUIRED CONFIG)
     else()
       # Prefer config mode first because it finds external
       # <proj>Config.cmake files pointed at by <proj>_DIR variables.
       # Otherwise, existing Find<proj>.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<proj>.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()
 
 link_directories(${Boost_LIBRARY_DIRS})
 
 if(MITK_USE_OpenIGTLink)
   link_directories(${OpenIGTLink_LIBRARY_DIRS})
 endif()
 
 if(MITK_USE_OpenCL)
   find_package(OpenCL REQUIRED)
 endif()
 
 if(MITK_USE_OpenMP)
   find_package(OpenMP REQUIRED COMPONENTS CXX)
 else()
   find_package(OpenMP QUIET COMPONENTS CXX)
 
   if(OpenMP_FOUND)
     set(MITK_USE_OpenMP ON CACHE BOOL "" FORCE)
   elseif(APPLE AND OpenMP_libomp_LIBRARY AND NOT OpenMP_CXX_LIB_NAMES)
     set(OpenMP_CXX_LIB_NAMES libomp CACHE STRING "" FORCE)
     get_filename_component(openmp_lib_dir "${OpenMP_libomp_LIBRARY}" DIRECTORY)
     set(openmp_include_dir "${openmp_lib_dir}/../include")
     if(EXISTS "${openmp_include_dir}")
       get_filename_component(openmp_include_dir "${openmp_include_dir}" REALPATH)
       set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${openmp_include_dir}" CACHE STRING "" FORCE)
       find_package(OpenMP QUIET COMPONENTS CXX)
       if(OpenMP_FOUND)
         set(MITK_USE_OpenMP ON CACHE BOOL "" FORCE)
       endif()
     endif()
   endif()
 endif()
 
 # Qt support
 if(MITK_USE_Qt5)
   find_package(Qt5Core ${MITK_QT5_MINIMUM_VERSION} REQUIRED) # at least Core required
   get_target_property(_qmake_exec Qt5::qmake LOCATION)
   execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS
     RESULT_VARIABLE _result
      OUTPUT_VARIABLE QT_BINARY_DIR
     ERROR_VARIABLE _error
   )
   string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR)
   if(_result OR NOT EXISTS "${QT_BINARY_DIR}")
     message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}")
   endif()
 
   find_program(QT_HELPGENERATOR_EXECUTABLE
     NAMES qhelpgenerator qhelpgenerator-qt5 qhelpgenerator5
     PATHS ${QT_BINARY_DIR}
     NO_DEFAULT_PATH
   )
 
   find_program(QT_COLLECTIONGENERATOR_EXECUTABLE
     NAMES qcollectiongenerator qcollectiongenerator-qt5 qcollectiongenerator5
     PATHS ${QT_BINARY_DIR}
     NO_DEFAULT_PATH
   )
 
   find_program(QT_ASSISTANT_EXECUTABLE
     NAMES assistant assistant-qt5 assistant5
     PATHS ${QT_BINARY_DIR}
     NO_DEFAULT_PATH
   )
 
   find_program(QT_XMLPATTERNS_EXECUTABLE
     NAMES xmlpatterns
     PATHS ${QT_BINARY_DIR}
     NO_DEFAULT_PATH
   )
 
   mark_as_advanced(QT_HELPGENERATOR_EXECUTABLE
                    QT_COLLECTIONGENERATOR_EXECUTABLE
                    QT_ASSISTANT_EXECUTABLE
                    QT_XMLPATTERNS_EXECUTABLE
                   )
 
   if(MITK_USE_BLUEBERRY)
     option(BLUEBERRY_USE_QT_HELP "Enable support for integrating plugin documentation into Qt Help" ${DOXYGEN_FOUND})
     mark_as_advanced(BLUEBERRY_USE_QT_HELP)
 
     # Sanity checks for in-application BlueBerry plug-in help generation
     if(BLUEBERRY_USE_QT_HELP)
       set(_force_blueberry_use_qt_help_to_off 0)
       if(NOT DOXYGEN_FOUND)
         message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen was not found.")
         set(_force_blueberry_use_qt_help_to_off 1)
       endif()
       if(DOXYGEN_FOUND AND DOXYGEN_VERSION VERSION_LESS 1.8.7)
         message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen version 1.8.7 or newer not found.")
         set(_force_blueberry_use_qt_help_to_off 1)
       endif()
 
       if(NOT QT_HELPGENERATOR_EXECUTABLE)
         message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because QT_HELPGENERATOR_EXECUTABLE is empty.")
         set(_force_blueberry_use_qt_help_to_off 1)
       endif()
 
       if(NOT MITK_USE_Qt5)
         message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because MITK_USE_Qt5 is OFF.")
         set(_force_blueberry_use_qt_help_to_off 1)
       endif()
 
       if(NOT QT_XMLPATTERNS_EXECUTABLE)
         message("You have enabled Qt Help support, but QT_XMLPATTERNS_EXECUTABLE is empty")
         set(_force_blueberry_use_qt_help_to_off 1)
       endif()
 
       if(_force_blueberry_use_qt_help_to_off)
         set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating plugin documentation into Qt Help" FORCE)
       endif()
     endif()
 
     if(BLUEBERRY_QT_HELP_REQUIRED AND NOT BLUEBERRY_USE_QT_HELP)
       message(FATAL_ERROR "BLUEBERRY_USE_QT_HELP is required to be set to ON")
     endif()
   endif()
 
 endif()
 
 #-----------------------------------------------------------------------------
 # Testing
 #-----------------------------------------------------------------------------
 
 if(BUILD_TESTING)
   enable_testing()
   include(CTest)
   mark_as_advanced(TCL_TCLSH DART_ROOT)
 
   # 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 <stdexcept>")
   set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN "
     try
       {")
   set(CMAKE_TESTDRIVER_AFTER_TESTMAIN "    }
       catch ( const 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 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})
     set_property(TARGET ${subproject} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/CTestSubprojects")
   endif()
 endforeach()
 
 #-----------------------------------------------------------------------------
 # Add subdirectories
 #-----------------------------------------------------------------------------
 
 add_subdirectory(Utilities)
 
 add_subdirectory(Modules)
 
 include("${CMAKE_CURRENT_SOURCE_DIR}/Modules/ModuleList.cmake")
 mitkFunctionWhitelistModules(MITK MITK_MODULES)
 
 set(MITK_ROOT_FOLDER_BACKUP "${MITK_ROOT_FOLDER}")
 foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS})
   get_filename_component(MITK_ROOT_FOLDER ${MITK_EXTENSION_DIR} NAME)
   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()
 set(MITK_ROOT_FOLDER "${MITK_ROOT_FOLDER_BACKUP}")
 
 add_subdirectory(Wrapping)
 
 set(MITK_DOXYGEN_OUTPUT_DIR "${PROJECT_BINARY_DIR}/Documentation/Doxygen" CACHE PATH
   "Output directory for doxygen generated documentation.")
 
 if(MITK_USE_BLUEBERRY)
 
   set(BLUEBERRY_XPDOC_OUTPUT_DIR "${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/")
   execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${BLUEBERRY_XPDOC_OUTPUT_DIR})
 
   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
   set(mitk_apps_fullpath "")
   foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS})
     set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications)
     get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE)
     if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake)
       set(MITK_APPS "")
       include(${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake)
       foreach(mitk_app ${MITK_APPS})
         # extract option_name
         string(REPLACE "^^" "\\;" target_info ${mitk_app})
         set(target_info_list ${target_info})
         list(GET target_info_list 0 directory_name)
         list(GET target_info_list 1 option_name)
         if(${option_name})
           list(APPEND mitk_apps_fullpath "${MITK_APPLICATIONS_EXTENSION_DIR}/${directory_name}^^${option_name}")
         endif()
       endforeach()
     endif()
   endforeach()
 
   if (mitk_plugins_fullpath)
     ctkMacroSetupPlugins(${mitk_plugins_fullpath}
                          BUILD_OPTION_PREFIX MITK_BUILD_
                          APPS ${mitk_apps_fullpath}
                          BUILD_ALL ${MITK_BUILD_ALL_PLUGINS}
                          COMPACT_OPTIONS)
   endif()
 
   set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake")
   if(${PROJECT_NAME}_PLUGIN_LIBRARIES)
     ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE})
   else()
     file(REMOVE ${MITK_PLUGIN_USE_FILE})
     set(MITK_PLUGIN_USE_FILE )
   endif()
 endif()
 
 #-----------------------------------------------------------------------------
 # Documentation
 #-----------------------------------------------------------------------------
 
 if(DOXYGEN_FOUND)
   add_subdirectory(Documentation)
 endif()
 
 #-----------------------------------------------------------------------------
 # Installation
 #-----------------------------------------------------------------------------
 
 
 # set MITK cpack variables
 # These are the default variables, which can be overwritten ( see below )
 include(mitkSetupCPack)
 
 set(use_default_config ON)
 
 set(ALL_MITK_APPS "")
 set(activated_apps_no 0)
 
 foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS})
   set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications)
   get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE)
   if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake)
     set(MITK_APPS "")
     include(${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake)
     foreach(mitk_app ${MITK_APPS})
       string(REPLACE "^^" "\\;" target_info ${mitk_app})
       set(target_info_list ${target_info})
       list(GET target_info_list 0 directory_name)
       list(GET target_info_list 1 option_name)
       list(GET target_info_list 2 executable_name)
       list(APPEND ALL_MITK_APPS "${MITK_EXTENSION_DIR}/Applications/${directory_name}^^${option_name}^^${executable_name}")
       if(${option_name} OR MITK_BUILD_ALL_APPS)
         MATH(EXPR activated_apps_no "${activated_apps_no} + 1")
       endif()
     endforeach()
   endif()
 endforeach()
 
 list(LENGTH ALL_MITK_APPS app_count)
 
 if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS))
   # Corner case if there is only one app in total
   set(use_project_cpack ON)
 elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS)
   # Only one app is enabled (no "build all" flag set)
   set(use_project_cpack ON)
 else()
   # Less or more then one app is enabled
   set(use_project_cpack OFF)
 endif()
 
 foreach(mitk_app ${ALL_MITK_APPS})
   # extract target_dir and option_name
   string(REPLACE "^^" "\\;" target_info ${mitk_app})
   set(target_info_list ${target_info})
   list(GET target_info_list 0 target_dir)
   list(GET target_info_list 1 option_name)
   list(GET target_info_list 2 executable_name)
   # check if the application is enabled
   if(${option_name} OR MITK_BUILD_ALL_APPS)
     # check whether application specific configuration files will be used
     if(use_project_cpack)
       # use files if they exist
       if(EXISTS "${target_dir}/CPackOptions.cmake")
         include("${target_dir}/CPackOptions.cmake")
       endif()
 
       if(EXISTS "${target_dir}/CPackConfig.cmake.in")
         set(CPACK_PROJECT_CONFIG_FILE "${target_dir}/CPackConfig.cmake")
         configure_file(${target_dir}/CPackConfig.cmake.in
                        ${CPACK_PROJECT_CONFIG_FILE} @ONLY)
         set(use_default_config OFF)
       endif()
     endif()
   # add link to the list
   list(APPEND CPACK_CREATE_DESKTOP_LINKS "${executable_name}")
   endif()
 endforeach()
 
 # if no application specific configuration file was used, use default
 if(use_default_config)
   configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in
                  ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY)
   set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake")
 endif()
 
 # include CPack model once all variables are set
 include(CPack)
 
 # Additional installation rules
 include(mitkInstallRules)
 
 #-----------------------------------------------------------------------------
 # Last configuration steps
 #-----------------------------------------------------------------------------
 
 # ---------------- Export targets -----------------
 
 set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake")
 file(REMOVE ${MITK_EXPORTS_FILE})
 
 set(targets_to_export)
 get_property(module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS)
 if(module_targets)
   list(APPEND targets_to_export ${module_targets})
 endif()
 
 if(MITK_USE_BLUEBERRY)
   if(MITK_PLUGIN_LIBRARIES)
     list(APPEND targets_to_export ${MITK_PLUGIN_LIBRARIES})
   endif()
 endif()
 
 export(TARGETS ${targets_to_export} APPEND
        FILE ${MITK_EXPORTS_FILE})
 
 set(MITK_EXPORTED_TARGET_PROPERTIES )
 foreach(target_to_export ${targets_to_export})
   get_target_property(autoload_targets ${target_to_export} MITK_AUTOLOAD_TARGETS)
   if(autoload_targets)
     set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES}
 set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_TARGETS \"${autoload_targets}\")")
   endif()
   get_target_property(autoload_dir ${target_to_export} MITK_AUTOLOAD_DIRECTORY)
   if(autoload_dir)
     set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES}
 set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_DIRECTORY \"${autoload_dir}\")")
   endif()
 
   get_target_property(deprecated_module ${target_to_export} MITK_MODULE_DEPRECATED_SINCE)
   if(deprecated_module)
     set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES}
 set_target_properties(${target_to_export} PROPERTIES MITK_MODULE_DEPRECATED_SINCE \"${deprecated_module}\")")
   endif()
 endforeach()
 
 # ---------------- External projects -----------------
 
 get_property(MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS_CONFIG GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS)
 
 set(MITK_CONFIG_EXTERNAL_PROJECTS )
 #string(REPLACE "^^" ";" _mitk_external_projects ${MITK_EXTERNAL_PROJECTS})
 
 foreach(ep ${MITK_EXTERNAL_PROJECTS})
   get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS)
   set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS}
 set(MITK_USE_${ep} ${MITK_USE_${ep}})
 set(MITK_${ep}_DIR \"${${ep}_DIR}\")
 set(MITK_${ep}_COMPONENTS ${_components})
 ")
 endforeach()
 
 foreach(ep ${MITK_EXTERNAL_PROJECTS})
   get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE)
   get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS)
   if(_components)
       set(_components_arg COMPONENTS \${_components})
   else()
     set(_components_arg)
   endif()
 
   if(_package)
     set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS}
 if(MITK_USE_${ep})
   set(${ep}_DIR \${MITK_${ep}_DIR})
   if(MITK_${ep}_COMPONENTS)
     mitkMacroFindDependency(${_package} COMPONENTS \${MITK_${ep}_COMPONENTS})
   else()
     mitkMacroFindDependency(${_package})
   endif()
 endif()")
   endif()
 endforeach()
 
 
 # ---------------- Tools -----------------
 
 configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in
                ${MITK_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY)
 configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in
                ${MITK_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY)
 configure_file(${MITK_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in
                ${MITK_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY)
 
 # ---------------- Configure files -----------------
 
 configure_file(mitkVersion.h.in ${MITK_BINARY_DIR}/mitkVersion.h)
 configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h)
 
 set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc)
 set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities)
 
 configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h)
 configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY)
 
 write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
   VERSION ${MITK_VERSION_STRING} COMPATIBILITY AnyNewerVersion)
 
 #-----------------------------------------------------------------------------
 # MITK Applications
 #-----------------------------------------------------------------------------
 
 # This must come after MITKConfig.h was generated, since applications
 # might do a find_package(MITK REQUIRED).
 add_subdirectory(Applications)
 
 if(MSVC AND TARGET MitkWorkbench)
   set_directory_properties(PROPERTIES VS_STARTUP_PROJECT MitkWorkbench)
 endif()
 
 foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS})
   set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications)
   get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE)
   if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/CMakeLists.txt)
     add_subdirectory(${MITK_APPLICATIONS_EXTENSION_DIR} Applications)
   endif()
 endforeach()
 
 #-----------------------------------------------------------------------------
 # MITK Examples
 #-----------------------------------------------------------------------------
 
 if(MITK_BUILD_EXAMPLES)
   # This must come after MITKConfig.h was generated, since applications
   # might do a find_package(MITK REQUIRED).
   add_subdirectory(Examples)
 endif()
 
 #-----------------------------------------------------------------------------
 # Print configuration summary
 #-----------------------------------------------------------------------------
 
 message("\n\n")
 feature_summary(
   DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------"
   WHAT ALL
 )
diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp
index 0fd2a438da..1bfdb684f6 100644
--- a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp
+++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp
@@ -1,91 +1,91 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkExampleDataStructureReaderService.h"
 
 // mitk includes
 #include "mitkExampleIOMimeTypes.h"
 #include "mitkGeometry3D.h"
 #include <mitkCustomMimeType.h>
 
 // itk includes
 #include "itksys/SystemTools.hxx"
 
 namespace mitk
 {
   ExampleDataStructureReaderService::ExampleDataStructureReaderService(const ExampleDataStructureReaderService &other)
     : mitk::AbstractFileReader(other)
   {
   }
 
   ExampleDataStructureReaderService::ExampleDataStructureReaderService()
     : mitk::AbstractFileReader(CustomMimeType(mitk::ExampleIOMimeTypes::EXAMPLE_MIMETYPE()),
                                "Default reader for the example data structure")
   {
     m_ServiceReg = this->RegisterService();
   }
 
   ExampleDataStructureReaderService::~ExampleDataStructureReaderService() {}
-  std::vector<itk::SmartPointer<BaseData>> ExampleDataStructureReaderService::Read()
+  std::vector<itk::SmartPointer<BaseData>> ExampleDataStructureReaderService::DoRead()
   {
     std::vector<itk::SmartPointer<mitk::BaseData>> result;
     std::string location = GetInputLocation();
 
     std::string ext = itksys::SystemTools::GetFilenameLastExtension(location);
     ext = itksys::SystemTools::LowerCase(ext);
 
     if (location == "")
     {
       MITK_ERROR << "No file name specified.";
     }
     try
     {
       std::ifstream file(location);
       std::string content("");
       std::string line("");
       if (file.is_open())
       {
         while (getline(file, line))
         {
           content += line;
           content += "\n";
         }
       }
       else
       {
         mitkThrow() << "Could not open file " << this->GetInputLocation() << " for reading.";
       }
 
       mitk::ExampleDataStructure::Pointer outputData = mitk::ExampleDataStructure::New();
       outputData->SetData(content);
       result.push_back(outputData.GetPointer());
       MITK_INFO << "Example file read";
     }
 
     catch (const mitk::Exception& e)
     {
       MITK_ERROR << e.GetDescription();
     }
     catch (...)
     {
       MITK_ERROR << "Unknown error occurred while trying to read file.";
     }
 
     return result;
   }
 
 } // namespace MITK
 
 mitk::ExampleDataStructureReaderService *mitk::ExampleDataStructureReaderService::Clone() const
 {
   return new ExampleDataStructureReaderService(*this);
 }
diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h
index 4f1384ed8e..bdc2ab20e8 100644
--- a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h
+++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h
@@ -1,47 +1,49 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkExampleDataStructureReaderService_h
 #define __mitkExampleDataStructureReaderService_h
 
 #include "mitkCommon.h"
 #include "mitkExampleDataStructure.h"
 #include <mitkAbstractFileReader.h>
 #include <mitkBaseData.h>
 #include <mitkMimeType.h>
 
 namespace mitk
 {
   /** \brief The reader service for the MITK example data type
   */
 
   class ExampleDataStructureReaderService : public mitk::AbstractFileReader
   {
   public:
     typedef mitk::ExampleDataStructure OutputType;
 
     ExampleDataStructureReaderService(const ExampleDataStructureReaderService &other);
     ExampleDataStructureReaderService();
     ~ExampleDataStructureReaderService() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
+
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     ExampleDataStructureReaderService *Clone() const override;
 
     us::ServiceRegistration<mitk::IFileReader> m_ServiceReg;
   };
 
 } // namespace MITK
 
 #endif // __mitkExampleDataStructureReaderService_h
diff --git a/Modules/Classification/CLVigraRandomForest/include/mitkDummyLsetReader.h b/Modules/Classification/CLVigraRandomForest/include/mitkDummyLsetReader.h
index b840cf141d..f118964448 100644
--- a/Modules/Classification/CLVigraRandomForest/include/mitkDummyLsetReader.h
+++ b/Modules/Classification/CLVigraRandomForest/include/mitkDummyLsetReader.h
@@ -1,45 +1,48 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef _MITK_DummyLsetFileReader__H_
 #define _MITK_DummyLsetFileReader__H_
 
 #include <mitkAbstractFileReader.h>
 
 namespace mitk
 {
 
 /**
  * Read deprecated *.lset format (Multilabel Image format 2014)
  * @ingroup Process
  */
 class DummyLsetFileReader : public mitk::AbstractFileReader
 {
 public:
 
     DummyLsetFileReader();
     DummyLsetFileReader(const mitk::DummyLsetFileReader& other);
     ~DummyLsetFileReader() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData> > Read() override;
+
+protected:
+   std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
 
   private:
     DummyLsetFileReader * Clone() const override;
 
 
 };
 
 
 } // end of namespace mitk
 
 #endif
diff --git a/Modules/Classification/CLVigraRandomForest/include/mitkRandomForestIO.h b/Modules/Classification/CLVigraRandomForest/include/mitkRandomForestIO.h
index 1bcb652b7f..456837251c 100644
--- a/Modules/Classification/CLVigraRandomForest/include/mitkRandomForestIO.h
+++ b/Modules/Classification/CLVigraRandomForest/include/mitkRandomForestIO.h
@@ -1,61 +1,62 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef _MITK_DecisionForestFileIO__H_
 #define _MITK_DecisionForestFileIO__H_
 
 #include <mitkAbstractFileIO.h>
 #include "vigra/random_forest.hxx"
 
 namespace mitk
 {
 
 /**
  * Writes vigra based mitk::DecisionForest
  * @ingroup Process
  */
 class RandomForestFileIO : public mitk::AbstractFileIO
 {
 public:
 
     RandomForestFileIO();
     RandomForestFileIO(const mitk::RandomForestFileIO& other);
     ~RandomForestFileIO() override;
 
     using AbstractFileIO::Write;
     void Write() override;
 
     using AbstractFileIO::Read;
-    std::vector<itk::SmartPointer<BaseData> > Read() override;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
     ConfidenceLevel GetWriterConfidenceLevel() const override;
 
 
-  protected:
+protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
 
     mutable vigra::RandomForest<int> m_rf;
 //    DecisionForestFileIO(const DecisionForestFileIO& other);
 //    virtual mitk::DecisionForestFileIO* Clone() const;
 
   private:
     AbstractFileIO* IOClone() const override;
 
 
 
 
 };
 
 
 } // end of namespace mitk
 
 #endif
diff --git a/Modules/Classification/CLVigraRandomForest/src/IO/mitkDummyLsetReader.cpp b/Modules/Classification/CLVigraRandomForest/src/IO/mitkDummyLsetReader.cpp
index a4e6256ba0..a1ae48a41a 100644
--- a/Modules/Classification/CLVigraRandomForest/src/IO/mitkDummyLsetReader.cpp
+++ b/Modules/Classification/CLVigraRandomForest/src/IO/mitkDummyLsetReader.cpp
@@ -1,66 +1,66 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 #include <mitkDummyLsetReader.h>
 #include <itksys/SystemTools.hxx>
 #include <itkImageFileReader.h>
 #include <itkNrrdImageIO.h>
 #include <mitkImageCast.h>
 #include <mitkCustomMimeType.h>
 
 typedef itk::Image<unsigned char, 3> ImageType;
 
-std::vector<itk::SmartPointer<mitk::BaseData> > mitk::DummyLsetFileReader::Read()
+std::vector<itk::SmartPointer<mitk::BaseData> > mitk::DummyLsetFileReader::DoRead()
 {
 
   std::vector<itk::SmartPointer<mitk::BaseData> > result;
   typedef itk::ImageFileReader<ImageType> FileReaderType;
   FileReaderType::Pointer reader = FileReaderType::New();
   reader->SetFileName(this->GetInputLocation());
   itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New();
   reader->SetImageIO(io);
   reader->Update();
 
   mitk::Image::Pointer img;
   mitk::CastToMitkImage(reader->GetOutput(),img);
   result.push_back(img.GetPointer());
 
   return result;
 }
 
 
 mitk::DummyLsetFileReader::DummyLsetFileReader(const DummyLsetFileReader & other)
   : AbstractFileReader(other)
 {
 }
 
 
 mitk::DummyLsetFileReader* mitk::DummyLsetFileReader::Clone() const
 {
   return new DummyLsetFileReader(*this);
 }
 
 
 mitk::DummyLsetFileReader::~DummyLsetFileReader()
 {}
 
 
 mitk::DummyLsetFileReader::DummyLsetFileReader()
 {
   CustomMimeType mimeType(this->GetMimeTypePrefix() + "lset");
   mimeType.AddExtension("lset");
   mimeType.SetCategory("Images");
   mimeType.SetComment("Experimental MBI LabelSetImage");
   this->SetMimeType(mimeType);
   this->SetDescription("MBI LabelSetImage");
   this->RegisterService();
 }
 
diff --git a/Modules/Classification/CLVigraRandomForest/src/IO/mitkRandomForestIO.cpp b/Modules/Classification/CLVigraRandomForest/src/IO/mitkRandomForestIO.cpp
index 4dedf92d42..79a0e270fb 100644
--- a/Modules/Classification/CLVigraRandomForest/src/IO/mitkRandomForestIO.cpp
+++ b/Modules/Classification/CLVigraRandomForest/src/IO/mitkRandomForestIO.cpp
@@ -1,218 +1,218 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkDecisionForestIO__cpp
 #define __mitkDecisionForestIO__cpp
 
 #include "mitkRandomForestIO.h"
 #include "itksys/SystemTools.hxx"
 //#include "mitkHDF5IOMimeTypes.h"
 
 #include "vigra/random_forest_hdf5_impex.hxx"
 
 #include <iostream>
 #include <fstream>
 
 #include "mitkVigraRandomForestClassifier.h"
 #include "mitkIOMimeTypes.h"
 
 #define GetAttribute(name,type)\
   type name;\
   hdf5_file.readAttribute(".",name,name);
 
 mitk::RandomForestFileIO::ConfidenceLevel mitk::RandomForestFileIO::GetReaderConfidenceLevel() const
 {
   std::string ext = itksys::SystemTools::GetFilenameLastExtension(this->GetLocalFileName().c_str());
   bool is_loaded = vigra::rf_import_HDF5(m_rf, this->GetInputLocation());
   return ext == ".forest"  && is_loaded == true? IFileReader::Supported : IFileReader::Unsupported;
 }
 
 mitk::RandomForestFileIO::ConfidenceLevel mitk::RandomForestFileIO::GetWriterConfidenceLevel() const
 {
   mitk::VigraRandomForestClassifier::ConstPointer input = dynamic_cast<const mitk::VigraRandomForestClassifier *>(this->GetInput());
   if (input.IsNull())
   {
     return IFileWriter::Unsupported;
   }else{
     return IFileWriter::Supported;
   }
 }
 
 mitk::RandomForestFileIO::RandomForestFileIO()
   : AbstractFileIO(mitk::VigraRandomForestClassifier::GetStaticNameOfClass())
 {
   CustomMimeType customReaderMimeType(mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".forest");
   std::string category = "Vigra Random Forest File";
   customReaderMimeType.SetComment("Vigra Random Forest");
   customReaderMimeType.SetCategory(category);
   customReaderMimeType.AddExtension("forest");
 
   //  this->AbstractFileIOWriter::SetRanking(100);
   this->AbstractFileWriter::SetMimeTypePrefix(mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".forest");
   this->AbstractFileWriter::SetMimeType(customReaderMimeType);
   this->SetWriterDescription("Vigra Random Forest");
   this->AbstractFileReader::SetMimeTypePrefix(mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".forest");
   this->AbstractFileReader::SetMimeType(customReaderMimeType);
   this->SetReaderDescription("Vigra Random Forest");
 
   //  this->SetReaderDescription(mitk::DecisionForestIOMimeTypes::DECISIONFOREST_MIMETYPE_DESCRIPTION());
   //  this->SetWriterDescription(mitk::DecisionForestIOMimeTypes::DECISIONFOREST_MIMETYPE_DESCRIPTION());
   this->RegisterService();
 }
 
 mitk::RandomForestFileIO::RandomForestFileIO(const mitk::RandomForestFileIO& other)
   : AbstractFileIO(other)
 {
 }
 
 mitk::RandomForestFileIO::~RandomForestFileIO()
 {}
 
 std::vector<itk::SmartPointer<mitk::BaseData> >
 mitk::RandomForestFileIO::
-Read()
+DoRead()
 {
   mitk::VigraRandomForestClassifier::Pointer output = mitk::VigraRandomForestClassifier::New();
   std::vector<itk::SmartPointer<mitk::BaseData> > result;
 
   if ( this->GetInputLocation().empty())
   {
     MITK_ERROR << "Sorry, filename has not been set!";
     return result;
   }
   else
   {
     const std::string& locale = "C";
     const std::string& currLocale = setlocale( LC_ALL, nullptr );
 
     if ( locale.compare(currLocale)!=0 )
     {
       try
       {
         setlocale(LC_ALL, locale.c_str());
       }
       catch(...)
       {
         MITK_INFO << "Could not set locale " << locale;
       }
     }
 
     output->SetRandomForest(m_rf);
     result.push_back(output.GetPointer());
     vigra::HDF5File hdf5_file(this->GetInputLocation() , vigra::HDF5File::Open);
 
 
     hdf5_file.cd_mk("/_mitkOptions");
 
     // ---------------------------------------------------------
     // Read tree weights
     if(hdf5_file.existsDataset("treeWeights"))
     {
       auto treeWeight = output->GetTreeWeights();
       treeWeight.resize(m_rf.tree_count(),1);
       vigra::MultiArrayView<2, double> W(vigra::Shape2(treeWeight.rows(),treeWeight.cols()),treeWeight.data());
       hdf5_file.read("treeWeights",W);
       output->SetTreeWeights(treeWeight);
     }
     // ---------------------------------------------------------
 
     // ---------------------------------------------------------
     // Read itemList
     if(hdf5_file.existsDataset("itemList")){
       std::string items_string;
       hdf5_file.read("itemList",items_string);
       auto itemlist = output->GetItemList();
 
       std::string current_item = "";
       for(auto character : items_string)
       {
         if(character == ';'){
           // skip seperator and push back item
           itemlist.push_back(current_item);
           current_item.clear();
         }else{
           current_item = current_item + character;
         }
       }
       output->SetItemList(itemlist);
     }
     // ---------------------------------------------------------
 
     hdf5_file.close();
 
     return result;
   }
 }
 
 void mitk::RandomForestFileIO::Write()
 {
   mitk::BaseData::ConstPointer input = this->GetInput();
   if (input.IsNull())
   {
     MITK_ERROR <<"Sorry, input to NrrdDiffusionImageWriter is nullptr!";
     return;
   }
   if ( this->GetOutputLocation().empty() )
   {
     MITK_ERROR << "Sorry, filename has not been set!";
     return ;
   }else{
     const std::string& locale = "C";
     const std::string& currLocale = setlocale( LC_ALL, nullptr );
 
     if ( locale.compare(currLocale)!=0 )
     {
       try
       {
         setlocale(LC_ALL, locale.c_str());
       }
       catch(...)
       {
         MITK_INFO << "Could not set locale " << locale;
       }
     }
 
     mitk::VigraRandomForestClassifier::ConstPointer mitkDC = dynamic_cast<const mitk::VigraRandomForestClassifier *>(input.GetPointer());
     //mitkDC->GetRandomForest()
     vigra::rf_export_HDF5(mitkDC->GetRandomForest(), this->GetOutputLocation());
 
     vigra::HDF5File hdf5_file(this->GetOutputLocation() , vigra::HDF5File::Open);
 
     hdf5_file.cd_mk("/_mitkOptions");
 
     // Write tree weights
     // ---------------------------------------------------------
     auto treeWeight = mitkDC->GetTreeWeights();
     vigra::MultiArrayView<2, double> W(vigra::Shape2(treeWeight.rows(),treeWeight.cols()),treeWeight.data());
     hdf5_file.write("treeWeights",W);
     // ---------------------------------------------------------
 
     // Write itemList
     // ---------------------------------------------------------
     auto items = mitkDC->GetItemList();
     std::string item_stringlist;
     for(auto entry : items)
       item_stringlist = item_stringlist + entry + ";";
 
     hdf5_file.write("itemList",item_stringlist);
     // ---------------------------------------------------------
 
     hdf5_file.close();
   }
 }
 
 mitk::AbstractFileIO* mitk::RandomForestFileIO::IOClone() const
 {
   return new RandomForestFileIO(*this);
 }
 
 #endif
diff --git a/Modules/ContourModel/IO/mitkContourModelReader.cpp b/Modules/ContourModel/IO/mitkContourModelReader.cpp
index a7864602f2..fa0ead2c5f 100644
--- a/Modules/ContourModel/IO/mitkContourModelReader.cpp
+++ b/Modules/ContourModel/IO/mitkContourModelReader.cpp
@@ -1,157 +1,157 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkContourModelReader.h"
 #include <fstream>
 #include <iostream>
 #include <mitkCustomMimeType.h>
 #include <mitkLocaleSwitch.h>
 
 mitk::ContourModelReader::ContourModelReader(const mitk::ContourModelReader &other) : mitk::AbstractFileReader(other)
 {
 }
 
 mitk::ContourModelReader::ContourModelReader() : AbstractFileReader()
 {
   std::string category = "Contour File";
   mitk::CustomMimeType customMimeType;
   customMimeType.SetCategory(category);
   customMimeType.AddExtension("cnt");
 
   this->SetDescription(category);
   this->SetMimeType(customMimeType);
 
   m_ServiceReg = this->RegisterService();
 }
 
 mitk::ContourModelReader::~ContourModelReader()
 {
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::ContourModelReader::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::ContourModelReader::DoRead()
 {
   std::vector<itk::SmartPointer<mitk::BaseData>> result;
   std::string location = GetInputLocation();
 
   // Switch the current locale to "C"
   LocaleSwitch localeSwitch("C");
 
   try
   {
     TiXmlDocument doc(location.c_str());
     bool loadOkay = doc.LoadFile();
     if (loadOkay)
     {
       TiXmlHandle docHandle(&doc);
 
       /*++++ handle n contourModels within data tags ++++*/
       for (TiXmlElement *currentContourElement = docHandle.FirstChildElement("contourModel").ToElement();
            currentContourElement != nullptr;
            currentContourElement = currentContourElement->NextSiblingElement())
       {
         mitk::ContourModel::Pointer newContourModel = mitk::ContourModel::New();
         if (currentContourElement->FirstChildElement("data")->FirstChildElement("timestep") != nullptr)
         {
           // handle geometry information
           // TiXmlElement* currentGeometryInfo =
           // currentContourElement->FirstChildElement("head")->FirstChildElement("geometryInformation")->ToElement();
           ///////////// NOT SUPPORTED YET ////////////////
 
           /*++++ handle n timesteps within timestep tags ++++*/
           for (TiXmlElement *currentTimeSeries =
                  currentContourElement->FirstChildElement("data")->FirstChildElement("timestep")->ToElement();
                currentTimeSeries != nullptr;
                currentTimeSeries = currentTimeSeries->NextSiblingElement())
           {
             unsigned int currentTimeStep(0);
 
             currentTimeStep = atoi(currentTimeSeries->Attribute("n"));
 
             this->ReadPoints(newContourModel, currentTimeSeries, currentTimeStep);
 
             int isClosed;
             currentTimeSeries->QueryIntAttribute("isClosed", &isClosed);
             if (isClosed)
             {
               newContourModel->Close(currentTimeStep);
             }
           }
           /*++++ END handle n timesteps within timestep tags ++++*/
         }
         else
         {
           // this should not happen
           MITK_WARN << "wrong file format!";
           // newContourModel = this->ReadPoint(newContourModel, currentContourElement, 0);
         }
         newContourModel->UpdateOutputInformation();
         result.push_back(dynamic_cast<mitk::BaseData *>(newContourModel.GetPointer()));
       }
       /*++++ END handle n contourModels within data tags ++++*/
     }
     else
     {
       MITK_WARN << "XML parser error!";
     }
   }
   catch (...)
   {
     MITK_ERROR << "Cannot read contourModel.";
   }
 
   return result;
 }
 
 mitk::ContourModelReader *mitk::ContourModelReader::Clone() const
 {
   return new ContourModelReader(*this);
 }
 
 void mitk::ContourModelReader::ReadPoints(mitk::ContourModel::Pointer newContourModel,
                                           TiXmlElement *currentTimeSeries,
                                           unsigned int currentTimeStep)
 {
   // check if the timesteps in contourModel have to be expanded
   if (currentTimeStep != newContourModel->GetTimeSteps())
   {
     newContourModel->Expand(currentTimeStep + 1);
   }
 
   // read all points within controlPoints tag
   if (currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point") != nullptr)
   {
     for (TiXmlElement *currentPoint =
            currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point")->ToElement();
          currentPoint != nullptr;
          currentPoint = currentPoint->NextSiblingElement())
     {
       double x(0.0);
       double y(0.0);
       double z(0.0);
 
       x = atof(currentPoint->FirstChildElement("x")->GetText());
       y = atof(currentPoint->FirstChildElement("y")->GetText());
       z = atof(currentPoint->FirstChildElement("z")->GetText());
 
       int isActivePoint;
       currentPoint->QueryIntAttribute("isActive", &isActivePoint);
 
       mitk::Point3D point;
       mitk::FillVector3D(point, x, y, z);
       newContourModel->AddVertex(point, isActivePoint, currentTimeStep);
     }
   }
   else
   {
     // nothing to read
   }
 }
diff --git a/Modules/ContourModel/IO/mitkContourModelReader.h b/Modules/ContourModel/IO/mitkContourModelReader.h
index d84bfdc3aa..bbeae0a7ec 100644
--- a/Modules/ContourModel/IO/mitkContourModelReader.h
+++ b/Modules/ContourModel/IO/mitkContourModelReader.h
@@ -1,56 +1,56 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 #ifndef _MITK_CONTOURMODEL_READER__H_
 #define _MITK_CONTOURMODEL_READER__H_
 
 // MITK
 #include <mitkAbstractFileReader.h>
 #include <mitkBaseData.h>
 #include <mitkContourModel.h>
 #include <mitkMimeType.h>
 
 #include <stack>
 #include <string>
 #include <tinyxml.h>
 #include <vtkXMLParser.h>
 
 namespace mitk
 {
   /**
    * @brief
    * @ingroup MitkContourModelModule
   */
   class ContourModelReader : public mitk::AbstractFileReader
   {
   public:
     ContourModelReader(const ContourModelReader &other);
 
     ContourModelReader();
 
     ~ContourModelReader() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
   protected:
     virtual void ReadPoints(mitk::ContourModel::Pointer newContourModel,
                             TiXmlElement *currentTimeSeries,
                             unsigned int currentTimeStep);
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     ContourModelReader *Clone() const override;
 
     us::ServiceRegistration<mitk::IFileReader> m_ServiceReg;
   };
 }
 
 #endif
diff --git a/Modules/ContourModel/IO/mitkContourModelSetReader.cpp b/Modules/ContourModel/IO/mitkContourModelSetReader.cpp
index 615a802fc1..9af5f8f49b 100644
--- a/Modules/ContourModel/IO/mitkContourModelSetReader.cpp
+++ b/Modules/ContourModel/IO/mitkContourModelSetReader.cpp
@@ -1,77 +1,77 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkContourModelSetReader.h"
 #include "mitkContourModelReader.h"
 #include <fstream>
 #include <iostream>
 #include <mitkCustomMimeType.h>
 #include <mitkLocaleSwitch.h>
 
 mitk::ContourModelSetReader::ContourModelSetReader(const mitk::ContourModelSetReader &other)
   : mitk::AbstractFileReader(other)
 {
 }
 
 mitk::ContourModelSetReader::ContourModelSetReader() : AbstractFileReader()
 {
   std::string category = "ContourModelSet File";
   CustomMimeType customMimeType;
   customMimeType.SetCategory(category);
   customMimeType.AddExtension("cnt_set");
 
   this->SetDescription(category);
   this->SetMimeType(customMimeType);
 
   m_ServiceReg = this->RegisterService();
 }
 
 mitk::ContourModelSetReader::~ContourModelSetReader()
 {
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::ContourModelSetReader::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::ContourModelSetReader::DoRead()
 {
   std::vector<itk::SmartPointer<mitk::BaseData>> result;
   std::vector<itk::SmartPointer<mitk::BaseData>> internalResult;
 
   std::string location = GetInputLocation();
 
   // Switch the current locale to "C"
   LocaleSwitch localeSwitch("C");
 
   try
   {
     mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New();
 
     mitk::ContourModelReader reader;
     reader.SetInput(location);
     internalResult = reader.Read();
 
     for (unsigned int i = 0; i < internalResult.size(); ++i)
     {
       contourSet->AddContourModel(dynamic_cast<mitk::ContourModel *>(internalResult.at(i).GetPointer()));
     }
     result.push_back(dynamic_cast<mitk::BaseData *>(contourSet.GetPointer()));
   }
   catch (...)
   {
     MITK_ERROR << "Cannot read contourModel.";
   }
 
   return result;
 }
 
 mitk::ContourModelSetReader *mitk::ContourModelSetReader::Clone() const
 {
   return new ContourModelSetReader(*this);
 }
diff --git a/Modules/ContourModel/IO/mitkContourModelSetReader.h b/Modules/ContourModel/IO/mitkContourModelSetReader.h
index 1434ab76ea..91e24180a1 100644
--- a/Modules/ContourModel/IO/mitkContourModelSetReader.h
+++ b/Modules/ContourModel/IO/mitkContourModelSetReader.h
@@ -1,53 +1,54 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 #ifndef _MITK_ContourModelSetReader__H_
 #define _MITK_ContourModelSetReader__H_
 
 // MITK
 #include <mitkAbstractFileReader.h>
 #include <mitkBaseData.h>
 #include <mitkContourModel.h>
 #include <mitkContourModelSet.h>
 #include <mitkMimeType.h>
 
 #include <stack>
 #include <string>
 #include <tinyxml.h>
 #include <vtkXMLParser.h>
 
 namespace mitk
 {
   /**
    * @brief
    * @ingroup MitkContourModelModule
   */
   class ContourModelSetReader : public mitk::AbstractFileReader
   {
   public:
     ContourModelSetReader(const ContourModelSetReader &other);
 
     ContourModelSetReader();
 
     ~ContourModelSetReader() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
   protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     ContourModelSetReader *Clone() const override;
 
     us::ServiceRegistration<mitk::IFileReader> m_ServiceReg;
   };
 }
 
 #endif
diff --git a/Modules/Core/files.cmake b/Modules/Core/files.cmake
index 78ae1b7ad2..75407c5ac8 100644
--- a/Modules/Core/files.cmake
+++ b/Modules/Core/files.cmake
@@ -1,324 +1,325 @@
 file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
 
 set(CPP_FILES
   mitkCoreActivator.cpp
   mitkCoreObjectFactoryBase.cpp
   mitkCoreObjectFactory.cpp
   mitkCoreServices.cpp
   mitkException.cpp
 
   Algorithms/mitkBaseDataSource.cpp
   Algorithms/mitkClippedSurfaceBoundsCalculator.cpp
   Algorithms/mitkCompareImageDataFilter.cpp
   Algorithms/mitkCompositePixelValueToString.cpp
   Algorithms/mitkConvert2Dto3DImageFilter.cpp
   Algorithms/mitkDataNodeSource.cpp
   Algorithms/mitkExtractSliceFilter.cpp
   Algorithms/mitkExtractSliceFilter2.cpp
   Algorithms/mitkHistogramGenerator.cpp
   Algorithms/mitkImageChannelSelector.cpp
   Algorithms/mitkImageSliceSelector.cpp
   Algorithms/mitkImageSource.cpp
   Algorithms/mitkImageTimeSelector.cpp
   Algorithms/mitkImageToImageFilter.cpp
   Algorithms/mitkImageToSurfaceFilter.cpp
   Algorithms/mitkMultiComponentImageDataComparisonFilter.cpp
   Algorithms/mitkPlaneGeometryDataToSurfaceFilter.cpp
   Algorithms/mitkPointSetSource.cpp
   Algorithms/mitkPointSetToPointSetFilter.cpp
   Algorithms/mitkRGBToRGBACastImageFilter.cpp
   Algorithms/mitkSubImageSelector.cpp
   Algorithms/mitkSurfaceSource.cpp
   Algorithms/mitkSurfaceToImageFilter.cpp
   Algorithms/mitkSurfaceToSurfaceFilter.cpp
   Algorithms/mitkUIDGenerator.cpp
   Algorithms/mitkVolumeCalculator.cpp
   Algorithms/mitkTemporalJoinImagesFilter.cpp
 
   Controllers/mitkBaseController.cpp
   Controllers/mitkCallbackFromGUIThread.cpp
   Controllers/mitkCameraController.cpp
   Controllers/mitkCameraRotationController.cpp
   Controllers/mitkLimitedLinearUndo.cpp
   Controllers/mitkOperationEvent.cpp
   Controllers/mitkPlanePositionManager.cpp
   Controllers/mitkProgressBar.cpp
   Controllers/mitkRenderingManager.cpp
   Controllers/mitkSliceNavigationController.cpp
   Controllers/mitkSlicesCoordinator.cpp
   Controllers/mitkStatusBar.cpp
   Controllers/mitkStepper.cpp
   Controllers/mitkTestManager.cpp
   Controllers/mitkUndoController.cpp
   Controllers/mitkVerboseLimitedLinearUndo.cpp
   Controllers/mitkVtkLayerController.cpp
   DataManagement/mitkAnatomicalStructureColorPresets.cpp
   DataManagement/mitkArbitraryTimeGeometry.cpp
   DataManagement/mitkAbstractTransformGeometry.cpp
   DataManagement/mitkAnnotationProperty.cpp
   DataManagement/mitkApplicationCursor.cpp
   DataManagement/mitkApplyTransformMatrixOperation.cpp
   DataManagement/mitkBaseData.cpp
   DataManagement/mitkBaseGeometry.cpp
   DataManagement/mitkBaseProperty.cpp
   DataManagement/mitkChannelDescriptor.cpp
   DataManagement/mitkClippingProperty.cpp
   DataManagement/mitkColorProperty.cpp
   DataManagement/mitkDataNode.cpp
   DataManagement/mitkDataStorage.cpp
   DataManagement/mitkEnumerationProperty.cpp
   DataManagement/mitkFloatPropertyExtension.cpp
   DataManagement/mitkGeometry3D.cpp
   DataManagement/mitkGeometryData.cpp
   DataManagement/mitkGeometryTransformHolder.cpp
   DataManagement/mitkGroupTagProperty.cpp
   DataManagement/mitkGenericIDRelationRule.cpp
   DataManagement/mitkIdentifiable.cpp
   DataManagement/mitkImageAccessorBase.cpp
   DataManagement/mitkImageCaster.cpp
   DataManagement/mitkImageCastPart1.cpp
   DataManagement/mitkImageCastPart2.cpp
   DataManagement/mitkImageCastPart3.cpp
   DataManagement/mitkImageCastPart4.cpp
   DataManagement/mitkImage.cpp
   DataManagement/mitkImageDataItem.cpp
   DataManagement/mitkImageDescriptor.cpp
   DataManagement/mitkImageReadAccessor.cpp
   DataManagement/mitkImageStatisticsHolder.cpp
   DataManagement/mitkImageVtkAccessor.cpp
   DataManagement/mitkImageVtkReadAccessor.cpp
   DataManagement/mitkImageVtkWriteAccessor.cpp
   DataManagement/mitkImageWriteAccessor.cpp
   DataManagement/mitkIntPropertyExtension.cpp
   DataManagement/mitkIPersistenceService.cpp
   DataManagement/mitkIPropertyAliases.cpp
   DataManagement/mitkIPropertyDescriptions.cpp
   DataManagement/mitkIPropertyExtensions.cpp
   DataManagement/mitkIPropertyFilters.cpp
   DataManagement/mitkIPropertyOwner.cpp
   DataManagement/mitkIPropertyPersistence.cpp
   DataManagement/mitkIPropertyProvider.cpp
   DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp
   DataManagement/mitkLandmarkProjector.cpp
   DataManagement/mitkLevelWindow.cpp
   DataManagement/mitkLevelWindowManager.cpp
   DataManagement/mitkLevelWindowPreset.cpp
   DataManagement/mitkLevelWindowProperty.cpp
   DataManagement/mitkLine.cpp
   DataManagement/mitkLookupTable.cpp
   DataManagement/mitkLookupTableProperty.cpp
   DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable
   DataManagement/mitkMaterial.cpp
   DataManagement/mitkMemoryUtilities.cpp
   DataManagement/mitkModalityProperty.cpp
   DataManagement/mitkModifiedLock.cpp
   DataManagement/mitkNodePredicateAnd.cpp
   DataManagement/mitkNodePredicateBase.cpp
   DataManagement/mitkNodePredicateCompositeBase.cpp
   DataManagement/mitkNodePredicateData.cpp
   DataManagement/mitkNodePredicateDataType.cpp
   DataManagement/mitkNodePredicateDataUID.cpp
   DataManagement/mitkNodePredicateDimension.cpp
   DataManagement/mitkNodePredicateFirstLevel.cpp
   DataManagement/mitkNodePredicateFunction.cpp
   DataManagement/mitkNodePredicateGeometry.cpp
   DataManagement/mitkNodePredicateNot.cpp
   DataManagement/mitkNodePredicateOr.cpp
   DataManagement/mitkNodePredicateProperty.cpp
   DataManagement/mitkNodePredicateDataProperty.cpp
   DataManagement/mitkNodePredicateSource.cpp
   DataManagement/mitkNumericConstants.cpp
   DataManagement/mitkPlaneGeometry.cpp
   DataManagement/mitkPlaneGeometryData.cpp
   DataManagement/mitkPlaneOperation.cpp
   DataManagement/mitkPlaneOrientationProperty.cpp
   DataManagement/mitkPointOperation.cpp
   DataManagement/mitkPointSet.cpp
   DataManagement/mitkPointSetShapeProperty.cpp
   DataManagement/mitkProperties.cpp
   DataManagement/mitkPropertyAliases.cpp
   DataManagement/mitkPropertyDescriptions.cpp
   DataManagement/mitkPropertyExtension.cpp
   DataManagement/mitkPropertyExtensions.cpp
   DataManagement/mitkPropertyFilter.cpp
   DataManagement/mitkPropertyFilters.cpp
   DataManagement/mitkPropertyKeyPath.cpp
   DataManagement/mitkPropertyList.cpp
   DataManagement/mitkPropertyListReplacedObserver.cpp
   DataManagement/mitkPropertyNameHelper.cpp
   DataManagement/mitkPropertyObserver.cpp
   DataManagement/mitkPropertyPersistence.cpp
   DataManagement/mitkPropertyPersistenceInfo.cpp
   DataManagement/mitkPropertyRelationRuleBase.cpp
   DataManagement/mitkProportionalTimeGeometry.cpp
   DataManagement/mitkRenderingModeProperty.cpp
   DataManagement/mitkResliceMethodProperty.cpp
   DataManagement/mitkRestorePlanePositionOperation.cpp
   DataManagement/mitkRotationOperation.cpp
   DataManagement/mitkScaleOperation.cpp
   DataManagement/mitkSlicedData.cpp
   DataManagement/mitkSlicedGeometry3D.cpp
   DataManagement/mitkSmartPointerProperty.cpp
   DataManagement/mitkStandaloneDataStorage.cpp
   DataManagement/mitkStringProperty.cpp
   DataManagement/mitkSurface.cpp
   DataManagement/mitkSurfaceOperation.cpp
   DataManagement/mitkSourceImageRelationRule.cpp
   DataManagement/mitkThinPlateSplineCurvedGeometry.cpp
   DataManagement/mitkTimeGeometry.cpp
   DataManagement/mitkTransferFunction.cpp
   DataManagement/mitkTransferFunctionInitializer.cpp
   DataManagement/mitkTransferFunctionProperty.cpp
   DataManagement/mitkTemporoSpatialStringProperty.cpp
   DataManagement/mitkUIDManipulator.cpp
   DataManagement/mitkVector.cpp
   DataManagement/mitkVectorProperty.cpp
   DataManagement/mitkVtkInterpolationProperty.cpp
   DataManagement/mitkVtkRepresentationProperty.cpp
   DataManagement/mitkVtkResliceInterpolationProperty.cpp
   DataManagement/mitkVtkScalarModeProperty.cpp
   DataManagement/mitkVtkVolumeRenderingProperty.cpp
   DataManagement/mitkWeakPointerProperty.cpp
   DataManagement/mitkIPropertyRelations.cpp
   DataManagement/mitkPropertyRelations.cpp
 
   Interactions/mitkAction.cpp
   Interactions/mitkBindDispatcherInteractor.cpp
   Interactions/mitkCrosshairPositionEvent.cpp
   Interactions/mitkDataInteractor.cpp
   Interactions/mitkDispatcher.cpp
   Interactions/mitkDisplayActionEventBroadcast.cpp
   Interactions/mitkDisplayActionEventFunctions.cpp
   Interactions/mitkDisplayActionEventHandler.cpp
   Interactions/mitkDisplayActionEventHandlerDesynchronized.cpp
   Interactions/mitkDisplayActionEventHandlerStd.cpp
   Interactions/mitkDisplayActionEventHandlerSynchronized.cpp
   Interactions/mitkDisplayCoordinateOperation.cpp
   Interactions/mitkDisplayInteractor.cpp
   Interactions/mitkEventConfig.cpp
   Interactions/mitkEventFactory.cpp
   Interactions/mitkEventRecorder.cpp
   Interactions/mitkEventStateMachine.cpp
   Interactions/mitkInteractionEventConst.cpp
   Interactions/mitkInteractionEvent.cpp
   Interactions/mitkInteractionEventHandler.cpp
   Interactions/mitkInteractionEventObserver.cpp
   Interactions/mitkInteractionKeyEvent.cpp
   Interactions/mitkInteractionPositionEvent.cpp
   Interactions/mitkInteractionSchemeSwitcher.cpp
   Interactions/mitkInternalEvent.cpp
   Interactions/mitkMouseDoubleClickEvent.cpp
   Interactions/mitkMouseModeSwitcher.cpp
   Interactions/mitkMouseMoveEvent.cpp
   Interactions/mitkMousePressEvent.cpp
   Interactions/mitkMouseReleaseEvent.cpp
   Interactions/mitkMouseWheelEvent.cpp
   Interactions/mitkPointSetDataInteractor.cpp
   Interactions/mitkSinglePointDataInteractor.cpp
   Interactions/mitkStateMachineAction.cpp
   Interactions/mitkStateMachineCondition.cpp
   Interactions/mitkStateMachineContainer.cpp
   Interactions/mitkStateMachineState.cpp
   Interactions/mitkStateMachineTransition.cpp
   Interactions/mitkVtkEventAdapter.cpp
   Interactions/mitkVtkInteractorStyle.cxx
   Interactions/mitkXML2EventParser.cpp
 
   IO/mitkAbstractFileIO.cpp
   IO/mitkAbstractFileReader.cpp
   IO/mitkAbstractFileWriter.cpp
   IO/mitkCustomMimeType.cpp
   IO/mitkFileReader.cpp
   IO/mitkFileReaderRegistry.cpp
   IO/mitkFileReaderSelector.cpp
   IO/mitkFileReaderWriterBase.cpp
   IO/mitkFileWriter.cpp
   IO/mitkFileWriterRegistry.cpp
   IO/mitkFileWriterSelector.cpp
   IO/mitkGeometry3DToXML.cpp
   IO/mitkIFileIO.cpp
   IO/mitkIFileReader.cpp
   IO/mitkIFileWriter.cpp
   IO/mitkGeometryDataReaderService.cpp
   IO/mitkGeometryDataWriterService.cpp
   IO/mitkImageGenerator.cpp
   IO/mitkImageVtkLegacyIO.cpp
   IO/mitkImageVtkXmlIO.cpp
   IO/mitkIMimeTypeProvider.cpp
   IO/mitkIOConstants.cpp
   IO/mitkIOMimeTypes.cpp
   IO/mitkIOUtil.cpp
   IO/mitkItkImageIO.cpp
   IO/mitkItkLoggingAdapter.cpp
   IO/mitkLegacyFileReaderService.cpp
   IO/mitkLegacyFileWriterService.cpp
   IO/mitkLocaleSwitch.cpp
   IO/mitkLog.cpp
   IO/mitkMimeType.cpp
   IO/mitkMimeTypeProvider.cpp
   IO/mitkOperation.cpp
   IO/mitkPixelType.cpp
   IO/mitkPointSetReaderService.cpp
   IO/mitkPointSetWriterService.cpp
   IO/mitkProportionalTimeGeometryToXML.cpp
   IO/mitkRawImageFileReader.cpp
   IO/mitkStandardFileLocations.cpp
   IO/mitkSurfaceStlIO.cpp
   IO/mitkSurfaceVtkIO.cpp
   IO/mitkSurfaceVtkLegacyIO.cpp
   IO/mitkSurfaceVtkXmlIO.cpp
   IO/mitkVtkLoggingAdapter.cpp
   IO/mitkPreferenceListReaderOptionsFunctor.cpp
+  IO/mitkIOMetaInformationPropertyConstants.cpp
 
   Rendering/mitkAbstractAnnotationRenderer.cpp
   Rendering/mitkAnnotationUtils.cpp
   Rendering/mitkBaseRenderer.cpp
   #Rendering/mitkGLMapper.cpp Moved to deprecated LegacyGL Module
   Rendering/mitkGradientBackground.cpp
   Rendering/mitkImageVtkMapper2D.cpp
   Rendering/mitkMapper.cpp
   Rendering/mitkAnnotation.cpp
   Rendering/mitkPlaneGeometryDataMapper2D.cpp
   Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp
   Rendering/mitkPointSetVtkMapper2D.cpp
   Rendering/mitkPointSetVtkMapper3D.cpp
   Rendering/mitkRenderWindowBase.cpp
   Rendering/mitkRenderWindow.cpp
   Rendering/mitkRenderWindowFrame.cpp
   #Rendering/mitkSurfaceGLMapper2D.cpp Moved to deprecated LegacyGL Module
   Rendering/mitkSurfaceVtkMapper2D.cpp
   Rendering/mitkSurfaceVtkMapper3D.cpp
   Rendering/mitkVtkEventProvider.cpp
   Rendering/mitkVtkMapper.cpp
   Rendering/mitkVtkPropRenderer.cpp
   Rendering/mitkVtkWidgetRendering.cpp
   Rendering/vtkMitkLevelWindowFilter.cpp
   Rendering/vtkMitkRectangleProp.cpp
   Rendering/vtkMitkRenderProp.cpp
   Rendering/vtkMitkThickSlicesFilter.cpp
   Rendering/vtkNeverTranslucentTexture.cpp
 )
 
 set(RESOURCE_FILES
 Interactions/globalConfig.xml
 Interactions/DisplayInteraction.xml
 Interactions/DisplayConfig.xml
 Interactions/DisplayConfigPACS.xml
 Interactions/DisplayConfigPACSPan.xml
 Interactions/DisplayConfigPACSScroll.xml
 Interactions/DisplayConfigPACSZoom.xml
 Interactions/DisplayConfigPACSLevelWindow.xml
 Interactions/DisplayConfigMITK.xml
 Interactions/DisplayConfigMITKNoCrosshair.xml
 Interactions/DisplayConfigMITKRotation.xml
 Interactions/DisplayConfigMITKRotationUnCoupled.xml
 Interactions/DisplayConfigMITKSwivel.xml
 Interactions/DisplayConfigMITKLimited.xml
 Interactions/PointSet.xml
 Interactions/Legacy/StateMachine.xml
 Interactions/Legacy/DisplayConfigMITKTools.xml
 Interactions/PointSetConfig.xml
 
 mitkLevelWindowPresets.xml
 mitkAnatomicalStructureColorPresets.xml
 )
diff --git a/Modules/Core/include/mitkAbstractFileReader.h b/Modules/Core/include/mitkAbstractFileReader.h
index 8b21bbde6b..83ab25d7f3 100644
--- a/Modules/Core/include/mitkAbstractFileReader.h
+++ b/Modules/Core/include/mitkAbstractFileReader.h
@@ -1,232 +1,241 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef AbstractFileReader_H_HEADER_INCLUDED_C1E7E521
 #define AbstractFileReader_H_HEADER_INCLUDED_C1E7E521
 
 // Macro
 #include <MitkCoreExports.h>
 
 // MITK
 #include <mitkBaseData.h>
 #include <mitkIFileReader.h>
 #include <mitkMimeType.h>
 
 // Microservices
 #include <usGetModuleContext.h>
 #include <usServiceProperties.h>
 #include <usServiceRegistration.h>
 
 namespace us
 {
   struct PrototypeServiceFactory;
 }
 
 namespace mitk
 {
   class CustomMimeType;
 
   /**
    * @brief Base class for creating mitk::BaseData objects from files or streams.
    * @ingroup IO
    */
   class MITKCORE_EXPORT AbstractFileReader : public mitk::IFileReader
   {
   public:
     void SetInput(const std::string &location) override;
 
     void SetInput(const std::string &location, std::istream *is) override;
 
     std::string GetInputLocation() const override;
 
     std::istream *GetInputStream() const override;
 
     MimeType GetRegisteredMimeType() const;
 
     /**
      * @brief Reads a path or stream and creates a list of BaseData objects.
      *
-     * This method must be implemented for each specific reader. Call
-     * GetInputStream() first and check for a non-null stream to read from.
-     * If the input stream is \c nullptr, use GetInputLocation() to read from a local
-     * file-system path.
-     *
-     * If the reader cannot use streams directly, use GetLocalFileName() instead.
-     *
-     * @return The created BaseData objects.
-     * @throws mitk::Exception
-     *
-     * @see GetLocalFileName()
-     * @see IFileReader::Read()
+     * The default implementation of this method (1) calls DoRead()
+     * (Implement the specific reader operation there) and (2) it addes general
+     * meta information about the loading process.
      */
-    std::vector<itk::SmartPointer<BaseData>> Read() override = 0;
+    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
     DataStorage::SetOfObjects::Pointer Read(mitk::DataStorage &ds) override;
 
     ConfidenceLevel GetConfidenceLevel() const override;
 
     Options GetOptions() const override;
     us::Any GetOption(const std::string &name) const override;
 
     void SetOptions(const Options &options) override;
     void SetOption(const std::string &name, const us::Any &value) override;
 
     void AddProgressCallback(const ProgressCallback &callback) override;
 
     void RemoveProgressCallback(const ProgressCallback &callback) override;
 
     /**
      * Associate this reader with the MIME type returned by the current IMimeTypeProvider
      * service for the provided extension if the MIME type exists, otherwise registers
      * a new MIME type when RegisterService() is called.
      *
      * If no MIME type for \c extension is already registered, a call to RegisterService()
      * will register a new MIME type and associate this reader instance with it. The MIME
      * type id can be set via SetMimeType() or it will be auto-generated using \c extension,
      * having the form "application/vnd.mitk.<extension>".
      *
      * @param extension The file extension (without a leading period) for which a registered
      *        mime-type object is looked up and associated with this reader instance.
      * @param description A human readable description of this reader.
      */
     us::ServiceRegistration<IFileReader> RegisterService(us::ModuleContext *context = us::GetModuleContext());
     void UnregisterService();
 
     /**
      * @return A list of files that were loaded during the last call of Read. Has to be filled by the actual reader class.
      */
     std::vector< std::string > GetReadFiles() override;
 
   protected:
     /**
      * @brief An input stream wrapper.
      *
      * If a reader can only work with input streams, use an instance
      * of this class to either wrap the specified input stream or
      * create a new input stream based on the input location in the
      * file system.
      */
     class MITKCORE_EXPORT InputStream : public std::istream
     {
     public:
       InputStream(IFileReader *writer, std::ios_base::openmode mode = std::ios_base::in);
       ~InputStream() override;
 
     private:
       std::istream *m_Stream;
     };
 
     AbstractFileReader();
     ~AbstractFileReader() override;
 
     AbstractFileReader(const AbstractFileReader &other);
 
     /**
      * Associate this reader instance with the given MIME type.
      *
      * If \c mimeType does not provide an extension list, an already
      * registered mime-type object is used. Otherwise, the first entry in
      * the extensions list is used to construct a mime-type name and
      * register it as a new CustomMimeType service object in the default
      * implementation of RegisterMimeType().
      *
      * @param mimeType The mime type this reader can read.
      * @param description A human readable description of this reader.
      *
      * @throws std::invalid_argument if \c mimeType is empty.
      *
      * @see RegisterService
      */
     explicit AbstractFileReader(const CustomMimeType &mimeType, const std::string &description);
 
+    /** Method that should be implemented by derived classes and does the real loading.
+     * This method is called by Read().
+     * This method must be implemented for each specific reader. Call
+     * GetInputStream() first and check for a non-null stream to read from.
+     * If the input stream is \c nullptr, use GetInputLocation() to read from a local
+     * file-system path.
+     *
+     * If the reader cannot use streams directly, use GetLocalFileName() instead.
+     *
+     * @return The created BaseData objects.
+     * @throws mitk::Exception
+     *
+     * @see GetLocalFileName()
+     * @see IFileReader::Read()
+     */
+    virtual std::vector<itk::SmartPointer<BaseData>> DoRead() = 0;
+
+
     virtual us::ServiceProperties GetServiceProperties() const;
 
     /**
      * Registers a new CustomMimeType service object.
      *
      * This method is called from RegisterService and the default implementation
      * registers a new mime-type service object if all of the following conditions
      * are true:
      *
      *  - TODO
      *
      * @param context
      * @return
      * @throws std::invalid_argument if \c context is nullptr.
      */
     virtual us::ServiceRegistration<CustomMimeType> RegisterMimeType(us::ModuleContext *context);
 
     void SetMimeType(const CustomMimeType &mimeType);
 
     /**
      * @return The mime-type this reader can handle.
      */
     const CustomMimeType *GetMimeType() const;
 
     void SetMimeTypePrefix(const std::string &prefix);
     std::string GetMimeTypePrefix() const;
 
     void SetDescription(const std::string &description);
     std::string GetDescription() const;
 
     void SetDefaultOptions(const Options &defaultOptions);
     Options GetDefaultOptions() const;
 
     /**
      * \brief Set the service ranking for this file reader.
      *
      * Default is zero and should only be chosen differently for a reason.
      * The ranking is used to determine which reader to use if several
      * equivalent readers have been found.
      * It may be used to replace a default reader from MITK in your own project.
      * E.g. if you want to use your own reader for nrrd files instead of the default,
      * implement it and give it a higher ranking than zero.
      */
     void SetRanking(int ranking);
     int GetRanking() const;
 
     /**
      * @brief Get a local file name for reading.
      *
      * This is a convenience method for readers which cannot work natively
      * with input streams. If no input stream has been been set,
      * this method just returns the result of GetLocation(). However, if
      * SetLocation(std::string, std::istream*) has been called with a non-null
      * input stream, this method writes the contents of the stream to a temporary
      * file and returns the name of the temporary file.
      *
      * The temporary file is deleted when either SetLocation(std::string, std::istream*)
      * is called again with a different input stream or the destructor of this
      * class is called.
      *
      * This method does not validate file names set via SetInput(std::string).
      *
      * @return A file path in the local file-system for reading.
      */
     std::string GetLocalFileName() const;
 
     virtual void SetDefaultDataNodeProperties(DataNode *node, const std::string &filePath);
 
     std::vector< std::string > m_ReadFiles;
 
   private:
     AbstractFileReader &operator=(const AbstractFileReader &other);
 
     virtual mitk::IFileReader *Clone() const = 0;
 
     class Impl;
     std::unique_ptr<Impl> d;
   };
 
 } // namespace mitk
 
 #endif /* AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 */
diff --git a/Modules/Core/include/mitkDataNode.h b/Modules/Core/include/mitkDataNode.h
index 7199095d72..13f64e52b6 100644
--- a/Modules/Core/include/mitkDataNode.h
+++ b/Modules/Core/include/mitkDataNode.h
@@ -1,598 +1,597 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef DATATREENODE_H_HEADER_INCLUDED_C1E14338
 #define DATATREENODE_H_HEADER_INCLUDED_C1E14338
 
 #include "mitkBaseData.h"
 //#include "mitkMapper.h"
 #include "mitkDataInteractor.h"
 #include "mitkIdentifiable.h"
 #include "mitkIPropertyOwner.h"
 
 #include <fstream>
 #include <iostream>
 
 #include "mitkColorProperty.h"
 #include "mitkPropertyList.h"
 #include "mitkStringProperty.h"
 //#include "mitkMapper.h"
 
 #include "mitkGeometry3D.h"
 #include "mitkLevelWindow.h"
 #include <map>
 #include <set>
 
 class vtkLinearTransform;
 
 namespace mitk
 {
   class BaseRenderer;
   class Mapper;
 
   /**
    * \brief Class for nodes of the DataTree
    *
    * Contains the data (instance of BaseData), a list of mappers, which can
    * draw the data, a transform (vtkTransform) and a list of properties
    * (PropertyList).
    * \ingroup DataManagement
    *
    * \todo clean up all the GetProperty methods. There are too many different flavours... Can most probably be reduced
    * to
    * <tt>bool GetProperty<type>(type&)</tt>
    *
    * \warning Change in semantics of SetProperty() since Aug 25th 2006. Check your usage of this method if you do
    *          more with properties than just call <tt>SetProperty( "key", new SomeProperty("value") )</tt>.
    */
   class MITKCORE_EXPORT DataNode : public itk::DataObject, public IPropertyOwner
   {
   public:
     typedef mitk::Geometry3D::Pointer Geometry3DPointer;
     typedef std::vector<itk::SmartPointer<Mapper>> MapperVector;
     typedef std::map<std::string, mitk::PropertyList::Pointer> MapOfPropertyLists;
     typedef std::vector<MapOfPropertyLists::key_type> PropertyListKeyNames;
     typedef std::set<std::string> GroupTagList;
 
     /**
      * \brief Definition of an itk::Event that is invoked when
      * a DataInteractor is set on this DataNode.
      */
     itkEventMacro(InteractorChangedEvent, itk::AnyEvent)
     mitkClassMacroItkParent(DataNode, itk::DataObject);
     itkFactorylessNewMacro(Self);
-    itkCloneMacro(Self);
 
     // IPropertyProvider
     BaseProperty::ConstPointer GetConstProperty(const std::string &propertyKey, const std::string &contextName = "", bool fallBackOnDefaultContext = true) const override;
     std::vector<std::string> GetPropertyKeys(const std::string &contextName = "", bool includeDefaultContext = false) const override;
     std::vector<std::string> GetPropertyContextNames() const override;
 
     // IPropertyOwner
     BaseProperty * GetNonConstProperty(const std::string &propertyKey, const std::string &contextName = "", bool fallBackOnDefaultContext = true) override;
     void SetProperty(const std::string &propertyKey, BaseProperty *property, const std::string &contextName = "", bool fallBackOnDefaultContext = false) override;
     void RemoveProperty(const std::string &propertyKey, const std::string &contextName = "", bool fallBackOnDefaultContext = false) override;
 
     mitk::Mapper *GetMapper(MapperSlotId id) const;
 
     /**
      * \brief Get the data object (instance of BaseData, e.g., an Image)
      * managed by this DataNode
      */
     BaseData *GetData() const;
 
     /**
      * \brief Get the transformation applied prior to displaying the data as
      * a vtkTransform
      * \deprecated use GetData()->GetGeometry()->GetVtkTransform() instead
      */
     vtkLinearTransform *GetVtkTransform(int t = 0) const;
 
     /**
      * \brief Set the data object (instance of BaseData, e.g., an Image)
      * managed by this DataNode
      *
      * Prior set properties are kept if previous data of the node already exists and has the same
      * type as the new data to be set. Otherwise, the default properties are used.
      * In case that previous data already exists, the property list of the data node is cleared
      * before setting new default properties.
      *
      * \warning the actor-mode of the vtkInteractor does not work any more, if the transform of the
      * data-tree-node is connected to the transform of the basedata via vtkTransform->SetInput.
      */
     virtual void SetData(mitk::BaseData *baseData);
 
     /**
      * \brief Set the Interactor.
      */
     virtual void SetDataInteractor(const DataInteractor::Pointer interactor);
     virtual DataInteractor::Pointer GetDataInteractor() const;
 
     mitk::DataNode &operator=(const DataNode &right);
 
     mitk::DataNode &operator=(BaseData *right);
     virtual void SetMapper(MapperSlotId id, mitk::Mapper *mapper);
     void UpdateOutputInformation() override;
 
     void SetRequestedRegionToLargestPossibleRegion() override;
 
     bool RequestedRegionIsOutsideOfTheBufferedRegion() override;
 
     bool VerifyRequestedRegion() override;
 
     void SetRequestedRegion(const itk::DataObject *data) override;
 
     void CopyInformation(const itk::DataObject *data) override;
 
     /**
      * \brief The "names" used for (renderer-specific) PropertyLists in GetPropertyList(string).
      *
      * All possible values for the "renderer" parameters of
      * the diverse GetProperty/List() methods.
      */
     PropertyListKeyNames GetPropertyListNames() const;
 
     /**
      * \brief Set the property (instance of BaseProperty) with key \a propertyKey in the PropertyList
      * of the \a renderer (if nullptr, use BaseRenderer-independent PropertyList). This is set-by-value.
      *
      * \warning Change in semantics since Aug 25th 2006. Check your usage of this method if you do
      *          more with properties than just call <tt>SetProperty( "key", new SomeProperty("value") )</tt>.
      *
      * \sa GetProperty
      * \sa m_PropertyList
      * \sa m_MapOfPropertyLists
      */
     void SetProperty(const char *propertyKey, BaseProperty *property, const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief Replace the property (instance of BaseProperty) with key \a propertyKey in the PropertyList
      * of the \a renderer (if nullptr, use BaseRenderer-independent PropertyList). This is set-by-reference.
      *
      * If \a renderer is \a nullptr the property is set in the BaseRenderer-independent
      * PropertyList of this DataNode.
      * \sa GetProperty
      * \sa m_PropertyList
      * \sa m_MapOfPropertyLists
      */
     void ReplaceProperty(const char *propertyKey, BaseProperty *property, const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief Add the property (instance of BaseProperty) if it does
      * not exist (or always if\a overwrite is\a true)
      * with key \a propertyKey in the PropertyList
      * of the \a renderer (if nullptr, use BaseRenderer-independent
      * PropertyList). This is set-by-value.
      *
      * For\a overwrite ==\a false the property is\em not changed
      * if it already exists. For\a overwrite ==\a true the method
      * is identical to SetProperty.
      *
      * \sa SetProperty
      * \sa GetProperty
      * \sa m_PropertyList
      * \sa m_MapOfPropertyLists
      */
     void AddProperty(const char *propertyKey,
                      BaseProperty *property,
                      const mitk::BaseRenderer *renderer = nullptr,
                      bool overwrite = false);
 
     /**
      * \brief Get the PropertyList of the \a renderer. If \a renderer is \a
      * nullptr, the BaseRenderer-independent PropertyList of this DataNode
      * is returned.
      * \sa GetProperty
      * \sa m_PropertyList
      * \sa m_MapOfPropertyLists
      */
     mitk::PropertyList *GetPropertyList(const mitk::BaseRenderer *renderer = nullptr) const;
     mitk::PropertyList *GetPropertyList(const std::string &rendererName) const;
 
     /**
      * \brief Add values from another PropertyList.
      *
      * Overwrites values in m_PropertyList only when possible (i.e. when types are compatible).
      * If you want to allow for object type changes (replacing a "visible":BoolProperty with "visible":IntProperty,
      * set the \param replace.
      *
      * \param replace true: if \param pList contains a property "visible" of type ColorProperty and our m_PropertyList
      * also has a "visible" property of a different type (e.g. BoolProperty), change the type, i.e. replace the objects
      * behind the pointer.
      *
      * \sa SetProperty
      * \sa ReplaceProperty
      * \sa m_PropertyList
      */
     void ConcatenatePropertyList(PropertyList *pList, bool replace = false);
 
     /**
      * \brief Get the property (instance of BaseProperty) with key \a propertyKey from the PropertyList
      * of the \a renderer, if available there, otherwise use the BaseRenderer-independent PropertyList.
      *
      * If \a renderer is \a nullptr or the \a propertyKey cannot be found
      * in the PropertyList specific to \a renderer or is disabled there, the BaseRenderer-independent
      * PropertyList of this DataNode is queried.
      *
      * If \a fallBackOnDataProperties is true, the data property list is queried as a last resort.
      *
      * \sa GetPropertyList
      * \sa m_PropertyList
      * \sa m_MapOfPropertyLists
      */
     mitk::BaseProperty *GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer = nullptr, bool fallBackOnDataProperties = true) const;
 
     /**
      * \brief Get the property of type T with key \a propertyKey from the PropertyList
      * of the \a renderer, if available there, otherwise use the BaseRenderer-independent PropertyList.
      *
      * If \a renderer is \a nullptr or the \a propertyKey cannot be found
      * in the PropertyList specific to \a renderer or is disabled there, the BaseRenderer-independent
      * PropertyList of this DataNode is queried.
      * \sa GetPropertyList
      * \sa m_PropertyList
      * \sa m_MapOfPropertyLists
      */
     template <typename T>
     bool GetProperty(itk::SmartPointer<T> &property,
                      const char *propertyKey,
                      const mitk::BaseRenderer *renderer = nullptr) const
     {
       property = dynamic_cast<T *>(GetProperty(propertyKey, renderer));
       return property.IsNotNull();
     }
 
     /**
      * \brief Get the property of type T with key \a propertyKey from the PropertyList
      * of the \a renderer, if available there, otherwise use the BaseRenderer-independent PropertyList.
      *
      * If \a renderer is \a nullptr or the \a propertyKey cannot be found
      * in the PropertyList specific to \a renderer or is disabled there, the BaseRenderer-independent
      * PropertyList of this DataNode is queried.
      * \sa GetPropertyList
      * \sa m_PropertyList
      * \sa m_MapOfPropertyLists
      */
     template <typename T>
     bool GetProperty(T *&property, const char *propertyKey, const mitk::BaseRenderer *renderer = nullptr) const
     {
       property = dynamic_cast<T *>(GetProperty(propertyKey, renderer));
       return property != nullptr;
     }
 
     /**
      * \brief Convenience access method for GenericProperty<T> properties
      * (T being the type of the second parameter)
      * \return \a true property was found
      */
     template <typename T>
     bool GetPropertyValue(const char *propertyKey, T &value, const mitk::BaseRenderer *renderer = nullptr) const
     {
       GenericProperty<T> *gp = dynamic_cast<GenericProperty<T> *>(GetProperty(propertyKey, renderer));
       if (gp != nullptr)
       {
         value = gp->GetValue();
         return true;
       }
       return false;
     }
 
     /// \brief Get a set of all group tags from this node's property list
     GroupTagList GetGroupTags() const;
 
     /**
      * \brief Convenience access method for bool properties (instances of
      * BoolProperty)
      * \return \a true property was found
      */
     bool GetBoolProperty(const char *propertyKey, bool &boolValue, const mitk::BaseRenderer *renderer = nullptr) const;
 
     /**
      * \brief Convenience access method for int properties (instances of
      * IntProperty)
      * \return \a true property was found
      */
     bool GetIntProperty(const char *propertyKey, int &intValue, const mitk::BaseRenderer *renderer = nullptr) const;
 
     /**
      * \brief Convenience access method for float properties (instances of
      * FloatProperty)
      * \return \a true property was found
      */
     bool GetFloatProperty(const char *propertyKey,
                           float &floatValue,
                           const mitk::BaseRenderer *renderer = nullptr) const;
 
     /**
      * \brief Convenience access method for double properties (instances of
      * DoubleProperty)
      *
      * If there is no DoubleProperty for the given\c propertyKey argument, the method
      * looks for a corresponding FloatProperty instance.
      *
      * \return \a true property was found
      */
     bool GetDoubleProperty(const char *propertyKey,
                            double &doubleValue,
                            const mitk::BaseRenderer *renderer = nullptr) const;
 
     /**
      * \brief Convenience access method for string properties (instances of
      * StringProperty)
      * \return \a true property was found
      */
     bool GetStringProperty(const char *propertyKey,
                            std::string &string,
                            const mitk::BaseRenderer *renderer = nullptr) const;
 
     /**
      * \brief Convenience access method for color properties (instances of
      * ColorProperty)
      * \return \a true property was found
      */
     bool GetColor(float rgb[3], const mitk::BaseRenderer *renderer = nullptr, const char *propertyKey = "color") const;
 
     /**
      * \brief Convenience access method for level-window properties (instances of
      * LevelWindowProperty)
      * \return \a true property was found
      */
     bool GetLevelWindow(mitk::LevelWindow &levelWindow,
                         const mitk::BaseRenderer *renderer = nullptr,
                         const char *propertyKey = "levelwindow") const;
 
     /**
      * \brief set the node as selected
      */
     void SetSelected(bool selected, const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief set the node as selected
      * \return \a true node is selected
      */
     bool IsSelected(const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief Convenience access method for accessing the name of an object (instance of
      * StringProperty with property-key "name")
      * \return \a true property was found
      */
     bool GetName(std::string &nodeName,
                  const mitk::BaseRenderer *renderer = nullptr,
                  const char *propertyKey = "name") const
     {
       return GetStringProperty(propertyKey, nodeName, renderer);
     }
 
     /**
      * \brief Extra convenience access method for accessing the name of an object (instance of
      * StringProperty with property-key "name").
      *
      * This method does not take the renderer specific
      * propertylists into account, because the name of an object should never be renderer specific.
      * \returns a std::string with the name of the object (content of "name" Property).
      * If there is no "name" Property, an empty string will be returned.
      */
     virtual std::string GetName() const
     {
       mitk::StringProperty *sp = dynamic_cast<mitk::StringProperty *>(this->GetProperty("name"));
       if (sp == nullptr)
         return "";
       return sp->GetValue();
     }
 
     /** Value constant that is used indicate that node names are not set so far.*/
     static std::string NO_NAME_VALUE()
     {
       return "No Name!";
     }
 
     /**
      * \brief Extra convenience access method to set the name of an object.
      *
      * The name will be stored in the non-renderer-specific PropertyList in a StringProperty named "name".
      */
     virtual void SetName(const char *name)
     {
       if (name == nullptr)
         return;
       this->SetProperty("name", StringProperty::New(name));
     }
     /**
      * \brief Extra convenience access method to set the name of an object.
      *
      * The name will be stored in the non-renderer-specific PropertyList in a StringProperty named "name".
      */
     virtual void SetName(const std::string name) { this->SetName(name.c_str()); }
     /**
      * \brief Convenience access method for visibility properties (instances
      * of BoolProperty with property-key "visible")
      * \return \a true property was found
      * \sa IsVisible
      */
     bool GetVisibility(bool &visible, const mitk::BaseRenderer *renderer, const char *propertyKey = "visible") const
     {
       return GetBoolProperty(propertyKey, visible, renderer);
     }
 
     /**
      * \brief Convenience access method for opacity properties (instances of
      * FloatProperty)
      * \return \a true property was found
      */
     bool GetOpacity(float &opacity, const mitk::BaseRenderer *renderer, const char *propertyKey = "opacity") const;
 
     /**
      * \brief Convenience access method for boolean properties (instances
      * of BoolProperty). Return value is the value of the property. If the property is
      * not found, the value of \a defaultIsOn is returned.
      *
      * Thus, the return value has a different meaning than in the
      * GetBoolProperty method!
      * \sa GetBoolProperty
      */
     bool IsOn(const char *propertyKey, const mitk::BaseRenderer *renderer, bool defaultIsOn = true) const
     {
       if (propertyKey == nullptr)
         return defaultIsOn;
       GetBoolProperty(propertyKey, defaultIsOn, renderer);
       return defaultIsOn;
     }
 
     /**
      * \brief Convenience access method for visibility properties (instances
      * of BoolProperty). Return value is the visibility. Default is
      * visible==true, i.e., true is returned even if the property (\a
      * propertyKey) is not found.
      *
      * Thus, the return value has a different meaning than in the
      * GetVisibility method!
      * \sa GetVisibility
      * \sa IsOn
      */
     bool IsVisible(const mitk::BaseRenderer *renderer,
                    const char *propertyKey = "visible",
                    bool defaultIsOn = true) const
     {
       return IsOn(propertyKey, renderer, defaultIsOn);
     }
 
     /**
      * \brief Convenience method for setting color properties (instances of
      * ColorProperty)
      */
     void SetColor(const mitk::Color &color,
                   const mitk::BaseRenderer *renderer = nullptr,
                   const char *propertyKey = "color");
 
     /**
      * \brief Convenience method for setting color properties (instances of
      * ColorProperty)
      */
     void SetColor(float red,
                   float green,
                   float blue,
                   const mitk::BaseRenderer *renderer = nullptr,
                   const char *propertyKey = "color");
 
     /**
      * \brief Convenience method for setting color properties (instances of
      * ColorProperty)
      */
     void SetColor(const float rgb[3], const mitk::BaseRenderer *renderer = nullptr, const char *propertyKey = "color");
 
     /**
      * \brief Convenience method for setting visibility properties (instances
      * of BoolProperty)
      * \param visible If set to true, the data will be rendered. If false, the render will skip this data.
      * \param renderer Specify a renderer if the visibility shall be specific to a renderer
      * \param propertykey Can be used to specify a user defined name of the visibility propery.
      */
     void SetVisibility(bool visible, const mitk::BaseRenderer *renderer = nullptr, const char *propertyKey = "visible");
 
     /**
      * \brief Convenience method for setting opacity properties (instances of
      * FloatProperty)
      */
     void SetOpacity(float opacity, const mitk::BaseRenderer *renderer = nullptr, const char *propertyKey = "opacity");
 
     /**
      * \brief Convenience method for setting level-window properties
      * (instances of LevelWindowProperty)
      */
     void SetLevelWindow(mitk::LevelWindow levelWindow,
                         const mitk::BaseRenderer *renderer = nullptr,
                         const char *propertyKey = "levelwindow");
 
     /**
      * \brief Convenience method for setting int properties (instances of
      * IntProperty)
      */
     void SetIntProperty(const char *propertyKey, int intValue, const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief Convenience method for setting boolean properties (instances of
      * BoolProperty)
      */
     void SetBoolProperty(const char *propertyKey, bool boolValue, const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief Convenience method for setting float properties (instances of
      * FloatProperty)
      */
     void SetFloatProperty(const char *propertyKey, float floatValue, const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief Convenience method for setting double properties (instances of
      * DoubleProperty)
      */
     void SetDoubleProperty(const char *propertyKey, double doubleValue, const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief Convenience method for setting string properties (instances of
      * StringProperty)
      */
     void SetStringProperty(const char *propertyKey, const char *string, const mitk::BaseRenderer *renderer = nullptr);
 
     /**
      * \brief Get the timestamp of the last change of the contents of this node or
      * the referenced BaseData.
      */
     unsigned long GetMTime() const override;
 
     /**
      * \brief Get the timestamp of the last change of the reference to the
      * BaseData.
      */
     unsigned long GetDataReferenceChangedTime() const { return m_DataReferenceChangedTime.GetMTime(); }
 
   protected:
     DataNode();
 
     ~DataNode() override;
 
     /// Invoked when the property list was modified. Calls Modified() of the DataNode
     virtual void PropertyListModified(const itk::Object *caller, const itk::EventObject &event);
 
     /// \brief Mapper-slots
     mutable MapperVector m_Mappers;
 
     /**
      * \brief The data object (instance of BaseData, e.g., an Image) managed
      * by this DataNode
      */
     BaseData::Pointer m_Data;
 
     /**
      * \brief BaseRenderer-independent PropertyList
      *
      * Properties herein can be overwritten specifically for each BaseRenderer
      * by the BaseRenderer-specific properties defined in m_MapOfPropertyLists.
      */
     PropertyList::Pointer m_PropertyList;
 
     /// \brief Map associating each BaseRenderer with its own PropertyList
     mutable MapOfPropertyLists m_MapOfPropertyLists;
 
     DataInteractor::Pointer m_DataInteractor;
 
     /// \brief Timestamp of the last change of m_Data
     itk::TimeStamp m_DataReferenceChangedTime;
 
     unsigned long m_PropertyListModifiedObserverTag;
   };
 
   MITKCORE_EXPORT std::istream &operator>>(std::istream &i, DataNode::Pointer &dtn);
   MITKCORE_EXPORT std::ostream &operator<<(std::ostream &o, DataNode::Pointer &dtn);
 } // namespace mitk
 
 #endif /* DATATREENODE_H_HEADER_INCLUDED_C1E14338 */
diff --git a/Modules/Core/include/mitkGenericIDRelationRule.h b/Modules/Core/include/mitkGenericIDRelationRule.h
index 36169d8dd3..f6e2c8fd96 100644
--- a/Modules/Core/include/mitkGenericIDRelationRule.h
+++ b/Modules/Core/include/mitkGenericIDRelationRule.h
@@ -1,132 +1,98 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef mitkGenericIDRelationRule_h
 #define mitkGenericIDRelationRule_h
 
 #include "mitkPropertyRelationRuleBase.h"
 
 namespace mitk
 {
   /**This rule class can be used for relations that are only defined on the ID-layer and
   where no connection on the Data-layer can be defined or deduced.
   So it can be used for all ID based relations between PropertyProviders that also implement the
   interface identifiable.
   In order to be able to use this class for different relation types based on ID, the ruleIDTag is
   used. It must be specified when creating a rule instance. The ruleIDTag will be used as suffix
   for the rule ID of the instance and therefore allows to create specific and distinguishable rules
   instances based on this class.
   One may also specify the display name and the role names of the instance. If not speficied the default values
   are used (display name: "<ruleIDTag> relation", source role name: "source of <ruleIDTag> relation",
   destination role name: "destination <ruleIDTag> of relation")
   */
   class MITKCORE_EXPORT GenericIDRelationRule : public mitk::PropertyRelationRuleBase
   {
   public:
     mitkClassMacro(GenericIDRelationRule, PropertyRelationRuleBase);
     itkCloneMacro(Self);
     mitkNewMacro1Param(Self, const RuleIDType &);
     mitkNewMacro2Param(Self, const RuleIDType &, const std::string &);
     mitkNewMacro4Param(Self, const RuleIDType &, const std::string &, const std::string &, const std::string &);
 
     using RuleIDType = PropertyRelationRuleBase::RuleIDType;
     using RelationUIDType = PropertyRelationRuleBase::RelationUIDType;
     using RelationUIDVectorType = PropertyRelationRuleBase::RelationUIDVectorType;
 
     /** Returns an ID string that identifies the rule class */
     RuleIDType GetRuleID() const override;
 
     bool IsAbstract() const override;
 
     /** Returns a human readable string that can be used to describe the rule. Does not need to be unique.*/
     std::string GetDisplayName() const override;
 
     /** Returns a human readable string that can be used to describe the role of a source in context of the rule
      * instance.*/
     std::string GetSourceRoleName() const override;
     /** Returns a human readable string that can be used to describe the role of a destination in context of the rule
      * instance.*/
     std::string GetDestinationRoleName() const override;
 
     /** Pass through to base implementation of PropertyRelationRuleBase. See PropertyRelationRuleBase::connect documentation for more information. */
     RelationUIDType Connect(IPropertyOwner *source, const IPropertyProvider *destination) const;
 
   protected:
     GenericIDRelationRule(const RuleIDType &ruleIDTag);
     GenericIDRelationRule(const RuleIDType &ruleIDTag, const std::string &displayName);
     GenericIDRelationRule(const RuleIDType &ruleIDTag,
                           const std::string &displayName,
                           const std::string &sourceRole,
                           const std::string &destinationRole);
     ~GenericIDRelationRule() override = default;
 
     using InstanceIDType = PropertyRelationRuleBase::InstanceIDType;
     using InstanceIDVectorType = PropertyRelationRuleBase::InstanceIDVectorType;
 
-    /** Is called if a instance ID cannot be deduced on the ID-layer.
-    Implement this method to check which existing relation(s) as Connected_Data exists between
-    both passed instances. If the passed instances have no
-    explicit relation of type Connected_Data, an empty vector will be returned.
-    @remark Per definition of property relation rules only 0 or 1 instance should be found for one provider
-    pair and rule. But the data layer may be ambiguous and there for muliple relation instances of the rule instance
-    could match. The implementation of this function should report all relation instances. The calling function
-    will take care of this violation.
-    @pre source must be a pointer to a valid IPropertyProvider instance.
-    @pre destination must be a pointer to a valid IPropertyProvider instance.*/
-    InstanceIDVectorType GetInstanceID_datalayer(const IPropertyProvider *source,
-                                                         const IPropertyProvider *destination) const override;
-
-    /** Is called by HasRelation() if no relation of type Connected_ID (GetInstanceID_IDLayer()) or
-    Connected_Data (GetInstanceID_datalayer()) is evident.
-      Implement this method to deduce if the passed instances have a relation of type
-      Implicit_Data.
-      @pre source must be a pointer to a valid IPropertyProvider instance.
-      @pre destination must be a pointer to a valid IPropertyProvider instance.
-      */
-    bool HasImplicitDataRelation(const IPropertyProvider *source,
-                                         const IPropertyProvider *destination) const override;
-
-    /**Is called by Connect() to ensure that source has correctly set properties to resemble
-    the relation on the data layer. This means that the method should set the properties that describe
-    and encode the relation on the data layer (data-layer-specific relation properties).
-    If the passed instance are already connected, the old settings should be
-    overwritten. Connect() will ensure that source and destination are valid pointers.
-    @param instanceID is the ID for the relation instance that should be connected. Existance of the relation instance
-    is ensured.
-    @pre source must be a valid instance.
-    @pre destination must be a valid instance.*/
+    using DataRelationUIDVectorType = PropertyRelationRuleBase::DataRelationUIDVectorType;
+    DataRelationUIDVectorType GetRelationUIDs_DataLayer(const IPropertyProvider* source,
+      const IPropertyProvider* destination, const InstanceIDVectorType& instances_IDLayer) const override;
+
     void Connect_datalayer(IPropertyOwner *source,
                                    const IPropertyProvider *destination,
                                    const InstanceIDType &instanceID) const override;
 
-    /**This method is called by Disconnect() to remove all properties of the relation from the source that
-    are set by Connect_datalayer().
-    @remark All RII-properties of this relation will removed by Disconnect() after this method call.
-    If the relationUID is not part of the source. Nothing will be changed. Disconnect() ensures that source is a valid
-    pointer if called.
-    @remark Disconnect() ensures that sourece is valid and only invokes if instance exists.*/
-    void Disconnect_datalayer(IPropertyOwner *source, const InstanceIDType &instanceID) const override;
+    void Disconnect_datalayer(IPropertyOwner *source, const RelationUIDType& relationUID) const override;
 
     bool IsSupportedRuleID(const RuleIDType& ruleID) const override;
 
     itk::LightObject::Pointer InternalClone() const override;
 
   private:
     RuleIDType m_RuleIDTag;
     std::string m_DisplayName;
     std::string m_SourceRole;
     std::string m_DestinationRole;
   };
 
 } // namespace mitk
 
 #endif
diff --git a/Modules/Core/include/mitkGeometryDataReaderService.h b/Modules/Core/include/mitkGeometryDataReaderService.h
index 6bdb38da25..1c7f8e23cb 100644
--- a/Modules/Core/include/mitkGeometryDataReaderService.h
+++ b/Modules/Core/include/mitkGeometryDataReaderService.h
@@ -1,60 +1,61 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef mitkGeometryDataReaderService_h
 #define mitkGeometryDataReaderService_h
 
 // MITK
 #include <mitkAbstractFileReader.h>
 #include <mitkGeometryData.h>
 
 class TiXmlElement;
 
 namespace mitk
 {
   /**
    * @internal
    *
    * @brief reads XML representations of mitk::GeometryData from a file/stream.
    *
    * To be used via IOUtil.
    *
    * Reader for XML files containing one or multiple XML represenations of
    * mitk::GeometryData. If multiple mitk::GeometryData objects are stored in one file,
    * these are assigned to multiple BaseData objects.
    *
    * @sa Geometry3DToXML
    *
    * @ingroup IO
    */
   class GeometryDataReaderService : public AbstractFileReader
   {
   public:
     GeometryDataReaderService();
     ~GeometryDataReaderService() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
     /**
      * @brief Provides the MIME type for reader and writer.
      */
     static CustomMimeType GEOMETRY_DATA_MIMETYPE();
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     GeometryDataReaderService(const GeometryDataReaderService &other);
 
     GeometryDataReaderService *Clone() const override;
   };
 }
 
 #endif
diff --git a/Modules/Core/include/mitkIOMetaInformationPropertyConstants.h b/Modules/Core/include/mitkIOMetaInformationPropertyConstants.h
new file mode 100644
index 0000000000..166bd66d3e
--- /dev/null
+++ b/Modules/Core/include/mitkIOMetaInformationPropertyConstants.h
@@ -0,0 +1,44 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#ifndef MITKIOMETAINFORMATIONCONSTANTS_H_
+#define MITKIOMETAINFORMATIONCONSTANTS_H_
+
+#include <MitkCoreExports.h>
+
+#include "mitkPropertyKeyPath.h"
+
+namespace mitk
+{
+  /**
+   * @ingroup IO
+   * @brief The IOMetaInformationPropertyConstants struct
+   */
+  struct MITKCORE_EXPORT IOMetaInformationPropertyConstants
+  {
+    //Path to the property containing the name of the reader used
+    static PropertyKeyPath READER_DESCRIPTION();
+    //Path to the property containing the version of mitk used to read the data
+    static PropertyKeyPath READER_VERSION();
+    //Path to the property containing the mine name detected used to read the data
+    static PropertyKeyPath READER_MIME_NAME();
+    //Path to the property containing the mime category detected to read the data
+    static PropertyKeyPath READER_MIME_CATEGORY();
+    //Path to the property containing the input location if loaded by file used to read the data
+    static PropertyKeyPath READER_INPUTLOCATION();
+    //Path to the properties containing the reader optins used to read the data
+    static PropertyKeyPath READER_OPTION_ROOT();
+    static PropertyKeyPath READER_OPTIONS_ANY();
+  };
+}
+
+#endif // MITKIOCONSTANTS_H_
diff --git a/Modules/Core/include/mitkImagePixelReadAccessor.h b/Modules/Core/include/mitkImagePixelReadAccessor.h
index 6034ce61bc..fdebe4c56f 100644
--- a/Modules/Core/include/mitkImagePixelReadAccessor.h
+++ b/Modules/Core/include/mitkImagePixelReadAccessor.h
@@ -1,177 +1,191 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKIMAGEPIXELREADACCESSOR_H
 #define MITKIMAGEPIXELREADACCESSOR_H
 
 #include "mitkImagePixelAccessor.h"
 #include "mitkImageReadAccessor.h"
 
 namespace mitk
 {
   class Image;
 
   /**
    * @brief Gives locked and index-based read access for a particular image part.
    * The class provides several set- and get-methods, which allow an easy pixel access.
    * It needs to know about pixel type and dimension of its image at compile time.
    * @tparam TPixel defines the PixelType
    * @tparam VDimension defines the dimension for accessing data
    * @ingroup Data
    */
   template <class TPixel, unsigned int VDimension = 3>
   class ImagePixelReadAccessor : public ImagePixelAccessor<TPixel, VDimension>
   {
     friend class Image;
 
   public:
     typedef ImagePixelAccessor<TPixel, VDimension> ImagePixelAccessorType;
     typedef itk::SmartPointer<mitk::Image> ImagePointer;
     typedef itk::SmartPointer<const mitk::Image> ImageConstPointer;
 
     /** \brief Instantiates a mitk::ImageReadAccessor (see its doxygen page for more details)
      *  \param Image::Pointer specifies the associated Image
      *  \param ImageDataItem* specifies the allocated image part
      *  \param OptionFlags properties from mitk::ImageAccessorBase::Options can be chosen and assembled with bitwise
      * unification.
      *  \throws mitk::Exception if the Constructor was created inappropriately
      *  \throws mitk::MemoryIsLockedException if requested image area is exclusively locked and
      * mitk::ImageAccessorBase::ExceptionIfLocked is set in OptionFlags
      *
      *   Includes a check if typeid of PixelType coincides with templated TPixel
      *   and a check if VDimension equals to the Dimension of the Image.
      */
     ImagePixelReadAccessor(ImageConstPointer iP,
                            const ImageDataItem *iDI = nullptr,
                            int OptionFlags = ImageAccessorBase::DefaultBehavior)
       : ImagePixelAccessor<TPixel, VDimension>(iP, iDI), m_ReadAccessor(iP, iDI, OptionFlags)
     {
     }
 
     ImagePixelReadAccessor(ImagePointer iP,
                            const ImageDataItem *iDI = nullptr,
                            int OptionFlags = ImageAccessorBase::DefaultBehavior)
       : ImagePixelAccessor<TPixel, VDimension>(iP.GetPointer(), iDI), m_ReadAccessor(iP, iDI, OptionFlags)
     {
     }
 
     ImagePixelReadAccessor(Image *iP,
                            const ImageDataItem *iDI = nullptr,
                            int OptionFlags = ImageAccessorBase::DefaultBehavior)
       : ImagePixelAccessor<TPixel, VDimension>(iP, iDI), m_ReadAccessor(mitk::Image::ConstPointer(iP), iDI, OptionFlags)
     {
     }
 
     ImagePixelReadAccessor(const Image *iP,
                            const ImageDataItem *iDI = nullptr,
                            int OptionFlags = ImageAccessorBase::DefaultBehavior)
       : ImagePixelAccessor<TPixel, VDimension>(iP, iDI), m_ReadAccessor(iP, iDI, OptionFlags)
     {
     }
 
     /** Destructor informs Image to unlock memory. */
     ~ImagePixelReadAccessor() override {}
     /** Returns a const reference to the pixel at given index. */
     const TPixel &GetPixelByIndex(const itk::Index<VDimension> &idx) const
     {
       unsigned int offset = ImagePixelAccessorType::GetOffset(idx);
 
       return *(((TPixel *)m_ReadAccessor.m_AddressBegin) + offset);
     }
 
     itk::VariableLengthVector<TPixel> GetConsecutivePixelsAsVector(const itk::Index<VDimension> &idx,
                                                                    int nrComponents) const
     {
       return itk::VariableLengthVector<TPixel>(
         (TPixel *)m_ReadAccessor.m_AddressBegin +
           ImagePixelAccessorType::GetOffset(idx) * m_ReadAccessor.GetImage()->GetPixelType().GetNumberOfComponents(),
         nrComponents);
     }
 
     /** Extends GetPixel by integrating index validation to prevent overflow.
       * \throws mitk::Exception in case of overflow
       */
     const TPixel &GetPixelByIndexSafe(const itk::Index<VDimension> &idx) const
     {
       unsigned int offset = ImagePixelAccessorType::GetOffset(idx);
 
       TPixel *targetAddress = ((TPixel *)m_ReadAccessor.m_AddressBegin) + offset;
 
       if (!(targetAddress >= m_ReadAccessor.m_AddressBegin && targetAddress < m_ReadAccessor.m_AddressEnd))
       {
         mitkThrow() << "ImageAccessor Overflow: image access exceeds the requested image area at " << idx << ".";
       }
 
       return *targetAddress;
     }
 
     /** Returns a const reference to the pixel at given world coordinate - works only with three-dimensional
      * ImageAccessor
      */
     const TPixel &GetPixelByWorldCoordinates(mitk::Point3D position)
     {
       itk::Index<3> itkIndex;
       m_ReadAccessor.GetImage()->GetGeometry()->WorldToIndex(position, itkIndex);
 
       return GetPixelByIndex(itkIndex);
     }
 
     /** Returns a const reference to the pixel at given world coordinate - works only with four-dimensional
      * ImageAccessor
      */
     const TPixel &GetPixelByWorldCoordinates(mitk::Point3D position, unsigned int timestep)
     {
       itk::Index<3> itkIndex;
       m_ReadAccessor.GetImage()->GetGeometry()->WorldToIndex(position, itkIndex);
       if (m_ReadAccessor.GetImage()->GetTimeSteps() < timestep)
       {
         timestep = m_ReadAccessor.GetImage()->GetTimeSteps();
       }
       itk::Index<4> itk4Index;
       for (int i = 0; i < 3; ++i)
         itk4Index[i] = itkIndex[i];
 
       itk4Index[3] = timestep;
       return GetPixelByIndex(itk4Index);
     }
 
     /** \brief Gives const access to the data. */
     inline const TPixel *GetData() const { return static_cast<const TPixel *>(m_ReadAccessor.m_AddressBegin); }
   protected:
     // protected members
 
   private:
     ImageReadAccessor m_ReadAccessor;
 
     ImagePixelReadAccessor &operator=(const ImagePixelReadAccessor &); // Not implemented on purpose.
     ImagePixelReadAccessor(const ImagePixelReadAccessor &);
   };
 
   /** Static method that gets direct access to a single pixel value.
    *  The value is not guaranteed to be in a well-defined state and is automatically casted to mitk::ScalarType
    *  The method can be called by the macros in mitkPixelTypeMultiplex.h
    */
   template <class TPixel>
   mitk::ScalarType FastSinglePixelAccess(mitk::PixelType,
                                          mitk::Image::Pointer im,
                                          ImageDataItem *item,
                                          itk::Index<3> idx,
                                          mitk::ScalarType &val,
                                          int component = 0)
   {
-    mitk::ImagePixelReadAccessor<TPixel, 3> imAccess(im, item, mitk::ImageAccessorBase::IgnoreLock);
+    ImagePixelReadAccessor<TPixel, 3> imAccess(im, item, mitk::ImageAccessorBase::IgnoreLock);
+    val = imAccess.GetConsecutivePixelsAsVector(idx, component + 1).GetElement(component);
+    return val;
+  }
+
+  /** Const overload of FastSinglePixelAccess*/
+  template <class TPixel>
+  mitk::ScalarType FastSinglePixelAccess(mitk::PixelType,
+    mitk::Image::ConstPointer im,
+    const ImageDataItem* item,
+    itk::Index<3> idx,
+    mitk::ScalarType& val,
+    int component = 0)
+  {
+    ImagePixelReadAccessor<TPixel, 3> imAccess(im, item, mitk::ImageAccessorBase::IgnoreLock);
     val = imAccess.GetConsecutivePixelsAsVector(idx, component + 1).GetElement(component);
     return val;
   }
 }
 
 #endif // MITKIMAGEPIXELREADACCESSOR_H
diff --git a/Modules/Core/include/mitkItkImageIO.h b/Modules/Core/include/mitkItkImageIO.h
index a1c488f9fb..cefc222130 100644
--- a/Modules/Core/include/mitkItkImageIO.h
+++ b/Modules/Core/include/mitkItkImageIO.h
@@ -1,77 +1,79 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKITKFILEIO_H
 #define MITKITKFILEIO_H
 
 #include "mitkAbstractFileIO.h"
 
 #include <itkImageIOBase.h>
 
 namespace mitk
 {
   /**
    * This class wraps ITK image IO objects as mitk::IFileReader and
    * mitk::IFileWriter objects.
    *
    * Instantiating this class with a given itk::ImageIOBase instance
    * will register corresponding MITK reader/writer services for that
    * ITK ImageIO object.
    */
   class MITKCORE_EXPORT ItkImageIO : public AbstractFileIO
   {
   public:
     ItkImageIO(itk::ImageIOBase::Pointer imageIO);
     ItkImageIO(const CustomMimeType &mimeType, itk::ImageIOBase::Pointer imageIO, int rank);
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
     ConfidenceLevel GetWriterConfidenceLevel() const override;
 
   protected:
     virtual std::vector<std::string> FixUpImageIOExtensions(const std::string &imageIOName);
     virtual void FixUpCustomMimeTypeName(const std::string &imageIOName, CustomMimeType &customMimeType);
 
     // Fills the m_DefaultMetaDataKeys vector with default values
     virtual void InitializeDefaultMetaDataKeys();
 
+    // -------------- AbstractFileReader -------------
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     ItkImageIO(const ItkImageIO &other);
 
     ItkImageIO *IOClone() const override;
 
     itk::ImageIOBase::Pointer m_ImageIO;
 
     std::vector<std::string> m_DefaultMetaDataKeys;
   };
 
   /**Helper function that converts the content of a meta data into a time point vector.
    * If MetaData is not valid or cannot be converted an empty vector is returned.*/
   MITKCORE_EXPORT std::vector<TimePointType> ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase* data);
 
 
   /**Helper function that converts the time points of a passed time geometry to a time point list
    and stores it in a itk::MetaDataObject. Use ConvertMetaDataObjectToTimePointList() to convert it back
    to a time point list.*/
   MITKCORE_EXPORT itk::MetaDataObjectBase::Pointer ConvertTimePointListToMetaDataObject(const mitk::TimeGeometry* timeGeometry);
 
 } // namespace mitk
 
 #endif /* MITKITKFILEIO_H */
diff --git a/Modules/Core/include/mitkPropertyKeyPath.h b/Modules/Core/include/mitkPropertyKeyPath.h
index 525503f634..134bb8e9ff 100644
--- a/Modules/Core/include/mitkPropertyKeyPath.h
+++ b/Modules/Core/include/mitkPropertyKeyPath.h
@@ -1,214 +1,216 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef mitkPropertyKeyPath_h
 #define mitkPropertyKeyPath_h
 
 #include <string>
 #include <vector>
 
 #include <mitkExceptionMacro.h>
 
 #include <MitkCoreExports.h>
 
 namespace mitk
 {
   /** @brief Class that can be used to specify nested or wild carded property keys. E.g.
    * for the use in context of the property persistence service or the property relation service.\n
    * Following assumptions are made /preconditions are defined:
    * - A property key is partitioned by "." into nodes (c.f. visualization of property keys in the PropertyView).
    * - A node can either be an element or a selection.
    * - An element has a name (alphanumric, - and space; "A-Za-z0-9- ") or is wildcarded ("*")
    * - A selection is either an index (e.g. "[1]") or a wildcard ("[*]").
    *
    * Selections are used to indicate that the preceding element has multiple occurences and which occurence is meant.
    * Example property keys would be:
    * - prop : A simple property key
    * - prop.subprop1 : A property key consting of two nodes
    * - prop.* : Any property key that starts with a node "prop"
    * - prop.sub.[2] : A property key that starts with a node "prop" and a has a second node that is selection and has
    * the index 2.
    * - prop.sub.[*] : Any property key that starts with a node "prop" and a has a second node that is selection (with
    * any index).
    *
    * To build a path one may use the Add* method to build up the PropertyKeyPath element by element.\n
    * "first.*.third.[3]" would be equivalent to
    * propKeyPath.AddElement("first");
    * propKeyPath.AddAnyElement();
    * propKeyPath.AddSelection("third",3);\n
    * or the inline version
    * propKeyPath.AddElement("first").AddAnyElement().AddSelection("third",3);
    */
   class MITKCORE_EXPORT PropertyKeyPath final
   {
   public:
     using ItemSelectionIndex = std::size_t;
     using ElementNameType = std::string;
 
     struct MITKCORE_EXPORT NodeInfo
     {
       enum class NodeType
       {
         Invalid = 0,      //*< Node does not exist or is invalid.
         Element,          //*< Selects an specific element given the node name.
         ElementSelection, //*< Selects an specific item in a sequence of items and has a item selector ("[n]").
         AnySelection,     //*< Selects all items of a specific element ("[*]").
         AnyElement //*< Selects any element/item. Node name is wildcarded ("*"); item selection as well implictily.
       };
 
       NodeType type;
       ElementNameType name;
       ItemSelectionIndex selection;
 
       NodeInfo();
       NodeInfo(const ElementNameType &name, NodeType type = NodeType::Element, ItemSelectionIndex index = 0);
       bool Matches(const NodeInfo &right) const;
 
       bool operator==(const NodeInfo &right) const;
     };
 
     using NodeInfoVectorType = std::vector<NodeInfo>;
     using PathIndexType = NodeInfoVectorType::size_type;
 
     /** Returns if the PropertyKeyPath is empty.*/
     bool IsEmpty() const;
 
     /** Returns if the path is explicit (has no wildcards).*/
     bool IsExplicit() const;
 
     /** Returns if the path has any nodes with item selection wild cards ([*]).*/
     bool HasItemSelectionWildcardsOnly() const;
 
     /** Number of path nodes the PropertyKeyPath contains.*/
     PathIndexType GetSize() const;
 
     /** Adds a new node to the end of the path.
     \param [in] newNode Reference to the node that should be added.
     \return Returns the index of the newly added node.*/
     PathIndexType AddNode(const NodeInfo &newNode);
 
     /** Function returns the node info of a path node specified by the index
      * within the PropertyKeyPath.
      * \pre Passed index must not be out of bounds.
      * \param [in] index Index of the node whose info should be retrieved.
      * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be
      * thrown.*/
     const NodeInfo &GetNode(const PathIndexType &index) const;
 
     /** Function returns the node info of a path node specified by the index
      * within the PropertyKeyPath.
      * \pre Passed index must not be out of bounds.
      * \param [in] index Index of the node whose info should be retrieved.
      * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be
      * thrown.*/
     NodeInfo &GetNode(const PathIndexType &index);
 
     /** Function returns the node info of the first path node within the PropertyKeyPath.
      * \pre PropertyKeyPath must not be empty.
      * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/
     NodeInfo &GetFirstNode();
 
     /** Function returns the node info of the first path node within the PropertyKeyPath.
      * \pre PropertyKeyPath must not be empty.
      * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/
     const NodeInfo &GetFirstNode() const;
 
     /** Function returns the node info of the last path node within the PropertyKeyPath.
      * \pre PropertyKeyPath must not be empty.
      * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/
     NodeInfo &GetLastNode();
 
     /** Function returns the node info of the last path node within the PropertyKeyPath.
      * \pre PropertyKeyPath must not be empty.
      * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/
     const NodeInfo &GetLastNode() const;
 
     const NodeInfoVectorType &GetNodes() const;
 
     /**Compares two PropertyKeyPaths for real equality. So it is a string comparison of their string conversion.*/
     bool operator==(const PropertyKeyPath &path) const;
 
     /**Operation equals like comparing the ToStr() results with operator <.*/
     bool operator<(const PropertyKeyPath &right) const;
 
     /**Operation equals like comparing the ToStr() results with operator <=.*/
     bool operator<=(const PropertyKeyPath &right) const;
 
     /**Operation equals like comparing the ToStr() results with operator >=.*/
     bool operator>=(const PropertyKeyPath &right) const;
 
     /**Operation equals like comparing the ToStr() results with operator >.*/
     bool operator>(const PropertyKeyPath &right) const;
 
     /**Checks if two PropertyKeyPaths specify the same node. Hence all wildcards will be processed.\n
      * E.G.: "item1.child1.grandChild2" == "item1.*.grandChild2" is true.
      * \remark If you want to check if two paths are "truly" equal and not only equal in terms of
      * pointing to the same node, use the member function operator ==().*/
     bool Equals(const PropertyKeyPath &path) const;
 
     PropertyKeyPath &operator=(const PropertyKeyPath &path);
 
     /** Appends an "any element" to the path instance.*/
     PropertyKeyPath &AddAnyElement();
     /** Appends an element with the passed name to the path instance.*/
     PropertyKeyPath &AddElement(const ElementNameType &name);
     /** Appends an element with the passed name and any selection to the path instance.*/
     PropertyKeyPath &AddAnySelection(const ElementNameType &name);
     /** Appends an element with the passed name and selection index to the path instance.*/
     PropertyKeyPath &AddSelection(const ElementNameType &name, ItemSelectionIndex index);
 
     PropertyKeyPath();
     PropertyKeyPath(const PropertyKeyPath &path);
+    /** overload constructor that supports simple key pathes consisting only of elements.*/
+    PropertyKeyPath(const std::initializer_list< ElementNameType >& list);
 
     ~PropertyKeyPath();
 
     void Reset();
 
   protected:
     NodeInfoVectorType m_NodeInfos;
 
     static bool PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right);
   };
 
   class MITKCORE_EXPORT InvalidPathNodeException : public mitk::Exception
   {
   public:
     mitkExceptionClassMacro(InvalidPathNodeException, mitk::Exception);
   };
 
   MITKCORE_EXPORT std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &path);
 
   /**Helper function that converts a path PropertyKeyPath into a regex string that can be used
    to search for property keys (using std::regex) that are matched by the PropertyKeyPath.
   This function is used in context of the property persistence service.*/
   MITKCORE_EXPORT std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath);
   /**Helper function that converts a path PropertyKeyPath into a regex string that can be used
   to search for property persistence keys (using std::regex) that are matched by the PropertyKeyPath.
   This function is used in context of the property persistence service.*/
   MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath);
   /**Helper function that converts a path PropertyKeyPath into a regex that can be used as key template
   in a PropertyPersistanceInfo.
   This function is used in context of the property persistence service.*/
   MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath);
   /**Helper function that converts a path PropertyKeyPath into a regex that can be used as name template
   in a PropertyPersistanceInfo.
   This function is used in context of the property persistence service.*/
   MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath);
 
   /** Converts the passed property name into a tag path. If the property name cannot be converted
    into a valid path, the returned path is empty.*/
   MITKCORE_EXPORT PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName);
   /** returns the correct property name for a given PropertyKeyPath instance. */
   MITKCORE_EXPORT std::string PropertyKeyPathToPropertyName(const PropertyKeyPath &tagPath);
 } // namespace mitk
 
 #endif
diff --git a/Modules/Core/include/mitkPropertyRelationRuleBase.h b/Modules/Core/include/mitkPropertyRelationRuleBase.h
index 05e9523af5..4758746f44 100644
--- a/Modules/Core/include/mitkPropertyRelationRuleBase.h
+++ b/Modules/Core/include/mitkPropertyRelationRuleBase.h
@@ -1,337 +1,374 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef mitkPropertyRelationRuleBase_h
 #define mitkPropertyRelationRuleBase_h
 
 #include "mitkIPropertyOwner.h"
 #include "mitkIdentifiable.h"
 
 #include "mitkException.h"
 #include "mitkNodePredicateBase.h"
 #include "mitkPropertyKeyPath.h"
 
 #include <MitkCoreExports.h>
 
 #include <string>
 
 namespace mitk
 {
   /**Base class to standardize/abstract/encapsulate rules and business logic to detect and define
   (property/data based) relations in MITK.
   Following important definitions must be regarded when using/implementing/specifing rule classes:
   - Releations represented by rules are directed relations that point from a source IPropertyOwner (Source)
   to a destination IPropertyOwner (Destination).
   - Rule can be abstract (indicated by IsAbstract()) or concrete. Abstract rules cannot be used to connect relations.
   Abstract rules can only be used to detect/indicate or disconnect relations. Therefore, in contrast to concrete rules,
   abstract rules can be used to indicate several relations that are established be "derived" rules. See e.g. GenericIDRelationRule:
   in its abstract state it cannot connect but be used to detect any type of generic ID relation.
   - A concrete rule ID (rule ID of a concrete rule) always "implements" a concrete relation type. E.g. In DICOM the
   way to express the source image relation to an input image and to a mask would be nearly the same
   and only differs by the encoded purpose. One may implement an interim or joined class that manages the mutual
   stuff, but the registered instances must be one concrete rule for "DICOM source input image" and one concrete rule for
   "DICOM source mask" and both rules must have distinct rule IDs.
   - Source may have several relations of a rule to different Destinations.
   Destination may have several relations of a rule from different Sources. But a specific source destination
   pair may have only one relation of a specific rule id (concrete rule). A specific source destination
   pair may however have multiple relations for an abstract rule.
   - The deletion of a Destination in the storage does not remove the relation implicitly. It becomes a "zombie" relation
   but it should still be documented, even if the destination is unknown. One has to explicitly
   disconnect a zombie relation to get rid of it.
   - Each relation has its own UID (relationUID) that can be used to address it.
 
   The basic concept of the rule design is that we have two layers of relation identification: Layer 1 is the ID-layer
   which uses the IIdentifiable interface and UIDs if available to encode "hard" relations. Layer 2 is the Data-layer
   which uses the properties of Source and Destination to deduce if there is a relation of the rule type.
-  The ID-layer is completely implemented by this base class. The base class only falls back to the Data-layer
-  (implemented by the concrete rule class) if the ID-layer is not sufficient or it is explicitly stated.
+  The ID-layer is completely implemented by this base class. The base class falls back to the Data-layer
+  (implemented by the concrete rule class) if the ID-layer is not sufficient or it is explicitly stated to (only)
+  look at the data layer.
   Reasons for the introduction of the ID-layer are: 1st, data-defined relations may be weak (several Destinations are
   possible; e.g. DICOM source images may point to several loaded mitk images). But if explicitly a relation was
   connected it should be deduceable. 2nd, checks on a UID are faster then unnecessary data deduction.
 
   Rules use relation instance identifing (RII) properties in order to manage their relations that are stored in the
   Source. The RII-properties follow the following naming schema:
-  "MITK.Relations.<InstanceID>.<RuleID>.[relationUID|destinationUID|ruleID|<data-layer-specific>]"
+  "MITK.Relations.<InstanceID>.[relationUID|destinationUID|ruleID|<data-layer-specific>]"
   - <InstanceID>: The unique index of the relation for the Source. Used to assign/group the properties to
   their relation. In the default implementation of this class the instance id is an positive integer (i>0).
   - relationUID: The UID of the relation. Set by the ID-layer (so by this class)
   - destinationUID: The UID of the Destination. Set by the ID-layer (so by this class) if Destination implements
   IIdentifiable.
   - ruleID: The identifier of the concrete rule that sets the property. Is specified by the derived class and set
   automaticaly be this base class.
   - <data-layer-specific>: Information needed by the Data-layer (so derived classes) to find the relationUID
   */
   class MITKCORE_EXPORT PropertyRelationRuleBase : public itk::Object
   {
   public:
     mitkClassMacroItkParent(PropertyRelationRuleBase, itk::Object);
     itkCloneMacro(Self);
     itkCreateAnotherMacro(Self);
 
     using RuleIDType = std::string;
     using RelationUIDType = Identifiable::UIDType;
     using RelationUIDVectorType = std::vector<RelationUIDType>;
 
     /** Enum class for different types of relations. */
     enum class RelationType
     {
       None = 0,           /**< Two IPropertyOwner have no relation under the rule.*/
-      Implicit_Data = 1,  /**< Two IPropertyOwner have a relation, but it is only deduced from the Data-layer and they
-                   were never explicitly connected.*/
-      Connected_Data = 2, /**< Two IPropertyOwner have a relation and there where connected on the Data-layer (so a bit
+      Data = 1,  /**< Two IPropertyOwner have a relation, but it is "only" deduced from the Data-layer (so a bit
                    "weaker" as ID). Reasons for the missing ID connection could be that Destintination has not
                    IIdentifiable implemented.*/
-      Connected_ID = 4    /**< Two IPropertyOwner have a relation and are fully explictly connected.*/
+      ID = 2,    /**< Two IPropertyOwner have a relation and are explictly connected via the ID of IIdentifiable of the Destination.*/
+      Complete = 3    /**< Two IPropertyOwner have a relation and are fully explictly connected (via data layer and ID layer).*/
     };
+    using RelationVectorType = std::vector<RelationType>;
 
     /** Returns the generic root path for relation rules ("MITK.Relations").*/
     static PropertyKeyPath GetRootKeyPath();
 
     /** Returns an ID string that identifies the rule class.
     @post The returned rule ID must met the preconditions of a PropertyKeyPath element name
     (see mitk::PropertyKeyPath*/
     virtual RuleIDType GetRuleID() const = 0;
 
     /** Returns a human readable string that can be used to describe the rule. Does not need to be unique.*/
     virtual std::string GetDisplayName() const = 0;
 
     /** Returns a human readable string that can be used to describe the role of a source in context of the rule
      * instance.*/
     virtual std::string GetSourceRoleName() const = 0;
     /** Returns a human readable string that can be used to describe the role of a destionation in context of the rule
      * instance.*/
     virtual std::string GetDestinationRoleName() const = 0;
 
     /** Returns if the instance is a abstract rule (true). Default implementation is true. Overwrite and reimplement
     if another behavior is needed.*/
     virtual bool IsAbstract() const;
 
     /** This method checks if owner is eligible to be a Source for the rule. The default implementation returns a
     True for every valid IPropertyProvider (so only a null_ptr results into false). May be reimplement by derived rules if
     they have requirements on potential Sources).*/
     virtual bool IsSourceCandidate(const IPropertyProvider *owner) const;
 
     /** This method checks if owner is eligible to be a Destination for the rule. The default implementation returns a
     True for every valid IPropertyProvider (so only a null_ptr results into false). May be reimplement by derived rules if
     they have requirements on potential Sources).*/
     virtual bool IsDestinationCandidate(const IPropertyProvider *owner) const;
 
-    /** Returns true if the passed owner is a Source of a relation defined by the rule so has at least one relation of
-    type Connected_Data or Connected_ID.
+    /** Returns true if the passed owner is a Source of a relation defined by the rule.
     @pre owner must be a pointer to a valid IPropertyProvider instance.*/
     bool IsSource(const IPropertyProvider *owner) const;
 
-    /** Returns the relation type of the passed IPropertyOwner instances.
+    /** Returns all relation types of the passed IPropertyOwner instances.
+    @remark Abstract rules may have several relationtypes between the instances (from different supported concrete rules), that cover
+    both ID and Data relations; thus it returns a vector of RelationTypes.
+    @result Vector of all relation types that exist between the given instances. Empty vector equals none relation at all.
     @pre source must be a pointer to a valid IPropertyProvider instance.
     @pre destination must be a pointer to a valid IPropertyProvider instance.
     */
-    RelationType HasRelation(const IPropertyProvider *source, const IPropertyProvider *destination) const;
+    RelationVectorType GetRelationTypes(const IPropertyProvider* source, const IPropertyProvider* destination) const;
+
+    /** Indicates if passed IPropertyOwner instances have a relation of a certain type.
+    @remark Abstract rules may also indicate RelationType::Complete if there
+    are multiple relations (from different supported concrete rules), that cover
+    both ID and Data relations.
+    @param requiredRelation Defines the type of relation that should be present. None: does not matter which one, as long as at least one is present.
+    Data: Only data layer exclusive connections, ID: Only ID layer exclusive connections. Complete: Only relations that are connected on both layers.
+    @pre source must be a pointer to a valid IPropertyProvider instance.
+    @pre destination must be a pointer to a valid IPropertyProvider instance.
+    */
+    bool HasRelation(const IPropertyProvider *source, const IPropertyProvider *destination, RelationType requiredRelation = RelationType::None) const;
 
     /** Returns a vector of relation UIDs for all relations of this rule instance that are defined for
-    the passed source (so relations of type Connected_Data and Connected_ID).
+    the passed source.
     @pre source must be a pointer to a valid IPropertyOwner instance.
-    */
-    RelationUIDVectorType GetExistingRelations(const IPropertyProvider *source) const;
+    @param layer Defines the layer the relations must be reflected. None: does not matter which one, as long as at least one is present.
+    Data: Only data layer exclusive connections, ID: Only ID layer exclusive connections. Complete: Only relations that are connected on both layers.*/
+    RelationUIDVectorType GetExistingRelations(const IPropertyProvider *source, RelationType layer = RelationType::None) const;
 
     /** Returns the relation UID(s) for the passed source and destination of this rule instance.
     If the rule is abstract multiple relation UIDs might be returned. In case of concrete rule only
     one relation UID.
-    If the passed instances have no explicit relation (so of type Connected_Data or Connected_ID),
-    no ID can be deduced and an empty relation UID vector is returned.
     @pre source must be a pointer to a valid IPropertyOwner instance.
     @pre destination must be a pointer to a valid IPropertyOwner instance.*/
     RelationUIDVectorType GetRelationUIDs(const IPropertyProvider *source, const IPropertyProvider *destination) const;
 
     /** Returns the relation UID for the passed source and destination of this rule instance.
-    If the passed instances have no explicit relation (so of type Connected_Data or Connected_ID),
-    no ID can be deduced and an exception will be thrown. If more then one relation is found, also
-    an exception will be thrown. Thus only use this convinience method, if you are sure that one(!)
-    relation UID can exist.
+    If the passed instances have no relation, no ID can be deduced and an exception will be thrown.
+    If more than one relation is found, also an exception will be thrown. Thus only use this convenience method,
+    if you are sure that one(!) relation UID can exist.
     @pre source must be a pointer to a valid IPropertyOwner instance.
     @pre destination must be a pointer to a valid IPropertyOwner instance.
-    @pre Source and destination have one relation of type Connected_Data or Connected_ID; otherwise
+    @pre Source and destination have one relation; otherwise
     if no relation exists a NoPropertyRelationException is thrown; if more than one relation exists
     a default MITK expception is thrown.*/
     RelationUIDType GetRelationUID(const IPropertyProvider *source, const IPropertyProvider *destination) const;
 
     /**Predicate that can be used to find nodes that qualify as source for that rule (but must not be a source yet).
     Thus all nodes where IsSourceCandidate() returns true. */
     NodePredicateBase::ConstPointer GetSourceCandidateIndicator() const;
     /**Predicate that can be used to find nodes that qualify as destination for that rule (but must not be a destination
     yet). Thus all nodes where IsDestinationCandidate() returns true. */
     NodePredicateBase::ConstPointer GetDestinationCandidateIndicator() const;
-    /**Predicate that can be used to find nodes that are Sources of that rule and explicitly connected.
+    /**Predicate that can be used to find nodes that are Sources of that rule and connected.
     Thus all nodes where IsSource() returns true.*/
     NodePredicateBase::ConstPointer GetConnectedSourcesDetector() const;
     /**Predicate that can be used to find nodes that are as source related to the passed Destination under the rule
     @param destination Pointer to the Destination instance that should be used for detection.
-    @param minimalRelation Defines the minimal strength of the relation type that should be detected.
+    @param exclusiveRelation Defines if only special types of relations should detected. None: All relations (default);
+    Data: must be a data relation (so Data or Complete); ID: must be an ID relation (so ID or Complete); Complete: only complete relations.
     @pre Destination must be a valid instance.*/
     NodePredicateBase::ConstPointer GetSourcesDetector(
-      const IPropertyProvider *destination, RelationType minimalRelation = RelationType::Implicit_Data) const;
+      const IPropertyProvider *destination, RelationType exclusiveRelation = RelationType::None) const;
     /**Predicate that can be used to find nodes that are as Destination related to the passed Source under the rule
     @param source Pointer to the Source instance that should be used for detection.
-    @param minimalRelation Defines the minimal strength of the relation type that should be detected.
+    @param exclusiveRelation Defines if only special types of relations should detected. None: All relations (default);
+    Data: must be a data relation (so Data or Complete); ID: must be an ID relation (so ID or Complete); Complete: only complete relations.
     @pre Destination must be a valid instance.*/
     NodePredicateBase::ConstPointer GetDestinationsDetector(
-      const IPropertyProvider *source, RelationType minimalRelation = RelationType::Implicit_Data) const;
+      const IPropertyProvider *source, RelationType exclusiveRelation = RelationType::None) const;
     /**Returns a predicate that can be used to find the Destination of the passed Source for a given relationUID.
     @param source Pointer to the Source instance that should be used for detection.
-    @param minimalRelation Defines the minimal strength of the relation type that should be detected.
     @pre source must be a valid instance.
     @pre relationUID must identify a relation of the passed source and rule. (This must be in the return of
     this->GetExistingRelations(source). */
     NodePredicateBase::ConstPointer GetDestinationDetector(const IPropertyProvider *source,
                                                            RelationUIDType relationUID) const;
 
-    /**Disconnect the passed instances. Afterwards they have a relation of None or Implicit_Data.
-    All RII-properties in the source for the passed destination will be removed.
+    /**Disconnect the passed instances by modifing source. One can specify which layer should be disconnected
+    via the argument "layer". Default is the complete disconnection.
+    All RII-properties or properties that define the connection on the data layer in the source
+    for the passed destination will be removed.
     @pre source must be a valid instance.
-    @pre destination must be a valid instance.*/
-    void Disconnect(IPropertyOwner *source, const IPropertyProvider *destination) const;
+    @pre destination must be a valid instance.
+    @param layer Defines the way of disconnection. Data: Only the remove the connection on the data layer. ID: Only remove the connection
+    on the ID layer. Complete: Remove the connection on all layers. If a connection does not exist on a selected layer, it is silently ignored.*/
+    void Disconnect(IPropertyOwner *source, const IPropertyProvider *destination, RelationType layer = RelationType::Complete) const;
     /**Disconnect the source from the passed relationUID (usefull for "zombie relations").
-    All RII-properties in the source for the passed relationUID will be removed.
+    One can specify which layer should be disconnected
+    via the argument "layer". Default is the complete disconnection.
+    All RII-properties or properties that define the connection on the data layer in the source
+    for the passed destination will be removed.
     If the relationUID is not part of the source. Nothing will be changed.
-    @pre source must be a valid instance.*/
-    void Disconnect(IPropertyOwner *source, RelationUIDType relationUID) const;
+    @pre source must be a valid instance.
+    @param layer Defines the way of disconnection. Data: Only the remove the connection on the data layer. ID: Only remove the connection
+    on the ID layer. Complete: Remove the connection on all layers. If a connection does not exist on a selected layer, it is silently ignored.*/
+    void Disconnect(IPropertyOwner *source, RelationUIDType relationUID, RelationType layer = RelationType::Complete) const;
+
+    /**Returns the list of PropertyKeyPaths of all properties that are relevant for a given relation.
+    @param source Pointer to the Source instance that containes the potential properties.
+    @param relationUID UID of the relation that is relevant for the requested properties.
+    @param layer Indicates which layer is requested. ID: returns all RII properties that belong to the relation. Data: returns all properties that are relevant/belong to the data layer of the relation. Complete: returns all properties (ID+Data)
+    @pre source must be a valid instance.
+    @pre relationUID must identify a relation of the passed source and rule. (This must be in the return of
+    this->GetExistingRelations(source). */
+    std::vector<PropertyKeyPath> GetReleationPropertyPaths(const IPropertyProvider* source,
+      RelationUIDType relationUID, RelationType layer = RelationType::Data) const;
 
   protected:
     PropertyRelationRuleBase() = default;
     ~PropertyRelationRuleBase() override = default;
 
     using InstanceIDType = std::string;
     using InstanceIDVectorType = std::vector<InstanceIDType>;
     static InstanceIDType NULL_INSTANCE_ID();
 
     /** Returns the instance IDs for the passed source and destination for this rule instance.
     If the passed source and destination instances has no explicit relation on the ID layer (Connected_ID),
     an empty vector will be returned.
     @remark Per definition of property relation rules only 0 or 1 instance should be found for one provider
-    pair and concrete rule. But for there might be more then one instanceID, because the rule is abstract and
-    supports multiple rule IDs. 2) the data layer may be ambiguous and therefore multiple relation instances of the rule instance
+    pair and concrete rule. But there might be more then one instanceID because either 1) the rule is abstract and
+    supports multiple rule IDs or 2) the data layer may be ambiguous and therefore multiple relation instances of the rule instance
     could match. The implementation of this function should report all relation instances. The calling function
     will take care.
     @pre source must be a pointer to a valid IPropertyProvider instance.
     @pre destination must be a pointer to a valid IPropertyProvider instance.*/
     InstanceIDVectorType GetInstanceID_IDLayer(const IPropertyProvider *source,
                                                                          const IPropertyProvider *destination) const;
 
-    /** Is called if an instance ID cannot be deduced on the ID-layer.
-    Implement this method to check which existing relation(s) as Connected_Data exists between
-    both passed instances. If the passed instances have no
-    explicit relation of type Connected_Data, an empty vector will be returned.
-    @remark Per definition of property relation rules only 0 or 1 instance should be found for one provider
-    pair and concrete rule. But for 2 reasons there might be more then one instanceID: 1) the rule is abstract and
-    supports multiple rule IDs. 2) the data layer may be ambiguous and therefore multiple relation instances of the rule instance
-    could match. The implementation of this function should report all relation instances. The calling function
+    using DataRelationUIDVectorType = std::vector< std::pair<RelationUIDType, RuleIDType> >;
+    /** Returns the ReleationUIDs of all relations that are defined by the data layer of source for
+    this rule instance and, if defined, destination.
+    If the passed source (and destination) instance has no relation on the data layer,
+    an empty vector will be returned.
+    @remark Per definition for property relation rules only 0 or 1 instance should be found for one provider
+    pair and concrete rule. But there might be more then one instance because either 1) the rule is abstract and
+    supports multiple rule IDs or 2) the data layer may be ambiguous (e.g. because the destination was not specified)
+    and therefore multiple relation instances of the rule instance could match.
+    The implementation of this function should report all relation instances. The calling function
     will take care.
     @pre source must be a pointer to a valid IPropertyProvider instance.
-    @pre destination must be a pointer to a valid IPropertyProvider instance.*/
-    virtual InstanceIDVectorType GetInstanceID_datalayer(const IPropertyProvider *source,
-                                                         const IPropertyProvider *destination) const = 0;
-
-    /** Is called by HasRelation() if no relation of type Connected_ID (GetInstanceID_IDLayer()) or
-    Connected_Data (GetInstanceID_datalayer()) is evident.
-      Implement this method to deduce if the passed instances have a relation of type
-      Implicit_Data.
-      @pre source must be a pointer to a valid IPropertyProvider instance.
-      @pre destination must be a pointer to a valid IPropertyProvider instance.
-      */
-    virtual bool HasImplicitDataRelation(const IPropertyProvider *source,
-                                         const IPropertyProvider *destination) const = 0;
+    @param destination Destination the find relations should point to. If destination is NULL any relation
+    on the data layer for this rule and source are wanted.
+    @param instances_IDLayer List of releation instances that are already defined by the ID layer. The implementation of this
+    function should only cover releations that are not already resembled in the passed relarions_IDLayer.*/
+    virtual DataRelationUIDVectorType GetRelationUIDs_DataLayer(const IPropertyProvider * source,
+      const IPropertyProvider * destination, const InstanceIDVectorType& instances_IDLayer) const = 0;
 
     /**Helper function that deduces the relation UID of the given relation instance.
     If it cannot be deduced an NoPropertyRelationException is thrown.*/
     RelationUIDType GetRelationUIDByInstanceID(const IPropertyProvider *source, const InstanceIDType &instanceID) const;
     /**Helper function that deduces the relation instance ID given the relation UID.
     If it cannot be deduced an NoPropertyRelationException is thrown.*/
     InstanceIDType GetInstanceIDByRelationUID(const IPropertyProvider *source,
                                               const RelationUIDType &relationUID) const;
 
-    /**Explicitly connects the passed instances. Afterwards they have a relation of Connected_Data or Connected_ID (if a
-    destination implements IIdentifiable). If the passed instance are already connected the old connection will be
-    overwritten (and raised to the highest possible connection level).
+    /**Explicitly connects the passed instances. Afterwards they have a relation of Data (if data layer is supported), ID (if a
+    destination implements IIdentifiable) or Complete (if Data and ID could be connected). If the passed instance are already
+    connected the old connection will be overwritten (and raised to the highest possible connection level).
     @remark This method has protected visibility in the base implementation, because it is a design decision of derived rule classes
     which interface they want to offer for connecting. It may just be made public (e.g. GenericIDRelationRule) or used by own implementations.
     @pre source must be a valid instance.
     @pre destination must be a valid instance.
     @pre the rule instance must not be abstract.
     @return Return the relation uid of the relation connected by this method call*/
     RelationUIDType Connect(IPropertyOwner *source, const IPropertyProvider *destination) const;
 
     /**Is called by Connect() to ensure that source has correctly set properties to resemble
     the relation on the data layer. This means that the method should set the properties that describe
     and encode the relation on the data layer (data-layer-specific relation properties).
     If the passed instance are already connected, the old settings should be
     overwritten. Connect() will ensure that source and destination are valid pointers.
     @param instanceID is the ID for the relation instance that should be connected. Existance of the relation instance
     is ensured.
     @pre source must be a valid instance.
     @pre destination must be a valid instance.*/
     virtual void Connect_datalayer(IPropertyOwner *source,
                                    const IPropertyProvider *destination,
                                    const InstanceIDType &instanceID) const = 0;
 
     /**This method is called by Disconnect() to remove all properties of the relation from the source that
     are set by Connect_datalayer().
-    @remark All RII-properties of this relation will removed by Disconnect() after this method call.
-    If the relationUID is not part of the source. Nothing will be changed. Disconnect() ensures that source is a valid
+    @remark This method should remove all properties that are set for a specific relation by Connect_datalayer(...).
+    If the relationUID is not part of the source, nothing will be changed. Disconnect() ensures that source is a valid
     pointer if called.
     @remark Disconnect() ensures that sourece is valid and only invokes if instance exists.*/
-    virtual void Disconnect_datalayer(IPropertyOwner *source, const InstanceIDType &instanceID) const = 0;
+    virtual void Disconnect_datalayer(IPropertyOwner *source, const RelationUIDType & relationUID) const = 0;
 
     /** Returns if the passed rule ID is supported/relevant for the rule. Either because it is the very ID of the rule (default implementation) or because
     it is an abstract rule which also supports the rule ID.
     @return true: If the rule ID can handle the rule ID. false: the rule does not support the rule ID.*/
     virtual bool IsSupportedRuleID(const RuleIDType& ruleID) const;
 
     /** Helper function that generates a reg ex that can be used to find a specific RII property for the rule instance.
      * @param propName If not empty a PropertyPath element will added (with the passed value) after the <RuleID> element.
      * @param instanceID If not empty only for the reg ex will only valid for the passed instanceID. Otherwise for all.*/
     std::string GetRIIPropertyRegEx(const std::string propName = "", const InstanceIDType &instanceID = "") const;
 
     /**Helper function that deduces the instance ID out of a property name.
     If it cannot be deduced an MITK exception is thrown.*/
     static InstanceIDType GetInstanceIDByPropertyName(const std::string propName);
 
     /**Helper function that retrives the rule ID of a relation instance of a passed source.
      @pre source must be valid.
      @pre source must have a relation instance with this ID*/
     RuleIDType GetRuleIDByInstanceID(const IPropertyProvider *source,
       const InstanceIDType &instanceID) const;
+    /**Helper function that retrives the destination UID of a relation instance of a passed
+       source. If the relation has no destination UID, an empty string will be returned.
+       @pre source must be valid.*/
+    std::string GetDestinationUIDByInstanceID(const IPropertyProvider * source,
+      const InstanceIDType & instanceID) const;
 
     itk::LightObject::Pointer InternalClone() const override;
 
-    static std::vector<std::string> GetPropertyKeys(const mitk::IPropertyProvider *owner);
+    /** helper method that serves as a workaround until T24729 is done.
+       Please remove if T24728 is done then could directly use owner->GetPropertyKeys() again.*/
+    static std::vector<std::string> GetPropertyKeys(const IPropertyProvider *owner);
+
+    /** Helper method that tries to cast the provider to the Identifiable interface.*/
+    const Identifiable* CastProviderAsIdentifiable(const mitk::IPropertyProvider* provider) const;
 
   private:
     /** Creats a relation UID*/
     static RelationUIDType CreateRelationUID();
 
     /**Prepares a new relation instance. Therefore an unused and valid instance ID for the passed source will be genarated
     and a relationUID property with the relationUID will be set to block the instance ID. The
     instance ID will be returned.
     @remark The method is guarded by a class wide mutex to avoid racing conditions in a scenario where rules are used
     concurrently.*/
     InstanceIDType CreateNewRelationInstance(IPropertyOwner *source, const RelationUIDType &relationUID) const;
   };
 
   /**Exception that is used by PropertyRelationRuleBase based classes to indicate that two objects have no relation.*/
   class NoPropertyRelationException : public Exception
   {
   public:
     mitkExceptionClassMacro(NoPropertyRelationException, Exception)
   };
 
 } // namespace mitk
 
 #endif
diff --git a/Modules/Core/include/mitkSourceImageRelationRule.h b/Modules/Core/include/mitkSourceImageRelationRule.h
index 3b33d42e80..037959ca07 100644
--- a/Modules/Core/include/mitkSourceImageRelationRule.h
+++ b/Modules/Core/include/mitkSourceImageRelationRule.h
@@ -1,160 +1,129 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef mitkGenericIDRelationRule_h
 #define mitkGenericIDRelationRule_h
 
 #include "mitkPropertyRelationRuleBase.h"
 #include "mitkImage.h"
 
 namespace mitk
 {
   /**This rule class can be used for relations that reference an image as source for a destination entity.
   (e.g. an image that is used to generate the relation source).
   The ID-layer is supported like for GenericIDReleations.
   So it can be used for all ID based relations between PropertyProviders
   that also implement the interface identifiable.
   In addition the rule uses the data-layer to deduce/define relations.
   For this layer it uses properties compliant to DICOM. Thus (1) the information is stored in
   a DICOM Source Image Sequence item (0x0008,0x2112) and (2) the destination must have properties
   DICOM SOP Instance UIDs (0x0008, 0x0018) and DICOM SOP Class UID (0x0008, 0x0016). If the destination
   does not have this properties, no connection can be made on the data-layer.
   @remark Please note that PropertyRelationRules and DICOM use the term "source" differently. The DICOM
   source (image) equals the PropertyRelationRule destination. This is due to
   an inverted relation direction. So in the context of the SourceImageRelationRule interface a derived data is
   the source and points to the original image, it derives from. In the context of DICOM this referenced original image would be
   called source image (as the name of this class).
   In order to be able to use this class for different relation types (DICOM would call it purposes),
   the purposeTag is used. It must be specified when creating a rule instance.
   The purposeTag will be used as suffix for the rule ID of the instance and therefore allows to create
   specific and distinguishable rules instances based on this class.
   One may also specify the display name and the role names of the instance. If not specified the default values
   are used (display name: "<purposeTag> relation", source role name: "derived data",
   destination role name: "source image")
   */
   class MITKCORE_EXPORT SourceImageRelationRule : public mitk::PropertyRelationRuleBase
   {
   public:
     mitkClassMacro(SourceImageRelationRule, PropertyRelationRuleBase);
     itkNewMacro(Self);
     mitkNewMacro1Param(Self, const RuleIDType &);
     mitkNewMacro2Param(Self, const RuleIDType &, const std::string &);
     mitkNewMacro4Param(Self, const RuleIDType &, const std::string &, const std::string &, const std::string &);
 
     using RuleIDType = PropertyRelationRuleBase::RuleIDType;
     using RelationUIDType = PropertyRelationRuleBase::RelationUIDType;
     using RelationUIDVectorType = PropertyRelationRuleBase::RelationUIDVectorType;
 
     /** Returns an ID string that identifies the rule class */
     RuleIDType GetRuleID() const override;
 
     bool IsAbstract() const override;
 
     /** Returns a human readable string that can be used to describe the rule. Does not need to be unique.*/
     std::string GetDisplayName() const override;
 
     /** Returns a human readable string that can be used to describe the role of a source in context of the rule
      * instance.*/
     std::string GetSourceRoleName() const override;
     /** Returns a human readable string that can be used to describe the role of a destination in context of the rule
      * instance.*/
     std::string GetDestinationRoleName() const override;
 
     bool IsDestinationCandidate(const IPropertyProvider *owner) const override;
 
     /** Connects to passed images.
     @remark destination must specifiy DICOM SOP Instance UIDs (0x0008, 0x0018) and DICOM SOP Class UID (0x0008, 0x0016)
     in order to establish a connection on the data layer.*/
     RelationUIDType Connect(Image *source, const Image *destination) const;
 
   protected:
     SourceImageRelationRule();
     SourceImageRelationRule(const RuleIDType &purposeTag);
     SourceImageRelationRule(const RuleIDType &purposeTag, const std::string &displayName);
     SourceImageRelationRule(const RuleIDType &purposeTag,
                           const std::string &displayName,
                           const std::string &sourceRole,
                           const std::string &destinationRole);
     ~SourceImageRelationRule() override = default;
 
     using InstanceIDType = PropertyRelationRuleBase::InstanceIDType;
     using InstanceIDVectorType = PropertyRelationRuleBase::InstanceIDVectorType;
 
-    /** Helper function that returns a vector of all selections of the property DICOM.0008.2112 that refer to destination or all (if no destination is passed).*/
-    std::vector<std::string> GetReferenceSequenceIndices(const IPropertyProvider * source,
-      const IPropertyProvider * destination = nullptr) const;
-
-    /** Is called if a instance ID cannot be deduced on the ID-layer.
-    Implement this method to check which existing relation(s) as Connected_Data exists between
-    both passed instances. If the passed instances have no
-    explicit relation of type Connected_Data, an empty vector will be returned.
-    @remark Per definition of property relation rules only 0 or 1 instance should be found for one provider
-    pair and rule. But the data layer may be ambiguous and there for muliple relation instances of the rule instance
-    could match. The implementation of this function should report all relation instances. The calling function
-    will take care of this violation.
-    @pre source must be a pointer to a valid IPropertyProvider instance.
-    @pre destination must be a pointer to a valid IPropertyProvider instance.*/
-    InstanceIDVectorType GetInstanceID_datalayer(const IPropertyProvider *source,
-                                                         const IPropertyProvider *destination) const override;
-
-    /** Is called by HasRelation() if no relation of type Connected_ID (GetInstanceID_IDLayer()) or
-    Connected_Data (GetInstanceID_datalayer()) is evident.
-      Implement this method to deduce if the passed instances have a relation of type
-      Implicit_Data.
-      @pre source must be a pointer to a valid IPropertyProvider instance.
-      @pre destination must be a pointer to a valid IPropertyProvider instance.
-      */
-    bool HasImplicitDataRelation(const IPropertyProvider *source,
-                                         const IPropertyProvider *destination) const override;
-
-    /**Is called by Connect() to ensure that source has correctly set properties to resemble
-    the relation on the data layer. This means that the method should set the properties that describe
-    and encode the relation on the data layer (data-layer-specific relation properties).
-    If the passed instance are already connected, the old settings should be
-    overwritten. Connect() will ensure that source and destination are valid pointers.
-    @param instanceID is the ID for the relation instance that should be connected. Existance of the relation instance
-    is ensured.
-    @pre source must be a valid instance.
-    @pre destination must be a valid instance.*/
+    /** Helper function that returns a vector of all selections of the property DICOM.0008.2112 (and its associated ruleID) that refer to destination or all (if no destination is passed) with a supported RuleID
+     and which are not already covered by the ignoreInstances.*/
+    std::vector<std::pair<size_t, std::string> > GetReferenceSequenceIndices(const IPropertyProvider * source,
+      const IPropertyProvider* destination = nullptr, InstanceIDVectorType ignoreInstances = {}) const;
+
+    using DataRelationUIDVectorType = PropertyRelationRuleBase::DataRelationUIDVectorType;
+    virtual DataRelationUIDVectorType GetRelationUIDs_DataLayer(const IPropertyProvider* source,
+      const IPropertyProvider* destination, const InstanceIDVectorType& instances_IDLayer) const override;
+
     void Connect_datalayer(IPropertyOwner *source,
                                    const IPropertyProvider *destination,
                                    const InstanceIDType &instanceID) const override;
 
-    /**This method is called by Disconnect() to remove all properties of the relation from the source that
-    are set by Connect_datalayer().
-    @remark All RII-properties of this relation will removed by Disconnect() after this method call.
-    If the relationUID is not part of the source. Nothing will be changed. Disconnect() ensures that source is a valid
-    pointer if called.
-    @remark Disconnect() ensures that sourece is valid and only invokes if instance exists.*/
-    void Disconnect_datalayer(IPropertyOwner *source, const InstanceIDType &instanceID) const override;
+    void Disconnect_datalayer(IPropertyOwner *source, const RelationUIDType& relationUID) const override;
 
     bool IsSupportedRuleID(const RuleIDType& ruleID) const override;
 
     itk::LightObject::Pointer InternalClone() const override;
 
     /**Prepares a new reference to an image on the data layer. Therefore an unused and valid sequence item index
     for the passed source will be genarated and a relationUID property with the relationUID will be set to block the instance ID. The
     instance ID will be returned.
     @remark The method is guarded by a class wide mutex to avoid racing conditions in a scenario where rules are used
     concurrently.*/
     PropertyKeyPath::ItemSelectionIndex CreateNewSourceImageSequenceItem(IPropertyOwner *source) const;
 
+    std::string GenerateRuleID(const std::string& purpose) const;
+
   private:
     RuleIDType m_PurposeTag;
     std::string m_DisplayName;
     std::string m_SourceRole;
     std::string m_DestinationRole;
   };
 
 } // namespace mitk
 
 #endif
diff --git a/Modules/Core/include/mitkTemporoSpatialStringProperty.h b/Modules/Core/include/mitkTemporoSpatialStringProperty.h
index 9636f383c7..e261df1331 100644
--- a/Modules/Core/include/mitkTemporoSpatialStringProperty.h
+++ b/Modules/Core/include/mitkTemporoSpatialStringProperty.h
@@ -1,131 +1,136 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKTEMPOROSPATIALSTRINGPROPERTY_H_HEADER
 #define MITKTEMPOROSPATIALSTRINGPROPERTY_H_HEADER
 
 #include <itkConfigure.h>
 
 #include "mitkBaseProperty.h"
 #include <MitkCoreExports.h>
 
 #include "mitkTimeGeometry.h"
 
 #include <string>
 
 namespace mitk
 {
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable : 4522)
 #endif
 
   /**
    * @brief Property for time and space resolved string values
    * @ingroup DataManagement
    */
   class MITKCORE_EXPORT TemporoSpatialStringProperty : public BaseProperty
   {
   public:
     typedef ::itk::IndexValueType IndexValueType;
     typedef std::string ValueType;
 
     mitkClassMacro(TemporoSpatialStringProperty, BaseProperty);
 
     itkFactorylessNewMacro(Self);
 
     itkCloneMacro(Self);
     mitkNewMacro1Param(TemporoSpatialStringProperty, const char*);
     mitkNewMacro1Param(TemporoSpatialStringProperty, const std::string &);
 
     /**Returns the value of the first time point in the first slice.
      * If now value is set it returns an empty string.*/
     ValueType GetValue() const;
     /**Returns the value of the passed time step and slice. If it does not exist and allowedClosed is true
      * it will look for the closest value. If nothing could be found an empty string will be returned.*/
     ValueType GetValue(const TimeStepType &timeStep,
                        const IndexValueType &zSlice,
                        bool allowCloseTime = false,
                        bool allowCloseSlice = false) const;
     ValueType GetValueBySlice(const IndexValueType &zSlice, bool allowClose = false) const;
     ValueType GetValueByTimeStep(const TimeStepType &timeStep, bool allowClose = false) const;
 
     bool HasValue() const;
     bool HasValue(const TimeStepType &timeStep,
                   const IndexValueType &zSlice,
                   bool allowCloseTime = false,
                   bool allowCloseSlice = false) const;
     bool HasValueBySlice(const IndexValueType &zSlice, bool allowClose = false) const;
     bool HasValueByTimeStep(const TimeStepType &timeStep, bool allowClose = false) const;
 
     /** return all slices stored for the specified timestep.*/
     std::vector<IndexValueType> GetAvailableSlices(const TimeStepType& timeStep) const;
     /** return all time steps stored for the specified slice.*/
     std::vector<TimeStepType> GetAvailableTimeSteps(const IndexValueType& slice) const;
     /** return all time steps stored in the property.*/
     std::vector<TimeStepType> GetAvailableTimeSteps() const;
     /** return all slices stored in the property. @Remark not all time steps may contain all slices.*/
     std::vector<IndexValueType> GetAvailableSlices() const;
 
     void SetValue(const TimeStepType &timeStep, const IndexValueType &zSlice, const ValueType &value);
 
     void SetValue(const ValueType &value);
 
     std::string GetValueAsString() const override;
 
+    /** Inidicates of all values (all time steps, all slices) are the same, or if at least one value stored
+    in the property is different. If IsUniform==true one can i.a. use GetValueAsString() without the loss of
+    information to retrieve the stored value.*/
+    bool IsUniform() const;
+
     using BaseProperty::operator=;
 
   protected:
     typedef std::map<IndexValueType, std::string> SliceMapType;
     typedef std::map<TimeStepType, SliceMapType> TimeMapType;
 
     TimeMapType m_Values;
 
     TemporoSpatialStringProperty(const char *string = nullptr);
     TemporoSpatialStringProperty(const std::string &s);
 
     TemporoSpatialStringProperty(const TemporoSpatialStringProperty &);
 
     std::pair<bool, ValueType> CheckValue(const TimeStepType &timeStep,
                                           const IndexValueType &zSlice,
                                           bool allowCloseTime = false,
                                           bool allowCloseSlice = false) const;
 
   private:
     // purposely not implemented
     TemporoSpatialStringProperty &operator=(const TemporoSpatialStringProperty &);
 
     itk::LightObject::Pointer InternalClone() const override;
 
     bool IsEqual(const BaseProperty &property) const override;
     bool Assign(const BaseProperty &property) override;
   };
 
   namespace PropertyPersistenceSerialization
   {
     /** Serialization of a TemporoSpatialStringProperty into a JSON string.*/
     MITKCORE_EXPORT::std::string serializeTemporoSpatialStringPropertyToJSON(const mitk::BaseProperty *prop);
   }
 
   namespace PropertyPersistenceDeserialization
   {
     /**Deserialize a passed JSON string into a TemporoSpatialStringProperty.*/
     MITKCORE_EXPORT mitk::BaseProperty::Pointer deserializeJSONToTemporoSpatialStringProperty(const std::string &value);
   }
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 } // namespace mitk
 
 #endif
diff --git a/Modules/Core/src/DataManagement/mitkGenericIDRelationRule.cpp b/Modules/Core/src/DataManagement/mitkGenericIDRelationRule.cpp
index 7681bb1fb2..5d5bae9ea7 100644
--- a/Modules/Core/src/DataManagement/mitkGenericIDRelationRule.cpp
+++ b/Modules/Core/src/DataManagement/mitkGenericIDRelationRule.cpp
@@ -1,92 +1,85 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkGenericIDRelationRule.h"
 
 bool mitk::GenericIDRelationRule::IsAbstract() const
 {
   return m_RuleIDTag.empty();
 };
 
 bool mitk::GenericIDRelationRule::IsSupportedRuleID(const RuleIDType& ruleID) const
 {
   return ruleID == this->GetRuleID() || (IsAbstract() && ruleID.find("IDRelation_") == 0);
 };
 
 mitk::GenericIDRelationRule::RuleIDType mitk::GenericIDRelationRule::GetRuleID() const
 {
   return "IDRelation_" + m_RuleIDTag;
 };
 
 std::string mitk::GenericIDRelationRule::GetDisplayName() const
 {
   return m_DisplayName;
 };
 
 std::string mitk::GenericIDRelationRule::GetSourceRoleName() const
 {
   return m_SourceRole;
 };
 
 std::string mitk::GenericIDRelationRule::GetDestinationRoleName() const
 {
   return m_DestinationRole;
 };
 
 mitk::GenericIDRelationRule::RelationUIDType mitk::GenericIDRelationRule::Connect(IPropertyOwner *source, const IPropertyProvider *destination) const
 {
   return Superclass::Connect(source, destination);
 };
 
 mitk::GenericIDRelationRule::GenericIDRelationRule(const RuleIDType &ruleIDTag)
   : GenericIDRelationRule(ruleIDTag, ruleIDTag + " relation"){};
 
 mitk::GenericIDRelationRule::GenericIDRelationRule(const RuleIDType &ruleIDTag, const std::string &displayName)
   : GenericIDRelationRule(
       ruleIDTag, displayName, "source of " + ruleIDTag + " relation", "destination of " + ruleIDTag + " relation"){};
 
 mitk::GenericIDRelationRule::GenericIDRelationRule(const RuleIDType &ruleIDTag,
                                                    const std::string &displayName,
                                                    const std::string &sourceRole,
                                                    const std::string &destinationRole)
   : m_RuleIDTag(ruleIDTag), m_DisplayName(displayName), m_SourceRole(sourceRole), m_DestinationRole(destinationRole){};
 
-mitk::GenericIDRelationRule::InstanceIDVectorType mitk::GenericIDRelationRule::GetInstanceID_datalayer(
-  const IPropertyProvider * /*source*/, const IPropertyProvider * /*destination*/) const
+mitk::GenericIDRelationRule::DataRelationUIDVectorType mitk::GenericIDRelationRule::GetRelationUIDs_DataLayer(
+  const IPropertyProvider * /*source*/, const IPropertyProvider * /*destination*/, const InstanceIDVectorType& /*instances_IDLayer*/) const
 {
   // Data layer is not supported by the class. Therefore return empty vector.
-  return InstanceIDVectorType();
-};
-
-bool mitk::GenericIDRelationRule::HasImplicitDataRelation(const IPropertyProvider * /*source*/,
-                                                          const IPropertyProvider * /*destination*/) const
-{
-  // Data layer is not supported by the class.
-  return false;
+  return DataRelationUIDVectorType();
 };
 
 void mitk::GenericIDRelationRule::Connect_datalayer(IPropertyOwner * /*source*/,
                                                     const IPropertyProvider * /*destination*/,
                                                     const InstanceIDType & /*instanceID*/) const {
   // Data layer is not supported by the class. => Do nothing
 };
 
-void mitk::GenericIDRelationRule::Disconnect_datalayer(IPropertyOwner * /*source*/, const InstanceIDType & /*instanceID*/) const {
+void mitk::GenericIDRelationRule::Disconnect_datalayer(IPropertyOwner * /*source*/, const RelationUIDType & /*relationUID*/) const {
   // Data layer is not supported by the class. => Do nothing
 };
 
 itk::LightObject::Pointer mitk::GenericIDRelationRule::InternalClone() const
 {
   itk::LightObject::Pointer result = Self::New(this->m_RuleIDTag, this->m_DisplayName, this->m_SourceRole, this->m_DestinationRole).GetPointer();
 
   return result;
 };
diff --git a/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp b/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp
index 83a2993207..27fa3f08a1 100644
--- a/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp
+++ b/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp
@@ -1,596 +1,605 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <algorithm>
 #include <utility>
 
 #include <mitkExceptionMacro.h>
 #include <mitkPropertyKeyPath.h>
 
 #include <regex>
 
 namespace mitk
 {
   PropertyKeyPath::NodeInfo::NodeInfo() : type(NodeType::Invalid), selection(0){};
 
   PropertyKeyPath::NodeInfo::NodeInfo(const ElementNameType &name, NodeType type, ItemSelectionIndex index)
     : type(type), name(name), selection(index){};
 
   bool PropertyKeyPath::NodeInfo::operator==(const NodeInfo &right) const
   {
     if (this->name != right.name)
       return false;
     if (this->type != right.type)
       return false;
     if (this->selection != right.selection)
       return false;
 
     return true;
   };
 
   bool PropertyKeyPath::NodeInfo::Matches(const NodeInfo &right) const
   {
     if (type == NodeType::Invalid || right.type == NodeType::Invalid)
     {
       return false;
     }
     else if (type == NodeType::AnyElement || right.type == NodeType::AnyElement)
     {
       return true;
     }
     else if (name == right.name)
     {
       if (type == NodeType::Element && right.type == NodeType::Element)
       {
         return true;
       }
       else if (selection == right.selection || type == NodeType::AnySelection || right.type == NodeType::AnySelection)
       {
         return true;
       }
     }
     return false;
   };
 
   bool PropertyKeyPath::IsEmpty() const { return m_NodeInfos.empty(); };
 
   bool PropertyKeyPath::IsExplicit() const
   {
     for (const auto &pos : m_NodeInfos)
     {
       if ((pos.type == NodeInfo::NodeType::AnySelection) || (pos.type == NodeInfo::NodeType::AnyElement))
       {
         return false;
       }
     }
 
     return true;
   };
 
   bool PropertyKeyPath::HasItemSelectionWildcardsOnly() const
   {
     bool result = false;
     for (const auto &pos : m_NodeInfos)
     {
       if (pos.type == NodeInfo::NodeType::AnyElement)
       {
         return false;
       }
       result = result || pos.type == NodeInfo::NodeType::AnySelection;
     }
 
     return result;
   };
 
   PropertyKeyPath::PathIndexType PropertyKeyPath::GetSize() const { return m_NodeInfos.size(); }
 
   PropertyKeyPath::PathIndexType PropertyKeyPath::AddNode(const NodeInfo &newNode)
   {
     m_NodeInfos.push_back(newNode);
     return m_NodeInfos.size() - 1;
   };
 
   const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetNode(const PathIndexType &index) const
   {
     if (index >= GetSize())
     {
       mitkThrowException(InvalidPathNodeException)
         << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index
         << "; Path: " << PropertyKeyPathToPropertyName(*this);
     }
 
     return m_NodeInfos[index];
   };
 
   PropertyKeyPath::NodeInfo &PropertyKeyPath::GetNode(const PathIndexType &index)
   {
     if (index >= this->GetSize())
     {
       mitkThrowException(InvalidPathNodeException)
         << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index
         << "; Path: " << PropertyKeyPathToPropertyName(*this);
     }
 
     return m_NodeInfos[index];
   };
 
   const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetFirstNode() const
   {
     if (m_NodeInfos.empty())
     {
       mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty.";
     }
     return this->GetNode(0);
   };
 
   PropertyKeyPath::NodeInfo &PropertyKeyPath::GetFirstNode()
   {
     if (m_NodeInfos.empty())
     {
       mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty.";
     }
     return this->GetNode(0);
   };
 
   const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetLastNode() const
   {
     if (m_NodeInfos.empty())
     {
       mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty.";
     }
     return this->GetNode(GetSize() - 1);
   };
 
   PropertyKeyPath::NodeInfo &PropertyKeyPath::GetLastNode()
   {
     if (m_NodeInfos.empty())
     {
       mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty.";
     }
     return this->GetNode(GetSize() - 1);
   };
 
   const PropertyKeyPath::NodeInfoVectorType &PropertyKeyPath::GetNodes() const { return m_NodeInfos; };
 
   bool PropertyKeyPath::operator==(const PropertyKeyPath &path) const { return m_NodeInfos == path.m_NodeInfos; };
 
   bool PropertyKeyPath::operator<(const PropertyKeyPath &right) const
   {
     auto rightIter = right.m_NodeInfos.cbegin();
     const auto rightEnd = right.m_NodeInfos.cend();
     for (const auto &leftPos : m_NodeInfos)
     {
       if (rightIter == rightEnd)
       {
         return false;
       }
 
       if (leftPos.name < rightIter->name)
       {
         return true;
       }
       if (rightIter->name < leftPos.name)
       {
         return false;
       }
 
       if (leftPos.type < rightIter->type)
       {
         return true;
       }
       if (rightIter->type < leftPos.type)
       {
         return false;
       }
 
       if (leftPos.selection < rightIter->selection)
       {
         return true;
       }
       if (rightIter->selection < leftPos.selection)
       {
         return false;
       }
 
       ++rightIter;
     }
     return rightIter != rightEnd;
   }
 
   bool PropertyKeyPath::operator>(const PropertyKeyPath &right) const
   {
     auto rightIter = right.m_NodeInfos.cbegin();
     const auto rightEnd = right.m_NodeInfos.cend();
     for (const auto &leftPos : m_NodeInfos)
     {
       if (rightIter == rightEnd)
         return false;
 
       if (leftPos.name > rightIter->name)
         return true;
       if (rightIter->name > leftPos.name)
         return false;
 
       if (leftPos.type > rightIter->type)
         return true;
       if (rightIter->type > leftPos.type)
         return false;
 
       if (leftPos.selection > rightIter->selection)
         return true;
       if (rightIter->selection > leftPos.selection)
         return false;
       ++rightIter;
     }
     return rightIter != rightEnd;
   }
 
   bool PropertyKeyPath::operator>=(const PropertyKeyPath &right) const { return !(*this < right); }
 
   bool PropertyKeyPath::operator<=(const PropertyKeyPath &right) const { return !(*this > right); }
 
   bool PropertyKeyPath::Equals(const PropertyKeyPath &path) const { return PropertyKeyPathsMatch(*this, path); };
 
   PropertyKeyPath &PropertyKeyPath::operator=(const PropertyKeyPath &path)
   {
     if (this != &path)
     {
       m_NodeInfos = path.m_NodeInfos;
     }
 
     return *this;
   };
 
   PropertyKeyPath &PropertyKeyPath::AddAnyElement()
   {
     m_NodeInfos.emplace_back("", NodeInfo::NodeType::AnyElement);
     return *this;
   };
 
   PropertyKeyPath &PropertyKeyPath::AddElement(const ElementNameType &name)
   {
     m_NodeInfos.emplace_back(name, NodeInfo::NodeType::Element);
     return *this;
   };
 
   PropertyKeyPath &PropertyKeyPath::AddAnySelection(const ElementNameType &name)
   {
     m_NodeInfos.emplace_back(name, NodeInfo::NodeType::AnySelection);
     return *this;
   };
 
   PropertyKeyPath &PropertyKeyPath::AddSelection(const ElementNameType &name, ItemSelectionIndex index)
   {
     m_NodeInfos.emplace_back(name, NodeInfo::NodeType::ElementSelection, index);
     return *this;
   };
 
   PropertyKeyPath::PropertyKeyPath() { this->Reset(); };
 
   PropertyKeyPath::PropertyKeyPath(const PropertyKeyPath &path) { *this = path; };
 
+  PropertyKeyPath::PropertyKeyPath(const std::initializer_list< ElementNameType >& list)
+  {
+    this->Reset();
+    for (const auto& name : list)
+    {
+      this->AddElement(name);
+    }
+  }
+
   PropertyKeyPath::~PropertyKeyPath(){};
 
   void PropertyKeyPath::Reset() { m_NodeInfos.clear(); };
 
   bool PropertyKeyPath::PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right)
   {
     auto leftPos = left.GetNodes().cbegin();
     auto rightPos = right.GetNodes().cbegin();
     auto leftEnd = left.GetNodes().cend();
     auto rightEnd = right.GetNodes().cend();
 
     while (leftPos != leftEnd && rightPos != rightEnd)
     {
       if (!leftPos->Matches(*rightPos))
       {
         break;
       }
       ++leftPos;
       ++rightPos;
     }
 
     if (leftPos == leftEnd && rightPos == rightEnd)
     {
       return true;
     }
     else
     {
       return false;
     }
   };
 
   std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &value)
   {
     os << PropertyKeyPathToPropertyName(value);
     return os;
   };
 
   std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath)
   {
     std::ostringstream nameStream;
 
     PropertyKeyPath::PathIndexType i = 0;
 
     for (const auto &node : tagPath.GetNodes())
     {
       if (i)
       {
         nameStream << "\\.";
       }
       ++i;
 
       if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement)
       {
         nameStream << "([a-zA-Z0-9- ]+)";
       }
       else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
       {
         nameStream << node.name;
 
         if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection)
         {
           nameStream << "\\.\\[" << node.selection << "\\]";
         }
         else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection)
         {
           nameStream << "\\.\\[(\\d*)\\]";
         }
       }
       else
       {
         nameStream << "INVALIDNODE";
       }
     }
 
     return nameStream.str();
   };
 
   std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath)
   {
     std::ostringstream nameStream;
 
     PropertyKeyPath::PathIndexType i = 0;
 
     for (const auto &node : tagPath.GetNodes())
     {
       if (i)
       {
         nameStream << "_";
       }
       ++i;
 
       if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement)
       {
         nameStream << "([a-zA-Z0-9- ]+)";
       }
       else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
       {
         nameStream << node.name;
 
         if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection)
         {
           nameStream << "_\\[" << node.selection << "\\]";
         }
         else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection)
         {
           nameStream << "_\\[(\\d*)\\]";
         }
       }
       else
       {
         nameStream << "INVALIDNODE";
       }
     }
 
     return nameStream.str();
   };
 
   std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath)
   {
     std::ostringstream nameStream;
 
     int captureGroup = 1;
 
     PropertyKeyPath::PathIndexType i = 0;
 
     for (const auto &node : tagPath.GetNodes())
     {
       if (i)
       {
         nameStream << "_";
       }
       ++i;
 
       if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement)
       {
         nameStream << "$" << captureGroup++;
       }
       else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
       {
         nameStream << node.name;
 
         if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection)
         {
           nameStream << "_[" << node.selection << "]";
         }
         else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection)
         {
           nameStream << "_[$" << captureGroup++ << "]";
         }
       }
       else
       {
         nameStream << "INVALID_NODE";
       }
     }
 
     return nameStream.str();
   };
 
   std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath)
   {
     std::ostringstream nameStream;
 
     int captureGroup = 1;
 
     PropertyKeyPath::PathIndexType i = 0;
 
     for (const auto &node : tagPath.GetNodes())
     {
       if (i)
       {
         nameStream << ".";
       }
       ++i;
 
       if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement)
       {
         nameStream << "$" << captureGroup++;
       }
       else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
       {
         nameStream << node.name;
 
         if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection)
         {
           nameStream << ".[" << node.selection << "]";
         }
         else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection)
         {
           nameStream << ".[$" << captureGroup++ << "]";
         }
       }
       else
       {
         nameStream << "INVALID_NODE";
       }
     }
 
     return nameStream.str();
   };
 
   PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName)
   {
     PropertyKeyPath result;
 
     std::regex reg_element("([a-zA-Z0-9- ]+)");
     std::regex reg_anySelection("\\[\\*\\]");
     std::regex reg_Selection("\\[(\\d+)\\]");
 
     std::istringstream f(propertyName);
     std::string subStr;
 
     PropertyKeyPath::ElementNameType name = "";
 
     while (getline(f, subStr, '.'))
     {
       if (subStr == "*")
       {
         if (!name.empty())
         {
           result.AddElement(name);
           name.clear();
         }
 
         result.AddAnyElement();
       }
       else
       {
         std::smatch sm;
         if (std::regex_match(subStr, sm, reg_anySelection))
         {
           if (!name.empty())
           {
             result.AddAnySelection(name);
             name.clear();
           }
           else
           { // invalid path
             return PropertyKeyPath();
           }
         }
         else if (std::regex_match(subStr, sm, reg_Selection))
         {
           if (!name.empty())
           {
             result.AddSelection(name, std::stoi(sm[1]));
             name.clear();
           }
           else
           { // invalid path
             return PropertyKeyPath();
           }
         }
         else if (std::regex_match(subStr, sm, reg_element))
         {
           if (!name.empty())
           { // store the last element and start the next
             result.AddElement(name);
           }
           name = sm[1];
         }
         else
         {
           return PropertyKeyPath();
         }
       }
     }
 
     if (!name.empty())
     { // add last element
       result.AddElement(name);
     }
 
     return result;
   };
 
   std::string PropertyKeyPathToPropertyName(const mitk::PropertyKeyPath &tagPath)
   {
     std::ostringstream nameStream;
 
     PropertyKeyPath::PathIndexType i = 0;
 
     for (const auto &node : tagPath.GetNodes())
     {
       if (i)
       {
         nameStream << ".";
       }
       ++i;
 
       if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement)
       {
         nameStream << "*";
       }
       else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid)
       {
         nameStream << node.name;
 
         if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection)
         {
           nameStream << ".[" << node.selection << "]";
         }
         else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection)
         {
           nameStream << ".[*]";
         }
       }
       else
       {
         nameStream << "INVALID_NODE";
       }
     }
 
     return nameStream.str();
   };
 } // namespace mitk
diff --git a/Modules/Core/src/DataManagement/mitkPropertyRelationRuleBase.cpp b/Modules/Core/src/DataManagement/mitkPropertyRelationRuleBase.cpp
index 8bfd7d09d6..e05a314b21 100644
--- a/Modules/Core/src/DataManagement/mitkPropertyRelationRuleBase.cpp
+++ b/Modules/Core/src/DataManagement/mitkPropertyRelationRuleBase.cpp
@@ -1,758 +1,852 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkPropertyRelationRuleBase.h"
 
 #include <mitkDataNode.h>
 #include <mitkExceptionMacro.h>
 #include <mitkNodePredicateBase.h>
 #include <mitkStringProperty.h>
 #include <mitkUIDGenerator.h>
 
 #include <mutex>
 #include <regex>
+#include <algorithm>
 
 bool mitk::PropertyRelationRuleBase::IsAbstract() const
 {
   return true;
-};
+}
 
 bool mitk::PropertyRelationRuleBase::IsSourceCandidate(const IPropertyProvider *owner) const
 {
   return owner != nullptr;
-};
+}
 
 bool mitk::PropertyRelationRuleBase::IsDestinationCandidate(const IPropertyProvider *owner) const
 {
   return owner != nullptr;
-};
+}
 
 mitk::PropertyKeyPath mitk::PropertyRelationRuleBase::GetRootKeyPath()
 {
   return PropertyKeyPath().AddElement("MITK").AddElement("Relations");
-};
+}
 
 bool mitk::PropertyRelationRuleBase::IsSupportedRuleID(const RuleIDType& ruleID) const
 {
   return ruleID == this->GetRuleID();
-};
+}
 
 
 std::string mitk::PropertyRelationRuleBase::GetRIIPropertyRegEx(const std::string propName, const InstanceIDType &instanceID) const
 {
   auto path = this->GetRootKeyPath();
   if (instanceID.empty())
   {
     path.AddAnyElement();
   }
   else
   {
     path.AddElement(instanceID);
   }
 
   if (!propName.empty())
   {
     path.AddElement(propName);
   }
 
   return PropertyKeyPathToPropertyRegEx(path);
-};
+}
 
 //workaround until T24729 is done. Please remove if T24728 is done
 //then could directly use owner->GetPropertyKeys() again.
 std::vector<std::string> mitk::PropertyRelationRuleBase::GetPropertyKeys(const mitk::IPropertyProvider *owner)
 {
   std::vector<std::string> keys;
   auto sourceCasted = dynamic_cast<const mitk::DataNode*>(owner);
   if (sourceCasted) {
     auto sourceData = sourceCasted->GetData();
     if (sourceData) {
       keys = sourceData->GetPropertyKeys();
     }
     else {
       keys = sourceCasted->GetPropertyKeys();
     }
   }
   else {
     keys = owner->GetPropertyKeys();
   }
   return keys;
-};
+}
 //end workaround for T24729
 
-
 bool mitk::PropertyRelationRuleBase::IsSource(const IPropertyProvider *owner) const
 {
-  if (!owner)
-  {
-    mitkThrow() << "Error. Passed owner pointer is NULL";
-  }
+  return !this->GetExistingRelations(owner).empty();
+}
 
-  std::vector<std::string> keys;
-  //workaround until T24729 is done. Please remove if T24728 is done
-  keys = GetPropertyKeys(owner);
-  //end workaround for T24729
+bool mitk::PropertyRelationRuleBase::HasRelation(
+  const IPropertyProvider* source, const IPropertyProvider* destination, RelationType requiredRelation) const
+{
+  auto relTypes = this->GetRelationTypes(source, destination);
 
-  auto sourceRegExStr = this->GetRIIPropertyRegEx("ruleID");
-  auto regEx = std::regex(sourceRegExStr);
 
-  for (const auto &key : keys)
+  if (requiredRelation == RelationType::None)
   {
-    if (std::regex_match(key, regEx))
-    {
-      auto idProp = owner->GetConstProperty(key);
-      auto ruleID = idProp->GetValueAsString();
-      if (this->IsSupportedRuleID(ruleID))
-      {
-        return true;
-      }
-    }
+    return !relTypes.empty();
   }
 
-  return false;
-};
+  RelationVectorType allowedTypes = { RelationType::Complete };
+  if (requiredRelation == RelationType::Data)
+  {
+    allowedTypes.emplace_back(RelationType::Data);
+  }
+  else if (requiredRelation == RelationType::ID)
+  {
+    allowedTypes.emplace_back(RelationType::ID);
+  }
 
-mitk::PropertyRelationRuleBase::RelationType mitk::PropertyRelationRuleBase::HasRelation(
-  const IPropertyProvider *source, const IPropertyProvider *destination) const
+  return relTypes.end() != std::find_first_of(relTypes.begin(), relTypes.end(), allowedTypes.begin(), allowedTypes.end());
+}
+
+mitk::PropertyRelationRuleBase::RelationVectorType mitk::PropertyRelationRuleBase::GetRelationTypes(
+  const IPropertyProvider* source, const IPropertyProvider* destination) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Passed source pointer is NULL";
   }
   if (!destination)
   {
     mitkThrow() << "Error. Passed owner pointer is NULL";
   }
 
-  RelationType result = RelationType::None;
-
-  if (!this->GetInstanceID_IDLayer(source, destination).empty())
-  { // has relations of type Connected_ID;
-    result = RelationType::Connected_ID;
+  auto instanceIDs_IDLayer = this->GetInstanceID_IDLayer(source, destination);
+  auto relIDs_dataLayer = this->GetRelationUIDs_DataLayer(source, destination, {});
+  if (relIDs_dataLayer.size() > 1)
+  {
+    MITK_WARN << "Property relation on data level is ambiguous. First relation is used. Relation UID: "
+              << relIDs_dataLayer.front().first;
   }
 
-  if (result == RelationType::None)
+  bool hasComplete = instanceIDs_IDLayer.end() != std::find_if(instanceIDs_IDLayer.begin(), instanceIDs_IDLayer.end(), [&](const InstanceIDVectorType::value_type& instanceID)
   {
-    auto instanceIDs_data = this->GetInstanceID_datalayer(source, destination);
+    auto relID_IDlayer = this->GetRelationUIDByInstanceID(source, instanceID);
+    auto ruleID_IDlayer = this->GetRuleIDByInstanceID(source, instanceID);
 
-    if (instanceIDs_data.size() > 1)
+    return relIDs_dataLayer.end() != std::find_if(relIDs_dataLayer.begin(), relIDs_dataLayer.end(), [&](const DataRelationUIDVectorType::value_type& relID)
     {
-      MITK_WARN << "Property relation on data level is ambiguous. First relation is used. Instance ID: "
-                << instanceIDs_data.front();
-    }
+      return relID.first == relID_IDlayer && relID.second == ruleID_IDlayer;
+    });
+  });
 
-    if (!instanceIDs_data.empty() && instanceIDs_data.front() != NULL_INSTANCE_ID())
-    { // has relations of type Connected_Data;
-      result = RelationType::Connected_Data;
-    }
-  }
+  bool hasID = instanceIDs_IDLayer.end() != std::find_if(instanceIDs_IDLayer.begin(), instanceIDs_IDLayer.end(), [&](const InstanceIDVectorType::value_type& instanceID)
+  {
+    auto relID_IDlayer = this->GetRelationUIDByInstanceID(source, instanceID);
+    auto ruleID_IDlayer = this->GetRuleIDByInstanceID(source, instanceID);
+
+    return relIDs_dataLayer.end() == std::find_if(relIDs_dataLayer.begin(), relIDs_dataLayer.end(), [&](const DataRelationUIDVectorType::value_type& relID)
+    {
+      return relID.first == relID_IDlayer && relID.second == ruleID_IDlayer;
+    });
+  });
 
-  if (result == RelationType::None)
+  bool hasData = relIDs_dataLayer.end() != std::find_if(relIDs_dataLayer.begin(), relIDs_dataLayer.end(), [&](const DataRelationUIDVectorType::value_type& relID)
   {
-    if (this->HasImplicitDataRelation(source, destination))
-    { // has relations of type Connected_Data;
-      result = RelationType::Implicit_Data;
-    }
+    return instanceIDs_IDLayer.end() == std::find_if(instanceIDs_IDLayer.begin(), instanceIDs_IDLayer.end(), [&](const InstanceIDVectorType::value_type& instanceID)
+    {
+      auto relID_IDlayer = this->GetRelationUIDByInstanceID(source, instanceID);
+      auto ruleID_IDlayer = this->GetRuleIDByInstanceID(source, instanceID);
+      return relID.first == relID_IDlayer && relID.second == ruleID_IDlayer;
+    });
+  });
+
+  RelationVectorType result;
+
+  if (hasData)
+  {
+    result.emplace_back(RelationType::Data);
+  }
+  if (hasID)
+  {
+    result.emplace_back(RelationType::ID);
+  }
+  if (hasComplete)
+  {
+    result.emplace_back(RelationType::Complete);
   }
 
   return result;
-};
+}
 
 mitk::PropertyRelationRuleBase::RelationUIDVectorType mitk::PropertyRelationRuleBase::GetExistingRelations(
-  const IPropertyProvider *source) const
+  const IPropertyProvider *source, RelationType layer) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Passed source pointer is NULL";
   }
 
-  auto ruleIDRegExStr = this->GetRIIPropertyRegEx("ruleID");
-  auto regEx = std::regex(ruleIDRegExStr);
-
-  //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed.
-  const auto keys = GetPropertyKeys(source);
-  //end workaround for T24729
-
   RelationUIDVectorType relationUIDs;
+  InstanceIDVectorType instanceIDs;
 
-  for (const auto &key : keys)
+  if (layer != RelationType::Data)
   {
-    if (std::regex_match(key, regEx))
+    auto ruleIDRegExStr = this->GetRIIPropertyRegEx("ruleID");
+    auto regEx = std::regex(ruleIDRegExStr);
+
+    //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed.
+    const auto keys = GetPropertyKeys(source);
+    //end workaround for T24729
+
+    for (const auto& key : keys)
     {
-      auto idProp = source->GetConstProperty(key);
-      auto ruleID = idProp->GetValueAsString();
-      if (this->IsSupportedRuleID(ruleID))
+      if (std::regex_match(key, regEx))
       {
-        auto instanceID = this->GetInstanceIDByPropertyName(key);
-        relationUIDs.push_back(this->GetRelationUIDByInstanceID(source, instanceID));
+        auto idProp = source->GetConstProperty(key);
+        auto ruleID = idProp->GetValueAsString();
+        if (this->IsSupportedRuleID(ruleID))
+        {
+          auto instanceID = this->GetInstanceIDByPropertyName(key);
+          instanceIDs.emplace_back(instanceID);
+          relationUIDs.push_back(this->GetRelationUIDByInstanceID(source, instanceID));
+        }
       }
     }
   }
 
-  return relationUIDs;
-};
+  if (layer == RelationType::ID)
+  {
+    return relationUIDs;
+  }
+
+  DataRelationUIDVectorType relationUIDandRuleID_Data;
+  if (layer != RelationType::ID)
+  {
+    relationUIDandRuleID_Data = this->GetRelationUIDs_DataLayer(source, nullptr, instanceIDs);
+  }
+
+  RelationUIDVectorType relationUIDs_Data;
+  std::transform(relationUIDandRuleID_Data.begin(), relationUIDandRuleID_Data.end(), std::back_inserter(relationUIDs_Data),
+    [](const DataRelationUIDVectorType::value_type& v) { return v.first; });
+
+  if (layer == RelationType::Data)
+  {
+    return relationUIDs_Data;
+  }
+
+  std::sort(relationUIDs.begin(), relationUIDs.end());
+  std::sort(relationUIDs_Data.begin(), relationUIDs_Data.end());
+
+  RelationUIDVectorType result;
+
+  if (layer == RelationType::Complete)
+  {
+    std::set_intersection(relationUIDs.begin(), relationUIDs.end(), relationUIDs_Data.begin(), relationUIDs_Data.end(), std::back_inserter(result));
+  }
+  else
+  {
+    std::set_union(relationUIDs.begin(), relationUIDs.end(), relationUIDs_Data.begin(), relationUIDs_Data.end(), std::back_inserter(result));
+  }
+
+  return result;
+}
 
 mitk::PropertyRelationRuleBase::RelationUIDVectorType mitk::PropertyRelationRuleBase::GetRelationUIDs(
   const IPropertyProvider *source, const IPropertyProvider *destination) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Passed source pointer is NULL";
   }
   if (!destination)
   {
     mitkThrow() << "Error. Passed destination pointer is NULL";
   }
 
-  RelationUIDVectorType result;
+  RelationUIDVectorType relUIDs_id;
 
   auto instanceIDs = this->GetInstanceID_IDLayer(source, destination);
   for (const auto instanceID : instanceIDs)
   {
-    result.push_back(this->GetRelationUIDByInstanceID(source, instanceID));
+    relUIDs_id.push_back(this->GetRelationUIDByInstanceID(source, instanceID));
   }
 
-  if (result.empty() || this->IsAbstract())
-  {
-    auto instanceIDs_data = this->GetInstanceID_datalayer(source, destination);
+  DataRelationUIDVectorType relationUIDandRuleID_Data = this->GetRelationUIDs_DataLayer(source,destination,instanceIDs);
+  RelationUIDVectorType relUIDs_Data;
+  std::transform(relationUIDandRuleID_Data.begin(), relationUIDandRuleID_Data.end(), std::back_inserter(relUIDs_Data),
+    [](const DataRelationUIDVectorType::value_type& v) { return v.first; });
 
-    for (const auto instanceID : instanceIDs_data)
-    {
-      if (std::find(std::begin(instanceIDs), std::end(instanceIDs), instanceID) == std::end(instanceIDs))
-      {
-        result.push_back(this->GetRelationUIDByInstanceID(source, instanceID));
-      }
-    }
-  }
+  std::sort(relUIDs_id.begin(), relUIDs_id.end());
+  std::sort(relUIDs_Data.begin(), relUIDs_Data.end());
+
+  RelationUIDVectorType result;
+  std::set_union(relUIDs_id.begin(), relUIDs_id.end(), relUIDs_Data.begin(), relUIDs_Data.end(), std::back_inserter(result));
 
   return result;
-};
+}
 
 mitk::PropertyRelationRuleBase::RelationUIDType
 mitk::PropertyRelationRuleBase::GetRelationUID(const IPropertyProvider *source, const IPropertyProvider *destination) const
 {
   auto result = this->GetRelationUIDs(source, destination);
 
   if (result.empty())
   {
     mitkThrowException(NoPropertyRelationException);
   }
   else if(result.size()>1)
   {
     mitkThrow() << "Cannot return one(!) relation UID. Multiple relations exists for given rule, source and destination.";
   }
 
   return result[0];
-};
+}
 
 mitk::PropertyRelationRuleBase::InstanceIDType mitk::PropertyRelationRuleBase::NULL_INSTANCE_ID()
 {
   return std::string();
 };
 
 mitk::PropertyRelationRuleBase::RelationUIDType mitk::PropertyRelationRuleBase::GetRelationUIDByInstanceID(
   const IPropertyProvider *source, const InstanceIDType &instanceID) const
 {
   RelationUIDType result;
 
   if (instanceID != NULL_INSTANCE_ID())
   {
     auto idProp = source->GetConstProperty(
       PropertyKeyPathToPropertyName(this->GetRootKeyPath().AddElement(instanceID).AddElement("relationUID")));
 
     if (idProp.IsNotNull())
     {
       result = idProp->GetValueAsString();
     }
   }
 
   if (result.empty())
   {
     mitkThrowException(NoPropertyRelationException);
   }
 
   return result;
-};
+}
 
 mitk::PropertyRelationRuleBase::InstanceIDType mitk::PropertyRelationRuleBase::GetInstanceIDByRelationUID(
   const IPropertyProvider *source, const RelationUIDType &relationUID) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Passed source pointer is NULL";
   }
 
   InstanceIDType result = NULL_INSTANCE_ID();
 
   auto destRegExStr =
     PropertyKeyPathToPropertyRegEx(GetRootKeyPath().AddAnyElement().AddElement("relationUID"));
   auto regEx = std::regex(destRegExStr);
   std::smatch instance_matches;
 
   //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed.
   const auto keys = GetPropertyKeys(source);
   //end workaround for T24729
 
   for (const auto &key : keys)
   {
     if (std::regex_search(key, instance_matches, regEx))
     {
       auto idProp = source->GetConstProperty(key);
       if (idProp->GetValueAsString() == relationUID)
       {
         if (instance_matches.size()>1)
         {
           result = instance_matches[1];
           break;
         }
       }
     }
   }
 
   return result;
-};
+}
 
 mitk::PropertyRelationRuleBase::InstanceIDVectorType mitk::PropertyRelationRuleBase::GetInstanceID_IDLayer(
   const IPropertyProvider *source, const IPropertyProvider *destination) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Passed source pointer is NULL";
   }
   if (!destination)
   {
     mitkThrow() << "Error. Passed destination pointer is NULL";
   }
 
-  auto identifiable = dynamic_cast<const Identifiable *>(destination);
-
-  if (!identifiable)
-  { //This check and pass through to data is needed due to solve T25711. See Task for more information.
-    //This could be removed at the point we can get rid of DataNodes or they get realy transparent.
-    auto node = dynamic_cast<const DataNode*>(destination);
-    if (node && node->GetData())
-    {
-      identifiable = dynamic_cast<const Identifiable *>(node->GetData());
-    }
-  }
+  auto identifiable = CastProviderAsIdentifiable(destination);
 
   InstanceIDVectorType result;
 
   if (identifiable)
   { // check for relations of type Connected_ID;
 
     auto destRegExStr = this->GetRIIPropertyRegEx("destinationUID");
     auto regEx = std::regex(destRegExStr);
     std::smatch instance_matches;
 
     auto destUID = identifiable->GetUID();
 
     //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed.
     const auto keys = GetPropertyKeys(source);
     //end workaround for T24729
 
     for (const auto &key : keys)
     {
       if (std::regex_search(key, instance_matches, regEx))
       {
         auto idProp = source->GetConstProperty(key);
         if (idProp->GetValueAsString() == destUID)
         {
           if (instance_matches.size()>1)
           {
             auto instanceID = instance_matches[1];
             if (this->IsSupportedRuleID(GetRuleIDByInstanceID(source, instanceID)))
             {
               result.push_back(instanceID);
             }
           }
         }
       }
     }
   }
 
   return result;
-};
+}
+
+const mitk::Identifiable* mitk::PropertyRelationRuleBase::CastProviderAsIdentifiable(const mitk::IPropertyProvider* destination) const
+{
+  auto identifiable = dynamic_cast<const Identifiable*>(destination);
+
+  if (!identifiable)
+  { //This check and pass through to data is needed due to solve T25711. See Task for more information.
+    //This could be removed at the point we can get rid of DataNodes or they get realy transparent.
+    auto node = dynamic_cast<const DataNode*>(destination);
+    if (node && node->GetData())
+    {
+      identifiable = dynamic_cast<const Identifiable*>(node->GetData());
+    }
+  }
+
+  return identifiable;
+}
 
 mitk::PropertyRelationRuleBase::RelationUIDType mitk::PropertyRelationRuleBase::Connect(IPropertyOwner *source, const IPropertyProvider *destination) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Passed source pointer is NULL";
   }
   if (!destination)
   {
     mitkThrow() << "Error. Passed destination pointer is NULL";
   }
   if (this->IsAbstract())
   {
     mitkThrow() << "Error. This is an abstract property relation rule. Abstract rule must not make a connection. Please use a concrete rule.";
   }
 
   auto instanceIDs = this->GetInstanceID_IDLayer(source, destination);
   bool hasIDlayer = !instanceIDs.empty();
 
-  auto instanceIDs_data = this->GetInstanceID_datalayer(source, destination);
-  if (instanceIDs_data.size() > 1)
-  {
-    MITK_WARN << "Property relation on data level is ambiguous. First relation is used. Instance ID: "
-              << instanceIDs_data.front();
-  }
-  bool hasDatalayer = !instanceIDs_data.empty();
+  auto relUIDs_data = this->GetRelationUIDs_DataLayer(source, destination, {});
 
-  if (hasIDlayer && hasDatalayer && instanceIDs.front() != instanceIDs_data.front())
+  if (relUIDs_data.size() > 1)
   {
-    mitkThrow() << "Property relation information is in an invalid state. ID and data layer point to different "
-                   "relation instances. Rule: "
-                << this->GetRuleID() << "; ID based instance: " << instanceIDs.front()
-                << "; Data base instance: " << instanceIDs_data.front();
+    MITK_WARN << "Property relation on data level is ambiguous. First relation is used. RelationUID ID: "
+              << relUIDs_data.front().first;
   }
 
+  bool hasDatalayer = !relUIDs_data.empty();
+
   RelationUIDType relationUID = this->CreateRelationUID();
 
-  InstanceIDType instanceID = "";
+  InstanceIDType instanceID = NULL_INSTANCE_ID();
 
   if (hasIDlayer)
   {
     instanceID = instanceIDs.front();
   }
   else if (hasDatalayer)
   {
-    instanceID = instanceIDs_data.front();
+    try
+    {
+      instanceID = this->GetInstanceIDByRelationUID(source, relUIDs_data.front().first);
+    }
+    catch(...)
+    { }
   }
-  else
+
+  if(instanceID == NULL_INSTANCE_ID())
   {
     instanceID = this->CreateNewRelationInstance(source, relationUID);
   }
 
   auto relUIDKey =
     PropertyKeyPathToPropertyName(GetRootKeyPath().AddElement(instanceID).AddElement("relationUID"));
   source->SetProperty(relUIDKey, mitk::StringProperty::New(relationUID));
 
   auto ruleIDKey =
     PropertyKeyPathToPropertyName(GetRootKeyPath().AddElement(instanceID).AddElement("ruleID"));
   source->SetProperty(ruleIDKey, mitk::StringProperty::New(this->GetRuleID()));
 
   if (!hasIDlayer)
   {
-    auto identifiable = dynamic_cast<const Identifiable *>(destination);
-
-    if (!identifiable)
-    { //This check and pass through to data is needed due to solve T25711. See Task for more information.
-      //This could be removed at the point we can get rid of DataNodes or they get realy transparent.
-      auto node = dynamic_cast<const DataNode*>(destination);
-      if (node && node->GetData())
-      {
-        identifiable = dynamic_cast<const Identifiable *>(node->GetData());
-      }
-    }
+    auto identifiable = this->CastProviderAsIdentifiable(destination);
 
     if (identifiable)
     {
       auto destUIDKey =
         PropertyKeyPathToPropertyName(GetRootKeyPath().AddElement(instanceID).AddElement("destinationUID"));
       source->SetProperty(destUIDKey, mitk::StringProperty::New(identifiable->GetUID()));
     }
   }
 
-  if (!hasDatalayer)
-  {
-    this->Connect_datalayer(source, destination, instanceID);
-  }
+  this->Connect_datalayer(source, destination, instanceID);
 
   return relationUID;
-};
+}
 
-void mitk::PropertyRelationRuleBase::Disconnect(IPropertyOwner *source, const IPropertyProvider *destination) const
+void mitk::PropertyRelationRuleBase::Disconnect(IPropertyOwner *source, const IPropertyProvider *destination, RelationType layer) const
 {
+  if (source == nullptr)
+  {
+    mitkThrow() << "Error. Source is invalid. Cannot disconnect.";
+  }
+
+  if (destination == nullptr)
+  {
+    mitkThrow() << "Error. Destination is invalid. Cannot disconnect.";
+  }
+
   try
   {
     const auto relationUIDs = this->GetRelationUIDs(source, destination);
     for (const auto relUID: relationUIDs)
     {
-      this->Disconnect(source, relUID);
+      this->Disconnect(source, relUID, layer);
     }
   }
   catch (const NoPropertyRelationException &)
   {
     // nothing to do and no real error in context of disconnect.
   }
-};
+}
 
-void mitk::PropertyRelationRuleBase::Disconnect(IPropertyOwner *source, RelationUIDType relationUID) const
+void mitk::PropertyRelationRuleBase::Disconnect(IPropertyOwner *source, RelationUIDType relationUID, RelationType layer) const
 {
-  auto instanceID = this->GetInstanceIDByRelationUID(source, relationUID);
+  if (source == nullptr)
+  {
+    mitkThrow() << "Error. Source is invalid. Cannot disconnect.";
+  }
 
-  if (instanceID != NULL_INSTANCE_ID())
+  if (layer == RelationType::Data || layer == RelationType::Complete)
   {
-    this->Disconnect_datalayer(source, instanceID);
+    this->Disconnect_datalayer(source, relationUID);
+  }
 
+  auto instanceID = this->GetInstanceIDByRelationUID(source, relationUID);
+  if ((layer == RelationType::ID || layer == RelationType::Complete) && instanceID != NULL_INSTANCE_ID())
+  {
     auto instancePrefix = PropertyKeyPathToPropertyName(GetRootKeyPath().AddElement(instanceID));
 
     //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed.
     const auto keys = GetPropertyKeys(source);
     //end workaround for T24729
 
 
     for (const auto &key : keys)
     {
       if (key.find(instancePrefix) == 0)
       {
         source->RemoveProperty(key);
       }
     }
   }
-};
+}
 
 mitk::PropertyRelationRuleBase::RelationUIDType mitk::PropertyRelationRuleBase::CreateRelationUID()
 {
   UIDGenerator generator;
   return generator.GetUID();
-};
+}
 
 /**This mutex is used to guard mitk::PropertyRelationRuleBase::CreateNewRelationInstance by a class wide mutex to avoid
   racing conditions in a scenario where rules are used concurrently. It is not in the class interface itself, because it
   is an implementation detail.
 */
 std::mutex relationCreationLock;
 
 mitk::PropertyRelationRuleBase::InstanceIDType mitk::PropertyRelationRuleBase::CreateNewRelationInstance(
   IPropertyOwner *source, const RelationUIDType &relationUID) const
 {
   std::lock_guard<std::mutex> guard(relationCreationLock);
 
   //////////////////////////////////////
   // Get all existing instanc IDs
 
   std::vector<int> instanceIDs;
   InstanceIDType newID = "1";
 
   auto destRegExStr =
     PropertyKeyPathToPropertyRegEx(this->GetRootKeyPath().AddAnyElement().AddElement("relationUID"));
   auto regEx = std::regex(destRegExStr);
   std::smatch instance_matches;
 
   //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed.
   const auto keys = GetPropertyKeys(source);
   //end workaround for T24729
 
 
   for (const auto &key : keys)
   {
     if (std::regex_search(key, instance_matches, regEx))
     {
       if (instance_matches.size()>1)
       {
         instanceIDs.push_back(std::stoi(instance_matches[1]));
       }
     }
   }
 
   //////////////////////////////////////
   // Get new ID
 
   std::sort(instanceIDs.begin(), instanceIDs.end());
   if (!instanceIDs.empty())
   {
     newID = std::to_string(instanceIDs.back() + 1);
   }
 
   //////////////////////////////////////
   // reserve new ID
   auto relUIDKey =
     PropertyKeyPathToPropertyName(this->GetRootKeyPath().AddElement(newID).AddElement("relationUID"));
   source->SetProperty(relUIDKey, mitk::StringProperty::New(relationUID));
 
   return newID;
-};
+}
 
 itk::LightObject::Pointer mitk::PropertyRelationRuleBase::InternalClone() const
 {
   return Superclass::InternalClone();
-};
+}
 
 
 mitk::PropertyRelationRuleBase::InstanceIDType mitk::PropertyRelationRuleBase::GetInstanceIDByPropertyName(const std::string propName)
 {
   auto proppath = PropertyNameToPropertyKeyPath(propName);
   auto ref = GetRootKeyPath();
 
   if (proppath.GetSize() < 3 || !(proppath.GetFirstNode() == ref.GetFirstNode()) || !(proppath.GetNode(1) == ref.GetNode(1)))
   {
     mitkThrow() << "Property name is not for a RII property or containes no instance ID. Wrong name: " << propName;
   }
 
   return proppath.GetNode(2).name;
-};
+}
 
 mitk::PropertyRelationRuleBase::RuleIDType mitk::PropertyRelationRuleBase::GetRuleIDByInstanceID(const IPropertyProvider *source,
   const InstanceIDType &instanceID) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Source is invalid. Cannot deduce rule ID";
   }
 
   auto path = GetRootKeyPath().AddElement(instanceID).AddElement("ruleID");
   auto name = PropertyKeyPathToPropertyName(path);
 
   const auto prop = source->GetConstProperty(name);
 
   std::string result;
 
  if (prop.IsNotNull())
  {
    result = prop->GetValueAsString();
  }
 
   if (result.empty())
   {
     mitkThrowException(NoPropertyRelationException) << "Error. Source has no property relation with the passed instance ID. Instance ID: " << instanceID;
   }
 
   return result;
-};
+}
+
+std::string mitk::PropertyRelationRuleBase::GetDestinationUIDByInstanceID(const IPropertyProvider* source,
+  const InstanceIDType& instanceID) const
+{
+  if (!source)
+  {
+    mitkThrow() << "Error. Source is invalid. Cannot deduce rule ID";
+  }
+
+  auto path = GetRootKeyPath().AddElement(instanceID).AddElement("destinationUID");
+  auto name = PropertyKeyPathToPropertyName(path);
+
+  const auto prop = source->GetConstProperty(name);
+
+  std::string result;
+
+  if (prop.IsNotNull())
+  {
+    result = prop->GetValueAsString();
+  }
+
+  return result;
+}
+
 
 namespace mitk
 {
   /**
   * \brief Predicate used to wrap rule checks.
   *
   * \ingroup DataStorage
   */
   class NodePredicateRuleFunction : public NodePredicateBase
   {
   public:
     using FunctionType = std::function<bool(const mitk::IPropertyProvider *, const mitk::PropertyRelationRuleBase *)>;
 
     mitkClassMacro(NodePredicateRuleFunction, NodePredicateBase)
       mitkNewMacro2Param(NodePredicateRuleFunction, const FunctionType &, PropertyRelationRuleBase::ConstPointer)
 
     ~NodePredicateRuleFunction() override = default;
 
     bool CheckNode(const mitk::DataNode *node) const override
     {
       if (!node)
       {
         return false;
       }
 
       return m_Function(node, m_Rule);
     };
 
   protected:
     explicit NodePredicateRuleFunction(const FunctionType &function, PropertyRelationRuleBase::ConstPointer rule) : m_Function(function), m_Rule(rule)
     {
     };
 
     FunctionType m_Function;
     PropertyRelationRuleBase::ConstPointer m_Rule;
   };
 
 } // namespace mitk
 
 mitk::NodePredicateBase::ConstPointer mitk::PropertyRelationRuleBase::GetSourceCandidateIndicator() const
 {
   auto check = [](const mitk::IPropertyProvider *node, const mitk::PropertyRelationRuleBase *rule) {
     return rule->IsSourceCandidate(node);
   };
 
   return NodePredicateRuleFunction::New(check, this).GetPointer();
-};
+}
 
 mitk::NodePredicateBase::ConstPointer mitk::PropertyRelationRuleBase::GetDestinationCandidateIndicator() const
 {
   auto check = [](const mitk::IPropertyProvider *node, const mitk::PropertyRelationRuleBase *rule) {
     return rule->IsDestinationCandidate(node);
   };
 
   return NodePredicateRuleFunction::New(check, this).GetPointer();
-};
+}
 
 mitk::NodePredicateBase::ConstPointer mitk::PropertyRelationRuleBase::GetConnectedSourcesDetector() const
 {
   auto check = [](const mitk::IPropertyProvider *node, const mitk::PropertyRelationRuleBase *rule)
   {
     return rule->IsSource(node);
   };
 
   return NodePredicateRuleFunction::New(check, this).GetPointer();
-};
+}
 
 mitk::NodePredicateBase::ConstPointer mitk::PropertyRelationRuleBase::GetSourcesDetector(
-  const IPropertyProvider *destination, RelationType minimalRelation) const
+  const IPropertyProvider *destination, RelationType exclusiveRelation) const
 {
   if (!destination)
   {
     mitkThrow() << "Error. Passed destination pointer is NULL";
   }
 
-  auto check = [destination, minimalRelation](const mitk::IPropertyProvider *node,
+  auto check = [destination, exclusiveRelation](const mitk::IPropertyProvider *node,
                                               const mitk::PropertyRelationRuleBase *rule) {
-    return rule->HasRelation(node, destination) >= minimalRelation;
+    return rule->HasRelation(node, destination, exclusiveRelation);
   };
 
   return NodePredicateRuleFunction::New(check, this).GetPointer();
-};
+}
 
 mitk::NodePredicateBase::ConstPointer mitk::PropertyRelationRuleBase::GetDestinationsDetector(
-  const IPropertyProvider *source, RelationType minimalRelation) const
+  const IPropertyProvider *source, RelationType exclusiveRelation) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Passed source pointer is NULL";
   }
 
-  auto check = [source, minimalRelation](const mitk::IPropertyProvider *node,
+  auto check = [source, exclusiveRelation](const mitk::IPropertyProvider *node,
                                          const mitk::PropertyRelationRuleBase *rule) {
-    return rule->HasRelation(source, node) >= minimalRelation;
+    return rule->HasRelation(source, node, exclusiveRelation);
   };
 
   return NodePredicateRuleFunction::New(check, this).GetPointer();
-};
+}
 
 mitk::NodePredicateBase::ConstPointer mitk::PropertyRelationRuleBase::GetDestinationDetector(
   const IPropertyProvider *source, RelationUIDType relationUID) const
 {
   if (!source)
   {
     mitkThrow() << "Error. Passed source pointer is NULL";
   }
 
   auto relUIDs = this->GetExistingRelations(source);
   if (std::find(relUIDs.begin(), relUIDs.end(), relationUID) == relUIDs.end())
   {
     mitkThrow()
       << "Error. Passed relationUID does not identify a relation instance of the passed source for this rule instance.";
   };
 
   auto check = [source, relationUID](const mitk::IPropertyProvider *node, const mitk::PropertyRelationRuleBase *rule) {
     try
     {
       auto relevantUIDs = rule->GetRelationUIDs(source, node);
       for (const auto& aUID : relevantUIDs)
       {
         if (aUID == relationUID)
         {
           return true;
         }
       }
     }
     catch(const NoPropertyRelationException &)
     {
       return false;
     }
     return false;
   };
 
   return NodePredicateRuleFunction::New(check, this).GetPointer();
-};
+}
diff --git a/Modules/Core/src/DataManagement/mitkSourceImageRelationRule.cpp b/Modules/Core/src/DataManagement/mitkSourceImageRelationRule.cpp
index 175829e218..6d9b58e301 100644
--- a/Modules/Core/src/DataManagement/mitkSourceImageRelationRule.cpp
+++ b/Modules/Core/src/DataManagement/mitkSourceImageRelationRule.cpp
@@ -1,376 +1,414 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <regex>
 #include <mutex>
 
 #include "mitkSourceImageRelationRule.h"
 #include "mitkPropertyNameHelper.h"
 #include "mitkStringProperty.h"
 #include "mitkTemporoSpatialStringProperty.h"
 #include "mitkDataNode.h"
+#include "mitkIdentifiable.h"
 
+std::string mitk::SourceImageRelationRule::GenerateRuleID(const std::string& purpose) const
+{
+  return "SourceImageRelation " + purpose;
+}
 
 bool mitk::SourceImageRelationRule::IsAbstract() const
 {
   return m_PurposeTag.empty();
 };
 
 bool mitk::SourceImageRelationRule::IsSupportedRuleID(const RuleIDType& ruleID) const
 {
   return ruleID == this->GetRuleID() || (IsAbstract() && ruleID.find("SourceImageRelation ") == 0);
 };
 
 mitk::SourceImageRelationRule::RuleIDType mitk::SourceImageRelationRule::GetRuleID() const
 {
-  return "SourceImageRelation " + m_PurposeTag;
+  return this->GenerateRuleID(m_PurposeTag);
 };
 
 std::string mitk::SourceImageRelationRule::GetDisplayName() const
 {
   return m_DisplayName;
 };
 
 std::string mitk::SourceImageRelationRule::GetSourceRoleName() const
 {
   return m_SourceRole;
 };
 
 std::string mitk::SourceImageRelationRule::GetDestinationRoleName() const
 {
   return m_DestinationRole;
 };
 
 bool mitk::SourceImageRelationRule::IsDestinationCandidate(const IPropertyProvider *owner) const
 {
   auto node = dynamic_cast<const DataNode*>(owner);
 
   auto image = nullptr != node
     ? dynamic_cast<const Image*>(node->GetData())
     : dynamic_cast<const Image*>(owner);
 
   return image != nullptr;
 }
 
 mitk::SourceImageRelationRule::RelationUIDType mitk::SourceImageRelationRule::Connect(Image *source, const Image *destination) const
 {
   return Superclass::Connect(source, destination);
 };
 
 mitk::SourceImageRelationRule::SourceImageRelationRule()
   : m_PurposeTag(""), m_DisplayName("Abstract image to image relation"), m_SourceRole("derived data"), m_DestinationRole("source image")
 {};
 
 mitk::SourceImageRelationRule::SourceImageRelationRule(const RuleIDType &purposeTag)
   : SourceImageRelationRule(purposeTag, purposeTag + " relation"){};
 
 mitk::SourceImageRelationRule::SourceImageRelationRule(const RuleIDType &purposeTag, const std::string &displayName)
   : SourceImageRelationRule(
       purposeTag, displayName, "derived data", "source image"){};
 
 mitk::SourceImageRelationRule::SourceImageRelationRule(const RuleIDType &purposeTag,
                                                    const std::string &displayName,
                                                    const std::string &sourceRole,
                                                    const std::string &destinationRole)
   : m_PurposeTag(purposeTag), m_DisplayName(displayName), m_SourceRole(sourceRole), m_DestinationRole(destinationRole){};
 
-mitk::SourceImageRelationRule::InstanceIDVectorType mitk::SourceImageRelationRule::GetInstanceID_datalayer(
-  const IPropertyProvider * source, const IPropertyProvider * destination) const
+mitk::SourceImageRelationRule::DataRelationUIDVectorType
+mitk::SourceImageRelationRule::GetRelationUIDs_DataLayer(const IPropertyProvider* source,
+  const IPropertyProvider* destination, const InstanceIDVectorType& instances_IDLayer) const
 {
-  InstanceIDVectorType result;
+  DataRelationUIDVectorType result;
 
-  auto relevantReferenceIndices = GetReferenceSequenceIndices(source, destination);
+  auto relevantIndicesAndRuleIDs = GetReferenceSequenceIndices(source, destination, instances_IDLayer);
 
-  auto itemRegExStr = this->GetRIIPropertyRegEx("SourceImageSequenceItem");
-  auto regEx = std::regex(itemRegExStr);
+  auto itemRIIRegExStr = this->GetRIIPropertyRegEx("SourceImageSequenceItem");
+  auto regEx = std::regex(itemRIIRegExStr);
 
   //workaround until T24729 is done. Please remove if T24728 is done
   auto keys = PropertyRelationRuleBase::GetPropertyKeys(source);
   //end workaround for T24729
 
-  for (const auto &key : keys)
+  for (const auto &indexNRule : relevantIndicesAndRuleIDs)
   {
-    if (std::regex_match(key, regEx))
+    bool relationCoveredByRII = false;
+    for (const auto& key : keys)
     {
-      auto sequItemProp = source->GetConstProperty(key);
-      if (sequItemProp.IsNotNull())
+      if (std::regex_match(key, regEx))
       {
-        auto finding = std::find(std::cbegin(relevantReferenceIndices), std::cend(relevantReferenceIndices), sequItemProp->GetValueAsString());
-        if (finding != std::cend(relevantReferenceIndices))
+        auto sequItemProp = source->GetConstProperty(key);
+        if (sequItemProp.IsNotNull() && sequItemProp->GetValueAsString() == std::to_string(indexNRule.first))
         {
+          relationCoveredByRII = true;
           auto instanceID = GetInstanceIDByPropertyName(key);
           auto ruleID = GetRuleIDByInstanceID(source, instanceID);
           if (this->IsSupportedRuleID(ruleID))
           {
-            result.push_back(instanceID);
+            result.emplace_back(this->GetRelationUIDByInstanceID(source, instanceID), ruleID);
           }
         }
       }
     }
+
+    if (!relationCoveredByRII)
+    {
+      //the relation is not covered on the RII level, so we generate the property path to the DICOM source reference (this is done via
+      //the SOP Instance UIDs which uniquely identify an DICOM IOD). We use this property path as relation UID because it is identifying
+      //on the data level (even so not long term stable if relations with a lower index are removed).
+      PropertyKeyPath referencedInstanceUIDs;
+      referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddSelection("2112", indexNRule.first).AddElement("0008").AddElement("1155");
+
+      std::string ruleID = "";
+      if (!indexNRule.second.empty())
+      {
+        ruleID = this->GenerateRuleID(indexNRule.second);
+      }
+
+      result.emplace_back(PropertyKeyPathToPropertyName(referencedInstanceUIDs), ruleID);
+    }
   }
 
   return result;
 };
 
-std::vector<std::string> mitk::SourceImageRelationRule::GetReferenceSequenceIndices(const IPropertyProvider * source,
-  const IPropertyProvider * destination) const
+std::vector<std::pair<size_t,std::string> > mitk::SourceImageRelationRule::GetReferenceSequenceIndices(const IPropertyProvider * source,
+  const IPropertyProvider * destination, InstanceIDVectorType ignoreInstances) const
 {
-  std::vector<std::string> result;
+  std::vector<std::pair<size_t, std::string> > result;
 
   BaseProperty::ConstPointer destInstanceUIDProp;
+  std::string destinationUID = "";
 
   if (destination)
   {
     destInstanceUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008, 0x0018));
 
     if (destInstanceUIDProp.IsNull())
     {
       return result;
     }
+
+    auto identifiable = this->CastProviderAsIdentifiable(destination);
+
+    if (identifiable)
+    {
+      destinationUID= identifiable->GetUID();
+    }
+  }
+
+  std::vector<std::string> ignoreItemIndices;
+  for (const auto& iID : ignoreInstances)
+  {
+    auto sourceImageRefPath = GetRootKeyPath().AddElement(iID).AddElement("SourceImageSequenceItem");
+    auto imageRefProp = source->GetConstProperty(PropertyKeyPathToPropertyName(sourceImageRefPath));
+
+    if (imageRefProp.IsNotNull())
+    {
+      ignoreItemIndices.emplace_back(imageRefProp->GetValueAsString());
+    }
   }
 
   PropertyKeyPath referencedInstanceUIDs;
   referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddAnySelection("2112").AddElement("0008").AddElement("1155");
 
-  auto sourceRegExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs);;
+  auto sourceRegExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs);
   auto regEx = std::regex(sourceRegExStr);
 
   std::vector<std::string> keys;
   //workaround until T24729 is done. Please remove if T24728 is done
   keys = PropertyRelationRuleBase::GetPropertyKeys(source);
   //end workaround for T24729
 
   for (const auto &key : keys)
   {
     if (std::regex_match(key, regEx))
     {
       auto refUIDProp = source->GetConstProperty(key);
       if (destination==nullptr || *refUIDProp == *destInstanceUIDProp)
       {
         auto currentKeyPath = PropertyNameToPropertyKeyPath(key);
         auto currentKeyPathSelection = currentKeyPath.GetNode(2).selection;
-        PropertyKeyPath purposePath;
-        purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", currentKeyPathSelection).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104");
 
-        auto purposeProp = source->GetConstProperty(PropertyKeyPathToPropertyName(purposePath));
-        if (this->IsAbstract() || (purposeProp.IsNotNull() && purposeProp->GetValueAsString() == this->m_PurposeTag))
+        auto finding = std::find(ignoreItemIndices.begin(), ignoreItemIndices.end(), std::to_string(currentKeyPathSelection));
+        if (finding == ignoreItemIndices.end())
         {
-          result.push_back(std::to_string(currentKeyPathSelection));
+          PropertyKeyPath purposePath;
+          purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", currentKeyPathSelection).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104");
+          auto purposeProp = source->GetConstProperty(PropertyKeyPathToPropertyName(purposePath));
+          std::string currentPurpose = "";
+          if (purposeProp.IsNotNull())
+          {
+            currentPurpose = purposeProp->GetValueAsString();
+          }
+          if (this->IsAbstract() || (purposeProp.IsNotNull() && currentPurpose == this->m_PurposeTag))
+          {
+            result.emplace_back(currentKeyPathSelection, currentPurpose);
+          }
         }
       }
     }
   }
 
   return result;
 };
 
-bool mitk::SourceImageRelationRule::HasImplicitDataRelation(const IPropertyProvider * source,
-                                                          const IPropertyProvider * destination) const
-{
-  auto relevantReferences = GetReferenceSequenceIndices(source, destination);
-
-  if (this->IsAbstract())
-  {
-    return !relevantReferences.empty();
-  }
-  else
-  {
-    for (auto referenceIndex : relevantReferences)
-    {
-      PropertyKeyPath purposePath;
-      purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", std::stoi(referenceIndex)).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104");
-      auto purposeProp = source->GetConstProperty(PropertyKeyPathToPropertyName(purposePath));
-
-      if (purposeProp.IsNotNull() && purposeProp->GetValueAsString() == this->m_PurposeTag)
-      {
-        return true;
-      }
-    }
-  }
-
-  return false;
-};
-
-
 /**This mutex is used to guard mitk::SourceImageRelationRule::CreateNewSourceImageSequenceItem by a class wide mutex to avoid
 racing conditions in a scenario where rules are used concurrently. It is not in the class interface itself, because it
 is an implementation detail.
 */
 namespace
 {
   std::mutex sequenceItemCreationLock;
 }
 
 mitk::PropertyKeyPath::ItemSelectionIndex mitk::SourceImageRelationRule::CreateNewSourceImageSequenceItem(
   IPropertyOwner *source) const
 {
   std::lock_guard<std::mutex> guard(sequenceItemCreationLock);
 
   //////////////////////////////////////
   // Get all existing sequence items
 
   std::vector<PropertyKeyPath::ItemSelectionIndex> instanceIDs;
   PropertyKeyPath::ItemSelectionIndex newID = 0;
 
   PropertyKeyPath referencedInstanceUIDs;
   referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddAnySelection("2112").AddElement("0008").AddElement("1155");
   auto regExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs);
   auto regEx = std::regex(regExStr);
   std::smatch instance_matches;
 
   //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed.
   const auto keys = GetPropertyKeys(source);
   //end workaround for T24729
 
   for (const auto &key : keys)
   {
     if (std::regex_search(key, instance_matches, regEx))
     {
       if (instance_matches.size()>1)
       {
         instanceIDs.push_back(std::stoi(instance_matches[1]));
       }
     }
   }
 
   //////////////////////////////////////
   // Get new ID
 
   std::sort(instanceIDs.begin(), instanceIDs.end());
   if (!instanceIDs.empty())
   {
     newID = instanceIDs.back()+1;
   }
 
   //////////////////////////////////////
   // reserve new ID
 
   PropertyKeyPath newSourceImageSequencePath;
   newSourceImageSequencePath.AddElement("DICOM").AddElement("0008").AddSelection("2112",newID).AddElement("0008").AddElement("1155");
 
   auto newKey =
     PropertyKeyPathToPropertyName(newSourceImageSequencePath);
   source->SetProperty(newKey, mitk::TemporoSpatialStringProperty::New("reserved slot for source image sequence"));
 
   return newID;
 };
 
 
 void mitk::SourceImageRelationRule::Connect_datalayer(IPropertyOwner * source,
                                                     const IPropertyProvider * destination,
                                                     const InstanceIDType & instanceID) const
 {
   auto destInstanceUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008,0x0018));
   auto destClassUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008, 0x0016));
 
   if (destInstanceUIDProp.IsNotNull() && destClassUIDProp.IsNotNull())
   {
     auto existingRefs = this->GetReferenceSequenceIndices(source, destination);
     std::string  newSelectionIndexStr;
     if (!existingRefs.empty())
     {
-      newSelectionIndexStr = existingRefs[0];
+      newSelectionIndexStr = std::to_string(existingRefs[0].first);
     }
     else
     {
       PropertyKeyPath::ItemSelectionIndex newSelectionIndex = CreateNewSourceImageSequenceItem(source);
 
       PropertyKeyPath refInstanceUIDPath;
       refInstanceUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0008").AddElement("1155");
       source->SetProperty(PropertyKeyPathToPropertyName(refInstanceUIDPath), destInstanceUIDProp->Clone());
 
       PropertyKeyPath refClassUIDPath;
       refClassUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0008").AddElement("1150");
       source->SetProperty(PropertyKeyPathToPropertyName(refClassUIDPath), destClassUIDProp->Clone());
 
       PropertyKeyPath purposePath;
       purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104");
       source->SetProperty(PropertyKeyPathToPropertyName(purposePath), StringProperty::New(m_PurposeTag));
 
       newSelectionIndexStr = std::to_string(newSelectionIndex);
     }
 
     auto sourceImageRefPath = GetRootKeyPath().AddElement(instanceID).AddElement("SourceImageSequenceItem");
     source->SetProperty(PropertyKeyPathToPropertyName(sourceImageRefPath), StringProperty::New(newSelectionIndexStr).GetPointer());
   }
   else
   {
     MITK_DEBUG << "Cannot connect SourceImageRelationRule on data layer. Passed destination does not have properties for DICOM SOP Instance UIDs(0x0008, 0x0018) and DICOM SOP Class UID(0x0008, 0x0016)";
   }
 };
 
-void mitk::SourceImageRelationRule::Disconnect_datalayer(IPropertyOwner * source, const InstanceIDType & instanceID) const
+void mitk::SourceImageRelationRule::Disconnect_datalayer(IPropertyOwner * source, const RelationUIDType & relationUID) const
 {
-  auto sourceImageRefPath = GetRootKeyPath().AddElement(instanceID).AddElement("SourceImageSequenceItem");
-  auto imageRefProp = source->GetConstProperty(PropertyKeyPathToPropertyName(sourceImageRefPath));
+  std::string deletedImageRefSequenceIndexStr = "";
 
-  if (imageRefProp.IsNotNull())
+  if (relationUID.find("DICOM") == 0)
+  { //relation that is purly data based.
+    auto currentKeyPath = PropertyNameToPropertyKeyPath(relationUID);
+    deletedImageRefSequenceIndexStr = std::to_string(currentKeyPath.GetNode(2).selection);
+  }
+  else
   {
-    auto deletedImageRefSequenceIndex = imageRefProp->GetValueAsString();
+    auto sourceImageRefPath = GetRootKeyPath().AddElement(this->GetInstanceIDByRelationUID(source,relationUID)).AddElement("SourceImageSequenceItem");
+    auto imageRefProp = source->GetConstProperty(PropertyKeyPathToPropertyName(sourceImageRefPath));
+    if (imageRefProp.IsNotNull())
+    {
+      deletedImageRefSequenceIndexStr = imageRefProp->GetValueAsString();
+    }
+  }
 
+  if(!deletedImageRefSequenceIndexStr.empty())
+  {
+    auto deletedImageRefSequenceIndex = std::stoull(deletedImageRefSequenceIndexStr);
     auto refs = GetReferenceSequenceIndices(source);
     std::sort(refs.begin(), refs.end());
 
-    for (auto refIndexStr : refs)
+    for (auto refIndex : refs)
     {
-      auto refIndex = std::stoi(refIndexStr);
-
-      if (refIndex >= std::stoi(deletedImageRefSequenceIndex))
+      if (refIndex.first >= deletedImageRefSequenceIndex)
       {
         PropertyKeyPath refDICOMDataPath;
-        refDICOMDataPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", refIndex);
+        refDICOMDataPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", refIndex.first);
         auto prefix = PropertyKeyPathToPropertyName(refDICOMDataPath);
 
         PropertyKeyPath refRelDataPath = GetRootKeyPath().AddAnyElement().AddElement("SourceImageSequenceItem");;
-        auto regEx = std::regex(PropertyKeyPathToPropertyRegEx(refRelDataPath));
+        auto riiRegEx = std::regex(PropertyKeyPathToPropertyRegEx(refRelDataPath));
 
         //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed.
         const auto keys = GetPropertyKeys(source);
         //end workaround for T24729
 
         for (const auto &key : keys)
         {
           if (key.find(prefix) == 0)
           { //its a relevant DICOM property delete or update
-            if (refIndexStr != deletedImageRefSequenceIndex)
+            if (refIndex.first != deletedImageRefSequenceIndex)
             {
               //reindex to close the gap in the dicom sequence.
               auto newPath = PropertyNameToPropertyKeyPath(key);
-              newPath.GetNode(2).selection = refIndex - 1;
+              newPath.GetNode(2).selection = refIndex.first - 1;
               source->SetProperty(PropertyKeyPathToPropertyName(newPath), source->GetNonConstProperty(key));
             }
             //remove old/outdated data layer information
             source->RemoveProperty(key);
-
-            auto sourceImageRefPath = GetRootKeyPath().AddElement(instanceID).AddElement("SourceImageSequenceItem");
           }
-          if (std::regex_match(key, regEx))
-          {
+          if (std::regex_match(key, riiRegEx))
+          { //it is a relevant RII property, remove it or update it.
             auto imageSequenceItemProp = source->GetConstProperty(key);
-            if (imageSequenceItemProp->GetValueAsString() == std::to_string(refIndex))
+            if (imageSequenceItemProp->GetValueAsString() == deletedImageRefSequenceIndexStr)
+            {
+              source->RemoveProperty(key);
+            }
+            else if (imageSequenceItemProp->GetValueAsString() == std::to_string(refIndex.first))
             {
-              //its a relevant data property of the relation rule.
-              source->SetProperty(key, StringProperty::New(std::to_string(refIndex - 1)));
+              //its a relevant data property of the relation rule reindex it.
+              source->SetProperty(key, StringProperty::New(std::to_string(refIndex.first - 1)));
             }
           }
         }
       }
     }
   }
 };
 
 itk::LightObject::Pointer mitk::SourceImageRelationRule::InternalClone() const
 {
   itk::LightObject::Pointer result = Self::New(this->m_PurposeTag, this->m_DisplayName, this->m_SourceRole, this->m_DestinationRole).GetPointer();
 
   return result;
 };
diff --git a/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp b/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp
index 826f79e642..845d8bd4d3 100644
--- a/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp
+++ b/Modules/Core/src/DataManagement/mitkTemporoSpatialStringProperty.cpp
@@ -1,483 +1,499 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <iterator>
 #include <set>
 
 #include "mitkTemporoSpatialStringProperty.h"
 
 #include <boost/property_tree/json_parser.hpp>
 #include <boost/property_tree/ptree.hpp>
 #include <boost/type_traits/make_unsigned.hpp>
 
 mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty(const char *s)
 {
   if (s)
   {
     SliceMapType slices{{0, s}};
 
     m_Values.insert(std::make_pair(0, slices));
   }
 }
 
 mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty(const std::string &s)
 {
   SliceMapType slices{{0, s}};
 
   m_Values.insert(std::make_pair(0, slices));
 }
 
 mitk::TemporoSpatialStringProperty::TemporoSpatialStringProperty(const TemporoSpatialStringProperty &other)
   : BaseProperty(other), m_Values(other.m_Values)
 {
 }
 
 bool mitk::TemporoSpatialStringProperty::IsEqual(const BaseProperty &property) const
 {
   return this->m_Values == static_cast<const Self &>(property).m_Values;
 }
 
 bool mitk::TemporoSpatialStringProperty::Assign(const BaseProperty &property)
 {
   this->m_Values = static_cast<const Self &>(property).m_Values;
   return true;
 }
 
 std::string mitk::TemporoSpatialStringProperty::GetValueAsString() const
 {
   return GetValue();
 }
 
+bool mitk::TemporoSpatialStringProperty::IsUniform() const
+{
+  auto refValue = this->GetValue();
+
+  for (const auto& timeStep : m_Values)
+  {
+    auto finding = std::find_if_not(timeStep.second.begin(), timeStep.second.end(), [&refValue](const mitk::TemporoSpatialStringProperty::SliceMapType::value_type& val) { return val.second == refValue; });
+    if (finding != timeStep.second.end())
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 itk::LightObject::Pointer mitk::TemporoSpatialStringProperty::InternalClone() const
 {
   itk::LightObject::Pointer result(new Self(*this));
   result->UnRegister();
   return result;
 }
 
 mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValue() const
 {
   std::string result = "";
 
   if (!m_Values.empty())
   {
     if (!m_Values.begin()->second.empty())
     {
       result = m_Values.begin()->second.begin()->second;
     }
   }
   return result;
 };
 
 std::pair<bool, mitk::TemporoSpatialStringProperty::ValueType> mitk::TemporoSpatialStringProperty::CheckValue(
   const TimeStepType &timeStep, const IndexValueType &zSlice, bool allowCloseTime, bool allowCloseSlice) const
 {
   std::string value = "";
   bool found = false;
 
   auto timeIter = m_Values.find(timeStep);
   auto timeEnd = m_Values.end();
   if (timeIter == timeEnd && allowCloseTime)
   { // search for closest time step (earlier preverd)
     timeIter = m_Values.upper_bound(timeStep);
     if (timeIter != m_Values.begin())
     { // there is a key lower than time step
       timeIter = std::prev(timeIter);
     }
   }
 
   if (timeIter != timeEnd)
   {
     const SliceMapType &slices = timeIter->second;
 
     auto sliceIter = slices.find(zSlice);
     auto sliceEnd = slices.end();
     if (sliceIter == sliceEnd && allowCloseSlice)
     { // search for closest slice (earlier preverd)
       sliceIter = slices.upper_bound(zSlice);
       if (sliceIter != slices.begin())
       { // there is a key lower than slice
         sliceIter = std::prev(sliceIter);
       }
     }
 
     if (sliceIter != sliceEnd)
     {
       value = sliceIter->second;
       found = true;
     }
   }
 
   return std::make_pair(found, value);
 };
 
 mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValue(const TimeStepType &timeStep,
                                                                                            const IndexValueType &zSlice,
                                                                                            bool allowCloseTime,
                                                                                            bool allowCloseSlice) const
 {
   return CheckValue(timeStep, zSlice, allowCloseTime, allowCloseSlice).second;
 };
 
 mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValueBySlice(
   const IndexValueType &zSlice, bool allowClose) const
 {
   return GetValue(0, zSlice, true, allowClose);
 };
 
 mitk::TemporoSpatialStringProperty::ValueType mitk::TemporoSpatialStringProperty::GetValueByTimeStep(
   const TimeStepType &timeStep, bool allowClose) const
 {
   return GetValue(timeStep, 0, allowClose, true);
 };
 
 bool mitk::TemporoSpatialStringProperty::HasValue() const
 {
   return !m_Values.empty();
 };
 
 bool mitk::TemporoSpatialStringProperty::HasValue(const TimeStepType &timeStep,
                                                   const IndexValueType &zSlice,
                                                   bool allowCloseTime,
                                                   bool allowCloseSlice) const
 {
   return CheckValue(timeStep, zSlice, allowCloseTime, allowCloseSlice).first;
 };
 
 bool mitk::TemporoSpatialStringProperty::HasValueBySlice(const IndexValueType &zSlice, bool allowClose) const
 {
   return HasValue(0, zSlice, true, allowClose);
 };
 
 bool mitk::TemporoSpatialStringProperty::HasValueByTimeStep(const TimeStepType &timeStep, bool allowClose) const
 {
   return HasValue(timeStep, 0, allowClose, true);
 };
 
 std::vector<mitk::TemporoSpatialStringProperty::IndexValueType> mitk::TemporoSpatialStringProperty::GetAvailableSlices() const
 {
   std::set<IndexValueType> uniqueSlices;
 
   for (const auto& timeStep : m_Values)
   {
     for (const auto& slice : timeStep.second)
     {
       uniqueSlices.insert(slice.first);
     }
   }
 
   return std::vector<IndexValueType>(std::begin(uniqueSlices), std::end(uniqueSlices));
 }
 
 std::vector<mitk::TemporoSpatialStringProperty::IndexValueType> mitk::TemporoSpatialStringProperty::GetAvailableSlices(
   const TimeStepType &timeStep) const
 {
   std::vector<IndexValueType> result;
 
   auto timeIter = m_Values.find(timeStep);
   auto timeEnd = m_Values.end();
 
   if (timeIter != timeEnd)
   {
     for (auto const &element : timeIter->second)
     {
       result.push_back(element.first);
     }
   }
 
   return result;
 };
 
 std::vector<mitk::TimeStepType> mitk::TemporoSpatialStringProperty::GetAvailableTimeSteps() const
 {
   std::vector<mitk::TimeStepType> result;
 
   for (auto const &element : m_Values)
   {
     result.push_back(element.first);
   }
 
   return result;
 };
 
 std::vector<mitk::TimeStepType> mitk::TemporoSpatialStringProperty::GetAvailableTimeSteps(const IndexValueType& slice) const
 {
   std::vector<mitk::TimeStepType> result;
 
   for (const auto& timeStep : m_Values)
   {
     if (timeStep.second.find(slice) != std::end(timeStep.second))
     {
       result.push_back(timeStep.first);
     }
   }
   return result;
 }
 
 
 void mitk::TemporoSpatialStringProperty::SetValue(const TimeStepType &timeStep,
                                                   const IndexValueType &zSlice,
                                                   const ValueType &value)
 {
   auto timeIter = m_Values.find(timeStep);
   auto timeEnd = m_Values.end();
 
   if (timeIter == timeEnd)
   {
     SliceMapType slices{{zSlice, value}};
     m_Values.insert(std::make_pair(timeStep, slices));
   }
   else
   {
     timeIter->second[zSlice] = value;
   }
   this->Modified();
 };
 
 void mitk::TemporoSpatialStringProperty::SetValue(const ValueType &value)
 {
   this->Modified();
   m_Values.clear();
   this->SetValue(0, 0, value);
 };
 
 // Create necessary escape sequences from illegal characters
 // REMARK: This code is based upon code from boost::ptree::json_writer.
 // The corresponding boost function was not used directly, because it is not part of
 // the public interface of ptree::json_writer. :(
 // A own serialization strategy was implemented instead of using boost::ptree::json_write because
 // currently (<= boost 1.60) everything (even numbers) are converted into string representations
 // by the writer, so e.g. it becomes "t":"2" instaed of "t":2
 template <class Ch>
 std::basic_string<Ch> CreateJSONEscapes(const std::basic_string<Ch> &s)
 {
   std::basic_string<Ch> result;
   typename std::basic_string<Ch>::const_iterator b = s.begin();
   typename std::basic_string<Ch>::const_iterator e = s.end();
   while (b != e)
   {
     typedef typename boost::make_unsigned<Ch>::type UCh;
     UCh c(*b);
     // This assumes an ASCII superset.
     // We escape everything outside ASCII, because this code can't
     // handle high unicode characters.
     if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) || (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0x7F))
       result += *b;
     else if (*b == Ch('\b'))
       result += Ch('\\'), result += Ch('b');
     else if (*b == Ch('\f'))
       result += Ch('\\'), result += Ch('f');
     else if (*b == Ch('\n'))
       result += Ch('\\'), result += Ch('n');
     else if (*b == Ch('\r'))
       result += Ch('\\'), result += Ch('r');
     else if (*b == Ch('\t'))
       result += Ch('\\'), result += Ch('t');
     else if (*b == Ch('/'))
       result += Ch('\\'), result += Ch('/');
     else if (*b == Ch('"'))
       result += Ch('\\'), result += Ch('"');
     else if (*b == Ch('\\'))
       result += Ch('\\'), result += Ch('\\');
     else
     {
       const char *hexdigits = "0123456789ABCDEF";
       unsigned long u = (std::min)(static_cast<unsigned long>(static_cast<UCh>(*b)), 0xFFFFul);
       int d1 = u / 4096;
       u -= d1 * 4096;
       int d2 = u / 256;
       u -= d2 * 256;
       int d3 = u / 16;
       u -= d3 * 16;
       int d4 = u;
       result += Ch('\\');
       result += Ch('u');
       result += Ch(hexdigits[d1]);
       result += Ch(hexdigits[d2]);
       result += Ch(hexdigits[d3]);
       result += Ch(hexdigits[d4]);
     }
     ++b;
   }
   return result;
 }
 
 using CondensedTimeKeyType = std::pair<mitk::TimeStepType, mitk::TimeStepType>;
 using CondensedTimePointsType = std::map<CondensedTimeKeyType, std::string>;
 
 using CondensedSliceKeyType = std::pair<mitk::TemporoSpatialStringProperty::IndexValueType, mitk::TemporoSpatialStringProperty::IndexValueType>;
 using CondensedSlicesType = std::map<CondensedSliceKeyType, CondensedTimePointsType>;
 
 /** Helper function that checks if between an ID and a successing ID is no gap.*/
 template<typename TValue>
 bool isGap(const TValue& value, const TValue& successor)
 {
   return value<successor || value > successor + 1;
 }
 
 
 template<typename TNewKey, typename TNewValue, typename TMasterKey, typename TMasterValue, typename TCondensedContainer>
 void CheckAndCondenseElement(const TNewKey& newKeyMinID, const TNewValue& newValue, TMasterKey& masterKey, TMasterValue& masterValue, TCondensedContainer& condensedContainer)
 {
   if (newValue != masterValue
     || isGap(newKeyMinID, masterKey.second))
   {
     condensedContainer[masterKey] = masterValue;
     masterValue = newValue;
     masterKey.first = newKeyMinID;
   }
   masterKey.second = newKeyMinID;
 }
 
 /** Helper function that tries to condense the values of time points for a slice as much as possible and returns all slices with condensed timepoint values.*/
 CondensedSlicesType CondenseTimePointValuesOfProperty(const mitk::TemporoSpatialStringProperty* tsProp)
 {
   CondensedSlicesType uncondensedSlices;
 
   auto zs = tsProp->GetAvailableSlices();
   for (const auto z : zs)
   {
     CondensedTimePointsType condensedTimePoints;
     auto timePointIDs = tsProp->GetAvailableTimeSteps(z);
     CondensedTimeKeyType condensedKey = { timePointIDs.front(),timePointIDs.front() };
     auto refValue = tsProp->GetValue(timePointIDs.front(), z);
 
     for (const auto timePointID : timePointIDs)
     {
       const auto& newVal = tsProp->GetValue(timePointID, z);
       CheckAndCondenseElement(timePointID, newVal, condensedKey, refValue, condensedTimePoints);
     }
     condensedTimePoints[condensedKey] = refValue;
     uncondensedSlices[{ z, z }] = condensedTimePoints;
   }
   return uncondensedSlices;
 }
 
 ::std::string mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON(
   const mitk::BaseProperty *prop)
 {
   // REMARK: Implemented own serialization instead of using boost::ptree::json_write because
   // currently (<= boost 1.60) everything (even numbers) are converted into string representations
   // by the writer, so e.g. it becomes "t":"2" instaed of "t":2
   // If this problem is fixed with boost, we shoud switch back to json_writer (and remove the custom
   // implementation of CreateJSONEscapes (see above)).
   const auto *tsProp = dynamic_cast<const mitk::TemporoSpatialStringProperty *>(prop);
 
   if (!tsProp)
   {
     mitkThrow() << "Cannot serialize properties of types other than TemporoSpatialStringProperty.";
   }
 
   std::ostringstream stream;
   stream.imbue(std::locale("C"));
   stream << "{\"values\":[";
 
   //we condense the content of the property to have a compact serialization.
   //we start with condensing time points and then slices (in difference to the
   //internal layout). Reason: There is more entropy in slices (looking at DICOM)
   //than across time points for one slice, so we can "compress" to a higher rate.
   //We don't wanted to change the internal structure of the property as it would
   //introduce API inconvinience and subtle changes in behavior.
   CondensedSlicesType uncondensedSlices = CondenseTimePointValuesOfProperty(tsProp);
 
   //now condense the slices
   CondensedSlicesType condensedSlices;
   if(!uncondensedSlices.empty())
   {
     CondensedTimePointsType& masterSlice = uncondensedSlices.begin()->second;
     CondensedSliceKeyType masterSliceKey = uncondensedSlices.begin()->first;
 
     for (const auto& uncondensedSlice : uncondensedSlices)
     {
       const auto& uncondensedSliceID = uncondensedSlice.first.first;
       CheckAndCondenseElement(uncondensedSliceID, uncondensedSlice.second, masterSliceKey, masterSlice, condensedSlices);
     }
     condensedSlices[masterSliceKey] = masterSlice;
   }
 
 
   bool first = true;
   for (const auto& z : condensedSlices)
   {
     for (const auto& t : z.second)
     {
       if (first)
       {
         first = false;
       }
       else
       {
         stream << ", ";
       }
 
       const auto& minSliceID = z.first.first;
       const auto& maxSliceID = z.first.second;
       const auto& minTimePointID = t.first.first;
       const auto& maxTimePointID = t.first.second;
 
       stream << "{\"z\":" << minSliceID << ", ";
       if (minSliceID != maxSliceID)
       {
         stream << "\"zmax\":" << maxSliceID << ", ";
       }
       stream << "\"t\":" << minTimePointID << ", ";
       if (minTimePointID != maxTimePointID)
       {
         stream << "\"tmax\":" << maxTimePointID << ", ";
       }
 
       const auto& value = t.second;
       stream << "\"value\":\"" << CreateJSONEscapes(value) << "\"}";
     }
   }
 
   stream << "]}";
 
   return stream.str();
 }
 
 mitk::BaseProperty::Pointer mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty(
   const std::string &value)
 {
   if (value.empty())
     return nullptr;
 
   mitk::TemporoSpatialStringProperty::Pointer prop = mitk::TemporoSpatialStringProperty::New();
 
   boost::property_tree::ptree root;
 
   std::istringstream stream(value);
   stream.imbue(std::locale("C"));
 
   boost::property_tree::read_json(stream, root);
 
   for (boost::property_tree::ptree::value_type &element : root.get_child("values"))
   {
     std::string value = element.second.get("value", "");
     mitk::TemporoSpatialStringProperty::IndexValueType z =
       element.second.get<mitk::TemporoSpatialStringProperty::IndexValueType>("z", 0);
     mitk::TemporoSpatialStringProperty::IndexValueType zmax =
       element.second.get<mitk::TemporoSpatialStringProperty::IndexValueType>("zmax", z);
     TimeStepType t = element.second.get<TimeStepType>("t", 0);
     TimeStepType tmax = element.second.get<TimeStepType>("tmax", t);
 
     for (auto currentT = t; currentT <= tmax; ++currentT)
     {
       for (auto currentZ = z; currentZ <= zmax; ++currentZ)
       {
         prop->SetValue(currentT, currentZ, value);
       }
     }
   }
 
   return prop.GetPointer();
 }
diff --git a/Modules/Core/src/IO/mitkAbstractFileReader.cpp b/Modules/Core/src/IO/mitkAbstractFileReader.cpp
index 05d7b1b837..af38ca14ad 100644
--- a/Modules/Core/src/IO/mitkAbstractFileReader.cpp
+++ b/Modules/Core/src/IO/mitkAbstractFileReader.cpp
@@ -1,320 +1,332 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <mitkAbstractFileReader.h>
 
 #include <mitkCustomMimeType.h>
 #include <mitkIOUtil.h>
-#include <mitkStandaloneDataStorage.h>
 
 #include <mitkFileReaderWriterBase.h>
+#include <mitkVersion.h>
+#include <mitkIOMetaInformationPropertyConstants.h>
 
 #include <usGetModuleContext.h>
 #include <usModuleContext.h>
 #include <usPrototypeServiceFactory.h>
 
 #include <itksys/SystemTools.hxx>
 
 #include <fstream>
 
 namespace mitk
 {
   AbstractFileReader::InputStream::InputStream(IFileReader *reader, std::ios_base::openmode mode)
     : std::istream(nullptr), m_Stream(nullptr)
   {
     std::istream *stream = reader->GetInputStream();
     if (stream)
     {
       this->init(stream->rdbuf());
     }
     else
     {
       m_Stream = new std::ifstream(reader->GetInputLocation().c_str(), mode);
       this->init(m_Stream->rdbuf());
     }
   }
 
   AbstractFileReader::InputStream::~InputStream() { delete m_Stream; }
   class AbstractFileReader::Impl : public FileReaderWriterBase
   {
   public:
     Impl() : FileReaderWriterBase(), m_Stream(nullptr), m_PrototypeFactory(nullptr) {}
     Impl(const Impl &other) : FileReaderWriterBase(other), m_Stream(nullptr), m_PrototypeFactory(nullptr) {}
     std::string m_Location;
     std::string m_TmpFile;
     std::istream *m_Stream;
 
     us::PrototypeServiceFactory *m_PrototypeFactory;
     us::ServiceRegistration<IFileReader> m_Reg;
   };
 
   AbstractFileReader::AbstractFileReader() : d(new Impl) {}
   AbstractFileReader::~AbstractFileReader()
   {
     UnregisterService();
 
     delete d->m_PrototypeFactory;
 
     if (!d->m_TmpFile.empty())
     {
       std::remove(d->m_TmpFile.c_str());
     }
   }
 
   AbstractFileReader::AbstractFileReader(const AbstractFileReader &other) : IFileReader(), d(new Impl(*other.d.get()))
   {
   }
 
   AbstractFileReader::AbstractFileReader(const CustomMimeType &mimeType, const std::string &description) : d(new Impl)
   {
     d->SetMimeType(mimeType);
     d->SetDescription(description);
   }
 
   ////////////////////// Reading /////////////////////////
 
   std::vector<BaseData::Pointer> AbstractFileReader::Read()
   {
-    std::vector<BaseData::Pointer> result;
-
-    DataStorage::Pointer ds = StandaloneDataStorage::New().GetPointer();
-    this->Read(*ds);
-    DataStorage::SetOfObjects::ConstPointer dataNodes = ds->GetAll();
-    for (DataStorage::SetOfObjects::ConstIterator iter = dataNodes->Begin(), iterEnd = dataNodes->End();
-         iter != iterEnd;
-         ++iter)
+    std::vector<BaseData::Pointer> result = this->DoRead();
+
+    const auto options = this->GetOptions();
+
+    for (auto& data : result)
     {
-      result.push_back(iter.Value()->GetData());
+      data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_DESCRIPTION()), StringProperty::New(d->GetDescription()));
+      data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_VERSION()), StringProperty::New(MITK_VERSION_STRING));
+      data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_MIME_NAME()), StringProperty::New(d->GetMimeType()->GetName()));
+      data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_MIME_CATEGORY()), StringProperty::New(d->GetMimeType()->GetCategory()));
+      if (this->GetInputStream() == nullptr)
+      {
+        data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_INPUTLOCATION()), StringProperty::New(this->GetInputLocation()));
+      }
+
+      for (const auto& option : options)
+      {
+        auto optionpath = IOMetaInformationPropertyConstants::READER_OPTION_ROOT().AddElement(option.first);
+        data->SetProperty(PropertyKeyPathToPropertyName(optionpath), StringProperty::New(option.second.ToString()));
+      }
     }
+
     return result;
   }
 
   DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(DataStorage &ds)
   {
     DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New();
     std::vector<BaseData::Pointer> data = this->Read();
     for (auto iter = data.begin(); iter != data.end(); ++iter)
     {
       mitk::DataNode::Pointer node = mitk::DataNode::New();
       node->SetData(*iter);
       this->SetDefaultDataNodeProperties(node, this->GetInputLocation());
       ds.Add(node);
       result->InsertElement(result->Size(), node);
     }
     return result;
   }
 
   IFileReader::ConfidenceLevel AbstractFileReader::GetConfidenceLevel() const
   {
     if (d->m_Stream)
     {
       if (*d->m_Stream)
         return Supported;
     }
     else
     {
       if (itksys::SystemTools::FileExists(this->GetInputLocation().c_str(), true))
       {
         return Supported;
       }
     }
     return Unsupported;
   }
 
   //////////// µS Registration & Properties //////////////
 
   us::ServiceRegistration<IFileReader> AbstractFileReader::RegisterService(us::ModuleContext *context)
   {
     if (d->m_PrototypeFactory)
       return us::ServiceRegistration<IFileReader>();
 
     if (context == nullptr)
     {
       context = us::GetModuleContext();
     }
 
     d->RegisterMimeType(context);
 
     if (this->GetMimeType()->GetName().empty())
     {
       MITK_WARN << "Not registering reader due to empty MIME type.";
       return us::ServiceRegistration<IFileReader>();
     }
 
     struct PrototypeFactory : public us::PrototypeServiceFactory
     {
       AbstractFileReader *const m_Prototype;
 
       PrototypeFactory(AbstractFileReader *prototype) : m_Prototype(prototype) {}
       us::InterfaceMap GetService(us::Module * /*module*/,
                                   const us::ServiceRegistrationBase & /*registration*/) override
       {
         return us::MakeInterfaceMap<IFileReader>(m_Prototype->Clone());
       }
 
       void UngetService(us::Module * /*module*/,
                         const us::ServiceRegistrationBase & /*registration*/,
                         const us::InterfaceMap &service) override
       {
         delete us::ExtractInterface<IFileReader>(service);
       }
     };
 
     d->m_PrototypeFactory = new PrototypeFactory(this);
     us::ServiceProperties props = this->GetServiceProperties();
     d->m_Reg = context->RegisterService<IFileReader>(d->m_PrototypeFactory, props);
     return d->m_Reg;
   }
 
   void AbstractFileReader::UnregisterService()
   {
     try
     {
       d->m_Reg.Unregister();
     }
     catch (const std::exception &)
     {
     }
   }
 
   us::ServiceProperties AbstractFileReader::GetServiceProperties() const
   {
     us::ServiceProperties result;
 
     result[IFileReader::PROP_DESCRIPTION()] = this->GetDescription();
     result[IFileReader::PROP_MIMETYPE()] = this->GetMimeType()->GetName();
     result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking();
     return result;
   }
 
   us::ServiceRegistration<CustomMimeType> AbstractFileReader::RegisterMimeType(us::ModuleContext *context)
   {
     return d->RegisterMimeType(context);
   }
 
   std::vector< std::string > AbstractFileReader::GetReadFiles(){ return m_ReadFiles; }
 
   void AbstractFileReader::SetMimeType(const CustomMimeType &mimeType) { d->SetMimeType(mimeType); }
   void AbstractFileReader::SetDescription(const std::string &description) { d->SetDescription(description); }
   void AbstractFileReader::SetRanking(int ranking) { d->SetRanking(ranking); }
   int AbstractFileReader::GetRanking() const { return d->GetRanking(); }
   std::string AbstractFileReader::GetLocalFileName() const
   {
     std::string localFileName;
     if (d->m_Stream)
     {
       if (d->m_TmpFile.empty())
       {
         // write the stream contents to temporary file
         std::string ext = itksys::SystemTools::GetFilenameExtension(this->GetInputLocation());
         std::ofstream tmpStream;
         localFileName = mitk::IOUtil::CreateTemporaryFile(
           tmpStream, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary, "XXXXXX" + ext);
         tmpStream << d->m_Stream->rdbuf();
         d->m_TmpFile = localFileName;
       }
       else
       {
         localFileName = d->m_TmpFile;
       }
     }
     else
     {
       localFileName = d->m_Location;
     }
     return localFileName;
   }
 
   //////////////////////// Options ///////////////////////
 
   void AbstractFileReader::SetDefaultOptions(const IFileReader::Options &defaultOptions)
   {
     d->SetDefaultOptions(defaultOptions);
   }
 
   IFileReader::Options AbstractFileReader::GetDefaultOptions() const { return d->GetDefaultOptions(); }
   void AbstractFileReader::SetInput(const std::string &location)
   {
     d->m_Location = location;
     d->m_Stream = nullptr;
   }
 
   void AbstractFileReader::SetInput(const std::string &location, std::istream *is)
   {
     if (d->m_Stream != is && !d->m_TmpFile.empty())
     {
       std::remove(d->m_TmpFile.c_str());
       d->m_TmpFile.clear();
     }
     d->m_Location = location;
     d->m_Stream = is;
   }
 
   std::string AbstractFileReader::GetInputLocation() const { return d->m_Location; }
   std::istream *AbstractFileReader::GetInputStream() const { return d->m_Stream; }
   MimeType AbstractFileReader::GetRegisteredMimeType() const { return d->GetRegisteredMimeType(); }
   IFileReader::Options AbstractFileReader::GetOptions() const { return d->GetOptions(); }
   us::Any AbstractFileReader::GetOption(const std::string &name) const { return d->GetOption(name); }
   void AbstractFileReader::SetOptions(const Options &options) { d->SetOptions(options); }
   void AbstractFileReader::SetOption(const std::string &name, const us::Any &value) { d->SetOption(name, value); }
   ////////////////// MISC //////////////////
 
   void AbstractFileReader::AddProgressCallback(const ProgressCallback &callback) { d->AddProgressCallback(callback); }
   void AbstractFileReader::RemoveProgressCallback(const ProgressCallback &callback)
   {
     d->RemoveProgressCallback(callback);
   }
 
   ////////////////// µS related Getters //////////////////
 
   const CustomMimeType *AbstractFileReader::GetMimeType() const { return d->GetMimeType(); }
   void AbstractFileReader::SetMimeTypePrefix(const std::string &prefix) { d->SetMimeTypePrefix(prefix); }
   std::string AbstractFileReader::GetMimeTypePrefix() const { return d->GetMimeTypePrefix(); }
   std::string AbstractFileReader::GetDescription() const { return d->GetDescription(); }
   void AbstractFileReader::SetDefaultDataNodeProperties(DataNode *node, const std::string &filePath)
   {
     // path
     if (!filePath.empty())
     {
       mitk::StringProperty::Pointer pathProp =
         mitk::StringProperty::New(itksys::SystemTools::GetFilenamePath(filePath));
       node->SetProperty(StringProperty::PATH, pathProp);
     }
 
     // name already defined?
     mitk::StringProperty::Pointer nameProp = dynamic_cast<mitk::StringProperty *>(node->GetProperty("name"));
     if (nameProp.IsNull() || nameProp->GetValue() == DataNode::NO_NAME_VALUE())
     {
       // name already defined in BaseData
       mitk::StringProperty::Pointer baseDataNameProp =
         dynamic_cast<mitk::StringProperty *>(node->GetData()->GetProperty("name").GetPointer());
       if (baseDataNameProp.IsNull() || baseDataNameProp->GetValue() == DataNode::NO_NAME_VALUE())
       {
         // name neither defined in node, nor in BaseData -> name = filebasename;
         nameProp = mitk::StringProperty::New(this->GetRegisteredMimeType().GetFilenameWithoutExtension(filePath));
         node->SetProperty("name", nameProp);
       }
       else
       {
         // name defined in BaseData!
         nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue());
         node->SetProperty("name", nameProp);
       }
     }
 
     // visibility
     if (!node->GetProperty("visible"))
     {
       node->SetVisibility(true);
     }
   }
 }
diff --git a/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp b/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp
index c95ed5eac5..0b13ffe89c 100644
--- a/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp
+++ b/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp
@@ -1,112 +1,112 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkGeometryDataReaderService.h"
 #include "mitkGeometry3DToXML.h"
 #include "mitkIOMimeTypes.h"
 #include "mitkProportionalTimeGeometryToXML.h"
 
 // STL
 #include <mitkLocaleSwitch.h>
 
 #include <tinyxml.h>
 
 mitk::GeometryDataReaderService::GeometryDataReaderService()
   : AbstractFileReader(IOMimeTypes::GEOMETRY_DATA_MIMETYPE(), "MITK Geometry Data Reader")
 {
   RegisterService();
 }
 
 mitk::GeometryDataReaderService::~GeometryDataReaderService()
 {
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::GeometryDataReaderService::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::GeometryDataReaderService::DoRead()
 {
   // Switch the current locale to "C"
   LocaleSwitch localeSwitch("C");
 
   std::vector<itk::SmartPointer<BaseData>> result;
 
   InputStream stream(this);
 
   TiXmlDocument doc;
   stream >> doc;
   if (!doc.Error())
   {
     TiXmlHandle docHandle(&doc);
 
     for (TiXmlElement *geomDataElement = docHandle.FirstChildElement("GeometryData").ToElement();
          geomDataElement != nullptr;
          geomDataElement = geomDataElement->NextSiblingElement())
     {
       for (TiXmlElement *currentElement = geomDataElement->FirstChildElement(); currentElement != nullptr;
            currentElement = currentElement->NextSiblingElement())
       {
         // different geometries could have been serialized from a GeometryData
         // object:
         std::string tagName = currentElement->Value();
         if (tagName == "Geometry3D")
         {
           Geometry3D::Pointer restoredGeometry = Geometry3DToXML::FromXML(currentElement);
           if (restoredGeometry.IsNotNull())
           {
             GeometryData::Pointer newGeometryData = GeometryData::New();
             newGeometryData->SetGeometry(restoredGeometry);
             result.push_back(newGeometryData.GetPointer());
           }
           else
           {
             MITK_ERROR << "Invalid <Geometry3D> tag encountered. Skipping.";
           }
         }
         else if (tagName == "ProportionalTimeGeometry")
         {
           ProportionalTimeGeometry::Pointer restoredTimeGeometry =
             ProportionalTimeGeometryToXML::FromXML(currentElement);
           if (restoredTimeGeometry.IsNotNull())
           {
             GeometryData::Pointer newGeometryData = GeometryData::New();
             newGeometryData->SetTimeGeometry(restoredTimeGeometry);
             result.push_back(newGeometryData.GetPointer());
           }
           else
           {
             MITK_ERROR << "Invalid <ProportionalTimeGeometry> tag encountered. Skipping.";
           }
         }
       } // for child of <GeometryData>
     }   // for <GeometryData>
   }
   else
   {
     mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc();
   }
 
   if (result.empty())
   {
     mitkThrow() << "Did not read a single GeometryData object from input.";
   }
 
   return result;
 }
 
 mitk::GeometryDataReaderService::GeometryDataReaderService(const mitk::GeometryDataReaderService &other)
   : mitk::AbstractFileReader(other)
 {
 }
 
 mitk::GeometryDataReaderService *mitk::GeometryDataReaderService::Clone() const
 {
   return new GeometryDataReaderService(*this);
 }
diff --git a/Modules/Core/src/IO/mitkIOMetaInformationPropertyConstants.cpp b/Modules/Core/src/IO/mitkIOMetaInformationPropertyConstants.cpp
new file mode 100644
index 0000000000..a57c640107
--- /dev/null
+++ b/Modules/Core/src/IO/mitkIOMetaInformationPropertyConstants.cpp
@@ -0,0 +1,52 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#include "mitkIOMetaInformationPropertyConstants.h"
+
+namespace mitk
+{
+
+  PropertyKeyPath IOMetaInformationPropertyConstants::READER_DESCRIPTION()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "description" });
+  }
+
+  PropertyKeyPath IOMetaInformationPropertyConstants::READER_VERSION()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "version" });
+  }
+
+  PropertyKeyPath IOMetaInformationPropertyConstants::READER_MIME_NAME()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "mime", "name" });
+  }
+
+  PropertyKeyPath IOMetaInformationPropertyConstants::READER_MIME_CATEGORY()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "mime", "category" });
+  }
+
+  PropertyKeyPath IOMetaInformationPropertyConstants::READER_INPUTLOCATION()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "inputlocation" });
+  }
+
+  PropertyKeyPath IOMetaInformationPropertyConstants::READER_OPTION_ROOT()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "option" });
+  }
+
+  PropertyKeyPath IOMetaInformationPropertyConstants::READER_OPTIONS_ANY()
+  {
+    return READER_OPTION_ROOT().AddAnyElement();
+  }
+}
diff --git a/Modules/Core/src/IO/mitkImageVtkLegacyIO.cpp b/Modules/Core/src/IO/mitkImageVtkLegacyIO.cpp
index cc5cb322a4..c7f39ed4d5 100644
--- a/Modules/Core/src/IO/mitkImageVtkLegacyIO.cpp
+++ b/Modules/Core/src/IO/mitkImageVtkLegacyIO.cpp
@@ -1,113 +1,113 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkImageVtkLegacyIO.h"
 
 #include "mitkIOMimeTypes.h"
 #include "mitkImage.h"
 #include "mitkImageVtkReadAccessor.h"
 
 #include <vtkErrorCode.h>
 #include <vtkSmartPointer.h>
 #include <vtkStructuredPoints.h>
 #include <vtkStructuredPointsReader.h>
 #include <vtkStructuredPointsWriter.h>
 
 namespace mitk
 {
   ImageVtkLegacyIO::ImageVtkLegacyIO()
     : AbstractFileIO(Image::GetStaticNameOfClass(), IOMimeTypes::VTK_IMAGE_LEGACY_MIMETYPE(), "VTK Legacy Image")
   {
     Options defaultOptions;
     defaultOptions["Save as binary file"] = false;
     this->SetDefaultWriterOptions(defaultOptions);
     this->RegisterService();
   }
 
-  std::vector<BaseData::Pointer> ImageVtkLegacyIO::Read()
+  std::vector<BaseData::Pointer> ImageVtkLegacyIO::DoRead()
   {
     // The legay vtk reader cannot work with input streams
     const std::string fileName = this->GetLocalFileName();
     vtkSmartPointer<vtkStructuredPointsReader> reader = vtkSmartPointer<vtkStructuredPointsReader>::New();
     reader->SetFileName(fileName.c_str());
     reader->Update();
 
     if (reader->GetOutput() != nullptr)
     {
       mitk::Image::Pointer output = mitk::Image::New();
       output->Initialize(reader->GetOutput());
       output->SetVolume(reader->GetOutput()->GetScalarPointer());
       std::vector<BaseData::Pointer> result;
       result.push_back(output.GetPointer());
       return result;
     }
     else
     {
       mitkThrow() << "vtkStructuredPointsReader error: "
                   << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode());
     }
   }
 
   IFileIO::ConfidenceLevel ImageVtkLegacyIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
     vtkSmartPointer<vtkStructuredPointsReader> reader = vtkSmartPointer<vtkStructuredPointsReader>::New();
     reader->SetFileName(this->GetLocalFileName().c_str());
     if (reader->IsFileStructuredPoints())
     {
       return Supported;
     }
     return Unsupported;
   }
 
   void ImageVtkLegacyIO::Write()
   {
     ValidateOutputLocation();
 
     const auto *input = dynamic_cast<const Image *>(this->GetInput());
 
     vtkSmartPointer<vtkStructuredPointsWriter> writer = vtkSmartPointer<vtkStructuredPointsWriter>::New();
 
     // The legacy vtk image writer cannot write to streams
     LocalFile localFile(this);
     writer->SetFileName(localFile.GetFileName().c_str());
 
     if (us::any_cast<bool>(GetWriterOption("Save as binary file")))
     {
       writer->SetFileTypeToBinary();
     }
 
     ImageVtkReadAccessor vtkReadAccessor(Image::ConstPointer(input), nullptr, input->GetVtkImageData());
     writer->SetInputData(const_cast<vtkImageData *>(vtkReadAccessor.GetVtkImageData()));
 
     if (writer->Write() == 0 || writer->GetErrorCode() != 0)
     {
       mitkThrow() << "vtkStructuredPointesWriter error: "
                   << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode());
     }
   }
 
   IFileIO::ConfidenceLevel ImageVtkLegacyIO::GetWriterConfidenceLevel() const
   {
     if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
       return Unsupported;
     const auto *input = static_cast<const Image *>(this->GetInput());
     if (input->GetDimension() == 3)
       return Supported;
     else if (input->GetDimension() < 3)
       return PartiallySupported;
     return Unsupported;
   }
 
   ImageVtkLegacyIO *ImageVtkLegacyIO::IOClone() const { return new ImageVtkLegacyIO(*this); }
 }
diff --git a/Modules/Core/src/IO/mitkImageVtkLegacyIO.h b/Modules/Core/src/IO/mitkImageVtkLegacyIO.h
index 7a0256ee21..efffa19b9d 100644
--- a/Modules/Core/src/IO/mitkImageVtkLegacyIO.h
+++ b/Modules/Core/src/IO/mitkImageVtkLegacyIO.h
@@ -1,42 +1,43 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKIMAGEVTKLEGACYIO_H
 #define MITKIMAGEVTKLEGACYIO_H
 
 #include "mitkAbstractFileIO.h"
 
 namespace mitk
 {
   class ImageVtkLegacyIO : public mitk::AbstractFileIO
   {
   public:
     ImageVtkLegacyIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    std::vector<BaseData::Pointer> Read() override;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
 
     ConfidenceLevel GetWriterConfidenceLevel() const override;
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     ImageVtkLegacyIO *IOClone() const override;
   };
 }
 #endif // MITKIMAGEVTKLEGACYIO_H
diff --git a/Modules/Core/src/IO/mitkImageVtkXmlIO.cpp b/Modules/Core/src/IO/mitkImageVtkXmlIO.cpp
index 8318508fc1..a7f04fc164 100644
--- a/Modules/Core/src/IO/mitkImageVtkXmlIO.cpp
+++ b/Modules/Core/src/IO/mitkImageVtkXmlIO.cpp
@@ -1,144 +1,144 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkImageVtkXmlIO.h"
 
 #include "mitkIOMimeTypes.h"
 #include "mitkImage.h"
 #include "mitkImageVtkReadAccessor.h"
 
 #include <vtkErrorCode.h>
 #include <vtkImageData.h>
 #include <vtkSmartPointer.h>
 #include <vtkXMLImageDataReader.h>
 #include <vtkXMLImageDataWriter.h>
 
 namespace mitk
 {
   class VtkXMLImageDataReader : public ::vtkXMLImageDataReader
   {
   public:
     static VtkXMLImageDataReader *New() { return new VtkXMLImageDataReader(); }
     vtkTypeMacro(VtkXMLImageDataReader, vtkXMLImageDataReader)
 
       void SetStream(std::istream *is)
     {
       this->Stream = is;
     }
     std::istream *GetStream() const { return this->Stream; }
   };
 
   class VtkXMLImageDataWriter : public ::vtkXMLImageDataWriter
   {
   public:
     static VtkXMLImageDataWriter *New() { return new VtkXMLImageDataWriter(); }
     vtkTypeMacro(VtkXMLImageDataWriter, vtkXMLImageDataWriter)
 
       void SetStream(std::ostream *os)
     {
       this->Stream = os;
     }
     std::ostream *GetStream() const { return this->Stream; }
   };
 
   ImageVtkXmlIO::ImageVtkXmlIO()
     : AbstractFileIO(Image::GetStaticNameOfClass(), IOMimeTypes::VTK_IMAGE_MIMETYPE(), "VTK XML Image")
   {
     this->RegisterService();
   }
 
-  std::vector<BaseData::Pointer> ImageVtkXmlIO::Read()
+  std::vector<BaseData::Pointer> ImageVtkXmlIO::DoRead()
   {
     vtkSmartPointer<VtkXMLImageDataReader> reader = vtkSmartPointer<VtkXMLImageDataReader>::New();
     if (this->GetInputStream())
     {
       reader->SetStream(this->GetInputStream());
     }
     else
     {
       reader->SetFileName(this->GetInputLocation().c_str());
     }
     reader->Update();
 
     if (reader->GetOutput() != nullptr)
     {
       mitk::Image::Pointer output = mitk::Image::New();
       output->Initialize(reader->GetOutput());
       output->SetVolume(reader->GetOutput()->GetScalarPointer());
       std::vector<BaseData::Pointer> result;
       result.push_back(output.GetPointer());
       return result;
     }
     else
     {
       mitkThrow() << "vtkXMLImageDataReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode());
     }
   }
 
   IFileIO::ConfidenceLevel ImageVtkXmlIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
     if (this->GetInputStream() == nullptr)
     {
       // check if the xml vtk reader can handle the file
       vtkSmartPointer<VtkXMLImageDataReader> xmlReader = vtkSmartPointer<VtkXMLImageDataReader>::New();
       if (xmlReader->CanReadFile(this->GetInputLocation().c_str()) != 0)
       {
         return Supported;
       }
       return Unsupported;
     }
     // in case of an input stream, VTK does not seem to have methods for
     // validating it
     return Supported;
   }
 
   void ImageVtkXmlIO::Write()
   {
     ValidateOutputLocation();
 
     const auto *input = dynamic_cast<const Image *>(this->GetInput());
 
     vtkSmartPointer<VtkXMLImageDataWriter> writer = vtkSmartPointer<VtkXMLImageDataWriter>::New();
     if (this->GetOutputStream())
     {
       writer->SetStream(this->GetOutputStream());
     }
     else
     {
       writer->SetFileName(this->GetOutputLocation().c_str());
     }
 
     ImageVtkReadAccessor vtkReadAccessor(Image::ConstPointer(input), nullptr, input->GetVtkImageData());
     writer->SetInputData(const_cast<vtkImageData *>(vtkReadAccessor.GetVtkImageData()));
 
     if (writer->Write() == 0 || writer->GetErrorCode() != 0)
     {
       mitkThrow() << "vtkXMLImageDataWriter error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode());
     }
   }
 
   IFileIO::ConfidenceLevel ImageVtkXmlIO::GetWriterConfidenceLevel() const
   {
     if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
       return Unsupported;
     const auto *input = static_cast<const Image *>(this->GetInput());
     if (input->GetDimension() == 3)
       return Supported;
     else if (input->GetDimension() < 3)
       return PartiallySupported;
     return Unsupported;
   }
 
   ImageVtkXmlIO *ImageVtkXmlIO::IOClone() const { return new ImageVtkXmlIO(*this); }
 }
diff --git a/Modules/Core/src/IO/mitkImageVtkXmlIO.h b/Modules/Core/src/IO/mitkImageVtkXmlIO.h
index bdfd759adc..5edc030350 100644
--- a/Modules/Core/src/IO/mitkImageVtkXmlIO.h
+++ b/Modules/Core/src/IO/mitkImageVtkXmlIO.h
@@ -1,42 +1,43 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKIMAGEVTKXMLIO_H
 #define MITKIMAGEVTKXMLIO_H
 
 #include "mitkAbstractFileIO.h"
 
 namespace mitk
 {
   class ImageVtkXmlIO : public mitk::AbstractFileIO
   {
   public:
     ImageVtkXmlIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    std::vector<BaseData::Pointer> Read() override;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
 
     ConfidenceLevel GetWriterConfidenceLevel() const override;
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     ImageVtkXmlIO *IOClone() const override;
   };
 }
 #endif // MITKIMAGEVTKXMLIO_H
diff --git a/Modules/Core/src/IO/mitkItkImageIO.cpp b/Modules/Core/src/IO/mitkItkImageIO.cpp
index f482ea5f13..d4666d22ed 100644
--- a/Modules/Core/src/IO/mitkItkImageIO.cpp
+++ b/Modules/Core/src/IO/mitkItkImageIO.cpp
@@ -1,708 +1,708 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkItkImageIO.h"
 
 #include <mitkArbitraryTimeGeometry.h>
 #include <mitkCoreServices.h>
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkIPropertyPersistence.h>
 #include <mitkImage.h>
 #include <mitkImageReadAccessor.h>
 #include <mitkLocaleSwitch.h>
 
 #include <itkImage.h>
 #include <itkImageFileReader.h>
 #include <itkImageIOFactory.h>
 #include <itkImageIORegion.h>
 #include <itkMetaDataObject.h>
 
 #include <algorithm>
 
 namespace mitk
 {
   const char *const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type";
   const char *const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints";
   const char *const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type";
   const char *const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints";
 
   ItkImageIO::ItkImageIO(const ItkImageIO &other)
     : AbstractFileIO(other), m_ImageIO(dynamic_cast<itk::ImageIOBase *>(other.m_ImageIO->Clone().GetPointer()))
   {
     this->InitializeDefaultMetaDataKeys();
   }
 
   std::vector<std::string> ItkImageIO::FixUpImageIOExtensions(const std::string &imageIOName)
   {
     std::vector<std::string> extensions;
     // Try to fix-up some known ITK image IO classes
     if (imageIOName == "GiplImageIO")
     {
       extensions.push_back("gipl");
       extensions.push_back("gipl.gz");
     }
     else if (imageIOName == "GDCMImageIO")
     {
       extensions.push_back("gdcm");
       extensions.push_back("dcm");
       extensions.push_back("DCM");
       extensions.push_back("dc3");
       extensions.push_back("DC3");
       extensions.push_back("ima");
       extensions.push_back("img");
     }
     else if (imageIOName == "PNGImageIO")
     {
       extensions.push_back("png");
       extensions.push_back("PNG");
     }
     else if (imageIOName == "StimulateImageIO")
     {
       extensions.push_back("spr");
     }
     else if (imageIOName == "HDF5ImageIO")
     {
       extensions.push_back("hdf");
       extensions.push_back("h4");
       extensions.push_back("hdf4");
       extensions.push_back("h5");
       extensions.push_back("hdf5");
       extensions.push_back("he4");
       extensions.push_back("he5");
       extensions.push_back("hd5");
     }
     else if ("GE4ImageIO" == imageIOName || "GE5ImageIO" == imageIOName || "Bruker2dseqImageIO" == imageIOName)
     {
       extensions.push_back("");
     }
 
     if (!extensions.empty())
     {
       MITK_DEBUG << "Fixing up known extensions for " << imageIOName;
     }
 
     return extensions;
   }
 
   void ItkImageIO::FixUpCustomMimeTypeName(const std::string &imageIOName, CustomMimeType &customMimeType)
   {
     if ("GE4ImageIO" == imageIOName)
     {
       customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "ge4");
     }
     else if ("GE5ImageIO" == imageIOName)
     {
       customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "ge5");
     }
     else if ("Bruker2dseqImageIO" == imageIOName)
     {
       customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "bruker2dseq");
     }
   }
 
   ItkImageIO::ItkImageIO(itk::ImageIOBase::Pointer imageIO)
     : AbstractFileIO(Image::GetStaticNameOfClass()), m_ImageIO(imageIO)
   {
     if (m_ImageIO.IsNull())
     {
       mitkThrow() << "ITK ImageIOBase argument must not be nullptr";
     }
 
     this->AbstractFileReader::SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".image.");
     this->InitializeDefaultMetaDataKeys();
 
     std::vector<std::string> readExtensions = m_ImageIO->GetSupportedReadExtensions();
 
     if (readExtensions.empty())
     {
       std::string imageIOName = m_ImageIO->GetNameOfClass();
       MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide read extensions";
       readExtensions = FixUpImageIOExtensions(imageIOName);
     }
 
     CustomMimeType customReaderMimeType;
     customReaderMimeType.SetCategory("Images");
     for (std::vector<std::string>::const_iterator iter = readExtensions.begin(), endIter = readExtensions.end();
          iter != endIter;
          ++iter)
     {
       std::string extension = *iter;
       if (!extension.empty() && extension[0] == '.')
       {
         extension.assign(iter->begin() + 1, iter->end());
       }
       customReaderMimeType.AddExtension(extension);
     }
 
     auto extensions = customReaderMimeType.GetExtensions();
     if (extensions.empty() || (extensions.size() == 1 && extensions[0].empty()))
     {
       std::string imageIOName = m_ImageIO->GetNameOfClass();
       FixUpCustomMimeTypeName(imageIOName, customReaderMimeType);
     }
 
     this->AbstractFileReader::SetMimeType(customReaderMimeType);
 
     std::vector<std::string> writeExtensions = imageIO->GetSupportedWriteExtensions();
     if (writeExtensions.empty())
     {
       std::string imageIOName = imageIO->GetNameOfClass();
       MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide write extensions";
       writeExtensions = FixUpImageIOExtensions(imageIOName);
     }
 
     if (writeExtensions != readExtensions)
     {
       CustomMimeType customWriterMimeType;
       customWriterMimeType.SetCategory("Images");
       for (std::vector<std::string>::const_iterator iter = writeExtensions.begin(), endIter = writeExtensions.end();
            iter != endIter;
            ++iter)
       {
         std::string extension = *iter;
         if (!extension.empty() && extension[0] == '.')
         {
           extension.assign(iter->begin() + 1, iter->end());
         }
         customWriterMimeType.AddExtension(extension);
       }
 
       auto extensions = customWriterMimeType.GetExtensions();
       if (extensions.empty() || (extensions.size() == 1 && extensions[0].empty()))
       {
         std::string imageIOName = m_ImageIO->GetNameOfClass();
         FixUpCustomMimeTypeName(imageIOName, customWriterMimeType);
       }
 
       this->AbstractFileWriter::SetMimeType(customWriterMimeType);
     }
 
     std::string description = std::string("ITK ") + imageIO->GetNameOfClass();
     this->SetReaderDescription(description);
     this->SetWriterDescription(description);
 
     this->RegisterService();
   }
 
   ItkImageIO::ItkImageIO(const CustomMimeType &mimeType, itk::ImageIOBase::Pointer imageIO, int rank)
     : AbstractFileIO(Image::GetStaticNameOfClass(), mimeType, std::string("ITK ") + imageIO->GetNameOfClass()),
       m_ImageIO(imageIO)
   {
     if (m_ImageIO.IsNull())
     {
       mitkThrow() << "ITK ImageIOBase argument must not be nullptr";
     }
 
     this->AbstractFileReader::SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".image.");
     this->InitializeDefaultMetaDataKeys();
 
     if (rank)
     {
       this->AbstractFileReader::SetRanking(rank);
       this->AbstractFileWriter::SetRanking(rank);
     }
 
     this->RegisterService();
   }
 
   std::vector<TimePointType> ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase* data)
   {
     const auto* timeGeometryTimeData =
       dynamic_cast<const itk::MetaDataObject<std::string>*>(data);
     std::vector<TimePointType> result;
 
     if (timeGeometryTimeData)
     {
       std::string dataStr = timeGeometryTimeData->GetMetaDataObjectValue();
       std::stringstream stream(dataStr);
       TimePointType tp;
       while (stream >> tp)
       {
         result.push_back(tp);
       }
     }
 
     return result;
   };
 
   itk::MetaDataObjectBase::Pointer ConvertTimePointListToMetaDataObject(const mitk::TimeGeometry* timeGeometry)
   {
     std::stringstream stream;
     stream << timeGeometry->GetTimeBounds(0)[0];
     const auto maxTimePoints = timeGeometry->CountTimeSteps();
     for (TimeStepType pos = 0; pos < maxTimePoints; ++pos)
     {
       stream << " " << timeGeometry->GetTimeBounds(pos)[1];
     }
     auto result = itk::MetaDataObject<std::string>::New();
     result->SetMetaDataObjectValue(stream.str());
     return result.GetPointer();
   };
 
-  std::vector<BaseData::Pointer> ItkImageIO::Read()
+  std::vector<BaseData::Pointer> ItkImageIO::DoRead()
   {
     std::vector<BaseData::Pointer> result;
     mitk::LocaleSwitch localeSwitch("C");
 
     Image::Pointer image = Image::New();
 
     const unsigned int MINDIM = 2;
     const unsigned int MAXDIM = 4;
 
     const std::string path = this->GetLocalFileName();
 
     MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << std::endl;
 
     // Check to see if we can read the file given the name or prefix
     if (path.empty())
     {
       mitkThrow() << "Empty filename in mitk::ItkImageIO ";
     }
 
     // Got to allocate space for the image. Determine the characteristics of
     // the image.
     m_ImageIO->SetFileName(path);
     m_ImageIO->ReadImageInformation();
 
     unsigned int ndim = m_ImageIO->GetNumberOfDimensions();
     if (ndim < MINDIM || ndim > MAXDIM)
     {
       MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim
                 << " dimensions! Reading as 4D.";
       ndim = MAXDIM;
     }
 
     itk::ImageIORegion ioRegion(ndim);
     itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize();
     itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex();
 
     unsigned int dimensions[MAXDIM];
     dimensions[0] = 0;
     dimensions[1] = 0;
     dimensions[2] = 0;
     dimensions[3] = 0;
 
     ScalarType spacing[MAXDIM];
     spacing[0] = 1.0f;
     spacing[1] = 1.0f;
     spacing[2] = 1.0f;
     spacing[3] = 1.0f;
 
     Point3D origin;
     origin.Fill(0);
 
     unsigned int i;
     for (i = 0; i < ndim; ++i)
     {
       ioStart[i] = 0;
       ioSize[i] = m_ImageIO->GetDimensions(i);
       if (i < MAXDIM)
       {
         dimensions[i] = m_ImageIO->GetDimensions(i);
         spacing[i] = m_ImageIO->GetSpacing(i);
         if (spacing[i] <= 0)
           spacing[i] = 1.0f;
       }
       if (i < 3)
       {
         origin[i] = m_ImageIO->GetOrigin(i);
       }
     }
 
     ioRegion.SetSize(ioSize);
     ioRegion.SetIndex(ioStart);
 
     MITK_INFO << "ioRegion: " << ioRegion << std::endl;
     m_ImageIO->SetIORegion(ioRegion);
     void *buffer = new unsigned char[m_ImageIO->GetImageSizeInBytes()];
     m_ImageIO->Read(buffer);
 
     image->Initialize(MakePixelType(m_ImageIO), ndim, dimensions);
     image->SetImportChannel(buffer, 0, Image::ManageMemory);
 
     const itk::MetaDataDictionary &dictionary = m_ImageIO->GetMetaDataDictionary();
 
     // access direction of itk::Image and include spacing
     mitk::Matrix3D matrix;
     matrix.SetIdentity();
     unsigned int j, itkDimMax3 = (ndim >= 3 ? 3 : ndim);
     for (i = 0; i < itkDimMax3; ++i)
       for (j = 0; j < itkDimMax3; ++j)
         matrix[i][j] = m_ImageIO->GetDirection(j)[i];
 
     // re-initialize PlaneGeometry with origin and direction
     PlaneGeometry *planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0);
     planeGeometry->SetOrigin(origin);
     planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix);
 
     // re-initialize SlicedGeometry3D
     SlicedGeometry3D *slicedGeometry = image->GetSlicedGeometry(0);
     slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2));
     slicedGeometry->SetSpacing(spacing);
 
     MITK_INFO << slicedGeometry->GetCornerPoint(false, false, false);
     MITK_INFO << slicedGeometry->GetCornerPoint(true, true, true);
 
     // re-initialize TimeGeometry
     TimeGeometry::Pointer timeGeometry;
 
     if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE) || dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TYPE))
     { // also check for the name because of backwards compatibility. Past code version stored with the name and not with
       // the key
       itk::MetaDataObject<std::string>::ConstPointer timeGeometryTypeData = nullptr;
       if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE))
       {
         timeGeometryTypeData =
           dynamic_cast<const itk::MetaDataObject<std::string> *>(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TYPE));
       }
       else
       {
         timeGeometryTypeData =
           dynamic_cast<const itk::MetaDataObject<std::string> *>(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TYPE));
       }
 
       if (timeGeometryTypeData->GetMetaDataObjectValue() == ArbitraryTimeGeometry::GetStaticNameOfClass())
       {
         MITK_INFO << "used time geometry: " << ArbitraryTimeGeometry::GetStaticNameOfClass();
         typedef std::vector<TimePointType> TimePointVector;
         TimePointVector timePoints;
 
         if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS))
         {
           timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS));
         }
         else if (dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS))
         {
           timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS));
         }
 
         if (timePoints.empty())
         {
           MITK_ERROR << "Stored timepoints are empty. Meta information seems to bee invalid. Switch to ProportionalTimeGeometry fallback";
         }
         else if (timePoints.size() - 1 != image->GetDimension(3))
         {
           MITK_ERROR << "Stored timepoints (" << timePoints.size() - 1 << ") and size of image time dimension ("
                      << image->GetDimension(3) << ") do not match. Switch to ProportionalTimeGeometry fallback";
         }
         else
         {
           ArbitraryTimeGeometry::Pointer arbitraryTimeGeometry = ArbitraryTimeGeometry::New();
           TimePointVector::const_iterator pos = timePoints.begin();
           auto prePos = pos++;
 
           for (; pos != timePoints.end(); ++prePos, ++pos)
           {
             arbitraryTimeGeometry->AppendNewTimeStepClone(slicedGeometry, *prePos, *pos);
           }
 
           timeGeometry = arbitraryTimeGeometry;
         }
       }
     }
 
     if (timeGeometry.IsNull())
     { // Fallback. If no other valid time geometry has been created, create a ProportionalTimeGeometry
       MITK_INFO << "used time geometry: " << ProportionalTimeGeometry::GetStaticNameOfClass();
       ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New();
       propTimeGeometry->Initialize(slicedGeometry, image->GetDimension(3));
       timeGeometry = propTimeGeometry;
     }
 
     image->SetTimeGeometry(timeGeometry);
 
     buffer = nullptr;
     MITK_INFO << "number of image components: " << image->GetPixelType().GetNumberOfComponents();
 
     for (auto iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd;
          ++iter)
     {
       if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string))
       {
         const std::string &key = iter->first;
         std::string assumedPropertyName = key;
         std::replace(assumedPropertyName.begin(), assumedPropertyName.end(), '_', '.');
 
         std::string mimeTypeName = GetMimeType()->GetName();
 
         // Check if there is already a info for the key and our mime type.
         mitk::CoreServicePointer<IPropertyPersistence> propPersistenceService(mitk::CoreServices::GetPropertyPersistence());
         IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfoByKey(key);
 
         auto predicate = [&mimeTypeName](const PropertyPersistenceInfo::ConstPointer &x) {
           return x.IsNotNull() && x->GetMimeTypeName() == mimeTypeName;
         };
         auto finding = std::find_if(infoList.begin(), infoList.end(), predicate);
 
         if (finding == infoList.end())
         {
           auto predicateWild = [](const PropertyPersistenceInfo::ConstPointer &x) {
             return x.IsNotNull() && x->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME();
           };
           finding = std::find_if(infoList.begin(), infoList.end(), predicateWild);
         }
 
         PropertyPersistenceInfo::ConstPointer info;
 
         if (finding != infoList.end())
         {
           assumedPropertyName = (*finding)->GetName();
           info = *finding;
         }
         else
         { // we have not found anything suitable so we generate our own info
           auto newInfo = PropertyPersistenceInfo::New();
           newInfo->SetNameAndKey(assumedPropertyName, key);
           newInfo->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME());
           info = newInfo;
         }
 
         std::string value =
           dynamic_cast<itk::MetaDataObject<std::string> *>(iter->second.GetPointer())->GetMetaDataObjectValue();
 
         mitk::BaseProperty::Pointer loadedProp = info->GetDeserializationFunction()(value);
 
         image->SetProperty(assumedPropertyName.c_str(), loadedProp);
 
         // Read properties should be persisted unless they are default properties
         // which are written anyway
         bool isDefaultKey(false);
 
         for (const auto &defaultKey : m_DefaultMetaDataKeys)
         {
           if (defaultKey.length() <= assumedPropertyName.length())
           {
             // does the start match the default key
             if (assumedPropertyName.substr(0, defaultKey.length()).find(defaultKey) != std::string::npos)
             {
               isDefaultKey = true;
               break;
             }
           }
         }
 
         if (!isDefaultKey)
         {
           propPersistenceService->AddInfo(info);
         }
       }
     }
 
     MITK_INFO << "...finished!";
 
     result.push_back(image.GetPointer());
     return result;
   }
 
   AbstractFileIO::ConfidenceLevel ItkImageIO::GetReaderConfidenceLevel() const
   {
     return m_ImageIO->CanReadFile(GetLocalFileName().c_str()) ? IFileReader::Supported : IFileReader::Unsupported;
   }
 
   void ItkImageIO::Write()
   {
     const auto *image = dynamic_cast<const mitk::Image *>(this->GetInput());
 
     if (image == nullptr)
     {
       mitkThrow() << "Cannot write non-image data";
     }
 
     // Switch the current locale to "C"
     LocaleSwitch localeSwitch("C");
 
     // Clone the image geometry, because we might have to change it
     // for writing purposes
     BaseGeometry::Pointer geometry = image->GetGeometry()->Clone();
 
     // Check if geometry information will be lost
     if (image->GetDimension() == 2 && !geometry->Is2DConvertable())
     {
       MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might "
                    "consider using Convert2Dto3DImageFilter before saving.";
 
       // set matrix to identity
       mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New();
       affTrans->SetIdentity();
       mitk::Vector3D spacing = geometry->GetSpacing();
       mitk::Point3D origin = geometry->GetOrigin();
       geometry->SetIndexToWorldTransform(affTrans);
       geometry->SetSpacing(spacing);
       geometry->SetOrigin(origin);
     }
 
     LocalFile localFile(this);
     const std::string path = localFile.GetFileName();
 
     MITK_INFO << "Writing image: " << path << std::endl;
 
     try
     {
       // Implementation of writer using itkImageIO directly. This skips the use
       // of templated itkImageFileWriter, which saves the multiplexing on MITK side.
 
       const unsigned int dimension = image->GetDimension();
       const unsigned int *const dimensions = image->GetDimensions();
       const mitk::PixelType pixelType = image->GetPixelType();
       const mitk::Vector3D mitkSpacing = geometry->GetSpacing();
       const mitk::Point3D mitkOrigin = geometry->GetOrigin();
 
       // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin,
       // though they are not supported in MITK
       itk::Vector<double, 4u> spacing4D;
       spacing4D[0] = mitkSpacing[0];
       spacing4D[1] = mitkSpacing[1];
       spacing4D[2] = mitkSpacing[2];
       spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here
 
       itk::Vector<double, 4u> origin4D;
       origin4D[0] = mitkOrigin[0];
       origin4D[1] = mitkOrigin[1];
       origin4D[2] = mitkOrigin[2];
       origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here
 
       // Set the necessary information for imageIO
       m_ImageIO->SetNumberOfDimensions(dimension);
       m_ImageIO->SetPixelType(pixelType.GetPixelType());
       m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ?
                                     static_cast<itk::ImageIOBase::IOComponentType>(pixelType.GetComponentType()) :
                                     itk::ImageIOBase::UNKNOWNCOMPONENTTYPE);
       m_ImageIO->SetNumberOfComponents(pixelType.GetNumberOfComponents());
 
       itk::ImageIORegion ioRegion(dimension);
 
       for (unsigned int i = 0; i < dimension; i++)
       {
         m_ImageIO->SetDimensions(i, dimensions[i]);
         m_ImageIO->SetSpacing(i, spacing4D[i]);
         m_ImageIO->SetOrigin(i, origin4D[i]);
 
         mitk::Vector3D mitkDirection;
         mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i));
         itk::Vector<double, 4u> direction4D;
         direction4D[0] = mitkDirection[0];
         direction4D[1] = mitkDirection[1];
         direction4D[2] = mitkDirection[2];
 
         // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must
         // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix.
         if (i == 3)
         {
           direction4D[3] = 1; // homogenous component
         }
         else
         {
           direction4D[3] = 0;
         }
         vnl_vector<double> axisDirection(dimension);
         for (unsigned int j = 0; j < dimension; j++)
         {
           axisDirection[j] = direction4D[j] / spacing4D[i];
         }
         m_ImageIO->SetDirection(i, axisDirection);
 
         ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i));
         ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i));
       }
 
       // use compression if available
       m_ImageIO->UseCompressionOn();
 
       m_ImageIO->SetIORegion(ioRegion);
       m_ImageIO->SetFileName(path);
 
       // Handle time geometry
       const auto *arbitraryTG = dynamic_cast<const ArbitraryTimeGeometry *>(image->GetTimeGeometry());
       if (arbitraryTG)
       {
         itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(),
                                               PROPERTY_KEY_TIMEGEOMETRY_TYPE,
                                               ArbitraryTimeGeometry::GetStaticNameOfClass());
 
         auto metaTimePoints = ConvertTimePointListToMetaDataObject(arbitraryTG);
         m_ImageIO->GetMetaDataDictionary().Set(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, metaTimePoints);
       }
 
       // Handle properties
       mitk::PropertyList::Pointer imagePropertyList = image->GetPropertyList();
 
       for (const auto &property : *imagePropertyList->GetMap())
       {
         mitk::CoreServicePointer<IPropertyPersistence> propPersistenceService(mitk::CoreServices::GetPropertyPersistence());
         IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfo(property.first, GetMimeType()->GetName(), true);
 
         if (infoList.empty())
         {
           continue;
         }
 
         std::string value = infoList.front()->GetSerializationFunction()(property.second);
 
         if (value == mitk::BaseProperty::VALUE_CANNOT_BE_CONVERTED_TO_STRING)
         {
           continue;
         }
 
         std::string key = infoList.front()->GetKey();
 
         itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(), key, value);
       }
 
       ImageReadAccessor imageAccess(image);
       LocaleSwitch localeSwitch2("C");
       m_ImageIO->Write(imageAccess.GetData());
     }
     catch (const std::exception &e)
     {
       mitkThrow() << e.what();
     }
   }
 
   AbstractFileIO::ConfidenceLevel ItkImageIO::GetWriterConfidenceLevel() const
   {
     // Check if the image dimension is supported
     const auto *image = dynamic_cast<const Image *>(this->GetInput());
     if (image == nullptr)
     {
       // We cannot write a null object, DUH!
       return IFileWriter::Unsupported;
     }
 
     if (!m_ImageIO->SupportsDimension(image->GetDimension()))
     {
       // okay, dimension is not supported. We have to look at a special case:
       // 3D-Image with one slice. We can treat that as a 2D image.
       if ((image->GetDimension() == 3) && (image->GetSlicedGeometry()->GetSlices() == 1))
         return IFileWriter::Supported;
       else
         return IFileWriter::Unsupported;
     }
 
     // Check if geometry information will be lost
     if (image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable())
     {
       return IFileWriter::PartiallySupported;
     }
     return IFileWriter::Supported;
   }
 
   ItkImageIO *ItkImageIO::IOClone() const { return new ItkImageIO(*this); }
   void ItkImageIO::InitializeDefaultMetaDataKeys()
   {
     this->m_DefaultMetaDataKeys.push_back("NRRD.space");
     this->m_DefaultMetaDataKeys.push_back("NRRD.kinds");
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE);
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS);
     this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName");
   }
 }
diff --git a/Modules/Core/src/IO/mitkLegacyFileReaderService.cpp b/Modules/Core/src/IO/mitkLegacyFileReaderService.cpp
index f206c43d22..d9abfa1bae 100644
--- a/Modules/Core/src/IO/mitkLegacyFileReaderService.cpp
+++ b/Modules/Core/src/IO/mitkLegacyFileReaderService.cpp
@@ -1,113 +1,113 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkLegacyFileReaderService.h"
 
 #include <mitkCustomMimeType.h>
 #include <mitkIOAdapter.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkProgressBar.h>
 
 mitk::LegacyFileReaderService::LegacyFileReaderService(const mitk::LegacyFileReaderService &other)
   : mitk::AbstractFileReader(other)
 {
 }
 
 mitk::LegacyFileReaderService::LegacyFileReaderService(const std::vector<std::string> &extensions,
                                                        const std::string &category)
   : AbstractFileReader()
 {
   this->SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".legacy.");
 
   CustomMimeType customMimeType;
   customMimeType.SetCategory(category);
 
   for (auto extension : extensions)
   {
     if (!extension.empty() && extension[0] == '.')
     {
       extension.assign(extension.begin() + 1, extension.end());
     }
     customMimeType.AddExtension(extension);
   }
   this->SetDescription(category);
   this->SetMimeType(customMimeType);
 
   m_ServiceReg = this->RegisterService();
 }
 
 mitk::LegacyFileReaderService::~LegacyFileReaderService()
 {
 }
 
 ////////////////////// Reading /////////////////////////
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::LegacyFileReaderService::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::LegacyFileReaderService::DoRead()
 {
   std::vector<BaseData::Pointer> result;
 
   std::list<IOAdapterBase::Pointer> possibleIOAdapter;
   std::list<itk::LightObject::Pointer> allobjects = itk::ObjectFactoryBase::CreateAllInstance("mitkIOAdapter");
 
   for (auto i = allobjects.begin(); i != allobjects.end(); ++i)
   {
     auto *io = dynamic_cast<IOAdapterBase *>(i->GetPointer());
     if (io)
     {
       possibleIOAdapter.push_back(io);
     }
     else
     {
       MITK_ERROR << "Error BaseDataIO factory did not return an IOAdapterBase: " << (*i)->GetNameOfClass() << std::endl;
     }
   }
 
   const std::string path = this->GetLocalFileName();
   for (auto k = possibleIOAdapter.begin(); k != possibleIOAdapter.end(); ++k)
   {
     bool canReadFile = (*k)->CanReadFile(path, "", ""); // they could read the file
 
     if (canReadFile)
     {
       BaseDataSource::Pointer ioObject = (*k)->CreateIOProcessObject(path, "", "");
       ioObject->Update();
       auto numberOfContents = static_cast<int>(ioObject->GetNumberOfOutputs());
 
       if (numberOfContents > 0)
       {
         BaseData::Pointer baseData;
         for (int i = 0; i < numberOfContents; ++i)
         {
           baseData = dynamic_cast<BaseData *>(ioObject->GetOutputs()[i].GetPointer());
           if (baseData) // this is what's wanted, right?
           {
             result.push_back(baseData);
           }
         }
       }
 
       break;
     }
   }
 
   if (result.empty())
   {
     mitkThrow() << "Could not read file '" << path << "'";
   }
 
   return result;
 }
 
 mitk::LegacyFileReaderService *mitk::LegacyFileReaderService::Clone() const
 {
   return new LegacyFileReaderService(*this);
 }
diff --git a/Modules/Core/src/IO/mitkLegacyFileReaderService.h b/Modules/Core/src/IO/mitkLegacyFileReaderService.h
index 598220201a..096ba02263 100644
--- a/Modules/Core/src/IO/mitkLegacyFileReaderService.h
+++ b/Modules/Core/src/IO/mitkLegacyFileReaderService.h
@@ -1,42 +1,44 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKLEGACYFILEREADERSERVICE_H
 #define MITKLEGACYFILEREADERSERVICE_H
 
 #include <mitkAbstractFileReader.h>
 
 namespace mitk
 {
   // This class wraps mitk::FileReader instances registered as
   // "mitkIOAdapter" via the ITK object factory system as a
   // micro service.
   class LegacyFileReaderService : public mitk::AbstractFileReader
   {
   public:
     LegacyFileReaderService(const LegacyFileReaderService &other);
 
     LegacyFileReaderService(const std::vector<std::string> &extensions, const std::string &category);
     ~LegacyFileReaderService() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
+
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     LegacyFileReaderService *Clone() const override;
 
     us::ServiceRegistration<mitk::IFileReader> m_ServiceReg;
   };
 
 } // namespace mitk
 
 #endif /* MITKLEGACYFILEREADERSERVICE_H */
diff --git a/Modules/Core/src/IO/mitkPointSetReaderService.cpp b/Modules/Core/src/IO/mitkPointSetReaderService.cpp
index 24dac6ba8c..68cc84f562 100644
--- a/Modules/Core/src/IO/mitkPointSetReaderService.cpp
+++ b/Modules/Core/src/IO/mitkPointSetReaderService.cpp
@@ -1,275 +1,275 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkPointSetReaderService.h"
 #include "mitkGeometry3DToXML.h"
 #include "mitkIOMimeTypes.h"
 #include "mitkProportionalTimeGeometry.h"
 
 // STL
 #include <fstream>
 #include <iostream>
 #include <mitkLocaleSwitch.h>
 
 #include <tinyxml.h>
 
 mitk::PointSetReaderService::PointSetReaderService()
   : AbstractFileReader(CustomMimeType(IOMimeTypes::POINTSET_MIMETYPE()), "MITK Point Set Reader")
 {
   RegisterService();
 }
 
 mitk::PointSetReaderService::~PointSetReaderService()
 {
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::PointSetReaderService::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::PointSetReaderService::DoRead()
 {
   // Switch the current locale to "C"
   LocaleSwitch localeSwitch("C");
 
   std::vector<itk::SmartPointer<mitk::BaseData>> result;
 
   InputStream stream(this);
 
   TiXmlDocument doc;
   stream >> doc;
   if (!doc.Error())
   {
     TiXmlHandle docHandle(&doc);
     // unsigned int pointSetCounter(0);
     for (TiXmlElement *currentPointSetElement =
            docHandle.FirstChildElement("point_set_file").FirstChildElement("point_set").ToElement();
          currentPointSetElement != nullptr;
          currentPointSetElement = currentPointSetElement->NextSiblingElement())
     {
       mitk::PointSet::Pointer newPointSet = mitk::PointSet::New();
 
       // time geometry assembled for addition after all points
       // else the SetPoint method would already transform the points that we provide it
       mitk::ProportionalTimeGeometry::Pointer timeGeometry = mitk::ProportionalTimeGeometry::New();
 
       if (currentPointSetElement->FirstChildElement("time_series") != nullptr)
       {
         for (TiXmlElement *currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement();
              currentTimeSeries != nullptr;
              currentTimeSeries = currentTimeSeries->NextSiblingElement())
         {
           unsigned int currentTimeStep(0);
           TiXmlElement *currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id");
 
           currentTimeStep = atoi(currentTimeSeriesID->GetText());
 
           timeGeometry->Expand(currentTimeStep + 1); // expand (default to identity) in any case
           TiXmlElement *geometryElem = currentTimeSeries->FirstChildElement("Geometry3D");
           if (geometryElem)
           {
             Geometry3D::Pointer geometry = Geometry3DToXML::FromXML(geometryElem);
             if (geometry.IsNotNull())
             {
               timeGeometry->SetTimeStepGeometry(geometry, currentTimeStep);
             }
             else
             {
               MITK_ERROR << "Could not deserialize Geometry3D element.";
             }
           }
           else
           {
             MITK_WARN << "Fallback to legacy behavior: defining PointSet geometry as identity";
           }
 
           newPointSet = this->ReadPoints(newPointSet, currentTimeSeries, currentTimeStep);
         }
       }
       else
       {
         newPointSet = this->ReadPoints(newPointSet, currentPointSetElement, 0);
       }
 
       newPointSet->SetTimeGeometry(timeGeometry);
 
       result.push_back(newPointSet.GetPointer());
     }
   }
   else
   {
     mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc();
   }
 
   return result;
 }
 
 mitk::BaseGeometry::Pointer mitk::PointSetReaderService::ReadGeometry(TiXmlElement *parentElement)
 {
   TiXmlElement *geometryElem = parentElement->FirstChildElement("geometry3d");
   if (!geometryElem)
     return nullptr;
 
   // data to generate
   AffineTransform3D::MatrixType matrix;
   AffineTransform3D::OffsetType offset;
   bool isImageGeometry(false);
   unsigned int frameOfReferenceID(0);
   BaseGeometry::BoundsArrayType bounds;
 
   bool somethingMissing(false);
 
   // find data in xml structure
   TiXmlElement *imageGeometryElem = geometryElem->FirstChildElement("image_geometry");
   if (imageGeometryElem)
   {
     std::string igs = imageGeometryElem->GetText();
     isImageGeometry = igs == "true" || igs == "TRUE" || igs == "1";
   }
   else
     somethingMissing = true;
 
   TiXmlElement *frameOfReferenceElem = geometryElem->FirstChildElement("frame_of_reference_id");
   if (frameOfReferenceElem)
   {
     frameOfReferenceID = atoi(frameOfReferenceElem->GetText());
   }
   else
     somethingMissing = true;
 
   TiXmlElement *indexToWorldElem = geometryElem->FirstChildElement("index_to_world");
   if (indexToWorldElem)
   {
     TiXmlElement *matrixElem = indexToWorldElem->FirstChildElement("matrix3x3");
     TiXmlElement *offsetElem = indexToWorldElem->FirstChildElement("offset");
     if (indexToWorldElem && offsetElem)
     {
       TiXmlElement *col0 = matrixElem->FirstChildElement("column_0");
       TiXmlElement *col1 = matrixElem->FirstChildElement("column_1");
       TiXmlElement *col2 = matrixElem->FirstChildElement("column_2");
 
       if (col0 && col1 && col2)
       {
         somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("x", &matrix[0][0]);
         somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("y", &matrix[1][0]);
         somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("z", &matrix[2][0]);
 
         somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("x", &matrix[0][1]);
         somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("y", &matrix[1][1]);
         somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("z", &matrix[2][1]);
 
         somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("x", &matrix[0][2]);
         somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("y", &matrix[1][2]);
         somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("z", &matrix[2][2]);
       }
       else
         somethingMissing = true;
 
       somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("x", &offset[0]);
       somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("y", &offset[1]);
       somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("z", &offset[2]);
     }
     else
       somethingMissing = true;
 
     TiXmlElement *boundsElem = geometryElem->FirstChildElement("bounds");
     if (boundsElem)
     {
       TiXmlElement *minBoundsElem = boundsElem->FirstChildElement("min");
       TiXmlElement *maxBoundsElem = boundsElem->FirstChildElement("max");
 
       if (minBoundsElem && maxBoundsElem)
       {
         somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("x", &bounds[0]);
         somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("y", &bounds[2]);
         somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("z", &bounds[4]);
 
         somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("x", &bounds[1]);
         somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("y", &bounds[3]);
         somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("z", &bounds[5]);
       }
       else
         somethingMissing = true;
     }
     else
       somethingMissing = true;
   }
   else
     somethingMissing = true;
 
   if (somethingMissing)
   {
     MITK_ERROR << "XML structure of geometry inside a PointSet file broken. Refusing to build Geometry3D";
     return nullptr;
   }
   else
   {
     Geometry3D::Pointer g = Geometry3D::New();
     g->SetImageGeometry(isImageGeometry);
     g->SetFrameOfReferenceID(frameOfReferenceID);
     g->SetBounds(bounds);
 
     AffineTransform3D::Pointer transform = AffineTransform3D::New();
     transform->SetMatrix(matrix);
     transform->SetOffset(offset);
 
     g->SetIndexToWorldTransform(transform);
 
     return g.GetPointer();
   }
 }
 
 mitk::PointSet::Pointer mitk::PointSetReaderService::ReadPoints(mitk::PointSet::Pointer newPointSet,
                                                                 TiXmlElement *currentTimeSeries,
                                                                 unsigned int currentTimeStep)
 {
   if (currentTimeSeries->FirstChildElement("point") != nullptr)
   {
     for (TiXmlElement *currentPoint = currentTimeSeries->FirstChildElement("point")->ToElement(); currentPoint != nullptr;
          currentPoint = currentPoint->NextSiblingElement())
     {
       unsigned int id(0);
       auto spec((mitk::PointSpecificationType)0);
       double x(0.0);
       double y(0.0);
       double z(0.0);
 
       id = atoi(currentPoint->FirstChildElement("id")->GetText());
       if (currentPoint->FirstChildElement("specification") != nullptr)
       {
         spec = (mitk::PointSpecificationType)atoi(currentPoint->FirstChildElement("specification")->GetText());
       }
       x = atof(currentPoint->FirstChildElement("x")->GetText());
       y = atof(currentPoint->FirstChildElement("y")->GetText());
       z = atof(currentPoint->FirstChildElement("z")->GetText());
 
       mitk::Point3D point;
       mitk::FillVector3D(point, x, y, z);
       newPointSet->SetPoint(id, point, spec, currentTimeStep);
     }
   }
   else
   {
     if (currentTimeStep != newPointSet->GetTimeSteps() + 1)
     {
       newPointSet->Expand(currentTimeStep + 1); // expand time step series with empty time step
     }
   }
   return newPointSet;
 }
 
 mitk::PointSetReaderService::PointSetReaderService(const mitk::PointSetReaderService &other)
   : mitk::AbstractFileReader(other)
 {
 }
 
 mitk::PointSetReaderService *mitk::PointSetReaderService::Clone() const
 {
   return new mitk::PointSetReaderService(*this);
 }
diff --git a/Modules/Core/src/IO/mitkPointSetReaderService.h b/Modules/Core/src/IO/mitkPointSetReaderService.h
index 42854d4aec..5aba51b592 100644
--- a/Modules/Core/src/IO/mitkPointSetReaderService.h
+++ b/Modules/Core/src/IO/mitkPointSetReaderService.h
@@ -1,60 +1,62 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef _MITK_POINT_SET_READER_SERVICE__H_
 #define _MITK_POINT_SET_READER_SERVICE__H_
 
 // MITK
 #include <mitkAbstractFileReader.h>
 #include <mitkPointSet.h>
 
 class TiXmlElement;
 
 namespace mitk
 {
   /**
    * @internal
    *
    * @brief reads xml representations of mitk::PointSets from a file
    *
    * Reader for xml files containing one or multiple xml represenations of
    * mitk::PointSet. If multiple mitk::PointSet objects are stored in one file,
    * these are assigned to multiple BaseData objects.
    *
    * The reader is able to read the old 3D Pointsets without the "specification" and "timeseries" tags and the new 4D
    * Pointsets.
    *
    * @ingroup IO
    */
   class PointSetReaderService : public AbstractFileReader
   {
   public:
     PointSetReaderService();
     ~PointSetReaderService() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
+
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     PointSetReaderService(const PointSetReaderService &other);
 
     mitk::BaseGeometry::Pointer ReadGeometry(TiXmlElement *parentElement);
 
     mitk::PointSet::Pointer ReadPoints(mitk::PointSet::Pointer newPointSet,
                                        TiXmlElement *currentTimeSeries,
                                        unsigned int currentTimeStep);
 
     PointSetReaderService *Clone() const override;
   };
 }
 
 #endif
diff --git a/Modules/Core/src/IO/mitkRawImageFileReader.cpp b/Modules/Core/src/IO/mitkRawImageFileReader.cpp
index 7bb6559e8c..ee98b414be 100644
--- a/Modules/Core/src/IO/mitkRawImageFileReader.cpp
+++ b/Modules/Core/src/IO/mitkRawImageFileReader.cpp
@@ -1,198 +1,198 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkRawImageFileReader.h"
 #include "mitkIOConstants.h"
 #include "mitkIOMimeTypes.h"
 #include "mitkITKImageImport.h"
 #include "mitkImageCast.h"
 
 #include <itkImage.h>
 #include <itkImageFileReader.h>
 #include <itkRawImageIO.h>
 
 mitk::RawImageFileReaderService::RawImageFileReaderService()
   : AbstractFileReader(CustomMimeType(IOMimeTypes::RAW_MIMETYPE()), "ITK raw image reader")
 {
   Options defaultOptions;
 
   defaultOptions[IOConstants::PIXEL_TYPE()] = IOConstants::PIXEL_TYPE_USHORT();
 
   std::vector<std::string> pixelEnum;
   pixelEnum.push_back(IOConstants::PIXEL_TYPE_UCHAR());
   pixelEnum.push_back(IOConstants::PIXEL_TYPE_CHAR());
   pixelEnum.push_back(IOConstants::PIXEL_TYPE_USHORT());
   pixelEnum.push_back(IOConstants::PIXEL_TYPE_SHORT());
   pixelEnum.push_back(IOConstants::PIXEL_TYPE_UINT());
   pixelEnum.push_back(IOConstants::PIXEL_TYPE_INT());
   pixelEnum.push_back(IOConstants::PIXEL_TYPE_FLOAT());
   pixelEnum.push_back(IOConstants::PIXEL_TYPE_DOUBLE());
   defaultOptions[IOConstants::PIXEL_TYPE_ENUM()] = pixelEnum;
 
   defaultOptions[IOConstants::DIMENSION()] = std::string("3");
   std::vector<std::string> dimEnum;
   dimEnum.push_back("2");
   dimEnum.push_back("3");
   defaultOptions[IOConstants::DIMENSION_ENUM()] = dimEnum;
 
   defaultOptions[IOConstants::ENDIANNESS()] = IOConstants::ENDIANNESS_LITTLE();
   std::vector<std::string> endianEnum;
   endianEnum.push_back(IOConstants::ENDIANNESS_LITTLE());
   endianEnum.push_back(IOConstants::ENDIANNESS_BIG());
   defaultOptions[IOConstants::ENDIANNESS_ENUM()] = endianEnum;
 
   defaultOptions[IOConstants::SIZE_X()] = 0;
   defaultOptions[IOConstants::SIZE_Y()] = 0;
   defaultOptions[IOConstants::SIZE_Z()] = 0;
   // defaultOptions[IOConstants::SIZE_T()] = 0;
 
   this->SetDefaultOptions(defaultOptions);
 
   this->RegisterService();
 }
 
 mitk::RawImageFileReaderService::RawImageFileReaderService(const mitk::RawImageFileReaderService &other)
   : AbstractFileReader(other)
 {
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::RawImageFileReaderService::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::RawImageFileReaderService::DoRead()
 {
   std::vector<mitk::BaseData::Pointer> result;
 
   const std::string path = this->GetLocalFileName();
 
   const Options options = this->GetOptions();
 
   const std::string dimensionality = options.find(IOConstants::DIMENSION())->second.ToString();
   const std::string pixelType = options.find(IOConstants::PIXEL_TYPE())->second.ToString();
 
   EndianityType endianity =
     options.find(IOConstants::ENDIANNESS())->second.ToString() == IOConstants::ENDIANNESS_LITTLE() ? LITTLE : BIG;
   int dimensions[4];
   dimensions[0] = us::any_cast<int>(options.find(IOConstants::SIZE_X())->second);
   dimensions[1] = us::any_cast<int>(options.find(IOConstants::SIZE_Y())->second);
   dimensions[2] = us::any_cast<int>(options.find(IOConstants::SIZE_Z())->second);
   dimensions[3] = 0; // us::any_cast<int>(options.find(IOConstants::SIZE_T())->second);
 
   // check file dimensionality and pixel type and perform reading according to it
   if (dimensionality == "2")
   {
     if (pixelType == IOConstants::PIXEL_TYPE_CHAR())
       result.push_back(TypedRead<signed char, 2>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_UCHAR())
       result.push_back(TypedRead<unsigned char, 2>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_SHORT())
       result.push_back(TypedRead<signed short int, 2>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_USHORT())
       result.push_back(TypedRead<unsigned short int, 2>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_UINT())
       result.push_back(TypedRead<unsigned int, 2>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_INT())
       result.push_back(TypedRead<signed int, 2>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_FLOAT())
       result.push_back(TypedRead<float, 2>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_DOUBLE())
       result.push_back(TypedRead<double, 2>(path, endianity, dimensions));
     else
     {
       MITK_INFO << "Error while reading raw file: Dimensionality or pixel type not supported or not properly set"
                 << std::endl;
     }
   }
   else if (dimensionality == "3")
   {
     if (pixelType == IOConstants::PIXEL_TYPE_CHAR())
       result.push_back(TypedRead<signed char, 3>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_UCHAR())
       result.push_back(TypedRead<unsigned char, 3>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_SHORT())
       result.push_back(TypedRead<signed short int, 3>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_USHORT())
       result.push_back(TypedRead<unsigned short int, 3>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_UINT())
       result.push_back(TypedRead<unsigned int, 3>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_INT())
       result.push_back(TypedRead<signed int, 3>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_FLOAT())
       result.push_back(TypedRead<float, 3>(path, endianity, dimensions));
     else if (pixelType == IOConstants::PIXEL_TYPE_DOUBLE())
       result.push_back(TypedRead<double, 3>(path, endianity, dimensions));
     else
     {
       MITK_INFO << "Error while reading raw file: Dimensionality or pixel type not supported or not properly set"
                 << std::endl;
     }
   }
   else
   {
     MITK_INFO << "Error while reading raw file: Dimensionality not supported" << std::endl;
   }
 
   return result;
 }
 
 template <typename TPixel, unsigned int VImageDimensions>
 mitk::BaseData::Pointer mitk::RawImageFileReaderService::TypedRead(const std::string &path,
                                                                    EndianityType endianity,
                                                                    int *size)
 {
   typedef itk::Image<TPixel, VImageDimensions> ImageType;
   typedef itk::ImageFileReader<ImageType> ReaderType;
   typedef itk::RawImageIO<TPixel, VImageDimensions> IOType;
 
   typename ReaderType::Pointer reader = ReaderType::New();
   typename IOType::Pointer io = IOType::New();
 
   io->SetFileDimensionality(VImageDimensions);
 
   for (unsigned short int dim = 0; dim < VImageDimensions; ++dim)
   {
     io->SetDimensions(dim, size[dim]);
   }
 
   if (endianity == LITTLE)
   {
     io->SetByteOrderToLittleEndian();
   }
   else if (endianity == BIG)
   {
     io->SetByteOrderToBigEndian();
   }
   else
   {
     MITK_INFO << "Warning: endianity not properly set. Resulting image might be incorrect";
   }
 
   reader->SetImageIO(io);
   reader->SetFileName(path);
 
   try
   {
     reader->Update();
   }
   catch ( const itk::ExceptionObject &err )
   {
     MITK_ERROR << "An error occurred during the raw image reading process: ";
     MITK_INFO << err.GetDescription() << std::endl;
   }
 
   mitk::Image::Pointer image = mitk::Image::New();
   mitk::CastToMitkImage(reader->GetOutput(), image);
   image->SetVolume(reader->GetOutput()->GetBufferPointer());
   return image.GetPointer();
 }
 
 mitk::RawImageFileReaderService *mitk::RawImageFileReaderService::Clone() const
 {
   return new RawImageFileReaderService(*this);
 }
diff --git a/Modules/Core/src/IO/mitkRawImageFileReader.h b/Modules/Core/src/IO/mitkRawImageFileReader.h
index 4752290370..3ad97d9199 100644
--- a/Modules/Core/src/IO/mitkRawImageFileReader.h
+++ b/Modules/Core/src/IO/mitkRawImageFileReader.h
@@ -1,54 +1,54 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKRAWIMAGEFILEREADER_H_
 #define MITKRAWIMAGEFILEREADER_H_
 
 #include "mitkAbstractFileReader.h"
 
 namespace mitk
 {
   /**
    * The user must set the dimensionality, the dimensions and the pixel type.
    * If they are incorrect, the image will not be opened or the visualization will be incorrect.
    */
   class RawImageFileReaderService : public AbstractFileReader
   {
   public:
     /** Supported pixel types. */
     typedef enum { UCHAR, SCHAR, USHORT, SSHORT, UINT, SINT, FLOAT, DOUBLE } IOPixelType;
 
     /** Endianity of bits. */
     typedef enum { LITTLE, BIG } EndianityType;
 
     RawImageFileReaderService();
 
   protected:
     RawImageFileReaderService(const RawImageFileReaderService &other);
 
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
     using mitk::AbstractFileReader::Read;
 
   private:
     template <typename TPixel, unsigned int VImageDimensions>
     mitk::BaseData::Pointer TypedRead(const std::string &path, EndianityType endianity, int *size);
 
     RawImageFileReaderService *Clone() const override;
 
     /** Vector containing dimensions of image to be read. */
     itk::Vector<int, 3> m_Dimensions;
   };
 
 } // namespace mitk
 
 #endif /* MITKRAWIMAGEFILEREADER_H_ */
diff --git a/Modules/Core/src/IO/mitkSurfaceStlIO.cpp b/Modules/Core/src/IO/mitkSurfaceStlIO.cpp
index fa919c857a..e64e9a1634 100644
--- a/Modules/Core/src/IO/mitkSurfaceStlIO.cpp
+++ b/Modules/Core/src/IO/mitkSurfaceStlIO.cpp
@@ -1,160 +1,160 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkSurfaceStlIO.h"
 
 #include "mitkIOMimeTypes.h"
 #include "mitkLocaleSwitch.h"
 #include "mitkSurface.h"
 
 #include <vtkCleanPolyData.h>
 #include <vtkErrorCode.h>
 #include <vtkPolyDataNormals.h>
 #include <vtkSTLReader.h>
 #include <vtkSTLWriter.h>
 #include <vtkSmartPointer.h>
 #include <vtkTriangleFilter.h>
 
 namespace mitk
 {
   std::string SurfaceStlIO::OPTION_MERGE_POINTS()
   {
     static std::string s = "Merge points";
     return s;
   }
 
   std::string SurfaceStlIO::OPTION_TAG_SOLIDS()
   {
     static std::string s = "Tag solids";
     return s;
   }
 
   std::string SurfaceStlIO::OPTION_CLEAN()
   {
     static std::string s = "Clean poly data";
     return s;
   }
 
   SurfaceStlIO::SurfaceStlIO()
     : SurfaceVtkIO(Surface::GetStaticNameOfClass(), IOMimeTypes::STEREOLITHOGRAPHY_MIMETYPE(), "Stereolithography")
   {
     Options defaultOptions;
 
     defaultOptions[OPTION_MERGE_POINTS()] = us::Any(true);
     defaultOptions[OPTION_TAG_SOLIDS()] = us::Any(false);
     defaultOptions[OPTION_CLEAN()] = us::Any(true);
 
     this->SetDefaultReaderOptions(defaultOptions);
 
     this->RegisterService();
   }
 
-  std::vector<itk::SmartPointer<BaseData>> SurfaceStlIO::Read()
+  std::vector<itk::SmartPointer<BaseData>> SurfaceStlIO::DoRead()
   {
     LocaleSwitch localeSwitch("C");
 
     Options options = this->GetReaderOptions();
 
     mitk::Surface::Pointer output = mitk::Surface::New();
 
     vtkSmartPointer<vtkSTLReader> stlReader = vtkSmartPointer<vtkSTLReader>::New();
     stlReader->SetFileName(this->GetLocalFileName().c_str());
 
     bool mergePoints = true;
     bool tagSolids = false;
     bool cleanData = true;
 
     try
     {
       mergePoints = us::any_cast<bool>(options[OPTION_MERGE_POINTS()]);
       tagSolids = us::any_cast<bool>(options[OPTION_TAG_SOLIDS()]);
       cleanData = us::any_cast<bool>(options[OPTION_CLEAN()]);
     }
     catch (const us::BadAnyCastException &e)
     {
       MITK_WARN << "Unexpected error: " << e.what();
     }
 
     stlReader->SetMerging(mergePoints);
     stlReader->SetScalarTags(tagSolids);
 
     vtkSmartPointer<vtkPolyDataNormals> normalsGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
     normalsGenerator->SetInputConnection(stlReader->GetOutputPort());
 
     vtkSmartPointer<vtkPolyDataAlgorithm> algo = normalsGenerator;
     if (cleanData)
     {
       vtkSmartPointer<vtkCleanPolyData> cleanPolyDataFilter = vtkSmartPointer<vtkCleanPolyData>::New();
       cleanPolyDataFilter->SetInputConnection(normalsGenerator->GetOutputPort());
       cleanPolyDataFilter->PieceInvariantOff();
       cleanPolyDataFilter->ConvertLinesToPointsOff();
       cleanPolyDataFilter->ConvertPolysToLinesOff();
       cleanPolyDataFilter->ConvertStripsToPolysOff();
       if (mergePoints)
       {
         cleanPolyDataFilter->PointMergingOn();
       }
       algo = cleanPolyDataFilter;
     }
     algo->Update();
 
     if (algo->GetOutput() != nullptr)
     {
       vtkSmartPointer<vtkPolyData> surfaceWithNormals = algo->GetOutput();
       output->SetVtkPolyData(surfaceWithNormals);
     }
 
     std::vector<BaseData::Pointer> result;
     result.push_back(output.GetPointer());
     return result;
   }
 
   void SurfaceStlIO::Write()
   {
     LocaleSwitch localeSwitch("C");
 
     ValidateOutputLocation();
     const auto *input = dynamic_cast<const Surface *>(this->GetInput());
 
     const unsigned int timesteps = input->GetTimeGeometry()->CountTimeSteps();
     for (unsigned int t = 0; t < timesteps; ++t)
     {
       std::string fileName;
       vtkSmartPointer<vtkPolyData> polyData = this->GetPolyData(t, fileName);
       vtkSmartPointer<vtkTriangleFilter> triangleFilter = vtkSmartPointer<vtkTriangleFilter>::New();
       triangleFilter->SetInputData(polyData);
       vtkSmartPointer<vtkSTLWriter> writer = vtkSmartPointer<vtkSTLWriter>::New();
       writer->SetInputConnection(triangleFilter->GetOutputPort());
 
       // The vtk stl writer cannot write to streams
       LocalFile localFile(this);
       writer->SetFileName(localFile.GetFileName().c_str());
 
       if (writer->Write() == 0 || writer->GetErrorCode() != 0)
       {
         mitkThrow() << "Error during surface writing"
                     << (writer->GetErrorCode() ?
                           std::string(": ") + vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) :
                           std::string());
       }
 
       if (this->GetOutputStream() && input->GetTimeGeometry()->CountTimeSteps() > 1)
       {
         MITK_WARN << "Writing multiple time-steps to output streams is not supported. "
                   << "Only the first time-step will be written";
         break;
       }
     }
   }
 
   SurfaceStlIO *SurfaceStlIO::IOClone() const { return new SurfaceStlIO(*this); }
 }
diff --git a/Modules/Core/src/IO/mitkSurfaceStlIO.h b/Modules/Core/src/IO/mitkSurfaceStlIO.h
index 4d9ef51748..ffe36e1e60 100644
--- a/Modules/Core/src/IO/mitkSurfaceStlIO.h
+++ b/Modules/Core/src/IO/mitkSurfaceStlIO.h
@@ -1,43 +1,45 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef _MITK_SURFACE_STL_IO_H_
 #define _MITK_SURFACE_STL_IO_H_
 
 #include "mitkSurfaceVtkIO.h"
 
 namespace mitk
 {
   class SurfaceStlIO : public mitk::SurfaceVtkIO
   {
   public:
     SurfaceStlIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
 
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     SurfaceStlIO *IOClone() const override;
 
     static std::string OPTION_MERGE_POINTS();
     static std::string OPTION_TAG_SOLIDS();
     static std::string OPTION_CLEAN();
   };
 }
 
 #endif //_MITK_SURFACE_STL_IO_H_
diff --git a/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.cpp b/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.cpp
index 36b25c483a..1dbc32bc49 100644
--- a/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.cpp
+++ b/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.cpp
@@ -1,117 +1,117 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkSurfaceVtkLegacyIO.h"
 
 #include "mitkIOMimeTypes.h"
 #include "mitkSurface.h"
 
 #include <vtkErrorCode.h>
 #include <vtkPolyDataReader.h>
 #include <vtkPolyDataWriter.h>
 #include <vtkSmartPointer.h>
 #include <vtkXMLPolyDataReader.h>
 #include <vtkXMLPolyDataWriter.h>
 
 namespace mitk
 {
   SurfaceVtkLegacyIO::SurfaceVtkLegacyIO()
     : SurfaceVtkIO(Surface::GetStaticNameOfClass(), IOMimeTypes::VTK_POLYDATA_LEGACY_MIMETYPE(), "VTK Legacy PolyData")
   {
     Options defaultOptions;
     defaultOptions["Save as binary file"] = false;
     this->SetDefaultWriterOptions(defaultOptions);
     this->RegisterService();
   }
 
-  std::vector<itk::SmartPointer<BaseData>> SurfaceVtkLegacyIO::Read()
+  std::vector<itk::SmartPointer<BaseData>> SurfaceVtkLegacyIO::DoRead()
   {
     mitk::Surface::Pointer output = mitk::Surface::New();
 
     // The legay vtk reader cannot work with input streams
     const std::string fileName = this->GetLocalFileName();
     vtkSmartPointer<vtkPolyDataReader> reader = vtkSmartPointer<vtkPolyDataReader>::New();
     reader->SetFileName(fileName.c_str());
     reader->Update();
 
     if (reader->GetOutput() != nullptr)
     {
       output->SetVtkPolyData(reader->GetOutput());
     }
     else
     {
       mitkThrow() << "vtkPolyDataReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode());
     }
 
     std::vector<BaseData::Pointer> result;
     result.push_back(output.GetPointer());
     return result;
   }
 
   IFileIO::ConfidenceLevel SurfaceVtkLegacyIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
     vtkSmartPointer<vtkPolyDataReader> reader = vtkSmartPointer<vtkPolyDataReader>::New();
     reader->SetFileName(this->GetLocalFileName().c_str());
     if (reader->IsFilePolyData())
     {
       if (std::strcmp(reader->GetHeader(), "vtk output") == 0)
       {
         return Supported;
       }
       else
         return PartiallySupported;
     }
     return Unsupported;
   }
 
   void SurfaceVtkLegacyIO::Write()
   {
     ValidateOutputLocation();
 
     const auto *input = dynamic_cast<const Surface *>(this->GetInput());
 
     const unsigned int timesteps = input->GetTimeGeometry()->CountTimeSteps();
     for (unsigned int t = 0; t < timesteps; ++t)
     {
       std::string fileName;
       vtkSmartPointer<vtkPolyData> polyData = this->GetPolyData(t, fileName);
       vtkSmartPointer<vtkPolyDataWriter> writer = vtkSmartPointer<vtkPolyDataWriter>::New();
       writer->SetInputData(polyData);
       if (us::any_cast<bool>(GetWriterOption("Save as binary file")))
       {
         writer->SetFileTypeToBinary();
       }
       // The legacy vtk poly data writer cannot write to streams
       LocalFile localFile(this);
       writer->SetFileName(localFile.GetFileName().c_str());
 
       if (writer->Write() == 0 || writer->GetErrorCode() != 0)
       {
         mitkThrow() << "Error during surface writing"
                     << (writer->GetErrorCode() ?
                           std::string(": ") + vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) :
                           std::string());
       }
 
       if (this->GetOutputStream() && input->GetTimeGeometry()->CountTimeSteps() > 1)
       {
         MITK_WARN << "Writing multiple time-steps to output streams is not supported. "
                   << "Only the first time-step will be written";
         break;
       }
     }
   }
 
   SurfaceVtkLegacyIO *SurfaceVtkLegacyIO::IOClone() const { return new SurfaceVtkLegacyIO(*this); }
 }
diff --git a/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.h b/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.h
index f9e0c062e1..7be88eaceb 100644
--- a/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.h
+++ b/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.h
@@ -1,43 +1,45 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef _MITK_SURFACE_VTK_LEGACY_IO_H_
 #define _MITK_SURFACE_VTK_LEGACY_IO_H_
 
 #include "mitkSurfaceVtkIO.h"
 
 #include "mitkBaseData.h"
 
 namespace mitk
 {
   class SurfaceVtkLegacyIO : public mitk::SurfaceVtkIO
   {
   public:
     SurfaceVtkLegacyIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    std::vector<BaseData::Pointer> Read() override;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
 
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     SurfaceVtkLegacyIO *IOClone() const override;
   };
 }
 
 #endif //_MITK_SURFACE_VTK_LEGACY_IO_H_
diff --git a/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.cpp b/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.cpp
index 394ab06b25..5b05614279 100644
--- a/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.cpp
+++ b/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.cpp
@@ -1,152 +1,152 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkSurfaceVtkXmlIO.h"
 
 #include "mitkIOMimeTypes.h"
 #include "mitkSurface.h"
 
 #include <vtkErrorCode.h>
 #include <vtkSmartPointer.h>
 #include <vtkXMLPolyDataReader.h>
 #include <vtkXMLPolyDataWriter.h>
 
 namespace mitk
 {
   class VtkXMLPolyDataReader : public ::vtkXMLPolyDataReader
   {
   public:
     static VtkXMLPolyDataReader *New() { return new VtkXMLPolyDataReader(); }
     vtkTypeMacro(VtkXMLPolyDataReader, vtkXMLPolyDataReader)
 
       void SetStream(std::istream *is)
     {
       this->Stream = is;
     }
     std::istream *GetStream() const { return this->Stream; }
   };
 
   class VtkXMLPolyDataWriter : public ::vtkXMLPolyDataWriter
   {
   public:
     static VtkXMLPolyDataWriter *New() { return new VtkXMLPolyDataWriter(); }
     vtkTypeMacro(VtkXMLPolyDataWriter, vtkXMLPolyDataWriter)
 
       void SetStream(std::ostream *os)
     {
       this->Stream = os;
     }
     std::ostream *GetStream() const { return this->Stream; }
   };
 
   SurfaceVtkXmlIO::SurfaceVtkXmlIO()
     : SurfaceVtkIO(Surface::GetStaticNameOfClass(), IOMimeTypes::VTK_POLYDATA_MIMETYPE(), "VTK XML PolyData")
   {
     this->RegisterService();
   }
 
-  std::vector<itk::SmartPointer<BaseData>> SurfaceVtkXmlIO::Read()
+  std::vector<itk::SmartPointer<BaseData>> SurfaceVtkXmlIO::DoRead()
   {
     mitk::Surface::Pointer output = mitk::Surface::New();
 
     vtkSmartPointer<VtkXMLPolyDataReader> reader = vtkSmartPointer<VtkXMLPolyDataReader>::New();
     if (this->GetInputStream())
     {
       reader->SetStream(this->GetInputStream());
     }
     else
     {
       reader->SetFileName(this->GetInputLocation().c_str());
     }
     reader->Update();
 
     if (reader->GetOutput() != nullptr)
     {
       output->SetVtkPolyData(reader->GetOutput());
     }
     else
     {
       mitkThrow() << "vtkXMLPolyDataReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode());
     }
 
     std::vector<BaseData::Pointer> result;
     result.push_back(output.GetPointer());
     return result;
   }
 
   IFileIO::ConfidenceLevel SurfaceVtkXmlIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
     if (this->GetInputStream() == nullptr)
     {
       // check if the xml vtk reader can handle the file
       vtkSmartPointer<VtkXMLPolyDataReader> xmlReader = vtkSmartPointer<VtkXMLPolyDataReader>::New();
       if (xmlReader->CanReadFile(this->GetInputLocation().c_str()) != 0)
       {
         return Supported;
       }
       return Unsupported;
     }
     // in case of an input stream, VTK does not seem to have methods for
     // validating it
     return Supported;
   }
 
   void SurfaceVtkXmlIO::Write()
   {
     ValidateOutputLocation();
 
     const auto *input = dynamic_cast<const Surface *>(this->GetInput());
 
     const unsigned int timesteps = input->GetTimeGeometry()->CountTimeSteps();
     for (unsigned int t = 0; t < timesteps; ++t)
     {
       std::string fileName;
       vtkSmartPointer<vtkPolyData> polyData = this->GetPolyData(t, fileName);
       if (polyData.Get() == nullptr)
       {
         mitkThrow() << "Cannot write empty surface";
       }
 
       vtkSmartPointer<VtkXMLPolyDataWriter> writer = vtkSmartPointer<VtkXMLPolyDataWriter>::New();
       writer->SetInputData(polyData);
 
       if (this->GetOutputStream())
       {
         if (input->GetTimeGeometry()->CountTimeSteps() > 1)
         {
           MITK_WARN << "Writing multiple time-steps to output streams is not supported. "
                     << "Only the first time-step will be written";
         }
         writer->SetStream(this->GetOutputStream());
       }
       else
       {
         writer->SetFileName(fileName.c_str());
       }
 
       if (writer->Write() == 0 || writer->GetErrorCode() != 0)
       {
         mitkThrow() << "Error during surface writing"
                     << (writer->GetErrorCode() ?
                           std::string(": ") + vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) :
                           std::string());
       }
 
       if (this->GetOutputStream())
         break;
     }
   }
 
   SurfaceVtkXmlIO *SurfaceVtkXmlIO::IOClone() const { return new SurfaceVtkXmlIO(*this); }
 }
diff --git a/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.h b/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.h
index 5fb62f41d6..ed4daa3a49 100644
--- a/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.h
+++ b/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.h
@@ -1,43 +1,45 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef _MITK_SURFACE_VTK_XML_IO_H_
 #define _MITK_SURFACE_VTK_XML_IO_H_
 
 #include "mitkSurfaceVtkIO.h"
 
 #include "mitkBaseData.h"
 
 namespace mitk
 {
   class SurfaceVtkXmlIO : public mitk::SurfaceVtkIO
   {
   public:
     SurfaceVtkXmlIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    std::vector<BaseData::Pointer> Read() override;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
 
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     SurfaceVtkXmlIO *IOClone() const override;
   };
 }
 
 #endif //_MITK_SURFACE_VTK_XML_IO_H_
diff --git a/Modules/Core/src/mitkCoreActivator.cpp b/Modules/Core/src/mitkCoreActivator.cpp
index 17a64bf8ae..4e2a3363d9 100644
--- a/Modules/Core/src/mitkCoreActivator.cpp
+++ b/Modules/Core/src/mitkCoreActivator.cpp
@@ -1,321 +1,357 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkCoreActivator.h"
 
+#include <mitkCoreServices.h>
+#include <mitkPropertyPersistenceInfo.h>
+
 // File IO
+#include <mitkIOMetaInformationPropertyConstants.h>
 #include <mitkGeometryDataReaderService.h>
 #include <mitkGeometryDataWriterService.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkIOUtil.h>
 #include <mitkImageVtkLegacyIO.h>
 #include <mitkImageVtkXmlIO.h>
 #include <mitkItkImageIO.h>
 #include <mitkMimeTypeProvider.h>
 #include <mitkPointSetReaderService.h>
 #include <mitkPointSetWriterService.h>
 #include <mitkRawImageFileReader.h>
 #include <mitkSurfaceStlIO.h>
 #include <mitkSurfaceVtkLegacyIO.h>
 #include <mitkSurfaceVtkXmlIO.h>
 
 #include "mitkLegacyFileWriterService.h"
 #include <mitkFileWriter.h>
 
 #include <itkGDCMImageIO.h>
 #include <itkNiftiImageIO.h>
 
 // Micro Services
 #include <usGetModuleContext.h>
 #include <usModule.h>
 #include <usModuleActivator.h>
 #include <usModuleContext.h>
 #include <usModuleEvent.h>
 #include <usModuleInitialization.h>
 #include <usModuleResource.h>
 #include <usModuleResourceStream.h>
 #include <usModuleSettings.h>
 #include <usServiceTracker.h>
 
 // ITK "injects" static initialization code for IO factories
 // via the itkImageIOFactoryRegisterManager.h header (which
 // is generated in the application library build directory).
 // To ensure that the code is called *before* the CppMicroServices
 // static initialization code (which triggers the Activator::Start
 // method), we include the ITK header here.
 #include <itkImageIOFactoryRegisterManager.h>
 
 void HandleMicroServicesMessages(us::MsgType type, const char *msg)
 {
   switch (type)
   {
     case us::DebugMsg:
       MITK_DEBUG << msg;
       break;
     case us::InfoMsg:
       MITK_INFO << msg;
       break;
     case us::WarningMsg:
       MITK_WARN << msg;
       break;
     case us::ErrorMsg:
       MITK_ERROR << msg;
       break;
   }
 }
 
 void AddMitkAutoLoadPaths(const std::string &programPath)
 {
   us::ModuleSettings::AddAutoLoadPath(programPath);
 #ifdef __APPLE__
   // Walk up three directories since that is where the .dylib files are located
   // for build trees.
   std::string additionalPath = programPath;
   bool addPath = true;
   for (int i = 0; i < 3; ++i)
   {
     std::size_t index = additionalPath.find_last_of('/');
     if (index != std::string::npos)
     {
       additionalPath = additionalPath.substr(0, index);
     }
     else
     {
       addPath = false;
       break;
     }
   }
   if (addPath)
   {
     us::ModuleSettings::AddAutoLoadPath(additionalPath);
   }
 #endif
 }
 
+void AddPropertyPersistence(const mitk::PropertyKeyPath& propPath)
+{
+  mitk::CoreServicePointer<mitk::IPropertyPersistence> persistenceService(mitk::CoreServices::GetPropertyPersistence());
+
+  auto info = mitk::PropertyPersistenceInfo::New();
+  if (propPath.IsExplicit())
+  {
+    std::string name = mitk::PropertyKeyPathToPropertyName(propPath);
+    std::string key = name;
+    std::replace(key.begin(), key.end(), '.', '_');
+    info->SetNameAndKey(name, key);
+  }
+  else
+  {
+    std::string key = mitk::PropertyKeyPathToPersistenceKeyRegEx(propPath);
+    std::string keyTemplate = mitk::PropertyKeyPathToPersistenceKeyTemplate(propPath);
+    std::string propRegEx = mitk::PropertyKeyPathToPropertyRegEx(propPath);
+    std::string propTemplate = mitk::PropertyKeyPathToPersistenceNameTemplate(propPath);
+    info->UseRegEx(propRegEx, propTemplate, key, keyTemplate);
+  }
+
+  persistenceService->AddInfo(info);
+}
+
 class FixedNiftiImageIO : public itk::NiftiImageIO
 {
 public:
   /** Standard class typedefs. */
   typedef FixedNiftiImageIO Self;
   typedef itk::NiftiImageIO Superclass;
   typedef itk::SmartPointer<Self> Pointer;
 
   /** Method for creation through the object factory. */
   itkNewMacro(Self)
 
     /** Run-time type information (and related methods). */
     itkTypeMacro(FixedNiftiImageIO, Superclass)
 
       bool SupportsDimension(unsigned long dim) override
   {
     return dim > 1 && dim < 5;
   }
 };
 
 void MitkCoreActivator::Load(us::ModuleContext *context)
 {
   // Handle messages from CppMicroServices
   us::installMsgHandler(HandleMicroServicesMessages);
 
   this->m_Context = context;
 
   // Add the current application directory to the auto-load paths.
   // This is useful for third-party executables.
   std::string programPath = mitk::IOUtil::GetProgramPath();
   if (programPath.empty())
   {
     MITK_WARN << "Could not get the program path.";
   }
   else
   {
     AddMitkAutoLoadPaths(programPath);
   }
 
   // m_RenderingManager = mitk::RenderingManager::New();
   // context->RegisterService<mitk::RenderingManager>(renderingManager.GetPointer());
   m_PlanePositionManager.reset(new mitk::PlanePositionManagerService);
   context->RegisterService<mitk::PlanePositionManagerService>(m_PlanePositionManager.get());
 
   m_PropertyAliases.reset(new mitk::PropertyAliases);
   context->RegisterService<mitk::IPropertyAliases>(m_PropertyAliases.get());
 
   m_PropertyDescriptions.reset(new mitk::PropertyDescriptions);
   context->RegisterService<mitk::IPropertyDescriptions>(m_PropertyDescriptions.get());
 
   m_PropertyExtensions.reset(new mitk::PropertyExtensions);
   context->RegisterService<mitk::IPropertyExtensions>(m_PropertyExtensions.get());
 
   m_PropertyFilters.reset(new mitk::PropertyFilters);
   context->RegisterService<mitk::IPropertyFilters>(m_PropertyFilters.get());
 
   m_PropertyPersistence.reset(new mitk::PropertyPersistence);
   context->RegisterService<mitk::IPropertyPersistence>(m_PropertyPersistence.get());
 
   m_PropertyRelations.reset(new mitk::PropertyRelations);
   context->RegisterService<mitk::IPropertyRelations>(m_PropertyRelations.get());
 
   m_MimeTypeProvider.reset(new mitk::MimeTypeProvider);
   m_MimeTypeProvider->Start();
   m_MimeTypeProviderReg = context->RegisterService<mitk::IMimeTypeProvider>(m_MimeTypeProvider.get());
 
   this->RegisterDefaultMimeTypes();
   this->RegisterItkReaderWriter();
   this->RegisterVtkReaderWriter();
 
   // Add custom Reader / Writer Services
   m_FileReaders.push_back(new mitk::PointSetReaderService());
   m_FileWriters.push_back(new mitk::PointSetWriterService());
   m_FileReaders.push_back(new mitk::GeometryDataReaderService());
   m_FileWriters.push_back(new mitk::GeometryDataWriterService());
   m_FileReaders.push_back(new mitk::RawImageFileReaderService());
 
+  //add properties that should be persistent (if possible/supported by the writer)
+  AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION());
+  AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION());
+  AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_MIME_CATEGORY());
+  AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_MIME_NAME());
+  AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_VERSION());
+  AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_OPTIONS_ANY());
+
   /*
     There IS an option to exchange ALL vtkTexture instances against vtkNeverTranslucentTextureFactory.
     This code is left here as a reminder, just in case we might need to do that some time.
 
     vtkNeverTranslucentTextureFactory* textureFactory = vtkNeverTranslucentTextureFactory::New();
     vtkObjectFactory::RegisterFactory( textureFactory );
     textureFactory->Delete();
     */
 
   this->RegisterLegacyWriter();
 }
 
 void MitkCoreActivator::Unload(us::ModuleContext *)
 {
   for (auto &elem : m_FileReaders)
   {
     delete elem;
   }
 
   for (auto &elem : m_FileWriters)
   {
     delete elem;
   }
 
   for (auto &elem : m_FileIOs)
   {
     delete elem;
   }
 
   for (auto &elem : m_LegacyWriters)
   {
     delete elem;
   }
 
   // The mitk::ModuleContext* argument of the Unload() method
   // will always be 0 for the Mitk library. It makes no sense
   // to use it at this stage anyway, since all libraries which
   // know about the module system have already been unloaded.
 
   // we need to close the internal service tracker of the
   // MimeTypeProvider class here. Otherwise it
   // would hold on to the ModuleContext longer than it is
   // actually valid.
   m_MimeTypeProviderReg.Unregister();
   m_MimeTypeProvider->Stop();
 
   for (std::vector<mitk::CustomMimeType *>::const_iterator mimeTypeIter = m_DefaultMimeTypes.begin(),
                                                            iterEnd = m_DefaultMimeTypes.end();
        mimeTypeIter != iterEnd;
        ++mimeTypeIter)
   {
     delete *mimeTypeIter;
   }
 }
 
 void MitkCoreActivator::RegisterDefaultMimeTypes()
 {
   // Register some default mime-types
 
   std::vector<mitk::CustomMimeType *> mimeTypes = mitk::IOMimeTypes::Get();
   for (std::vector<mitk::CustomMimeType *>::const_iterator mimeTypeIter = mimeTypes.begin(), iterEnd = mimeTypes.end();
        mimeTypeIter != iterEnd;
        ++mimeTypeIter)
   {
     m_DefaultMimeTypes.push_back(*mimeTypeIter);
     m_Context->RegisterService(m_DefaultMimeTypes.back());
   }
 }
 
 void MitkCoreActivator::RegisterItkReaderWriter()
 {
   std::list<itk::LightObject::Pointer> allobjects = itk::ObjectFactoryBase::CreateAllInstance("itkImageIOBase");
 
   for (auto &allobject : allobjects)
   {
     auto *io = dynamic_cast<itk::ImageIOBase *>(allobject.GetPointer());
 
     // NiftiImageIO does not provide a correct "SupportsDimension()" methods
     // and the supported read/write extensions are not ordered correctly
     if (dynamic_cast<itk::NiftiImageIO *>(io))
       continue;
 
     // Use a custom mime-type for GDCMImageIO below
     if (dynamic_cast<itk::GDCMImageIO *>(allobject.GetPointer()))
     {
       // MITK provides its own DICOM reader (which internally uses GDCMImageIO).
       continue;
     }
 
     if (io)
     {
       m_FileIOs.push_back(new mitk::ItkImageIO(io));
     }
     else
     {
       MITK_WARN << "Error ImageIO factory did not return an ImageIOBase: " << (allobject)->GetNameOfClass();
     }
   }
 
   FixedNiftiImageIO::Pointer itkNiftiIO = FixedNiftiImageIO::New();
   mitk::ItkImageIO *niftiIO = new mitk::ItkImageIO(mitk::IOMimeTypes::NIFTI_MIMETYPE(), itkNiftiIO.GetPointer(), 0);
   m_FileIOs.push_back(niftiIO);
 }
 
 void MitkCoreActivator::RegisterVtkReaderWriter()
 {
   m_FileIOs.push_back(new mitk::SurfaceVtkXmlIO());
   m_FileIOs.push_back(new mitk::SurfaceStlIO());
   m_FileIOs.push_back(new mitk::SurfaceVtkLegacyIO());
 
   m_FileIOs.push_back(new mitk::ImageVtkXmlIO());
   m_FileIOs.push_back(new mitk::ImageVtkLegacyIO());
 }
 
 void MitkCoreActivator::RegisterLegacyWriter()
 {
   std::list<itk::LightObject::Pointer> allobjects = itk::ObjectFactoryBase::CreateAllInstance("IOWriter");
 
   for (auto i = allobjects.begin(); i != allobjects.end(); ++i)
   {
     mitk::FileWriter::Pointer io = dynamic_cast<mitk::FileWriter *>(i->GetPointer());
     if (io)
     {
       std::string description = std::string("Legacy ") + io->GetNameOfClass() + " Writer";
       mitk::IFileWriter *writer = new mitk::LegacyFileWriterService(io, description);
       m_LegacyWriters.push_back(writer);
     }
     else
     {
       MITK_ERROR << "Error IOWriter override is not of type mitk::FileWriter: " << (*i)->GetNameOfClass() << std::endl;
     }
   }
 }
 
 US_EXPORT_MODULE_ACTIVATOR(MitkCoreActivator)
 
 // Call CppMicroservices initialization code at the end of the file.
 // This especially ensures that VTK object factories have already
 // been registered (VTK initialization code is injected by implicitly
 // include VTK header files at the top of this file).
 US_INITIALIZE_MODULE
diff --git a/Modules/Core/test/mitkFileReaderRegistryTest.cpp b/Modules/Core/test/mitkFileReaderRegistryTest.cpp
index 66670f36c3..94b414c0fc 100644
--- a/Modules/Core/test/mitkFileReaderRegistryTest.cpp
+++ b/Modules/Core/test/mitkFileReaderRegistryTest.cpp
@@ -1,212 +1,212 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkAbstractFileReader.h"
 #include "mitkFileReaderRegistry.h"
 #include "mitkIFileReader.h"
 #include "mitkTestingMacros.h"
 #include <mitkBaseData.h>
 #include <mitkCustomMimeType.h>
 #include <mitkImage.h>
 
 class DummyReader : public mitk::AbstractFileReader
 {
 public:
   DummyReader(const DummyReader &other) : mitk::AbstractFileReader(other) {}
   DummyReader(const std::string &mimeTypeName, const std::string &extension, int priority) : mitk::AbstractFileReader()
   {
     mitk::CustomMimeType mimeType(mimeTypeName);
     mimeType.AddExtension(extension);
     mimeType.SetComment("This is a dummy description");
 
     this->SetMimeType(mimeType);
 
     this->SetRanking(priority);
     m_ServiceReg = this->RegisterService();
   }
 
   ~DummyReader() override
   {
     if (m_ServiceReg)
       m_ServiceReg.Unregister();
   }
 
   using mitk::AbstractFileReader::Read;
 
-  std::vector<itk::SmartPointer<mitk::BaseData>> Read() override
+  std::vector<itk::SmartPointer<mitk::BaseData>> DoRead() override
   {
     std::vector<mitk::BaseData::Pointer> result;
     return result;
   }
 
 private:
   DummyReader *Clone() const override { return new DummyReader(*this); }
   us::ServiceRegistration<mitk::IFileReader> m_ServiceReg;
 }; // End of internal dummy reader
 
 class DummyReader2 : public mitk::AbstractFileReader
 {
 public:
   DummyReader2(const DummyReader2 &other) : mitk::AbstractFileReader(other) {}
   DummyReader2(const std::string &mimeTypeName, const std::string &extension, int priority) : mitk::AbstractFileReader()
   {
     mitk::CustomMimeType mimeType(mimeTypeName);
     mimeType.AddExtension(extension);
     mimeType.SetComment("This is a second dummy description");
     this->SetMimeType(mimeType);
 
     this->SetRanking(priority);
     m_ServiceReg = this->RegisterService();
   }
 
   ~DummyReader2() override
   {
     if (m_ServiceReg)
       m_ServiceReg.Unregister();
   }
 
   using mitk::AbstractFileReader::Read;
 
-  std::vector<itk::SmartPointer<mitk::BaseData>> Read() override
+  std::vector<itk::SmartPointer<mitk::BaseData>> DoRead() override
   {
     std::vector<mitk::BaseData::Pointer> result;
     return result;
   }
 
 private:
   DummyReader2 *Clone() const override { return new DummyReader2(*this); }
   us::ServiceRegistration<mitk::IFileReader> m_ServiceReg;
 }; // End of internal dummy reader 2
 
 /**
 *  TODO
 */
 int mitkFileReaderRegistryTest(int /*argc*/, char * /*argv*/ [])
 {
   // always start with this!
   MITK_TEST_BEGIN("FileReaderRegistry");
   // mitk::FileReaderRegistry::Pointer frm = mitk::FileReaderRegistry::New();
   // MITK_TEST_CONDITION_REQUIRED(argc == 2,"Testing FileReaderRegistry instantiation");
 
   // DummyReader testDR("application/dummy", "test",1);
   // DummyReader otherDR("application/dummy2", "other",1);
 
   // MITK_TEST_CONDITION_REQUIRED(!testDR.CanRead("/this/is/a/folder/file.tes"),"Negative test of default CanRead()
   // implementation");
 
   // mitk::FileReaderRegistry* readerRegistry = new mitk::FileReaderRegistry;
   // mitk::IFileReader* returned = readerRegistry->GetReader("bla.test");
 
   // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast<mitk::IFileReader&>(testDR) != returned,"Testing correct
   // retrieval of FileReader 1/2");
 
   // returned = readerRegistry->GetReader("other");
 
   // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast<mitk::IFileReader&>(otherDR) != returned,"Testing correct
   // retrieval of FileReader 2/2");
 
   // DummyReader mediocreTestDR("application/dummy", "test", 20);
   // DummyReader prettyFlyTestDR("application/dummy", "test", 50);
   // DummyReader2 awesomeTestDR("application/dummy", "test", 100);
 
   // returned = readerRegistry->GetReader("test");
   // MITK_TEST_CONDITION_REQUIRED(dynamic_cast<DummyReader2*>(returned), "Testing correct priorized retrieval of
   // FileReader: Best reader");
 
   // Now to give those readers some options, then we will try again
 
   //  mitk::IFileReader::OptionList options;
   //  options.push_back(std::make_pair("isANiceGuy", true));
   //  mediocreTestDR.SetOptions(options);
   //  options.clear();
   //  options.push_back(std::make_pair("canFly", true));
   //  prettyFlyTestDR.SetOptions(options);
   //  options.push_back(std::make_pair("isAwesome", true));
   //  awesomeTestDR.SetOptions(options); //note: awesomeReader canFly and isAwesome
 
   //  // Reset Options, use to define what we want the reader to do
   //  options.clear();
   //  mitk::IFileReader::OptionNames optionsFilter;
   //  optionsFilter.push_back("canFly");
   //  returned = readerRegistry->GetReader("test", optionsFilter);
   //  MITK_TEST_CONDITION_REQUIRED(returned && &static_cast<mitk::IFileReader&>(awesomeTestDR) != returned, "Testing
   //  correct retrieval of FileReader with Options: Best reader with options");
 
   //  optionsFilter.push_back("isAwesome");
   //  returned = readerRegistry->GetReader("test", optionsFilter);
   //  MITK_TEST_CONDITION_REQUIRED(returned && &static_cast<mitk::IFileReader&>(awesomeTestDR) != returned, "Testing
   //  correct retrieval of FileReader with multiple Options: Best reader with options");
 
   //  optionsFilter.clear();
   //  optionsFilter.push_back("isANiceGuy");
   //  returned = readerRegistry->GetReader("test", optionsFilter);
   //  MITK_TEST_CONDITION_REQUIRED(returned && &static_cast<mitk::IFileReader&>(mediocreTestDR) != returned, "Testing
   //  correct retrieval of specific FileReader with Options: Low priority reader with specific option");
 
   //  optionsFilter.push_back("canFly");
   //  returned = readerRegistry->GetReader("test", optionsFilter);
   //  MITK_TEST_CONDITION_REQUIRED(returned == nullptr, "Testing correct return of 0 value when no matching reader was
   //  found");
 
   //  // Onward to test the retrieval of multiple readers
 
   //  std::vector< mitk::IFileReader* > returnedList;
   //  returnedList = readerRegistry->GetReaders("test", optionsFilter);
   //  MITK_TEST_CONDITION_REQUIRED(returnedList.empty(), "Testing correct return of zero readers when no matching reader
   //  was found, asking for all compatibles");
 
   //  optionsFilter.clear();
   //  optionsFilter.push_back("canFly");
   //  returnedList = readerRegistry->GetReaders("test", optionsFilter);
   //  MITK_TEST_CONDITION_REQUIRED(returnedList.size() == 2, "Testing correct return of two readers when two matching
   //  reader was found, asking for all compatibles");
   //  MITK_TEST_CONDITION_REQUIRED(dynamic_cast<DummyReader2*>(returnedList.front()), "Testing correct priorization of
   //  returned Readers with options 1/2");
 
   //  optionsFilter.clear();
   //  optionsFilter.push_back("isAwesome");
   //  returnedList = readerRegistry->GetReaders("test", optionsFilter);
   //  MITK_TEST_CONDITION_REQUIRED(returnedList.size() == 1, "Testing correct return of one readers when one matching
   //  reader was found, asking for all compatibles");
   //  MITK_TEST_CONDITION_REQUIRED(dynamic_cast<DummyReader2*>(returnedList.front()), "Testing correctness of result
   //  from former query");
 
   // And now to verify a working read chain for a mps file:
   // mitk::PointSetReader::Pointer psr = mitk::PointSetReader::New();
   // std::vector<mitk::BaseData::Pointer> basedata;
   // basedata = mitk::FileReaderRegistry::Read("F://Build//MITK-Data//pointSet.mps");
   // MITK_TEST_CONDITION_REQUIRED(basedata.size() > 0, "Testing correct read of PointSet");
 
   // Testing templated call to ReaderRegistry
   // mitk::PointSet::Pointer pointset = mitk::FileReaderRegistry::Read< mitk::PointSet
   // >("F://Build//MITK-Data//pointSet.mps");
   // MITK_TEST_CONDITION_REQUIRED(pointset.IsNotNull(), "Testing templated call of Read()");
 
   // And now for something completely different... (Debug)
   // mitk::LegacyFileReaderService::Pointer lfr = mitk::LegacyFileReaderService::New(".nrrd", "Nearly Raw Raster Data");
   // returned = mitk::FileReaderRegistry::GetReader(".nrrd");
   // MITK_TEST_CONDITION_REQUIRED(lfr == returned, "Testing correct retrieval of specific FileReader with Options: Low
   // priority reader with specific option");
 
   // std::vector<mitk::BaseData::Pointer> image =
   // mitk::FileReaderRegistry::Read("F://Build//MITK-Data//Pic2DplusT.nrrd");
   // MITK_TEST_CONDITION_REQUIRED(image.size() > 0, "Testing whether image was returned or not");
   // mitk::Image::Pointer image2 = dynamic_cast<mitk::Image*> (image.front().GetPointer());
   // MITK_TEST_CONDITION_REQUIRED(image2.IsNotNull(), "Testing if BaseData is an image");
 
   // Delete this here because it will call the PrototypeServiceFactory::Unget() method
   // of the dummy readers.
   // delete readerRegistry;
 
   // always end with this!
   MITK_TEST_END();
 }
diff --git a/Modules/Core/test/mitkIOUtilTest.cpp b/Modules/Core/test/mitkIOUtilTest.cpp
index e1e1f73e98..1a7ddd83f3 100644
--- a/Modules/Core/test/mitkIOUtilTest.cpp
+++ b/Modules/Core/test/mitkIOUtilTest.cpp
@@ -1,231 +1,293 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkTestingMacros.h"
 #include <mitkTestFixture.h>
 #include <mitkTestingConfig.h>
 
 #include <mitkIOUtil.h>
 #include <mitkImageGenerator.h>
+#include <mitkIOMetaInformationPropertyConstants.h>
+#include <mitkVersion.h>
 
+#include <itkMetaDataObject.h>
+#include <itkNrrdImageIO.h>
 #include <itksys/SystemTools.hxx>
 
 class mitkIOUtilTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkIOUtilTestSuite);
   MITK_TEST(TestTempMethods);
   MITK_TEST(TestSaveEmptyData);
   MITK_TEST(TestLoadAndSaveImage);
   MITK_TEST(TestNullLoad);
   MITK_TEST(TestNullSave);
   MITK_TEST(TestLoadAndSavePointSet);
   MITK_TEST(TestLoadAndSaveSurface);
   MITK_TEST(TestTempMethodsForUniqueFilenames);
   MITK_TEST(TestTempMethodsForUniqueFilenames);
+  MITK_TEST(TestIOMetaInformation);
   CPPUNIT_TEST_SUITE_END();
 
 private:
   std::string m_ImagePath;
   std::string m_SurfacePath;
   std::string m_PointSetPath;
 
 public:
   void setUp() override
   {
     m_ImagePath = GetTestDataFilePath("Pic3D.nrrd");
     m_SurfacePath = GetTestDataFilePath("binary.stl");
     m_PointSetPath = GetTestDataFilePath("pointSet.mps");
   }
 
   void TestSaveEmptyData()
   {
     mitk::Surface::Pointer data = mitk::Surface::New();
     CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(data, "/tmp/dummy"), mitk::Exception);
   }
 
   void TestTempMethods()
   {
     std::string tmpPath = mitk::IOUtil::GetTempPath();
     CPPUNIT_ASSERT(!tmpPath.empty());
 
     std::ofstream tmpFile;
     std::string tmpFilePath = mitk::IOUtil::CreateTemporaryFile(tmpFile);
     CPPUNIT_ASSERT(tmpFile && tmpFile.is_open());
     CPPUNIT_ASSERT(tmpFilePath.size() > tmpPath.size());
     CPPUNIT_ASSERT(tmpFilePath.substr(0, tmpPath.size()) == tmpPath);
 
     tmpFile.close();
     CPPUNIT_ASSERT(std::remove(tmpFilePath.c_str()) == 0);
 
     std::string programPath = mitk::IOUtil::GetProgramPath();
     CPPUNIT_ASSERT(!programPath.empty());
     std::ofstream tmpFile2;
     std::string tmpFilePath2 = mitk::IOUtil::CreateTemporaryFile(tmpFile2, "my-XXXXXX", programPath);
     CPPUNIT_ASSERT(tmpFile2 && tmpFile2.is_open());
     CPPUNIT_ASSERT(tmpFilePath2.size() > programPath.size());
     CPPUNIT_ASSERT(tmpFilePath2.substr(0, programPath.size()) == programPath);
     tmpFile2.close();
     CPPUNIT_ASSERT(std::remove(tmpFilePath2.c_str()) == 0);
 
     std::ofstream tmpFile3;
     std::string tmpFilePath3 =
       mitk::IOUtil::CreateTemporaryFile(tmpFile3, std::ios_base::binary, "my-XXXXXX.TXT", programPath);
     CPPUNIT_ASSERT(tmpFile3 && tmpFile3.is_open());
     CPPUNIT_ASSERT(tmpFilePath3.size() > programPath.size());
     CPPUNIT_ASSERT(tmpFilePath3.substr(0, programPath.size()) == programPath);
     CPPUNIT_ASSERT(tmpFilePath3.substr(tmpFilePath3.size() - 13, 3) == "my-");
     CPPUNIT_ASSERT(tmpFilePath3.substr(tmpFilePath3.size() - 4) == ".TXT");
     tmpFile3.close();
     // CPPUNIT_ASSERT(std::remove(tmpFilePath3.c_str()) == 0)
 
     std::string tmpFilePath4 = mitk::IOUtil::CreateTemporaryFile();
     std::ofstream file;
     file.open(tmpFilePath4.c_str());
     CPPUNIT_ASSERT_MESSAGE("Testing if file exists after CreateTemporaryFile()", file.is_open());
 
     CPPUNIT_ASSERT_THROW(mitk::IOUtil::CreateTemporaryFile(tmpFile2, "XX"), mitk::Exception);
 
     std::string tmpDir = mitk::IOUtil::CreateTemporaryDirectory();
     CPPUNIT_ASSERT(tmpDir.size() > tmpPath.size());
     CPPUNIT_ASSERT(tmpDir.substr(0, tmpPath.size()) == tmpPath);
     CPPUNIT_ASSERT(itksys::SystemTools::RemoveADirectory(tmpDir.c_str()));
 
     std::string tmpDir2 = mitk::IOUtil::CreateTemporaryDirectory("my-XXXXXX", programPath);
     CPPUNIT_ASSERT(tmpDir2.size() > programPath.size());
     CPPUNIT_ASSERT(tmpDir2.substr(0, programPath.size()) == programPath);
     CPPUNIT_ASSERT(itksys::SystemTools::RemoveADirectory(tmpDir2.c_str()));
   }
 
   void TestTempMethodsForUniqueFilenames()
   {
     int numberOfFiles = 100;
 
     // create 100 empty files
     std::vector<std::string> v100filenames;
     for (int i = 0; i < numberOfFiles; i++)
     {
       v100filenames.push_back(mitk::IOUtil::CreateTemporaryFile());
     }
 
     // check if all of them are unique
     for (int i = 0; i < numberOfFiles; i++)
       for (int j = 0; j < numberOfFiles; j++)
       {
         if (i != j)
         {
           std::stringstream message;
           message << "Checking if file " << i << " and file " << j
                   << " are different, which should be the case because each of them should be unique.";
           CPPUNIT_ASSERT_MESSAGE(message.str(), (v100filenames.at(i) != v100filenames.at(j)));
         }
       }
 
     // delete all the files / clean up
     for (int i = 0; i < numberOfFiles; i++)
     {
       std::remove(v100filenames.at(i).c_str());
     }
   }
 
   void TestLoadAndSaveImage()
   {
     mitk::Image::Pointer img1 = mitk::IOUtil::Load<mitk::Image>(m_ImagePath);
     CPPUNIT_ASSERT(img1.IsNotNull());
 
     std::ofstream tmpStream;
     std::string imagePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "diffpic3d-XXXXXX.nrrd");
     tmpStream.close();
     std::string imagePath2 = mitk::IOUtil::CreateTemporaryFile(tmpStream, "diffpic3d-XXXXXX.nii.gz");
     tmpStream.close();
 
     // the cases where no exception should be thrown
     CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(img1, imagePath));
     CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(img1.GetPointer(), imagePath2));
 
     // load data which does not exist
     CPPUNIT_ASSERT_THROW(mitk::IOUtil::Load("fileWhichDoesNotExist.nrrd"), mitk::Exception);
 
     // delete the files after the test is done
     std::remove(imagePath.c_str());
     std::remove(imagePath2.c_str());
 
     mitk::Image::Pointer relativImage = mitk::ImageGenerator::GenerateGradientImage<float>(4, 4, 4, 1);
     std::string imagePath3 = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX.nrrd");
     tmpStream.close();
     mitk::IOUtil::Save(relativImage, imagePath3);
     CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Load(imagePath3));
     std::remove(imagePath3.c_str());
   }
 
   /**
   * \brief This method calls all available load methods with a nullpointer and an empty pathand expects an exception
   **/
   void TestNullLoad()
   {
     CPPUNIT_ASSERT_THROW(mitk::IOUtil::Load(""), mitk::Exception);
   }
 
   /**
   * \brief This method calls the save method (to which all other convenience save methods reference) with null
   *parameters
   **/
   void TestNullSave()
   {
     CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(nullptr, mitk::IOUtil::CreateTemporaryFile()), mitk::Exception);
     CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(mitk::Image::New().GetPointer(), ""), mitk::Exception);
   }
 
   void TestLoadAndSavePointSet()
   {
     mitk::PointSet::Pointer pointset = mitk::IOUtil::Load<mitk::PointSet>(m_PointSetPath);
     CPPUNIT_ASSERT(pointset.IsNotNull());
 
     std::ofstream tmpStream;
     std::string pointSetPath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX.mps");
     tmpStream.close();
     std::string pointSetPathWithDefaultExtension = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX.mps");
     tmpStream.close();
     std::string pointSetPathWithoutDefaultExtension = mitk::IOUtil::CreateTemporaryFile(tmpStream);
     tmpStream.close();
 
     // the cases where no exception should be thrown
     CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(pointset, pointSetPathWithDefaultExtension));
 
     // test if defaultextension is inserted if no extension is present
     CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(pointset, pointSetPathWithoutDefaultExtension.c_str()));
 
     // delete the files after the test is done
     std::remove(pointSetPath.c_str());
     std::remove(pointSetPathWithDefaultExtension.c_str());
     std::remove(pointSetPathWithoutDefaultExtension.c_str());
   }
 
   void TestLoadAndSaveSurface()
   {
     mitk::Surface::Pointer surface = mitk::IOUtil::Load<mitk::Surface>(m_SurfacePath);
     CPPUNIT_ASSERT(surface.IsNotNull());
 
     std::ofstream tmpStream;
     std::string surfacePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "diffsurface-XXXXXX.stl");
 
     // the cases where no exception should be thrown
     CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(surface, surfacePath));
 
     // test if exception is thrown as expected on unknown extsension
     CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(surface, "testSurface.xXx"), mitk::Exception);
 
     // delete the files after the test is done
     std::remove(surfacePath.c_str());
   }
+
+  std::string GenerateMetaDictKey(const mitk::PropertyKeyPath& propKey)
+  {
+    auto result = mitk::PropertyKeyPathToPropertyName(propKey);
+    std::replace(result.begin(), result.end(), '.', '_');
+    return result;
+  }
+
+  std::string GetValueFromMetaDict(const itk::MetaDataDictionary& dict, const mitk::PropertyKeyPath& propKey)
+  {
+    auto metaValueBase = dict.Get(GenerateMetaDictKey(propKey));
+    auto metaValue = dynamic_cast<const itk::MetaDataObject<std::string>*>(metaValueBase);
+    return metaValue->GetMetaDataObjectValue();
+  }
+
+  void TestIOMetaInformation()
+  {
+    mitk::Image::Pointer img = mitk::IOUtil::Load<mitk::Image>(m_ImagePath);
+    CPPUNIT_ASSERT(img.IsNotNull());
+    
+    auto value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION()).c_str())->GetValueAsString();
+    CPPUNIT_ASSERT_EQUAL(std::string("ITK NrrdImageIO"), value);
+    value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION()).c_str())->GetValueAsString();
+    CPPUNIT_ASSERT_EQUAL(m_ImagePath, value);
+    value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_MIME_CATEGORY()).c_str())->GetValueAsString();
+    CPPUNIT_ASSERT_EQUAL(std::string("Images"), value);
+    value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_MIME_NAME()).c_str())->GetValueAsString();
+    CPPUNIT_ASSERT_EQUAL(std::string("application/vnd.mitk.image.nrrd"), value);
+    value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_VERSION()).c_str())->GetValueAsString();
+    CPPUNIT_ASSERT_EQUAL(std::string(MITK_VERSION_STRING), value);
+
+    //check if the information is persistet correctly on save.
+    std::ofstream tmpStream;
+    std::string imagePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "ioMeta_XXXXXX.nrrd");
+    tmpStream.close();
+    mitk::IOUtil::Save(img, imagePath);
+
+    auto io = itk::NrrdImageIO::New();
+    io->SetFileName(imagePath);
+    io->ReadImageInformation();
+    auto metaDict = io->GetMetaDataDictionary();
+
+    auto metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION());
+    CPPUNIT_ASSERT_EQUAL(std::string("ITK NrrdImageIO"), metaValue);
+    metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION());
+    CPPUNIT_ASSERT_EQUAL(m_ImagePath, metaValue);
+    metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_MIME_CATEGORY());
+    CPPUNIT_ASSERT_EQUAL(std::string("Images"), metaValue);
+    metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_MIME_NAME());
+    CPPUNIT_ASSERT_EQUAL(std::string("application/vnd.mitk.image.nrrd"), metaValue);
+    metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_VERSION());
+    CPPUNIT_ASSERT_EQUAL(std::string(MITK_VERSION_STRING), metaValue);
+
+    // delete the files after the test is done
+    std::remove(imagePath.c_str());
+  }
+
 };
 
 MITK_TEST_SUITE_REGISTRATION(mitkIOUtil)
diff --git a/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp b/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp
index c779a6aefc..c4af10cd1c 100644
--- a/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp
+++ b/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp
@@ -1,199 +1,199 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkPreferenceListReaderOptionsFunctor.h"
 #include "mitkTestFixture.h"
 #include "mitkTestingMacros.h"
 #include <mitkAbstractFileReader.h>
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 #include <usModuleContext.h>
 
 #include <limits>
 
 namespace mitk
 {
   class TestFileReaderService : public mitk::AbstractFileReader
   {
   public:
     TestFileReaderService(const std::string &description)
     : AbstractFileReader(CustomMimeType("TestMimeType"), description)
     {
       m_ServiceRegistration = RegisterService();
     };
 
     ~TestFileReaderService() override
     {
     };
 
     using AbstractFileReader::Read;
 
-    std::vector<itk::SmartPointer<BaseData>> Read() override
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override
     {
       std::vector<itk::SmartPointer<BaseData>> result;
       return result;
     };
 
     ConfidenceLevel GetConfidenceLevel() const override
     {
       return Supported;
     };
 
   private:
     TestFileReaderService * Clone() const override
     {
       return new TestFileReaderService(*this);
     };
 
     us::ServiceRegistration<IFileWriter> m_ServiceRegistration;
   };
 
 } // namespace mitk
 
 
 class mitkPreferenceListReaderOptionsFunctorTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkPreferenceListReaderOptionsFunctorTestSuite);
 
   MITK_TEST(UsePreferenceList);
   MITK_TEST(UseBlackList);
   MITK_TEST(UseNoList);
   MITK_TEST(UseBlackAndPreferenceList);
   MITK_TEST(UseOverlappingBlackAndPreferenceList);
   MITK_TEST(UsePreferenceListWithInexistantReaders);
   MITK_TEST(UseAllBlackedList);
 
 
   CPPUNIT_TEST_SUITE_END();
 
 private:
   std::string m_ImagePath;
   mitk::PreferenceListReaderOptionsFunctor::ListType preference;
   mitk::PreferenceListReaderOptionsFunctor::ListType black;
   mitk::PreferenceListReaderOptionsFunctor::ListType emptyList;
 
   mitk::TestFileReaderService* m_NormalService;
   mitk::TestFileReaderService* m_PrefService;
   mitk::TestFileReaderService* m_BlackService;
   mitk::CustomMimeType* m_TestMimeType;
 
 public:
   void setUp() override
   {
     m_ImagePath = GetTestDataFilePath("BallBinary30x30x30.nrrd");
 
     preference = { "Prefered Test Service" };
     black = { "Unwanted Test Service" };
     emptyList = {};
 
     m_TestMimeType = new mitk::CustomMimeType("TestMimeType");
     m_TestMimeType->AddExtension("nrrd");
     m_TestMimeType->SetCategory(mitk::IOMimeTypes::CATEGORY_IMAGES());
     m_TestMimeType->SetComment("Test mime type");
 
     us::ModuleContext *context = us::GetModuleContext();
     us::ServiceProperties props;
     props[us::ServiceConstants::SERVICE_RANKING()] = 10;
     context->RegisterService(m_TestMimeType, props);
 
     m_NormalService = new mitk::TestFileReaderService("Normal Test Service");
     m_PrefService = new mitk::TestFileReaderService("Prefered Test Service");
     m_BlackService = new mitk::TestFileReaderService("Unwanted Test Service");
   }
 
   void tearDown() override
   {
     delete m_PrefService;
     delete m_BlackService;
     delete m_NormalService;
     delete m_TestMimeType;
   }
 
   void UsePreferenceList()
   {
     mitk::IOUtil::LoadInfo info(m_ImagePath);
 
     mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, emptyList);
     CPPUNIT_ASSERT(true == functor(info));
     auto description = info.m_ReaderSelector.GetSelected().GetDescription();
     CPPUNIT_ASSERT_EQUAL(std::string("Prefered Test Service"), description);
   }
 
   void UseNoList()
   {
     mitk::IOUtil::LoadInfo info(m_ImagePath);
 
     mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, emptyList);
     CPPUNIT_ASSERT(true == functor(info));
     auto description = info.m_ReaderSelector.GetSelected().GetDescription();
     CPPUNIT_ASSERT_EQUAL(std::string("Normal Test Service"), description);
   }
 
   void UseBlackList()
   {
     mitk::IOUtil::LoadInfo info(m_ImagePath);
 
     mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, black);
     CPPUNIT_ASSERT(true == functor(info));
     auto description = info.m_ReaderSelector.GetSelected().GetDescription();
     CPPUNIT_ASSERT(description != "Unwanted Test Service");
   }
 
   void UseBlackAndPreferenceList()
   {
     mitk::IOUtil::LoadInfo info(m_ImagePath);
 
     mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, black);
     CPPUNIT_ASSERT(true == functor(info));
     auto description = info.m_ReaderSelector.GetSelected().GetDescription();
     CPPUNIT_ASSERT_EQUAL(std::string("Prefered Test Service"), description);
   }
 
   void UseOverlappingBlackAndPreferenceList()
   {
     mitk::IOUtil::LoadInfo info(m_ImagePath);
 
     black.push_back("Prefered Test Service");
     black.push_back("Normal Test Service");
 
     mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, black);
     CPPUNIT_ASSERT(true == functor(info));
     auto description = info.m_ReaderSelector.GetSelected().GetDescription();
     CPPUNIT_ASSERT_EQUAL(std::string("ITK NrrdImageIO"), description);
   }
 
   void UsePreferenceListWithInexistantReaders()
   {
     mitk::IOUtil::LoadInfo info(m_ImagePath);
     preference.push_back("InexistantReader");
 
     mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, emptyList);
     CPPUNIT_ASSERT(true == functor(info));
     auto description = info.m_ReaderSelector.GetSelected().GetDescription();
     CPPUNIT_ASSERT_EQUAL(std::string("Prefered Test Service"), description);
   }
 
   void UseAllBlackedList()
   {
     mitk::IOUtil::LoadInfo info(m_ImagePath);
 
     for (auto reader : info.m_ReaderSelector.Get())
     {
       black.push_back(reader.GetDescription());
     }
 
     mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, black);
     CPPUNIT_ASSERT_THROW(functor(info), mitk::Exception);
   }
 };
 
 MITK_TEST_SUITE_REGISTRATION(mitkPreferenceListReaderOptionsFunctor)
diff --git a/Modules/Core/test/mitkPropertyKeyPathTest.cpp b/Modules/Core/test/mitkPropertyKeyPathTest.cpp
index 338df2a20f..2ef686768e 100644
--- a/Modules/Core/test/mitkPropertyKeyPathTest.cpp
+++ b/Modules/Core/test/mitkPropertyKeyPathTest.cpp
@@ -1,314 +1,321 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkPropertyKeyPath.h"
 
 #include "mitkTestFixture.h"
 #include "mitkTestingMacros.h"
 
 #include <regex>
 
 class mitkPropertyKeyPathTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkPropertyKeyPathTestSuite);
 
   MITK_TEST(AccessFunctions);
   MITK_TEST(PropertyKeyPathToPropertyRegEx);
   MITK_TEST(PropertyKeyPathToPersistenceKeyRegEx);
   MITK_TEST(PropertyKeyPathToPersistenceKeyTemplate);
   MITK_TEST(PropertyKeyPathToPersistenceNameTemplate);
   MITK_TEST(PropertyNameToPropertyKeyPath);
   MITK_TEST(PropertyKeyPathToPropertyName);
   MITK_TEST(ExecutePropertyRegEx);
   MITK_TEST(Comparison);
+  MITK_TEST(InitializerList);
 
   CPPUNIT_TEST_SUITE_END();
 
 private:
   mitk::PropertyKeyPath simplePath;
   mitk::PropertyKeyPath simplePath2;
   mitk::PropertyKeyPath deepPath;
   mitk::PropertyKeyPath deepPath_withAnyElement;
   mitk::PropertyKeyPath deepPath_withAnySelection;
   mitk::PropertyKeyPath deepPath_withSelection;
   mitk::PropertyKeyPath verydeepPath;
 
   mitk::PropertyKeyPath emptyPath;
 
 public:
   void setUp() override
   {
     simplePath.AddElement("simple");
 
     simplePath2.AddElement("AA-11");
 
     deepPath.AddElement("a").AddElement("b2").AddElement("c3");
 
     deepPath_withAnyElement.AddElement("a");
     deepPath_withAnyElement.AddAnyElement();
     deepPath_withAnyElement.AddElement("c3");
 
     deepPath_withAnySelection.AddElement("a");
     deepPath_withAnySelection.AddAnySelection("b");
     deepPath_withAnySelection.AddElement("c");
 
     deepPath_withSelection.AddElement("a");
     deepPath_withSelection.AddSelection("b", 6);
     deepPath_withSelection.AddElement("c");
 
     verydeepPath.AddAnySelection("a");
     verydeepPath.AddAnyElement();
     verydeepPath.AddElement("c");
     verydeepPath.AddSelection("d", 4);
     verydeepPath.AddElement("e");
   }
 
   void tearDown() override {}
 
   void AccessFunctions()
   {
     const auto constEmptyPath = emptyPath;
     const auto constVerydeepPath = verydeepPath;
 
     CPPUNIT_ASSERT_THROW(emptyPath.GetFirstNode(), mitk::InvalidPathNodeException);
     CPPUNIT_ASSERT_THROW(emptyPath.GetLastNode(), mitk::InvalidPathNodeException);
     CPPUNIT_ASSERT_THROW(emptyPath.GetNode(0), mitk::InvalidPathNodeException);
     CPPUNIT_ASSERT_THROW(constEmptyPath.GetFirstNode(), mitk::InvalidPathNodeException);
     CPPUNIT_ASSERT_THROW(constEmptyPath.GetLastNode(), mitk::InvalidPathNodeException);
     CPPUNIT_ASSERT_THROW(constEmptyPath.GetNode(0), mitk::InvalidPathNodeException);
 
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing GetFirstNode with 'a.[*].*.c.d.[4].e'", std::string("a"), verydeepPath.GetFirstNode().name);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing const GetFirstNode with 'a.[*].*.c.d.[4].e'", std::string("a"), constVerydeepPath.GetFirstNode().name);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing GetLastNode with 'a.[*].*.c.d.[4].e'", std::string("e"), verydeepPath.GetLastNode().name);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing GetLastNode with 'a.[*].*.c.d.[4].e'", std::string("e"), constVerydeepPath.GetLastNode().name);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing GetNode(3) with 'a.[*].*.c.d.[4].e'", std::string("d"), verydeepPath.GetNode(3).name);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing GetNode(3) with 'a.[*].*.c.d.[4].e'", std::string("d"), constVerydeepPath.GetNode(3).name);
 
     CPPUNIT_ASSERT(5 == constVerydeepPath.GetSize());
     CPPUNIT_ASSERT(0 == emptyPath.GetSize());
   }
 
   void PropertyKeyPathToPropertyRegEx()
   {
     std::string result = mitk::PropertyKeyPathToPropertyRegEx(simplePath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyRegEx() with 'simple'", std::string("simple"), result);
     result = mitk::PropertyKeyPathToPropertyRegEx(deepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyRegEx() with 'a.b2.c3'", std::string("a\\.b2\\.c3"), result);
     result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnyElement);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyRegEx() with 'a.*.c3'", std::string("a\\.([a-zA-Z0-9- ]+)\\.c3"), result);
     result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnySelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyRegEx() with 'a.b.[*].c'", std::string("a\\.b\\.\\[(\\d*)\\]\\.c"), result);
     result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withSelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyRegEx() with 'a.b.[6].c'", std::string("a\\.b\\.\\[6\\]\\.c"), result);
     result = mitk::PropertyKeyPathToPropertyRegEx(verydeepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPropertyRegEx() with 'a.[*].*.c.d.[4].e'",
                                  std::string("a\\.\\[(\\d*)\\]\\.([a-zA-Z0-9- ]+)\\.c\\.d\\.\\[4\\]\\.e"),
                                  result);
   }
 
   void PropertyKeyPathToPersistenceKeyRegEx()
   {
     std::string result = mitk::PropertyKeyPathToPersistenceKeyRegEx(simplePath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'simple'", std::string("simple"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b2.c3'", std::string("a_b2_c3"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withAnyElement);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.*.c3'", std::string("a_([a-zA-Z0-9- ]+)_c3"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withAnySelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b.[*].c'", std::string("a_b_\\[(\\d*)\\]_c"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withSelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b.[6].c'", std::string("a_b_\\[6\\]_c"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyRegEx(verydeepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.[*].*.c.d.[4].e'",
                                  std::string("a_\\[(\\d*)\\]_([a-zA-Z0-9- ]+)_c_d_\\[4\\]_e"),
                                  result);
   }
 
   void PropertyKeyPathToPersistenceKeyTemplate()
   {
     std::string result = mitk::PropertyKeyPathToPersistenceKeyTemplate(simplePath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'simple'", std::string("simple"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b2.c3'", std::string("a_b2_c3"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withAnyElement);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.*.c3'", std::string("a_$1_c3"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withAnySelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b.[*].c'", std::string("a_b_[$1]_c"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withSelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b.[6].c'", std::string("a_b_[6]_c"), result);
     result = mitk::PropertyKeyPathToPersistenceKeyTemplate(verydeepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.[*].*.c.d.[4].e'",
                                  std::string("a_[$1]_$2_c_d_[4]_e"),
                                  result);
   }
 
   void PropertyKeyPathToPersistenceNameTemplate()
   {
     std::string result = mitk::PropertyKeyPathToPersistenceNameTemplate(simplePath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceNameTemplate() with 'simple'", std::string("simple"), result);
     result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b2.c3'", std::string("a.b2.c3"), result);
     result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withAnyElement);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.*.c3'", std::string("a.$1.c3"), result);
     result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withAnySelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b.[*].c'", std::string("a.b.[$1].c"), result);
     result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withSelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b.[6].c'", std::string("a.b.[6].c"), result);
     result = mitk::PropertyKeyPathToPersistenceNameTemplate(verydeepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.[*].*.c.d.[4].e'",
                                  std::string("a.[$1].$2.c.d.[4].e"),
                                  result);
   }
 
   void PropertyNameToPropertyKeyPath()
   {
     mitk::PropertyKeyPath result = mitk::PropertyNameToPropertyKeyPath("simple");
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'simple'", simplePath, result);
     result = mitk::PropertyNameToPropertyKeyPath("a.b2.c3");
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'a.b2.c3'", deepPath, result);
     result = mitk::PropertyNameToPropertyKeyPath("a.*.c3");
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyNameToPropertyKeyPath() with 'a.*.c3'", deepPath_withAnyElement, result);
     result = mitk::PropertyNameToPropertyKeyPath("a.b.[*].c");
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyNameToPropertyKeyPath() with 'a.b.[*].c'", deepPath_withAnySelection, result);
     result = mitk::PropertyNameToPropertyKeyPath("a.b.[6].c");
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyNameToPropertyKeyPath() with 'a.b.[6].c'", deepPath_withSelection, result);
     result = mitk::PropertyNameToPropertyKeyPath("a.[*].*.c.d.[4].e");
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyNameToPropertyKeyPath() with 'a.[*].*.c.d.[4].e'", verydeepPath, result);
 
     result = mitk::PropertyNameToPropertyKeyPath("AA-11");
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'AA-11'", simplePath2, result);
 
     result = mitk::PropertyNameToPropertyKeyPath("$$$IlligalNameChar.sub");
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result);
     result = mitk::PropertyNameToPropertyKeyPath("emptyNode..sub");
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result);
     result = mitk::PropertyNameToPropertyKeyPath("wrongIndex.[d]");
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result);
   }
 
   void PropertyKeyPathToPropertyName()
   {
     std::string result = mitk::PropertyKeyPathToPropertyName(simplePath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyName() with 'simple'", result, std::string("simple"));
     result = mitk::PropertyKeyPathToPropertyName(deepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyName() with 'a.b2.c3'", result, std::string("a.b2.c3"));
     result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnyElement);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyName() with 'a.*.c3'", result, std::string("a.*.c3"));
     result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnySelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyName() with 'a.b.[*].c'", result, std::string("a.b.[*].c"));
     result = mitk::PropertyKeyPathToPropertyName(deepPath_withSelection);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyName() with 'a.b.[6].c'", result, std::string("a.b.[6].c"));
     result = mitk::PropertyKeyPathToPropertyName(verydeepPath);
     CPPUNIT_ASSERT_EQUAL_MESSAGE(
       "Testing PropertyKeyPathToPropertyName() with 'a.[*].*.c.d.[4].e'", result, std::string("a.[*].*.c.d.[4].e"));
   }
 
   void Comparison()
   {
     mitk::PropertyKeyPath deepPath_noSelection =
       mitk::PropertyKeyPath().AddElement("a").AddElement("b").AddElement("c");
 
     CPPUNIT_ASSERT(deepPath_noSelection < deepPath);
     CPPUNIT_ASSERT(deepPath_noSelection < deepPath_withSelection);
     CPPUNIT_ASSERT(deepPath_withSelection < deepPath);
     CPPUNIT_ASSERT(deepPath_withSelection < deepPath_withAnySelection);
     CPPUNIT_ASSERT(deepPath_withAnyElement < deepPath_noSelection);
 
     CPPUNIT_ASSERT(!(deepPath_noSelection < deepPath_noSelection));
     CPPUNIT_ASSERT(!(deepPath_noSelection > deepPath_noSelection));
     CPPUNIT_ASSERT(deepPath_noSelection <= deepPath_noSelection);
     CPPUNIT_ASSERT(deepPath_noSelection >= deepPath_noSelection);
   }
 
   void ExecutePropertyRegEx()
   {
     std::regex regEx(mitk::PropertyKeyPathToPropertyRegEx(simplePath));
     std::string result = mitk::PropertyKeyPathToPropertyName(simplePath);
     CPPUNIT_ASSERT(std::regex_match(result, regEx));
     regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath));
     result = mitk::PropertyKeyPathToPropertyName(deepPath);
     CPPUNIT_ASSERT(std::regex_match(result, regEx));
 
     regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnyElement));
     result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnyElement);
     auto position = result.find("*");
     if (std::string::npos != position)
     {
       result.replace(position, 1, "ConcreteNode1");
       CPPUNIT_ASSERT(std::regex_match(result, regEx));
     }
 
     regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnySelection));
     result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnySelection);
     position = result.find("[*]");
     if (std::string::npos != position)
     {
       result.replace(position, 3, "[10]");
       CPPUNIT_ASSERT(std::regex_match(result, regEx));
     }
 
     regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withSelection));
     result = mitk::PropertyKeyPathToPropertyName(deepPath_withSelection);
     CPPUNIT_ASSERT(std::regex_match(result, regEx));
 
     regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(verydeepPath));
     result = mitk::PropertyKeyPathToPropertyName(verydeepPath);
     position = result.find("[*]");
     if (std::string::npos != position)
     {
       result.replace(position, 3, "[1]");
       position = result.find("*");
       if (std::string::npos != position)
       {
         result.replace(position, 1, "ConcreteNode2");
         CPPUNIT_ASSERT(std::regex_match(result, regEx));
       }
     }
   }
+
+  void InitializerList()
+  {
+    mitk::PropertyKeyPath newPath = {"a","b2","c3"};
+    CPPUNIT_ASSERT(newPath == deepPath);
+  }
 };
 
 MITK_TEST_SUITE_REGISTRATION(mitkPropertyKeyPath)
diff --git a/Modules/Core/test/mitkPropertyRelationRuleBaseTest.cpp b/Modules/Core/test/mitkPropertyRelationRuleBaseTest.cpp
index 04768c9a2d..1be7a6b47e 100644
--- a/Modules/Core/test/mitkPropertyRelationRuleBaseTest.cpp
+++ b/Modules/Core/test/mitkPropertyRelationRuleBaseTest.cpp
@@ -1,915 +1,1101 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkPropertyRelationRuleBase.h"
 
 #include "mitkDataNode.h"
 #include "mitkPointSet.h"
 #include "mitkStringProperty.h"
 
 #include "mitkTestFixture.h"
 #include "mitkTestingMacros.h"
 
 #include <regex>
 
 /** This class is used to test PropertyRelationRuleBase and get access to internals where needed to test them as well.
  */
 namespace mitk
 {
   class TestRule : public mitk::PropertyRelationRuleBase
   {
   public:
     mitkClassMacro(TestRule, mitk::PropertyRelationRuleBase);
     itkFactorylessNewMacro(Self);
     itkCloneMacro(Self);
 
     using RuleIDType = PropertyRelationRuleBase::RuleIDType;
     using RelationUIDType = PropertyRelationRuleBase::RelationUIDType;
     using RelationUIDVectorType = PropertyRelationRuleBase::RelationUIDVectorType;
 
     RuleIDType GetRuleID() const override
     {
       if (m_AbstractMode)
       {
         return "TestRule";
       }
       else
       {
         return "TestRule_type1";
       }
     };
 
     std::string GetDisplayName() const override { return "TestDisplayName"; }
     std::string GetSourceRoleName() const override { return "source role"; }
     std::string GetDestinationRoleName() const override { return "destination role"; }
 
     bool m_AbstractMode;
 
     bool IsAbstract() const override { return m_AbstractMode; }
 
     using Superclass::GetRootKeyPath;
     using Superclass::Connect;
 
   protected:
     TestRule() : m_AbstractMode(false)
     {
     };
 
     ~TestRule() override = default;
 
     using InstanceIDType = PropertyRelationRuleBase::InstanceIDType;
     using InstanceIDVectorType = PropertyRelationRuleBase::InstanceIDVectorType;
 
     bool IsSupportedRuleID(const RuleIDType& ruleID) const override
     {
       if (m_AbstractMode)
       {
         return ruleID.find(this->GetRuleID()) == 0;
       }
       else
       {
         return Superclass::IsSupportedRuleID(ruleID);
       }
     };
 
-    InstanceIDVectorType GetInstanceID_datalayer(const IPropertyProvider *source,
-                                                         const IPropertyProvider *destination) const override
+    DataRelationUIDVectorType GetRelationUIDs_DataLayer(const IPropertyProvider* source,
+      const IPropertyProvider* destination, const InstanceIDVectorType& instances_IDLayer) const override
     {
-      InstanceIDVectorType result;
+      DataRelationUIDVectorType result;
 
-      auto destProp = destination->GetConstProperty("name");
+      mitk::BaseProperty::ConstPointer destProp;
+
+      if (destination != nullptr)
+      {
+        destProp = destination->GetConstProperty("name");
+      }
 
       if (destProp.IsNotNull())
       {
         auto destRegExStr =
           PropertyKeyPathToPropertyRegEx(Superclass::GetRootKeyPath().AddAnyElement().AddElement("dataHandle"));
         auto regEx = std::regex(destRegExStr);
         std::smatch instance_matches;
 
         auto keys = source->GetPropertyKeys();
 
         for (const auto &key : keys)
         {
           if (std::regex_search(key, instance_matches, regEx))
           {
             auto sourceProp = source->GetConstProperty(key);
             if (sourceProp->GetValueAsString() == destProp->GetValueAsString())
             {
               if (instance_matches.size()>1)
               {
-                result.push_back(instance_matches[1]);
+                auto finding = std::find(instances_IDLayer.begin(), instances_IDLayer.end(), instance_matches[1]);
+                if (finding == instances_IDLayer.end())
+                {
+                  result.emplace_back(this->GetRelationUIDByInstanceID(source, instance_matches[1]), this->GetRuleIDByInstanceID(source, instance_matches[1]));
+                }
               }
             }
           }
         }
       }
-      return result;
-    };
 
-    bool HasImplicitDataRelation(const IPropertyProvider *source,
-                                         const IPropertyProvider *destination) const override
-    {
-      auto destProp = destination->GetConstProperty("name");
-      auto sourceProp = source->GetConstProperty("referencedName");
+      if (result.empty() && instances_IDLayer.empty())
+      {
+        auto refNameProp = source->GetConstProperty("referencedName");
+        if (refNameProp.IsNotNull() && (destProp.IsNull() || destProp->GetValueAsString() == refNameProp->GetValueAsString()))
+        {
+          result.emplace_back(refNameProp->GetValueAsString(),"");
+        }
+      }
 
-      return destProp.IsNotNull() && sourceProp.IsNotNull() &&
-             destProp->GetValueAsString() == sourceProp->GetValueAsString();
+      return result;
     };
 
     void Connect_datalayer(IPropertyOwner *source,
                                    const IPropertyProvider *destination,
                                    const InstanceIDType &instanceID) const override
     {
       auto destProp = destination->GetConstProperty("name");
 
       source->SetProperty("referencedName", StringProperty::New(destProp->GetValueAsString()));
       source->SetProperty(
         PropertyKeyPathToPropertyName(Superclass::GetRootKeyPath().AddElement(instanceID).AddElement("dataHandle")),
         StringProperty::New(destProp->GetValueAsString()));
     };
 
-    void Disconnect_datalayer(IPropertyOwner *source, const InstanceIDType & /*instanceID*/) const override
+    void Disconnect_datalayer(IPropertyOwner *source, const RelationUIDType & relationUID) const override
     {
       source->RemoveProperty("referencedName");
+      try
+      {
+        auto instanceID = this->GetInstanceIDByRelationUID(source, relationUID);
+        source->RemoveProperty(
+            PropertyKeyPathToPropertyName(Superclass::GetRootKeyPath().AddElement(instanceID).AddElement("dataHandle")));
+      }
+      catch(...)
+      { }
     };
   };
 } // namespace mitk
 
 class mitkPropertyRelationRuleBaseTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkPropertyRelationRuleBaseTestSuite);
 
   MITK_TEST(GetRootKeyPath);
   MITK_TEST(IsSourceCandidate);
   MITK_TEST(IsDestinationCandidate);
   MITK_TEST(IsSource);
   MITK_TEST(HasRelation);
   MITK_TEST(GetExistingRelations);
   MITK_TEST(GetRelationUIDs);
   MITK_TEST(GetSourceCandidateIndicator);
   MITK_TEST(GetDestinationCandidateIndicator);
   MITK_TEST(GetConnectedSourcesDetector);
   MITK_TEST(GetSourcesDetector);
   MITK_TEST(GetDestinationsDetector);
   MITK_TEST(GetDestinationDetector);
   MITK_TEST(Connect);
   MITK_TEST(Disconnect);
+  MITK_TEST(Disconnect_partial_ID);
+  MITK_TEST(Disconnect_partial_Data);
   MITK_TEST(Connect_abstract);
   MITK_TEST(Disconnect_abstract);
 
   CPPUNIT_TEST_SUITE_END();
 
 private:
   mitk::TestRule::Pointer rule;
   mitk::TestRule::Pointer abstractRule;
 
   mitk::DataNode::Pointer unRelated;
   mitk::PointSet::Pointer unRelated_1_data;
 
   mitk::DataNode::Pointer source_implicit_1;
   mitk::DataNode::Pointer source_data_1;
   mitk::DataNode::Pointer source_idOnly_1;
   mitk::DataNode::Pointer source_1;
 
   mitk::DataNode::Pointer source_multi;
 
   mitk::DataNode::Pointer source_otherRule;
 
   mitk::DataNode::Pointer source_otherTypeRule; //relevant for abstract rule checks. Abstract rule should see it concrete rule not.
 
   mitk::DataNode::Pointer dest_1;
   mitk::PointSet::Pointer dest_1_data;
   mitk::DataNode::Pointer dest_2;
   mitk::PointSet::Pointer dest_2_data;
 
   bool hasRelationProperties(mitk::IPropertyProvider *provider, std::string instance = "") const
   {
     auto keyPath = mitk::PropertyRelationRuleBase::GetRootKeyPath();
     if (!instance.empty())
     {
       keyPath.AddElement(instance);
     }
 
     auto prefix = mitk::PropertyKeyPathToPropertyName(keyPath);
     auto keys = provider->GetPropertyKeys();
 
     for (const auto &key : keys)
     {
       if (key.find(prefix) == 0)
       {
         return true;
       }
     }
 
     return false;
   }
 
 public:
   void setUp() override
   {
     rule = mitk::TestRule::New();
 
     abstractRule = mitk::TestRule::New();
     abstractRule->m_AbstractMode = true;
 
     unRelated = mitk::DataNode::New();
     unRelated->SetName("unRelated");
     unRelated_1_data = mitk::PointSet::New();
     unRelated->SetData(unRelated_1_data);
 
     dest_1 = mitk::DataNode::New();
     dest_1->SetName("dest_1");
     dest_1_data = mitk::PointSet::New();
     dest_1->SetData(dest_1_data);
 
     dest_2 = mitk::DataNode::New();
     dest_2->SetName("dest_2");
     dest_2_data = mitk::PointSet::New();
     dest_2->SetData(dest_2_data);
 
     source_implicit_1 = mitk::DataNode::New();
     source_implicit_1->AddProperty("referencedName", mitk::StringProperty::New(dest_1->GetName()));
 
     source_idOnly_1 = mitk::DataNode::New();
     std::string name = "MITK.Relations.1.relationUID";
     source_idOnly_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid1"));
     name = "MITK.Relations.1.destinationUID";
     source_idOnly_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID()));
     name = "MITK.Relations.1.ruleID";
     source_idOnly_1->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
 
-    source_data_1 = source_implicit_1->Clone();
+    source_data_1 = mitk::DataNode::New();
+    source_data_1->AddProperty("referencedName", mitk::StringProperty::New(dest_1->GetName()));
     name = "MITK.Relations.1.relationUID";
     source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid2"));
     name = "MITK.Relations.1.dataHandle";
     source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetName()));
     name = "MITK.Relations.1.ruleID";
     source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
     name = "MITK.Relations.2.relationUID";
     source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid10"), nullptr, true);
     name = "MITK.Relations.2.destinationUID";
     source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID()));
     name = "MITK.Relations.2.ruleID";
     source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New("TestRule_othertype"));
 
-    source_1 = source_data_1->Clone();
+    source_1 = mitk::DataNode::New();
+    source_1->AddProperty("referencedName", mitk::StringProperty::New(dest_1->GetName()));
     name = "MITK.Relations.1.relationUID";
     source_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid3"), nullptr, true);
     name = "MITK.Relations.1.destinationUID";
     source_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID()));
+    name = "MITK.Relations.1.dataHandle";
+    source_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetName()));
     name = "MITK.Relations.1.ruleID";
     source_1->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
     name = "MITK.Relations.2.relationUID";
     source_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid8"), nullptr, true);
     name = "MITK.Relations.2.destinationUID";
     source_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_2_data->GetUID()));
     name = "MITK.Relations.2.ruleID";
     source_1->AddProperty(name.c_str(), mitk::StringProperty::New("TestRule_othertype"));
 
-    source_multi = source_1->Clone();
+    source_multi = mitk::DataNode::New();
+    source_multi->AddProperty("referencedName", mitk::StringProperty::New(dest_1->GetName()));
     name = "MITK.Relations.1.relationUID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New("uid4"), nullptr, true);
     name = "MITK.Relations.1.destinationUID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID()));
     name = "MITK.Relations.1.ruleID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
+    name = "MITK.Relations.1.dataHandle";
+    source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetName()));
     name = "MITK.Relations.4.relationUID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New("uid5"));
     name = "MITK.Relations.4.destinationUID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(dest_2_data->GetUID()));
     name = "MITK.Relations.4.ruleID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
     name = "MITK.Relations.2.relationUID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New("uid6"));
     name = "MITK.Relations.2.destinationUID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New("unknown"));
     name = "MITK.Relations.2.ruleID";
     source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
 
     source_otherRule = mitk::DataNode::New();
     name = "MITK.Relations.1.relationUID";
     source_otherRule->AddProperty(name.c_str(), mitk::StringProperty::New("uid7"));
     name = "MITK.Relations.1.destinationUID";
     source_otherRule->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID()));
     name = "MITK.Relations.1.ruleID";
     source_otherRule->AddProperty(name.c_str(), mitk::StringProperty::New("otherRuleID"));
 
     source_otherTypeRule = mitk::DataNode::New();
     name = "MITK.Relations.1.relationUID";
     source_otherTypeRule->AddProperty(name.c_str(), mitk::StringProperty::New("uid9"));
     name = "MITK.Relations.1.destinationUID";
     source_otherTypeRule->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID()));
     name = "MITK.Relations.1.ruleID";
     source_otherTypeRule->AddProperty(name.c_str(), mitk::StringProperty::New("TestRule_othertype"));
   }
 
   void tearDown() override {}
 
   void GetRootKeyPath()
   {
     mitk::PropertyKeyPath ref;
     ref.AddElement("MITK").AddElement("Relations");
     CPPUNIT_ASSERT(mitk::PropertyRelationRuleBase::GetRootKeyPath() == ref);
   }
 
   void IsSourceCandidate()
   {
     CPPUNIT_ASSERT(rule->IsSourceCandidate(mitk::DataNode::New()));
     CPPUNIT_ASSERT(!rule->IsSourceCandidate(nullptr));
   }
 
   void IsDestinationCandidate()
   {
     CPPUNIT_ASSERT(rule->IsDestinationCandidate(mitk::DataNode::New()));
     CPPUNIT_ASSERT(!rule->IsDestinationCandidate(nullptr));
   }
 
   void IsSource()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE(
       "Violated precondition (nullptr) does not throw.", rule->IsSource(nullptr), itk::ExceptionObject);
 
     CPPUNIT_ASSERT(!rule->IsSource(unRelated));
-    CPPUNIT_ASSERT(!rule->IsSource(source_implicit_1));
+    CPPUNIT_ASSERT(rule->IsSource(source_implicit_1));
     CPPUNIT_ASSERT(rule->IsSource(source_data_1));
     CPPUNIT_ASSERT(rule->IsSource(source_idOnly_1));
     CPPUNIT_ASSERT(rule->IsSource(source_1));
     CPPUNIT_ASSERT(rule->IsSource(source_multi));
 
     CPPUNIT_ASSERT(!rule->IsSource(source_otherRule));
     CPPUNIT_ASSERT(!rule->IsSource(source_otherTypeRule));
 
     CPPUNIT_ASSERT(!abstractRule->IsSource(unRelated));
-    CPPUNIT_ASSERT(!abstractRule->IsSource(source_implicit_1));
+    CPPUNIT_ASSERT(abstractRule->IsSource(source_implicit_1));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_data_1));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_idOnly_1));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_1));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_multi));
 
     CPPUNIT_ASSERT(!abstractRule->IsSource(source_otherRule));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_otherTypeRule));
   }
 
   void HasRelation()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->HasRelation(nullptr, dest_1),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->HasRelation(source_1, nullptr),
                                  itk::ExceptionObject);
 
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(rule->HasRelation(source_otherRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(rule->HasRelation(source_otherTypeRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-
-    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Implicit_Data);
-    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
-    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_2) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-
-
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherTypeRule, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Implicit_Data);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_data_1, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_2) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated));
+    CPPUNIT_ASSERT(!rule->HasRelation(unRelated, dest_1));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_otherRule, dest_1));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_otherTypeRule, dest_1));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1));
+    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1));
+    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1));
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, dest_2));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1));
+    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_2));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_multi, dest_2, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_2, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_multi, dest_2, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_1, unRelated));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(unRelated, dest_1));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_otherRule, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherTypeRule, dest_1));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_otherTypeRule, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherTypeRule, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_otherTypeRule, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_data_1, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_2));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_multi, dest_2, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_2, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_multi, dest_2, mitk::PropertyRelationRuleBase::RelationType::Complete));
   }
 
   void GetExistingRelations()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->GetExistingRelations(nullptr),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT(rule->GetExistingRelations(unRelated).empty());
     CPPUNIT_ASSERT(rule->GetExistingRelations(source_otherRule).empty());
     CPPUNIT_ASSERT(rule->GetExistingRelations(source_otherTypeRule).empty());
-    CPPUNIT_ASSERT(rule->GetExistingRelations(source_implicit_1).empty());
 
-    auto uids = rule->GetExistingRelations(source_idOnly_1);
+    auto uids = rule->GetExistingRelations(source_implicit_1);
+    CPPUNIT_ASSERT(uids.size() == 1);
+    CPPUNIT_ASSERT(uids.front() == dest_1->GetName());
+
+    uids = rule->GetExistingRelations(source_idOnly_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid1");
 
     uids = rule->GetExistingRelations(source_data_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid2");
 
     uids = rule->GetExistingRelations(source_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid3");
 
     uids = rule->GetExistingRelations(source_multi);
     CPPUNIT_ASSERT(uids.size() == 3);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid4") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid5") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid6") != uids.end());
 
 
     CPPUNIT_ASSERT(abstractRule->GetExistingRelations(unRelated).empty());
     CPPUNIT_ASSERT(abstractRule->GetExistingRelations(source_otherRule).empty());
-    CPPUNIT_ASSERT(abstractRule->GetExistingRelations(source_implicit_1).empty());
+
+    uids = abstractRule->GetExistingRelations(source_implicit_1);
+    CPPUNIT_ASSERT(uids.size() == 1);
+    CPPUNIT_ASSERT(uids.front() == dest_1->GetName());
 
     uids = abstractRule->GetExistingRelations(source_idOnly_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid1");
 
     uids = abstractRule->GetExistingRelations(source_data_1);
     CPPUNIT_ASSERT(uids.size() == 2);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid2") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid10") != uids.end());
 
     uids = abstractRule->GetExistingRelations(source_1);
     CPPUNIT_ASSERT(uids.size() == 2);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid3") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid8") != uids.end());
 
     uids = abstractRule->GetExistingRelations(source_multi);
     CPPUNIT_ASSERT(uids.size() == 3);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid4") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid5") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid6") != uids.end());
 
     uids = abstractRule->GetExistingRelations(source_otherTypeRule);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid9");
 
   }
 
   void GetRelationUIDs()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->GetRelationUIDs(nullptr, dest_1),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->GetRelationUIDs(source_1, nullptr),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_1, unRelated).empty());
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_1, dest_2).empty());
     CPPUNIT_ASSERT(rule->GetRelationUIDs(unRelated, dest_1).empty());
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_otherRule, dest_1).empty());
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_otherTypeRule, dest_1).empty());
 
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_idOnly_1, dest_1).front() == "uid1");
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_data_1, dest_1).front() == "uid2");
     auto uids = rule->GetRelationUIDs(source_1, dest_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid3");
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_multi, dest_1).front() == "uid4");
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_multi, dest_2).front() == "uid5");
 
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_1, unRelated).empty());
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(unRelated, dest_1).empty());
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_otherRule, dest_1).empty());
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_otherTypeRule, dest_1).front() == "uid9");
 
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_idOnly_1, dest_1).front() == "uid1");
     uids = abstractRule->GetRelationUIDs(source_data_1, dest_1);
     CPPUNIT_ASSERT(uids.size() == 2);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid2") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid10") != uids.end());
     uids = abstractRule->GetRelationUIDs(source_1, dest_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid3") != uids.end());
     uids = abstractRule->GetRelationUIDs(source_1, dest_2);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid8") != uids.end());
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_1, dest_1).front() == "uid3");
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_multi, dest_1).front() == "uid4");
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_multi, dest_2).front() == "uid5");
 
   }
 
   void GetSourceCandidateIndicator()
   {
     auto predicate = rule->GetSourceCandidateIndicator();
 
     CPPUNIT_ASSERT(predicate->CheckNode(mitk::DataNode::New()));
     CPPUNIT_ASSERT(!predicate->CheckNode(nullptr));
   }
 
   void GetDestinationCandidateIndicator()
   {
     auto predicate = rule->GetDestinationCandidateIndicator();
 
     CPPUNIT_ASSERT(predicate->CheckNode(mitk::DataNode::New()));
     CPPUNIT_ASSERT(!predicate->CheckNode(nullptr));
   }
 
   void GetConnectedSourcesDetector()
   {
     auto predicate = rule->GetConnectedSourcesDetector();
 
     CPPUNIT_ASSERT(!predicate->CheckNode(nullptr));
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
-    CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_data_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule));
 
 
     auto predicate2 = abstractRule->GetConnectedSourcesDetector();
 
     CPPUNIT_ASSERT(!predicate2->CheckNode(nullptr));
     CPPUNIT_ASSERT(!predicate2->CheckNode(unRelated));
-    CPPUNIT_ASSERT(!predicate2->CheckNode(source_implicit_1));
+    CPPUNIT_ASSERT(predicate2->CheckNode(source_implicit_1));
     CPPUNIT_ASSERT(predicate2->CheckNode(source_data_1));
     CPPUNIT_ASSERT(predicate2->CheckNode(source_idOnly_1));
     CPPUNIT_ASSERT(predicate2->CheckNode(source_1));
     CPPUNIT_ASSERT(predicate2->CheckNode(source_multi));
 
     CPPUNIT_ASSERT(!predicate2->CheckNode(source_otherRule));
     CPPUNIT_ASSERT(predicate2->CheckNode(source_otherTypeRule));
   }
 
   void GetSourcesDetector()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->GetSourcesDetector(nullptr),
                                  itk::ExceptionObject);
 
     auto predicate = rule->GetSourcesDetector(dest_1);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule));
 
     CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_data_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
 
-    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Data);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule));
 
-    CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_data_1));
-    CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
 
-    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::ID);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
 
-    predicate = rule->GetSourcesDetector(dest_2, mitk::PropertyRelationRuleBase::RelationType::Implicit_Data);
+    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
+
+    CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule));
+
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
+
+    predicate = rule->GetSourcesDetector(dest_2);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
 
-    predicate = abstractRule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    predicate = abstractRule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::ID);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
     CPPUNIT_ASSERT(predicate->CheckNode(source_otherTypeRule));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_data_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
 
+    predicate = abstractRule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+
+    CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule));
+
+    CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_data_1));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
+
+    predicate = abstractRule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
+
+    CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule));
+
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_1));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
+
     predicate = abstractRule->GetSourcesDetector(dest_1);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule));
     CPPUNIT_ASSERT(predicate->CheckNode(source_otherTypeRule));
 
     CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_data_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1));
     CPPUNIT_ASSERT(predicate->CheckNode(source_multi));
   }
 
   void GetDestinationsDetector()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->GetDestinationsDetector(nullptr),
                                  itk::ExceptionObject);
 
     auto predicate = rule->GetDestinationsDetector(source_otherRule);
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
 
     predicate = rule->GetDestinationsDetector(source_otherTypeRule);
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
 
     predicate = rule->GetDestinationsDetector(source_implicit_1);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     predicate =
-      rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+      rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
+    predicate =
+      rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
+    predicate =
+      rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
 
     predicate = rule->GetDestinationsDetector(source_data_1);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     predicate =
-      rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+      rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Data);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     predicate =
-      rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+      rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
+    predicate =
+      rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
 
     predicate = rule->GetDestinationsDetector(source_idOnly_1);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     predicate =
-      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
-    CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
+      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
     predicate =
-      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::ID);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
+    predicate =
+      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
 
     predicate = rule->GetDestinationsDetector(source_1);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_2));
     predicate =
-      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Data);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_2));
     predicate =
-      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
+    CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_2));
+    predicate =
+      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_2));
 
     predicate = rule->GetDestinationsDetector(source_multi);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     CPPUNIT_ASSERT(predicate->CheckNode(dest_2));
     predicate =
-      rule->GetDestinationsDetector(source_multi, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+      rule->GetDestinationsDetector(source_multi, mitk::PropertyRelationRuleBase::RelationType::Data);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
-    CPPUNIT_ASSERT(predicate->CheckNode(dest_2));
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_2));
     predicate =
-      rule->GetDestinationsDetector(source_multi, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+      rule->GetDestinationsDetector(source_multi, mitk::PropertyRelationRuleBase::RelationType::ID);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     CPPUNIT_ASSERT(predicate->CheckNode(dest_2));
+    predicate =
+      rule->GetDestinationsDetector(source_multi, mitk::PropertyRelationRuleBase::RelationType::Complete);
+    CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_2));
 
     predicate = abstractRule->GetDestinationsDetector(source_otherTypeRule);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     predicate = abstractRule->GetDestinationsDetector(source_otherTypeRule);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
 
   }
 
   void GetDestinationDetector()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->GetDestinationDetector(nullptr, "uid1"),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (relation uid is invalid) does not throw.",
                                  rule->GetDestinationDetector(source_1, "invalid uid"),
                                  itk::ExceptionObject);
 
     auto predicate = rule->GetDestinationDetector(source_1, "uid3");
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_2));
 
     predicate = rule->GetDestinationDetector(source_multi, "uid5");
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1));
     CPPUNIT_ASSERT(predicate->CheckNode(dest_2));
   }
 
   void Connect()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->Connect(nullptr, dest_1),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->Connect(source_1, nullptr),
                                  itk::ExceptionObject);
 
     // check upgrade of an implicit connection
-    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Implicit_Data);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     rule->Connect(source_implicit_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
 
     // check upgrade of an data connection
-    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     rule->Connect(source_data_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     std::string name = "MITK.Relations.1.destinationUID";
     auto prop = source_data_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE(
       "Destination uid was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was  stored.", prop->GetValueAsString() == dest_1_data->GetUID());
 
     // check actualization of an id only connection
+    CPPUNIT_ASSERT(!rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     rule->Connect(source_idOnly_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     CPPUNIT_ASSERT_MESSAGE("Additional relation was defined instead of updating exting one.",
                            rule->GetExistingRelations(source_1).size() == 1);
     name = "MITK.Relations.1.dataHandle";
     prop = source_idOnly_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE(
       "Data layer information was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information not stored.",
                            prop->GetValueAsString() == dest_1->GetName());
     prop = source_idOnly_1->GetProperty("referencedName");
     CPPUNIT_ASSERT_MESSAGE(
       "Data layer information was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was stored.",
                            prop->GetValueAsString() == dest_1->GetName());
 
     // check actualization of an existing connection
     rule->Connect(source_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     CPPUNIT_ASSERT_MESSAGE("Additional relation was defined instead of updating exting one.",
                            rule->GetExistingRelations(source_1).size() == 1);
 
     // check new connection
     auto newConnectUID = rule->Connect(source_multi, unRelated);
-    CPPUNIT_ASSERT(rule->HasRelation(source_multi, unRelated) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_multi, unRelated, mitk::PropertyRelationRuleBase::RelationType::Complete));
     name = "MITK.Relations.5.dataHandle";
     prop = source_multi->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE(
       "Data layer information was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was stored.",
                            prop->GetValueAsString() == unRelated->GetName());
     prop = source_multi->GetProperty("referencedName");
     CPPUNIT_ASSERT_MESSAGE(
       "Data layer information was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was stored.",
                            prop->GetValueAsString() == unRelated->GetName());
     name = "MITK.Relations.5.destinationUID";
     prop = source_multi->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE(
       "Destination uid was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == unRelated_1_data->GetUID());
 
     auto storedRelationUIDs = rule->GetRelationUIDs(source_multi, unRelated);
     CPPUNIT_ASSERT_MESSAGE(
       "Relation uid was not stored for given source and destination.", storedRelationUIDs.size() == 1);
     CPPUNIT_ASSERT_MESSAGE("Incorrect Relation uid was stored.", storedRelationUIDs[0] == newConnectUID);
   }
 
   void Disconnect()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->Disconnect(nullptr, dest_1),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->Disconnect(source_1, nullptr),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->Disconnect(nullptr, "uid"),
                                  itk::ExceptionObject);
 
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
     rule->Disconnect(source_1, unRelated);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT_MESSAGE("Data property was not removed.", !source_1->GetProperty("referencedName"));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT_MESSAGE("Data property was illegaly removed.", source_1->GetProperty("referencedName"));
 
     rule->Disconnect(source_1, dest_2);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_1));
 
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     rule->Disconnect(source_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "1"));
     CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.",this->hasRelationProperties(source_1, "2"));
 
-    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     rule->Disconnect(source_multi, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "2"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4"));
 
     rule->Disconnect(source_multi, "uid6");
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1"));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "2"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4"));
 
     rule->Disconnect(source_multi, "unkownRelationUID");
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1"));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "2"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4"));
 
     rule->Disconnect(source_otherTypeRule, dest_1);
     CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.", this->hasRelationProperties(source_otherTypeRule, "1"));
   }
 
+  void Disconnect_partial_ID()
+  {
+    CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
+      rule->Disconnect(nullptr, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID),
+      itk::ExceptionObject);
+
+    CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
+      rule->Disconnect(source_1, nullptr, mitk::PropertyRelationRuleBase::RelationType::ID),
+      itk::ExceptionObject);
+
+    CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
+      rule->Disconnect(nullptr, "uid", mitk::PropertyRelationRuleBase::RelationType::ID),
+      itk::ExceptionObject);
+
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
+    rule->Disconnect(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT_MESSAGE("Data property was illegaly removed.", source_1->GetProperty("referencedName"));
+
+    rule->Disconnect(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+
+    rule->Disconnect(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+    rule->Disconnect(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "1"));
+    CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.", this->hasRelationProperties(source_1, "2"));
+  }
+
+  void Disconnect_partial_Data()
+  {
+    CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
+      rule->Disconnect(nullptr, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data),
+      itk::ExceptionObject);
+
+    CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
+      rule->Disconnect(source_1, nullptr, mitk::PropertyRelationRuleBase::RelationType::Data),
+      itk::ExceptionObject);
+
+    CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
+      rule->Disconnect(nullptr, "uid", mitk::PropertyRelationRuleBase::RelationType::Data),
+      itk::ExceptionObject);
+
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
+    rule->Disconnect(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT_MESSAGE("Data property was illegaly removed.", source_1->GetProperty("referencedName"));
+
+    rule->Disconnect(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+
+    rule->Disconnect(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+    rule->Disconnect(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+  }
+
   void Connect_abstract()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (abstract does not connect) does not throw.",
       abstractRule->Connect(nullptr, dest_1),
       itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (abstract does not connect) does not throw.",
       abstractRule->Connect(source_1, nullptr),
       itk::ExceptionObject);
   }
 
   void Disconnect_abstract()
   {
-
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::ID));
     abstractRule->Disconnect(source_1, dest_2);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "2"));
 
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     abstractRule->Disconnect(source_1, dest_1);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "1"));
 
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     abstractRule->Disconnect(source_multi, dest_1);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_multi, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "2"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4"));
 
     abstractRule->Disconnect(source_multi, "uid6");
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1"));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "2"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4"));
 
     abstractRule->Disconnect(source_multi, "unkownRelationUID");
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1"));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "2"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4"));
 
     abstractRule->Disconnect(source_otherTypeRule, dest_1);
     CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.", !this->hasRelationProperties(source_otherTypeRule, "1"));
-
   }
 
 };
 
 MITK_TEST_SUITE_REGISTRATION(mitkPropertyRelationRuleBase)
diff --git a/Modules/Core/test/mitkSourceImageRelationRuleTest.cpp b/Modules/Core/test/mitkSourceImageRelationRuleTest.cpp
index 2494c9c792..006153952b 100644
--- a/Modules/Core/test/mitkSourceImageRelationRuleTest.cpp
+++ b/Modules/Core/test/mitkSourceImageRelationRuleTest.cpp
@@ -1,880 +1,944 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkSourceImageRelationRule.h"
 
 #include "mitkDataNode.h"
 #include "mitkPointSet.h"
 #include "mitkStringProperty.h"
 
 #include "mitkTestFixture.h"
 #include "mitkTestingMacros.h"
 #include "mitkPropertyNameHelper.h"
 #include "mitkTemporoSpatialStringProperty.h"
 #include "mitkPropertyNameHelper.h"
 
 #include <regex>
 
 class mitkSourceImageRelationRuleTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkSourceImageRelationRuleTestSuite);
 
   MITK_TEST(IsSourceCandidate);
   MITK_TEST(IsDestinationCandidate);
   MITK_TEST(IsSource);
   MITK_TEST(HasRelation);
   MITK_TEST(GetExistingRelations);
   MITK_TEST(GetRelationUIDs);
   MITK_TEST(GetSourceCandidateIndicator);
   MITK_TEST(GetDestinationCandidateIndicator);
   MITK_TEST(GetConnectedSourcesDetector);
   MITK_TEST(GetSourcesDetector);
   MITK_TEST(GetDestinationsDetector);
   MITK_TEST(GetDestinationDetector);
   MITK_TEST(Connect);
   MITK_TEST(Disconnect);
   MITK_TEST(Connect_abstract);
   MITK_TEST(Disconnect_abstract);
 
   CPPUNIT_TEST_SUITE_END();
 
 private:
   mitk::SourceImageRelationRule::Pointer rule;
   mitk::SourceImageRelationRule::Pointer abstractRule;
 
   mitk::Image::Pointer unRelated;
   mitk::DataNode::Pointer unRelated_Node;
 
   mitk::Image::Pointer source_implicit_1;
   mitk::DataNode::Pointer source_implicit_1_Node;
-  mitk::Image::Pointer source_data_1;
-  mitk::DataNode::Pointer source_data_1_Node;
+  mitk::Image::Pointer source_Data_1;
+  mitk::DataNode::Pointer source_Data_1_Node;
   mitk::Image::Pointer source_idOnly_1;
   mitk::DataNode::Pointer source_idOnly_1_Node;
   mitk::Image::Pointer source_1;
   mitk::DataNode::Pointer source_1_Node;
 
   mitk::Image::Pointer source_otherRule;
   mitk::DataNode::Pointer source_otherRule_Node;
 
   mitk::Image::Pointer source_otherPurpose;
   mitk::DataNode::Pointer source_otherPurpose_Node; //relevant for abstract rule checks. Abstract rule should see it concrete rule not.
 
   mitk::DataNode::Pointer dest_1_Node;
   mitk::Image::Pointer dest_1;
   mitk::DataNode::Pointer dest_2_Node;
   mitk::Image::Pointer dest_2;
 
   bool hasRelationProperties(mitk::IPropertyProvider *provider, std::string instance = "") const
   {
     auto keyPath = mitk::PropertyRelationRuleBase::GetRootKeyPath();
     if (!instance.empty())
     {
       keyPath.AddElement(instance);
     }
 
     auto prefix = mitk::PropertyKeyPathToPropertyName(keyPath);
     auto keys = provider->GetPropertyKeys();
 
     for (const auto &key : keys)
     {
       if (key.find(prefix) == 0)
       {
         return true;
       }
     }
 
     return false;
   }
 
   std::vector<std::string> GetReferenceSequenceIndices(const mitk::IPropertyProvider * source,
     const mitk::IPropertyProvider * destination) const
   {
     std::vector<std::string> result;
 
     auto destInstanceUIDProp = destination->GetConstProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0018));
 
     if (destInstanceUIDProp.IsNull())
     {
       return result;
     }
 
     mitk::PropertyKeyPath referencedInstanceUIDs;
     referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddAnySelection("2112").AddElement("0008").AddElement("1155");
 
     auto sourceRegExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs);;
     auto regEx = std::regex(sourceRegExStr);
 
     std::vector<std::string> keys;
     //workaround until T24729 is done. Please remove if T24728 is done
     keys = source->GetPropertyKeys();
     //end workaround for T24729
 
     for (const auto &key : keys)
     {
       if (std::regex_match(key, regEx))
       {
         auto refUIDProp = source->GetConstProperty(key);
         if (*refUIDProp == *destInstanceUIDProp)
         {
           mitk::PropertyKeyPath finding = mitk::PropertyNameToPropertyKeyPath(key);
           result.push_back(std::to_string(finding.GetNode(2).selection));
         }
       }
     }
 
     return result;
   };
 
   void SetDICOMReferenceInfo(mitk::IPropertyOwner* owner, const std::string& instanceUID, const std::string& classUID, const std::string& purpose, unsigned int sequElement)
   {
     mitk::PropertyKeyPath refInstanceUIDPath;
     refInstanceUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0008").AddElement("1155");
     owner->SetProperty(PropertyKeyPathToPropertyName(refInstanceUIDPath), mitk::TemporoSpatialStringProperty::New(instanceUID));
 
     mitk::PropertyKeyPath refClassUIDPath;
     refClassUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0008").AddElement("1150");
     owner->SetProperty(PropertyKeyPathToPropertyName(refClassUIDPath), mitk::TemporoSpatialStringProperty::New(classUID));
 
     mitk::PropertyKeyPath purposePath;
     purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104");
     owner->SetProperty(PropertyKeyPathToPropertyName(purposePath), mitk::TemporoSpatialStringProperty::New(purpose));
   }
 
   bool IsCorrectDICOMReference(const mitk::IPropertyOwner* owner, const std::string& instanceUID, const std::string& classUID, const std::string& purpose, unsigned int sequElement) const
   {
     mitk::PropertyKeyPath refInstanceUIDPath;
     refInstanceUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0008").AddElement("1155");
     auto prop = owner->GetConstProperty(PropertyKeyPathToPropertyName(refInstanceUIDPath));
     if (prop->GetValueAsString() != instanceUID)
     {
       return false;
     }
 
     mitk::PropertyKeyPath refClassUIDPath;
     refClassUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0008").AddElement("1150");
     prop = owner->GetConstProperty(PropertyKeyPathToPropertyName(refClassUIDPath));
     if (prop->GetValueAsString() != classUID)
     {
       return false;
     }
 
     mitk::PropertyKeyPath purposePath;
     purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104");
     prop = owner->GetConstProperty(PropertyKeyPathToPropertyName(purposePath));
     if (prop->GetValueAsString() != purpose)
     {
       return false;
     }
 
     return true;
   }
 
 
 public:
   void setUp() override
   {
     auto instanceUIDPropName = mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0018);
     auto classUIDPropName = mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0016);
 
     rule = mitk::SourceImageRelationRule::New("Test");
 
     abstractRule = mitk::SourceImageRelationRule::New();
 
     unRelated = mitk::Image::New();
     unRelated->SetProperty(instanceUIDPropName, mitk::TemporoSpatialStringProperty::New("unRelated"));
     unRelated->SetProperty(classUIDPropName, mitk::TemporoSpatialStringProperty::New("image"));
     unRelated_Node = mitk::DataNode::New();
     unRelated_Node->SetData(unRelated);
 
     dest_1_Node = mitk::DataNode::New();
     dest_1_Node->SetName("dest_1");
     dest_1 = mitk::Image::New();
     dest_1->SetProperty(instanceUIDPropName, mitk::TemporoSpatialStringProperty::New("dest_1"));
     dest_1->SetProperty(classUIDPropName, mitk::TemporoSpatialStringProperty::New("image"));
     dest_1_Node->SetData(dest_1);
 
 
 
     dest_2_Node = mitk::DataNode::New();
     dest_2_Node->SetName("dest_2");
     dest_2 = mitk::Image::New();
     dest_2->SetProperty(instanceUIDPropName, mitk::TemporoSpatialStringProperty::New("dest_2"));
     dest_2->SetProperty(classUIDPropName, mitk::TemporoSpatialStringProperty::New("image"));
     dest_2_Node->SetData(dest_2);
 
     source_implicit_1 = mitk::Image::New();
     SetDICOMReferenceInfo(source_implicit_1, "dest_1", "image", "Test", 0);
     source_implicit_1_Node = mitk::DataNode::New();
     source_implicit_1_Node->SetData(source_implicit_1);
 
     source_idOnly_1 = mitk::Image::New();
     std::string name = "MITK.Relations.1.relationUID";
     source_idOnly_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid1"));
     name = "MITK.Relations.1.destinationUID";
     source_idOnly_1->SetProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetUID()));
     name = "MITK.Relations.1.ruleID";
     source_idOnly_1->SetProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
     source_idOnly_1_Node = mitk::DataNode::New();
     source_idOnly_1_Node->SetData(source_idOnly_1);
 
-    source_data_1 = mitk::Image::New();
-    SetDICOMReferenceInfo(source_data_1, "dest_1", "image", "Test", 0);
-    SetDICOMReferenceInfo(source_data_1, "dest_2", "image", "otherpurpose", 1);
+    source_Data_1 = mitk::Image::New();
+    SetDICOMReferenceInfo(source_Data_1, "dest_1", "image", "Test", 0);
+    SetDICOMReferenceInfo(source_Data_1, "dest_2", "image", "otherpurpose", 1);
     name = "MITK.Relations.1.relationUID";
-    source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid2"));
+    source_Data_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid2"));
     name = "MITK.Relations.1.ruleID";
-    source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
+    source_Data_1->SetProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
     name = "MITK.Relations.1.SourceImageSequenceItem";
-    source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("0"));
+    source_Data_1->SetProperty(name.c_str(), mitk::StringProperty::New("0"));
     name = "MITK.Relations.2.relationUID";
-    source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid10"));
+    source_Data_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid10"));
     name = "MITK.Relations.2.SourceImageSequenceItem";
-    source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("1"));
+    source_Data_1->SetProperty(name.c_str(), mitk::StringProperty::New("1"));
     name = "MITK.Relations.2.ruleID";
-    source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("SourceImageRelation otherpurpose"));
-    source_data_1_Node = mitk::DataNode::New();
-    source_data_1_Node->SetData(source_data_1);
+    source_Data_1->SetProperty(name.c_str(), mitk::StringProperty::New("SourceImageRelation otherpurpose"));
+    source_Data_1_Node = mitk::DataNode::New();
+    source_Data_1_Node->SetData(source_Data_1);
 
     source_1 = mitk::Image::New();
     SetDICOMReferenceInfo(source_1, "dest_1", "image", "Test", 0);
     SetDICOMReferenceInfo(source_1, "dest_2", "image", "otherpurpose", 1);
     name = "MITK.Relations.1.relationUID";
     source_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid3"));
     name = "MITK.Relations.1.destinationUID";
     source_1->SetProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetUID()));
     name = "MITK.Relations.1.ruleID";
     source_1->SetProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID()));
     name = "MITK.Relations.1.SourceImageSequenceItem";
     source_1->SetProperty(name.c_str(), mitk::StringProperty::New("0"));
     name = "MITK.Relations.2.relationUID";
     source_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid8"));
     name = "MITK.Relations.2.destinationUID";
     source_1->SetProperty(name.c_str(), mitk::StringProperty::New(dest_2->GetUID()));
     name = "MITK.Relations.2.ruleID";
     source_1->SetProperty(name.c_str(), mitk::StringProperty::New("SourceImageRelation otherpurpose"));
     name = "MITK.Relations.2.SourceImageSequenceItem";
     source_1->SetProperty(name.c_str(), mitk::StringProperty::New("1"));
     source_1_Node = mitk::DataNode::New();
     source_1_Node->SetData(source_1);
 
     source_otherRule = mitk::Image::New();
     name = "MITK.Relations.1.relationUID";
     source_otherRule->SetProperty(name.c_str(), mitk::StringProperty::New("uid7"));
     name = "MITK.Relations.1.destinationUID";
     source_otherRule->SetProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetUID()));
     name = "MITK.Relations.1.ruleID";
     source_otherRule->SetProperty(name.c_str(), mitk::StringProperty::New("otherRuleID"));
     source_otherRule_Node = mitk::DataNode::New();
     source_otherRule_Node->SetData(source_otherRule);
 
     source_otherPurpose = mitk::Image::New();
     name = "MITK.Relations.1.relationUID";
     source_otherPurpose->SetProperty(name.c_str(), mitk::StringProperty::New("uid9"));
     name = "MITK.Relations.1.destinationUID";
     source_otherPurpose->SetProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetUID()));
     name = "MITK.Relations.1.ruleID";
     source_otherPurpose->SetProperty(name.c_str(), mitk::StringProperty::New("SourceImageRelation otherpurpose"));
     source_otherPurpose_Node = mitk::DataNode::New();
     source_otherPurpose_Node->SetData(source_otherPurpose);
   }
 
   void tearDown() override {}
 
   void IsSourceCandidate()
   {
     CPPUNIT_ASSERT(rule->IsSourceCandidate(mitk::DataNode::New()));
     CPPUNIT_ASSERT(!rule->IsSourceCandidate(nullptr));
   }
 
   void IsDestinationCandidate()
   {
     CPPUNIT_ASSERT(rule->IsDestinationCandidate(this->dest_1_Node));
     CPPUNIT_ASSERT(rule->IsDestinationCandidate(this->dest_1));
     CPPUNIT_ASSERT(!rule->IsDestinationCandidate(mitk::DataNode::New()));
     CPPUNIT_ASSERT(!rule->IsDestinationCandidate(nullptr));
   }
 
   void IsSource()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE(
       "Violated precondition (nullptr) does not throw.", rule->IsSource(nullptr), itk::ExceptionObject);
 
     CPPUNIT_ASSERT(!rule->IsSource(unRelated));
-    CPPUNIT_ASSERT(!rule->IsSource(source_implicit_1));
-    CPPUNIT_ASSERT(rule->IsSource(source_data_1));
+    CPPUNIT_ASSERT(rule->IsSource(source_implicit_1));
+    CPPUNIT_ASSERT(rule->IsSource(source_Data_1));
     CPPUNIT_ASSERT(rule->IsSource(source_idOnly_1));
     CPPUNIT_ASSERT(rule->IsSource(source_1));
 
     CPPUNIT_ASSERT(!rule->IsSource(source_otherRule));
     CPPUNIT_ASSERT(!rule->IsSource(source_otherPurpose));
 
-    CPPUNIT_ASSERT(!rule->IsSource(source_implicit_1_Node));
-    CPPUNIT_ASSERT(rule->IsSource(source_data_1_Node));
+    CPPUNIT_ASSERT(rule->IsSource(source_implicit_1_Node));
+    CPPUNIT_ASSERT(rule->IsSource(source_Data_1_Node));
     CPPUNIT_ASSERT(rule->IsSource(source_idOnly_1_Node));
     CPPUNIT_ASSERT(rule->IsSource(source_1_Node));
 
     CPPUNIT_ASSERT(!rule->IsSource(source_otherRule_Node));
     CPPUNIT_ASSERT(!rule->IsSource(source_otherPurpose_Node));
 
 
     CPPUNIT_ASSERT(!abstractRule->IsSource(unRelated));
-    CPPUNIT_ASSERT(!abstractRule->IsSource(source_implicit_1));
-    CPPUNIT_ASSERT(abstractRule->IsSource(source_data_1));
+    CPPUNIT_ASSERT(abstractRule->IsSource(source_implicit_1));
+    CPPUNIT_ASSERT(abstractRule->IsSource(source_Data_1));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_idOnly_1));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_1));
 
     CPPUNIT_ASSERT(!abstractRule->IsSource(source_otherRule));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_otherPurpose));
 
     CPPUNIT_ASSERT(!abstractRule->IsSource(unRelated_Node));
-    CPPUNIT_ASSERT(!abstractRule->IsSource(source_implicit_1_Node));
-    CPPUNIT_ASSERT(abstractRule->IsSource(source_data_1_Node));
+    CPPUNIT_ASSERT(abstractRule->IsSource(source_implicit_1_Node));
+    CPPUNIT_ASSERT(abstractRule->IsSource(source_Data_1_Node));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_idOnly_1_Node));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_1_Node));
 
     CPPUNIT_ASSERT(!abstractRule->IsSource(source_otherRule_Node));
     CPPUNIT_ASSERT(abstractRule->IsSource(source_otherPurpose_Node));
   }
 
   void HasRelation()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->HasRelation(nullptr, dest_1),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->HasRelation(source_1, nullptr),
                                  itk::ExceptionObject);
 
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(rule->HasRelation(source_otherRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(rule->HasRelation(source_otherPurpose, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-
-    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Implicit_Data);
-    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
-    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None);
-
-
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherPurpose, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Implicit_Data);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_data_1, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1) ==
-      mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
-
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(!rule->HasRelation(unRelated, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_otherRule, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_otherPurpose, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1));
+    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_Data_1, dest_1));
+    CPPUNIT_ASSERT(rule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(rule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1));
+    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1));
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::None));
+
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(unRelated, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_otherRule, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherPurpose, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherPurpose, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_otherPurpose, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherPurpose, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_otherPurpose, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_Data_1, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::ID));
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
+
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::Complete));
   }
 
   void GetExistingRelations()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->GetExistingRelations(nullptr),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT(rule->GetExistingRelations(unRelated).empty());
     CPPUNIT_ASSERT(rule->GetExistingRelations(source_otherRule).empty());
     CPPUNIT_ASSERT(rule->GetExistingRelations(source_otherPurpose).empty());
-    CPPUNIT_ASSERT(rule->GetExistingRelations(source_implicit_1).empty());
 
-    auto uids = rule->GetExistingRelations(source_idOnly_1);
+    auto uids = rule->GetExistingRelations(source_implicit_1);
+    CPPUNIT_ASSERT(uids.size() == 1);
+    CPPUNIT_ASSERT(uids.front() == "DICOM.0008.2112.[0].0008.1155");
+
+    uids = rule->GetExistingRelations(source_idOnly_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid1");
 
-    uids = rule->GetExistingRelations(source_data_1);
+    uids = rule->GetExistingRelations(source_Data_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid2");
 
     uids = rule->GetExistingRelations(source_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid3");
 
-
     CPPUNIT_ASSERT(abstractRule->GetExistingRelations(unRelated).empty());
     CPPUNIT_ASSERT(abstractRule->GetExistingRelations(source_otherRule).empty());
-    CPPUNIT_ASSERT(abstractRule->GetExistingRelations(source_implicit_1).empty());
+
+    uids = abstractRule->GetExistingRelations(source_implicit_1);
+    CPPUNIT_ASSERT(uids.size() == 1);
+    CPPUNIT_ASSERT(uids.front() == "DICOM.0008.2112.[0].0008.1155");
 
     uids = abstractRule->GetExistingRelations(source_idOnly_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid1");
 
-    uids = abstractRule->GetExistingRelations(source_data_1);
+    uids = abstractRule->GetExistingRelations(source_Data_1);
     CPPUNIT_ASSERT(uids.size() == 2);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid2") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid10") != uids.end());
 
     uids = abstractRule->GetExistingRelations(source_1);
     CPPUNIT_ASSERT(uids.size() == 2);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid3") != uids.end());
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid8") != uids.end());
 
     uids = abstractRule->GetExistingRelations(source_otherPurpose);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid9");
   }
 
   void GetRelationUIDs()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->GetRelationUIDs(nullptr, dest_1),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->GetRelationUIDs(source_1, nullptr),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_1, unRelated).empty());
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_1, dest_2).empty());
     CPPUNIT_ASSERT(rule->GetRelationUIDs(unRelated, dest_1).empty());
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_otherRule, dest_1).empty());
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_otherPurpose, dest_1).empty());
 
     CPPUNIT_ASSERT(rule->GetRelationUIDs(source_idOnly_1, dest_1).front() == "uid1");
-    CPPUNIT_ASSERT(rule->GetRelationUIDs(source_data_1, dest_1).front() == "uid2");
+    CPPUNIT_ASSERT(rule->GetRelationUIDs(source_Data_1, dest_1).front() == "uid2");
     auto uids = rule->GetRelationUIDs(source_1, dest_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(uids.front() == "uid3");
 
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_1, unRelated).empty());
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(unRelated, dest_1).empty());
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_otherRule, dest_1).empty());
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_otherPurpose, dest_1).front() == "uid9");
 
     CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_idOnly_1, dest_1).front() == "uid1");
-    uids = abstractRule->GetRelationUIDs(source_data_1, dest_1);
+    uids = abstractRule->GetRelationUIDs(source_Data_1, dest_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid2") != uids.end());
     uids = abstractRule->GetRelationUIDs(source_1, dest_1);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid3") != uids.end());
     uids = abstractRule->GetRelationUIDs(source_1, dest_2);
     CPPUNIT_ASSERT(uids.size() == 1);
     CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid8") != uids.end());
   }
 
   void GetSourceCandidateIndicator()
   {
     auto predicate = rule->GetSourceCandidateIndicator();
 
     CPPUNIT_ASSERT(predicate->CheckNode(mitk::DataNode::New()));
     CPPUNIT_ASSERT(!predicate->CheckNode(nullptr));
   }
 
   void GetDestinationCandidateIndicator()
   {
     auto predicate = rule->GetDestinationCandidateIndicator();
 
     CPPUNIT_ASSERT(predicate->CheckNode(this->dest_1_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(mitk::DataNode::New()));
     CPPUNIT_ASSERT(!predicate->CheckNode(nullptr));
   }
 
   void GetConnectedSourcesDetector()
   {
     auto predicate = rule->GetConnectedSourcesDetector();
 
     CPPUNIT_ASSERT(!predicate->CheckNode(nullptr));
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
-    CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node));
-    CPPUNIT_ASSERT(predicate->CheckNode(source_data_1_Node));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1_Node));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_Data_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node));
 
 
     auto predicate2 = abstractRule->GetConnectedSourcesDetector();
 
     CPPUNIT_ASSERT(!predicate2->CheckNode(nullptr));
     CPPUNIT_ASSERT(!predicate2->CheckNode(unRelated_Node));
-    CPPUNIT_ASSERT(!predicate2->CheckNode(source_implicit_1_Node));
-    CPPUNIT_ASSERT(predicate2->CheckNode(source_data_1_Node));
+    CPPUNIT_ASSERT(predicate2->CheckNode(source_implicit_1_Node));
+    CPPUNIT_ASSERT(predicate2->CheckNode(source_Data_1_Node));
     CPPUNIT_ASSERT(predicate2->CheckNode(source_idOnly_1_Node));
     CPPUNIT_ASSERT(predicate2->CheckNode(source_1_Node));
 
     CPPUNIT_ASSERT(!predicate2->CheckNode(source_otherRule_Node));
     CPPUNIT_ASSERT(predicate2->CheckNode(source_otherPurpose_Node));
   }
 
   void GetSourcesDetector()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->GetSourcesDetector(nullptr),
                                  itk::ExceptionObject);
 
     auto predicate = rule->GetSourcesDetector(dest_1);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node));
 
     CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1_Node));
-    CPPUNIT_ASSERT(predicate->CheckNode(source_data_1_Node));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_Data_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node));
 
-    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+
+    CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node));
+
+    CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1_Node));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_Data_1_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1_Node));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node));
+
+    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::ID);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node));
-    CPPUNIT_ASSERT(predicate->CheckNode(source_data_1_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_Data_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node));
 
-    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node));
-    CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1_Node));
-    CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_Data_1_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node));
 
-    predicate = rule->GetSourcesDetector(dest_2, mitk::PropertyRelationRuleBase::RelationType::Implicit_Data);
+    predicate = rule->GetSourcesDetector(dest_2, mitk::PropertyRelationRuleBase::RelationType::Data);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node));
-    CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_Data_1_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_1_Node));
 
-    predicate = abstractRule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    predicate = abstractRule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::ID);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_otherPurpose_Node));
 
     CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node));
-    CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(source_Data_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node));
 
     predicate = abstractRule->GetSourcesDetector(dest_1);
 
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_otherPurpose_Node));
 
     CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1_Node));
-    CPPUNIT_ASSERT(predicate->CheckNode(source_data_1_Node));
+    CPPUNIT_ASSERT(predicate->CheckNode(source_Data_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node));
   }
 
   void GetDestinationsDetector()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->GetDestinationsDetector(nullptr),
                                  itk::ExceptionObject);
 
     auto predicate = rule->GetDestinationsDetector(source_otherRule);
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node));
 
     predicate = rule->GetDestinationsDetector(source_otherPurpose);
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node));
 
     predicate = rule->GetDestinationsDetector(source_implicit_1);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     predicate =
-      rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+      rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
+    predicate =
+      rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node));
+    predicate =
+      rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node));
 
-    predicate = rule->GetDestinationsDetector(source_data_1);
+    predicate = rule->GetDestinationsDetector(source_Data_1);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     predicate =
-      rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+      rule->GetDestinationsDetector(source_Data_1, mitk::PropertyRelationRuleBase::RelationType::Data);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     predicate =
-      rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+      rule->GetDestinationsDetector(source_Data_1, mitk::PropertyRelationRuleBase::RelationType::ID);
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node));
+    predicate =
+      rule->GetDestinationsDetector(source_Data_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node));
 
     predicate = rule->GetDestinationsDetector(source_idOnly_1);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     predicate =
-      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
-    CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
+      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node));
     predicate =
-      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::ID);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
+    predicate =
+      rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node));
 
     predicate = rule->GetDestinationsDetector(source_1);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node));
     predicate =
-      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
+      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Data);
+    CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
+    CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node));
+    predicate =
+      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::ID);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node));
     predicate =
-      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+      rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Complete);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node));
 
     predicate = abstractRule->GetDestinationsDetector(source_otherPurpose);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     predicate = abstractRule->GetDestinationsDetector(source_otherPurpose);
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
   }
 
   void GetDestinationDetector()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->GetDestinationDetector(nullptr, "uid1"),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (relation uid is invalid) does not throw.",
                                  rule->GetDestinationDetector(source_1, "invalid uid"),
                                  itk::ExceptionObject);
 
     auto predicate = rule->GetDestinationDetector(source_1, "uid3");
     CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node));
     CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node));
     CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node));
   }
 
   void Connect()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->Connect(nullptr, dest_1),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->Connect(source_1, nullptr),
                                  itk::ExceptionObject);
 
     // check upgrade of an implicit connection
-    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Implicit_Data);
+    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
     rule->Connect(source_implicit_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     auto dcmRefs = GetReferenceSequenceIndices(source_implicit_1, dest_1);
     CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was defined instead of using the existing one.", dcmRefs.size() == 1);
     CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(source_implicit_1, "dest_1", "image", "Test", 0));
 
-    // check upgrade and reuse of an data connection (no new relation should be generated).
-    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_Data);
-    rule->Connect(source_data_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    // check upgrade and reuse of an Data connection (no new relation should be generated).
+    CPPUNIT_ASSERT(rule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Data));
+    rule->Connect(source_Data_1, dest_1);
+    CPPUNIT_ASSERT(rule->HasRelation(source_Data_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
 
-    auto relUID = rule->GetRelationUIDs(source_data_1, dest_1);
+    auto relUID = rule->GetRelationUIDs(source_Data_1, dest_1);
     CPPUNIT_ASSERT(relUID.size() == 1);
 
     std::string name = "MITK.Relations.1.destinationUID";
-    auto prop = source_data_1->GetProperty(name.c_str());
+    auto prop = source_Data_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE(
       "Destination uid was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1->GetUID());
 
     name = "MITK.Relations.1.ruleID";
-    prop = source_data_1->GetProperty(name.c_str());
+    prop = source_Data_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID());
 
     name = "MITK.Relations.1.SourceImageSequenceItem";
-    prop = source_data_1->GetProperty(name.c_str());
+    prop = source_Data_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "0");
 
-    dcmRefs = GetReferenceSequenceIndices(source_data_1, dest_1);
+    dcmRefs = GetReferenceSequenceIndices(source_Data_1, dest_1);
     CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was defined instead of using the existing one.", dcmRefs.size() == 1);
-    CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(source_data_1, "dest_1", "image", "Test", 0));
+    CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(source_Data_1, "dest_1", "image", "Test", 0));
 
     // check actualization of an id only connection
     rule->Connect(source_idOnly_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1) ==
-                   mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     CPPUNIT_ASSERT_MESSAGE("Additional relation was defined instead of updating exting one.",
                            rule->GetExistingRelations(source_1).size() == 1);
 
     // check actualization of an existing connection
     rule->Connect(source_1, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     CPPUNIT_ASSERT_MESSAGE("Additional relation was defined instead of updating exting one.",
                            rule->GetExistingRelations(source_1).size() == 1);
     name = "MITK.Relations.1.destinationUID";
     prop = source_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE(
       "Destination uid was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1->GetUID());
 
     name = "MITK.Relations.1.ruleID";
     prop = source_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID());
 
     name = "MITK.Relations.1.SourceImageSequenceItem";
     prop = source_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "0");
 
     dcmRefs = GetReferenceSequenceIndices(source_1, dest_1);
     CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was defined instead of using the existing one.", dcmRefs.size() == 1);
     CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(source_1, "dest_1", "image", "Test", 0));
 
     // check creation of an new connection
     rule->Connect(unRelated, dest_1);
-    CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     CPPUNIT_ASSERT_MESSAGE("Relation was not defined instead of updating exting one.",
       rule->GetExistingRelations(unRelated).size() == 1);
     name = "MITK.Relations.1.destinationUID";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1->GetUID());
 
     name = "MITK.Relations.1.ruleID";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID());
 
     name = "MITK.Relations.1.SourceImageSequenceItem";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "0");
 
     dcmRefs = GetReferenceSequenceIndices(unRelated, dest_1);
     CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was defined instead of using the existing one.", dcmRefs.size() == 1);
     CPPUNIT_ASSERT_MESSAGE("Dicom reference squence is corrupted. Should be just an index 0.", dcmRefs[0] == "0");
     CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(unRelated, "dest_1", "image", "Test", 0));
 
     // check creation of a 2nd connection of the same purpose
     rule->Connect(unRelated, dest_2);
-    CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_2, mitk::PropertyRelationRuleBase::RelationType::Complete));
     CPPUNIT_ASSERT_MESSAGE("Additional relation was not defined.",
       rule->GetExistingRelations(unRelated).size() == 2);
     name = "MITK.Relations.1.destinationUID";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1->GetUID());
 
     name = "MITK.Relations.1.ruleID";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID());
 
     name = "MITK.Relations.1.SourceImageSequenceItem";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "0");
 
     name = "MITK.Relations.2.destinationUID";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_2->GetUID());
 
     name = "MITK.Relations.2.ruleID";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID());
 
     name = "MITK.Relations.2.SourceImageSequenceItem";
     prop = unRelated->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "1");
 
 
     dcmRefs = GetReferenceSequenceIndices(unRelated, dest_2);
     CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was not defined.", dcmRefs.size() == 1);
     CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(unRelated, "dest_1", "image", "Test", 0));
     CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(unRelated, "dest_2", "image", "Test", 1));
   }
 
   void Disconnect()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.",
                                  rule->Disconnect(nullptr, dest_1),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->Disconnect(source_1, nullptr),
                                  itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.",
                                  rule->Disconnect(nullptr, "uid"),
                                  itk::ExceptionObject);
 
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
     rule->Disconnect(source_1, unRelated);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None);
-    CPPUNIT_ASSERT_MESSAGE("Other relationdata property was removed.", IsCorrectDICOMReference(source_1, "dest_1", "image", "Test", 0));
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT_MESSAGE("Other relationData property was removed.", IsCorrectDICOMReference(source_1, "dest_1", "image", "Test", 0));
 
     //check if index correction is correct, when disconnecting
     rule->Connect(source_1, dest_2);
     rule->Connect(source_1, unRelated);
     rule->Disconnect(source_1, dest_2);
-    CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!rule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::None));
+    CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_1, "1"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_1, "2"));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "3"));
     CPPUNIT_ASSERT(this->hasRelationProperties(source_1, "4"));
     CPPUNIT_ASSERT_MESSAGE("Dicom reference to dest_1 has been removed.", IsCorrectDICOMReference(source_1, "dest_1", "image", "Test", 0));
     CPPUNIT_ASSERT_MESSAGE("Dicom reference to dest_2 (other purpose) has been removed or has not a corrected sequence index (1 instead of 2).", IsCorrectDICOMReference(source_1, "dest_2", "image", "otherpurpose", 1));
     CPPUNIT_ASSERT_MESSAGE("Dicom reference to unRelated has been removed or has not a corrected sequence index (1 instead of 2).", IsCorrectDICOMReference(source_1, "unRelated", "image", "Test", 2));
 
     std::string name = "MITK.Relations.4.destinationUID";
     auto prop = source_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE(
       "Destination uid was not stored with the correct key. Already existing session should be used.", prop);
     CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == unRelated->GetUID());
     name = "MITK.Relations.4.SourceImageSequenceItem";
     prop = source_1->GetProperty(name.c_str());
     CPPUNIT_ASSERT_MESSAGE("SourceImageSequenceItem was not actualized correctly.", prop->GetValueAsString() == "2");
 
     rule->Disconnect(source_otherPurpose, dest_1);
     CPPUNIT_ASSERT_MESSAGE("Data of other rule purpose was removed.", this->hasRelationProperties(source_otherPurpose, "1"));
   }
 
   void Connect_abstract()
   {
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (abstract does not connect) does not throw.",
       abstractRule->Connect(nullptr, dest_1),
       itk::ExceptionObject);
 
     CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (abstract does not connect) does not throw.",
       abstractRule->Connect(source_1, nullptr),
       itk::ExceptionObject);
   }
 
   void Disconnect_abstract()
   {
 
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::Complete));
     abstractRule->Disconnect(source_1, dest_2);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_1, dest_2, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "2"));
 
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID);
+    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::Complete));
     abstractRule->Disconnect(source_1, dest_1);
-    CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None);
+    CPPUNIT_ASSERT(!abstractRule->HasRelation(source_1, dest_1, mitk::PropertyRelationRuleBase::RelationType::None));
     CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "1"));
 
     abstractRule->Disconnect(source_otherPurpose, dest_1);
     CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.", !this->hasRelationProperties(source_otherPurpose, "1"));
   }
 
 };
 
 MITK_TEST_SUITE_REGISTRATION(mitkSourceImageRelationRule)
diff --git a/Modules/Core/test/mitkTemporoSpatialStringPropertyTest.cpp b/Modules/Core/test/mitkTemporoSpatialStringPropertyTest.cpp
index 67676b38c8..ae79c6260b 100644
--- a/Modules/Core/test/mitkTemporoSpatialStringPropertyTest.cpp
+++ b/Modules/Core/test/mitkTemporoSpatialStringPropertyTest.cpp
@@ -1,233 +1,242 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkTemporoSpatialStringProperty.h"
 #include "mitkTestFixture.h"
 #include "mitkTestingMacros.h"
 
 #include <limits>
 
 class mitkTemporoSpatialStringPropertyTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkTemporoSpatialStringPropertyTestSuite);
 
   MITK_TEST(GetValue);
   MITK_TEST(HasValue);
   MITK_TEST(SetValue);
+  MITK_TEST(IsUniform);
 
   MITK_TEST(serializeTemporoSpatialStringPropertyToJSON);
   MITK_TEST(deserializeJSONToTemporoSpatialStringProperty);
 
   CPPUNIT_TEST_SUITE_END();
 
 private:
   std::string refJSON;
   std::string refJSON_legacy;
   std::string refPartlyCondensibleJSON;
   std::string refCondensibleJSON;
   mitk::TemporoSpatialStringProperty::Pointer refProp;
   mitk::TemporoSpatialStringProperty::Pointer refPartlyCondensibleProp;
   mitk::TemporoSpatialStringProperty::Pointer refCondensibleProp;
 
 public:
   void setUp() override
   {
     refJSON_legacy = "{\"values\":[{\"t\":0, \"z\":0, \"value\":\"v_0_0\"}, {\"t\":3, \"z\":0, \"value\":\"v_3_0\"}, "
                      "{\"t\":3, \"z\":2, \"value\":\"v_3_2\"}, {\"t\":6, \"z\":1, \"value\":\"v_6_1\"}]}";
     refJSON = "{\"values\":[{\"z\":0, \"t\":0, \"value\":\"v_0_0\"}, {\"z\":0, \"t\":3, \"value\":\"v_3_0\"}, {\"z\":1, \"t\":6, \"value\":\"v_6_1\"}, {\"z\":2, \"t\":3, \"value\":\"v_3_2\"}]}";
     refPartlyCondensibleJSON = "{\"values\":[{\"z\":0, \"t\":0, \"value\":\"0\"}, {\"z\":1, \"t\":0, \"tmax\":1, \"value\":\"0\"}, {\"z\":1, \"t\":3, \"tmax\":5, \"value\":\"0\"}, {\"z\":1, \"t\":6, \"value\":\"otherValue\"}, {\"z\":2, \"t\":6, \"value\":\"0\"}]}";
     refCondensibleJSON = "{\"values\":[{\"z\":0, \"zmax\":2, \"t\":0, \"tmax\":1, \"value\":\"1\"}]}";
     refProp = mitk::TemporoSpatialStringProperty::New();
     refProp->SetValue(0, 0, "v_0_0");
     refProp->SetValue(3, 0, "v_3_0");
     refProp->SetValue(3, 2, "v_3_2");
     refProp->SetValue(6, 1, "v_6_1");
 
     refPartlyCondensibleProp = mitk::TemporoSpatialStringProperty::New();
     refPartlyCondensibleProp->SetValue(0, 0, "0");
     refPartlyCondensibleProp->SetValue(0, 1, "0");
     refPartlyCondensibleProp->SetValue(1, 1, "0");
     refPartlyCondensibleProp->SetValue(3, 1, "0");
     refPartlyCondensibleProp->SetValue(4, 1, "0");
     refPartlyCondensibleProp->SetValue(5, 1, "0");
     refPartlyCondensibleProp->SetValue(6, 1, "otherValue");
     refPartlyCondensibleProp->SetValue(6, 2, "0");
 
     refCondensibleProp = mitk::TemporoSpatialStringProperty::New();
     refCondensibleProp->SetValue(0, 0, "1");
     refCondensibleProp->SetValue(1, 0, "1");
     refCondensibleProp->SetValue(0, 1, "1");
     refCondensibleProp->SetValue(1, 1, "1");
     refCondensibleProp->SetValue(0, 2, "1");
     refCondensibleProp->SetValue(1, 2, "1");
   }
 
   void tearDown() override {}
+
   void GetValue()
   {
     CPPUNIT_ASSERT(refProp->GetValue() == "v_0_0");
 
     CPPUNIT_ASSERT(refProp->GetValue(3, 0) == "v_3_0");
     CPPUNIT_ASSERT(refProp->GetValue(3, 2) == "v_3_2");
     CPPUNIT_ASSERT(refProp->GetValue(3, 1, false, true) == "v_3_0");
     CPPUNIT_ASSERT(refProp->GetValue(3, 5, false, true) == "v_3_2");
 
     CPPUNIT_ASSERT(refProp->GetValueBySlice(0) == "v_0_0");
     CPPUNIT_ASSERT(refProp->GetValueBySlice(4, true) == "v_0_0");
 
     CPPUNIT_ASSERT(refProp->GetValueByTimeStep(3) == "v_3_0");
     CPPUNIT_ASSERT(refProp->GetValueByTimeStep(6) == "v_6_1");
     CPPUNIT_ASSERT(refProp->GetValueByTimeStep(5, true) == "v_3_0");
 
     CPPUNIT_ASSERT(refProp->GetValueAsString() == "v_0_0");
 
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps().size() == 3);
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps()[0] == 0);
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps()[1] == 3);
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps()[2] == 6);
 
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps(0).size() == 2);
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps(0)[0] == 0);
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps(0)[1] == 3);
 
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps(1).size() == 1);
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps(1)[0] == 6);
 
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps(5).size() == 0);
 
     CPPUNIT_ASSERT(refProp->GetAvailableSlices().size() == 3);
     CPPUNIT_ASSERT(refProp->GetAvailableSlices()[0] == 0);
     CPPUNIT_ASSERT(refProp->GetAvailableSlices()[1] == 1);
     CPPUNIT_ASSERT(refProp->GetAvailableSlices()[2] == 2);
 
     CPPUNIT_ASSERT(refProp->GetAvailableSlices(0).size() == 1);
     CPPUNIT_ASSERT(refProp->GetAvailableSlices(0)[0] == 0);
     CPPUNIT_ASSERT(refProp->GetAvailableSlices(3).size() == 2);
     CPPUNIT_ASSERT(refProp->GetAvailableSlices(3)[0] == 0);
     CPPUNIT_ASSERT(refProp->GetAvailableSlices(3)[1] == 2);
 
     CPPUNIT_ASSERT(refProp->GetAvailableSlices(2).size() == 0);
   }
 
   void HasValue()
   {
     CPPUNIT_ASSERT(refProp->HasValue());
 
     CPPUNIT_ASSERT(refProp->HasValue(3, 0));
     CPPUNIT_ASSERT(refProp->HasValue(3, 2));
     CPPUNIT_ASSERT(refProp->HasValue(3, 1, false, true));
     CPPUNIT_ASSERT(refProp->HasValue(3, 5, false, true));
     CPPUNIT_ASSERT(!refProp->HasValue(3, 1));
     CPPUNIT_ASSERT(!refProp->HasValue(3, 5));
     CPPUNIT_ASSERT(refProp->HasValue(4, 2, true, true));
     CPPUNIT_ASSERT(refProp->HasValue(4, 2, true, false));
     CPPUNIT_ASSERT(!refProp->HasValue(4, 2, false, true));
 
     CPPUNIT_ASSERT(refProp->HasValueBySlice(0));
     CPPUNIT_ASSERT(refProp->HasValueBySlice(4, true));
     CPPUNIT_ASSERT(!refProp->HasValueBySlice(4));
 
     CPPUNIT_ASSERT(refProp->HasValueByTimeStep(3));
     CPPUNIT_ASSERT(refProp->HasValueByTimeStep(6));
     CPPUNIT_ASSERT(refProp->HasValueByTimeStep(5, true));
     CPPUNIT_ASSERT(!refProp->HasValueByTimeStep(5));
   }
 
   void SetValue()
   {
     CPPUNIT_ASSERT_NO_THROW(refProp->SetValue(8, 9, "v_8_9"));
     CPPUNIT_ASSERT(refProp->GetValue(8, 9) == "v_8_9");
 
     CPPUNIT_ASSERT_NO_THROW(refProp->SetValue("newValue"));
     CPPUNIT_ASSERT(refProp->GetValue(0, 0) == "newValue");
     CPPUNIT_ASSERT(refProp->GetAvailableTimeSteps().size() == 1);
     CPPUNIT_ASSERT(refProp->GetAvailableSlices(0).size() == 1);
   }
 
+  void IsUniform()
+  {
+    CPPUNIT_ASSERT(!refProp->IsUniform());
+    CPPUNIT_ASSERT(!refPartlyCondensibleProp->IsUniform());
+    CPPUNIT_ASSERT(refCondensibleProp->IsUniform());
+  }
+
   void serializeTemporoSpatialStringPropertyToJSON()
   {
     std::string data = mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON(refProp);
     CPPUNIT_ASSERT(refJSON ==
       data); //"Testing serializeTemporoSpatialStringPropertyToJSON() producing correct string.");
 
     data = mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON(refPartlyCondensibleProp);
     CPPUNIT_ASSERT(refPartlyCondensibleJSON ==
       data);
 
     data = mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON(refCondensibleProp);
     CPPUNIT_ASSERT(refCondensibleJSON ==
       data);
   }
 
   void deserializeJSONToTemporoSpatialStringProperty()
   {
     mitk::BaseProperty::Pointer prop =
       mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty(refJSON);
 
     auto *tsProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(prop.GetPointer());
 
     CPPUNIT_ASSERT(
       tsProp->GetValue(0, 0) ==
       "v_0_0"); //"Testing deserializeJSONToTemporoSpatialStringProperty() producing property with correct value 1");
     CPPUNIT_ASSERT(
       tsProp->GetValue(3, 0) ==
       "v_3_0"); //"Testing deserializeJSONToTemporoSpatialStringProperty() producing property with correct value 2");
     CPPUNIT_ASSERT(
       tsProp->GetValue(3, 2) ==
       "v_3_2"); //"Testing deserializeJSONToTemporoSpatialStringProperty() producing property with correct value 3");
     CPPUNIT_ASSERT(
       tsProp->GetValue(6, 1) ==
       "v_6_1"); //"Testing deserializeJSONToTemporoSpatialStringProperty() producing property with correct value 4");
     CPPUNIT_ASSERT(*tsProp == *refProp); //"Testing deserializeJSONToTemporoSpatialStringProperty()");
 
     prop = mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty(refJSON_legacy);
     tsProp = dynamic_cast<mitk::TemporoSpatialStringProperty*>(prop.GetPointer());
     CPPUNIT_ASSERT(
       tsProp->GetValue(0, 0) ==
       "v_0_0"); //"Testing deserializeJSONToTemporoSpatialStringProperty() producing property with correct value 1");
     CPPUNIT_ASSERT(
       tsProp->GetValue(3, 0) ==
       "v_3_0"); //"Testing deserializeJSONToTemporoSpatialStringProperty() producing property with correct value 2");
     CPPUNIT_ASSERT(
       tsProp->GetValue(3, 2) ==
       "v_3_2"); //"Testing deserializeJSONToTemporoSpatialStringProperty() producing property with correct value 3");
     CPPUNIT_ASSERT(
       tsProp->GetValue(6, 1) ==
       "v_6_1"); //"Testing deserializeJSONToTemporoSpatialStringProperty() producing property with correct value 4");
     CPPUNIT_ASSERT(*tsProp == *refProp); //"Testing deserializeJSONToTemporoSpatialStringProperty()");
 
 
     prop = mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty(refPartlyCondensibleJSON);
     tsProp = dynamic_cast<mitk::TemporoSpatialStringProperty*>(prop.GetPointer());
     CPPUNIT_ASSERT(tsProp->GetValue(0, 0) =="0");
     CPPUNIT_ASSERT(tsProp->GetValue(0, 1) == "0");
     CPPUNIT_ASSERT(tsProp->GetValue(1, 1) == "0");
     CPPUNIT_ASSERT(tsProp->GetValue(3, 1) == "0");
     CPPUNIT_ASSERT(tsProp->GetValue(4, 1) == "0");
     CPPUNIT_ASSERT(tsProp->GetValue(5, 1) == "0");
     CPPUNIT_ASSERT(tsProp->GetValue(6, 1) == "otherValue");
     CPPUNIT_ASSERT(tsProp->GetValue(6, 2) == "0");
     CPPUNIT_ASSERT(*tsProp == *refPartlyCondensibleProp);
     
     prop = mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty(refCondensibleJSON);
     tsProp = dynamic_cast<mitk::TemporoSpatialStringProperty*>(prop.GetPointer());
     CPPUNIT_ASSERT(tsProp->GetValue(0, 0) == "1");
     CPPUNIT_ASSERT(tsProp->GetValue(1, 0) == "1");
     CPPUNIT_ASSERT(tsProp->GetValue(0, 1) == "1");
     CPPUNIT_ASSERT(tsProp->GetValue(1, 1) == "1");
     CPPUNIT_ASSERT(tsProp->GetValue(0, 2) == "1");
     CPPUNIT_ASSERT(tsProp->GetValue(1, 2) == "1");
     CPPUNIT_ASSERT(*tsProp == *refCondensibleProp);
   }
 };
 
 MITK_TEST_SUITE_REGISTRATION(mitkTemporoSpatialStringProperty)
diff --git a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp
index 643fd7dc94..b03d29e22e 100644
--- a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp
+++ b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp
@@ -1,217 +1,217 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkDICOMPMIO__cpp
 #define __mitkDICOMPMIO__cpp
 
 #include "mitkDICOMPMIO.h"
 #include "mitkDICOMPMIOMimeTypes.h"
 #include <mitkDICOMDCMTKTagScanner.h>
 #include <mitkDICOMIOHelper.h>
 #include <mitkDICOMProperty.h>
 #include <mitkIDICOMTagsOfInterest.h>
 #include <mitkImageAccessByItk.h>
 #include <mitkImageCast.h>
 #include <mitkLocaleSwitch.h>
 #include <mitkPropertyNameHelper.h>
 #include <dcmqi/ParaMapConverter.h>
 #include "mitkParamapPresetsParser.h"
 
 
 // us
 #include <usGetModuleContext.h>
 #include <usModuleContext.h>
 
 // model fit parameters
 #include "mitkModelFitConstants.h"
 
 
 namespace mitk
 {
   DICOMPMIO::DICOMPMIO()
     : AbstractFileIO(Image::GetStaticNameOfClass(),
                      mitk::MitkDICOMPMIOMimeTypes::DICOMPM_MIMETYPE_NAME(),
                      "DICOM PM")
 
   {
     AbstractFileWriter::SetRanking(10);
     AbstractFileReader::SetRanking(10);
     this->RegisterService();
   }
 
   IFileIO::ConfidenceLevel DICOMPMIO::GetWriterConfidenceLevel() const
   {
   if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
     return Unsupported;
 
   const Image *PMinput = static_cast<const Image *>(this->GetInput());
   if (PMinput)
   {
     auto modalityProperty = PMinput->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0060).c_str());
     if (modalityProperty.IsNotNull())
     {
       std::string modality = modalityProperty->GetValueAsString();
       if (modality == "PM")
       {
         return Supported;
       }
       else return Unsupported;
     }
     else return Unsupported;
   }
   else return Unsupported;
   }
 
   void DICOMPMIO::Write()
   {
     ValidateOutputLocation();
     mitk::LocaleSwitch localeSwitch("C");
     LocalFile localFile(this);
     const std::string path = localFile.GetFileName();
 
 	auto PMinput = dynamic_cast<const Image *>(this->GetInput());
 	if (PMinput == nullptr)
 		mitkThrow() << "Cannot write non-image data";
 
     // Get DICOM information from referenced image
     vector<std::unique_ptr<DcmDataset>> dcmDatasetsSourceImage;
     std::unique_ptr<DcmFileFormat> readFileFormat(new DcmFileFormat());
 
     try
     {
       // Generate dcmdataset witk DICOM tags from property list; ATM the source are the filepaths from the
       // property list
       mitk::StringLookupTableProperty::Pointer filesProp =
         dynamic_cast<mitk::StringLookupTableProperty *>(PMinput->GetProperty("referenceFiles").GetPointer());
 
       if (filesProp.IsNull())
       {
         mitkThrow() << "No property with dicom file path.";
         return;
       }
 
 	  // returns a list of all referenced files
       StringLookupTable filesLut = filesProp->GetValue();
 
       const StringLookupTable::LookupTableType &lookUpTableMap = filesLut.GetLookupTable();
       for (auto it : lookUpTableMap)
       {
         const char *fileName = (it.second).c_str();
         if (readFileFormat->loadFile(fileName, EXS_Unknown).good())
         {
           std::unique_ptr<DcmDataset> readDCMDataset(readFileFormat->getAndRemoveDataset());
           dcmDatasetsSourceImage.push_back(std::move(readDCMDataset));
         }
       }
     }
     catch (const std::exception &e)
     {
       MITK_ERROR << "An error occurred while getting the dicom information: " << e.what() << endl;
       return;
     }
 
 	mitk::Image *mitkPMImage = const_cast<mitk::Image *>(PMinput);
 	// Cast input PMinput to itk image
 	ImageToItk<PMitkInputImageType>::Pointer PMimageToItkFilter = ImageToItk<PMitkInputImageType>::New();
 	PMimageToItkFilter->SetInput(mitkPMImage);
 
 	// Cast from original itk type to dcmqi input itk image type
 	typedef itk::CastImageFilter<PMitkInputImageType, PMitkInternalImageType> castItkImageFilterType;
 	castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New();
 	castFilter->SetInput(PMimageToItkFilter->GetOutput());
 	castFilter->Update();
 	PMitkInternalImageType::Pointer itkParamapImage = castFilter->GetOutput();
 
 	// Create PM meta information
     const std::string tmpMetaInfoFile = this->CreateMetaDataJsonFilePM();
 	// Convert itk PM images to dicom image
 	MITK_INFO << "Writing PM image: " << path << std::endl;
 	try
 	  {
 	    // convert from unique to raw pointer
 	    vector<DcmDataset*> rawVecDataset;
 	    for ( const auto& dcmDataSet : dcmDatasetsSourceImage ) { rawVecDataset.push_back( dcmDataSet.get() ); }
 
 	    std::unique_ptr<dcmqi::ParaMapConverter> PMconverter(new dcmqi::ParaMapConverter());
 	    std::unique_ptr<DcmDataset> PMresult (PMconverter->itkimage2paramap(itkParamapImage, rawVecDataset, tmpMetaInfoFile));
 	    // Write dicom file
 	    DcmFileFormat dcmFileFormat(PMresult.get());
 	    std::string filePath = path.substr(0, path.find_last_of("."));
 	    filePath = filePath + ".dcm";
 	    dcmFileFormat.saveFile(filePath.c_str(), EXS_LittleEndianExplicit);
 
 	  }
 	catch (const std::exception &e)
 	  {
 		MITK_ERROR << "An error occurred during writing the DICOM Paramap: " << e.what() << endl;
 		return;
 	  }
 
   }
 
   const std::string mitk::DICOMPMIO::CreateMetaDataJsonFilePM() const
   {
 	  const mitk::Image *PMimage = dynamic_cast<const mitk::Image *>(this->GetInput());
 	  dcmqi::JSONParametricMapMetaInformationHandler PMhandler;
 
 
 	  // Get Metadata from modelFitConstants
 	  std::string parameterName;
 	  PMimage->GetPropertyList()->GetStringProperty(ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), parameterName);
 	  std::string modelName;
 	  PMimage->GetPropertyList()->GetStringProperty(ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), modelName);
 
     mitk::ParamapPresetsParser* pmPresets = mitk::ParamapPresetsParser::New();
       // Here the mitkParamapPresets.xml file containing the Coding Schmeme Designator and Code Value are parsed and the relevant values extracted
 	  pmPresets->LoadPreset();
 	  auto pmType_parameterName = pmPresets->GetType(parameterName);
 	  auto pmType_modelName = pmPresets->GetType(modelName);
 
 	  // Pass codes to Paramap Converter
 	  PMhandler.setDerivedPixelContrast("TCS");
 	  PMhandler.setFrameLaterality("U");
 	  PMhandler.setQuantityValueCode(pmType_parameterName.codeValue, pmType_parameterName.codeScheme, parameterName);
 	  PMhandler.setMeasurementMethodCode(pmType_modelName.codeValue, pmType_modelName.codeScheme, modelName);
 	  PMhandler.setMeasurementUnitsCode("/min", "UCUM", "/m");
 	  PMhandler.setSeriesNumber("1");
 	  PMhandler.setInstanceNumber("1");
 	  PMhandler.setDerivationCode("129104", "DCM", "Perfusion image analysis");
 	  PMhandler.setRealWorldValueSlope("1");
 
 	  return PMhandler.getJSONOutputAsString();
   }
 
 
-  std::vector<BaseData::Pointer> DICOMPMIO::Read()
+  std::vector<BaseData::Pointer> DICOMPMIO::DoRead()
   {
 	  mitk::LocaleSwitch localeSwitch("C");
 	  std::vector<BaseData::Pointer> result;
 
 	  return result;
   }
 
   IFileIO::ConfidenceLevel DICOMPMIO::GetReaderConfidenceLevel() const
   {
 	  return Unsupported;
   }
 
 
 
   DICOMPMIO *DICOMPMIO::IOClone() const { return new DICOMPMIO(*this); }
 } // namespace
 
 
 
 
 
 
 #endif //__mitkDICOMPMIO__cpp
diff --git a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.h b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.h
index f7ecd5cb52..46056c0d3e 100644
--- a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.h
+++ b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.h
@@ -1,68 +1,69 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkDICOMPMIO_h
 #define __mitkDICOMPMIO_h
 
 #include <mitkAbstractFileIO.h>
 #include <mitkImage.h>
 #include <dcmtk/dcmpmap/dpmparametricmapiod.h>
 #include <dcmqi/JSONSegmentationMetaInformationHandler.h>
 #include <dcmqi/JSONParametricMapMetaInformationHandler.h>
 
 
 namespace mitk
 {
   /**
    * Read and Writes a Parametric map to a dcm file
    * @ingroup Process
    */
   class DICOMPMIO : public mitk::AbstractFileIO
   {
   public:
 
 
     DICOMPMIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
 
-    /**
-     * @brief Reads a DICOM parametric maps from the file system
-     * @return a  mitk::Image
-     * @throws throws an mitk::Exception if an error ocurrs
-     */
-    std::vector<BaseData::Pointer> Read() override;
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
     ConfidenceLevel GetWriterConfidenceLevel() const override;
+  protected:
+    /**
+     * @brief Reads a DICOM parametric map from the file system
+     * @return an mitk::Image
+     * @throws an mitk::Exception if an error ocurrs
+     */
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
 
     typedef mitk::Image PMInputType;
     typedef itk::Image<double, 3> PMitkInputImageType;
     typedef IODFloatingPointImagePixelModule::value_type PMFloatPixelType; // input type required for DCMQI
     typedef itk::Image<PMFloatPixelType, 3> PMitkInternalImageType;
     DICOMPMIO *IOClone() const override;
 
     // -------------- DICOMPMIO specific functions -------------
 
 	const std::string CreateMetaDataJsonFilePM() const;
 
   };
 } // end of namespace mitk
 
 #endif // __mitkDICOMPMIO_h
diff --git a/Modules/DICOMReader/files.cmake b/Modules/DICOMReader/files.cmake
index e72f2b58c1..7218fa0662 100644
--- a/Modules/DICOMReader/files.cmake
+++ b/Modules/DICOMReader/files.cmake
@@ -1,62 +1,63 @@
 file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
 
 set(CPP_FILES
   mitkBaseDICOMReaderService.cpp
   mitkDICOMFileReader.cpp
   mitkDICOMTagScanner.cpp
   mitkDICOMGDCMTagScanner.cpp
   mitkDICOMDCMTKTagScanner.cpp
   mitkDICOMImageBlockDescriptor.cpp
   mitkDICOMITKSeriesGDCMReader.cpp
   mitkDICOMDatasetSorter.cpp
   mitkDICOMTagBasedSorter.cpp
   mitkDICOMGDCMImageFrameInfo.cpp
   mitkDICOMImageFrameInfo.cpp
   mitkDICOMIOHelper.cpp
   mitkDICOMGenericImageFrameInfo.cpp
   mitkDICOMDatasetAccessingImageFrameInfo.cpp
   mitkDICOMSortCriterion.cpp
   mitkDICOMSortByTag.cpp
   mitkITKDICOMSeriesReaderHelper.cpp
   mitkEquiDistantBlocksSorter.cpp
   mitkNormalDirectionConsistencySorter.cpp
   mitkSortByImagePositionPatient.cpp
   mitkGantryTiltInformation.cpp
   mitkClassicDICOMSeriesReader.cpp
   mitkThreeDnTDICOMSeriesReader.cpp
   mitkDICOMTag.cpp
   mitkDICOMTagsOfInterestHelper.cpp
   mitkDICOMTagCache.cpp
   mitkDICOMGDCMTagCache.cpp
   mitkDICOMGenericTagCache.cpp
   mitkDICOMEnums.cpp
   mitkDICOMReaderConfigurator.cpp
   mitkDICOMFileReaderSelector.cpp
   mitkIDICOMTagsOfInterest.cpp
   mitkDICOMTagPath.cpp
   mitkDICOMProperty.cpp
   mitkDICOMFilesHelper.cpp
+  mitkDICOMIOMetaInformationPropertyConstants.cpp
   legacy/mitkDicomSeriesReader.cpp
   legacy/mitkDicomSR_GantryTiltInformation.cpp
   legacy/mitkDicomSR_ImageBlockDescriptor.cpp
   legacy/mitkDicomSR_LoadDICOMRGBPixel.cpp
   legacy/mitkDicomSR_LoadDICOMRGBPixel4D.cpp
   legacy/mitkDicomSR_LoadDICOMScalar.cpp
   legacy/mitkDicomSR_LoadDICOMScalar4D.cpp
   legacy/mitkDicomSR_SliceGroupingResult.cpp
 )
 
 set(RESOURCE_FILES
   configurations/3D/classicreader.xml
   configurations/3D/imageposition.xml
   configurations/3D/imageposition_byacquisition.xml
   configurations/3D/instancenumber.xml
   configurations/3D/instancenumber_soft.xml
   configurations/3D/slicelocation.xml
   configurations/3D/simpleinstancenumber_soft.xml
 
   configurations/3DnT/classicreader.xml
   configurations/3DnT/imageposition.xml
   configurations/3DnT/imageposition_byacquisition.xml
   configurations/3DnT/imageposition_bytriggertime.xml
 )
diff --git a/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h b/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h
index 1acff14ce9..aa56718ad8 100644
--- a/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h
+++ b/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h
@@ -1,70 +1,70 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKBASEDICOMREADERSERVICE_H
 #define MITKBASEDICOMREADERSERVICE_H
 
 #include <mitkAbstractFileReader.h>
 #include <mitkDICOMFileReader.h>
 
 #include "MitkDICOMReaderExports.h"
 
 namespace mitk {
 
   /**
   Base class for service wrappers that make DICOMFileReader from
   the DICOMReader module usable.
   */
 class MITKDICOMREADER_EXPORT BaseDICOMReaderService : public AbstractFileReader
 {
 public:
   BaseDICOMReaderService(const std::string& description);
   BaseDICOMReaderService(const mitk::CustomMimeType& customType, const std::string& description);
 
   using AbstractFileReader::Read;
 
-  /** Uses this->GetRelevantFile() and this->GetReader to load the image.
-   * data and puts it into base data instances-*/
-  std::vector<itk::SmartPointer<BaseData> > Read() override;
-
   IFileReader::ConfidenceLevel GetConfidenceLevel() const override;
 
 protected:
-  /** Returns the list of all DCM files that are in the same directory
+  /** Uses this->GetRelevantFile() and this->GetReader to load the image.
+   * data and puts it into base data instances-*/
+  std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
+ /** Returns the list of all DCM files that are in the same directory
    * like this->GetLocalFileName().*/
   mitk::StringList GetDICOMFilesInSameDirectory() const;
 
   /** Returns the reader instance that should be used. The descission may be based
    * one the passed relevant file list.*/
   virtual mitk::DICOMFileReader::Pointer GetReader(const mitk::StringList& relevantFiles) const = 0;
 
   void SetOnlyRegardOwnSeries(bool);
   bool GetOnlyRegardOwnSeries() const;
 
 private:
   /** Flags that constrols if the read() operation should only regard DICOM files of the same series
   if the specified GetLocalFileName() is a file. If it is a director, this flag has no impact (it is
   assumed false then).
   */
   bool m_OnlyRegardOwnSeries = true;
 };
 
 
 class IPropertyProvider;
 
 /** Helper function that generates a name string (e.g. for DataNode names) from the DICOM properties of the passed
   provider instance. If the instance is nullptr, or has no dicom properties DataNode::NO_NAME_VALUE() will be returned.*/
 std::string MITKDICOMREADER_EXPORT GenerateNameFromDICOMProperties(const mitk::IPropertyProvider* provider);
 
 }
 
 #endif // MITKBASEDICOMREADERSERVICE_H
diff --git a/Modules/DICOMReader/include/mitkDICOMIOMetaInformationPropertyConstants.h b/Modules/DICOMReader/include/mitkDICOMIOMetaInformationPropertyConstants.h
new file mode 100644
index 0000000000..5a6bc3eaa7
--- /dev/null
+++ b/Modules/DICOMReader/include/mitkDICOMIOMetaInformationPropertyConstants.h
@@ -0,0 +1,51 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#ifndef MITKDICOMIOMETAINFORMATIONCONSTANTS_H_
+#define MITKDICOMIOMETAINFORMATIONCONSTANTS_H_
+
+#include <MitkDICOMReaderExports.h>
+
+#include "mitkPropertyKeyPath.h"
+
+namespace mitk
+{
+  /**
+   * @ingroup IO
+   * @brief The IOMetaInformationPropertyConsants struct
+   */
+  struct MITKDICOMREADER_EXPORT DICOMIOMetaInformationPropertyConstants
+  {
+    //Path to the property containing the name of the dicom reader configuration used to read the data
+    static PropertyKeyPath READER_CONFIGURATION();
+    //Path to the property containing the files the dicom reader used in a TemporoSpatialProperty
+    static PropertyKeyPath READER_FILES();
+    //Path to the property containing PixelSpacingInterpretationString for the read data
+    static PropertyKeyPath READER_PIXEL_SPACING_INTERPRETATION_STRING();
+    //Path to the property containing PixelSpacingInterpretation for the read data
+    static PropertyKeyPath READER_PIXEL_SPACING_INTERPRETATION();
+    //Path to the property containing ReaderImplementationLevelString for the read data
+    static PropertyKeyPath READER_IMPLEMENTATION_LEVEL_STRING();
+    //Path to the property containing ReaderImplementationLevel for the read data
+    static PropertyKeyPath READER_IMPLEMENTATION_LEVEL();
+    //Path to the property containing the indicator of the gantry tilt was corrected when reading the data
+    static PropertyKeyPath READER_GANTRY_TILT_CORRECTED();
+    //Path to the property containing the indicator of the data was read as 3D+t
+    static PropertyKeyPath READER_3D_plus_t();
+    //Path to the property containing the version of GDCM used to read the data
+    static PropertyKeyPath READER_GDCM();
+    //Path to the property containing the version of DCMTK used to read the data
+    static PropertyKeyPath READER_DCMTK();
+  };
+}
+
+#endif // MITKIOCONSTANTS_H_
diff --git a/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp b/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp
index aa9d0f3e4b..2163a64b75 100644
--- a/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp
+++ b/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp
@@ -1,221 +1,225 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkBaseDICOMReaderService.h"
 
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkDICOMFileReaderSelector.h>
 #include <mitkImage.h>
 #include <mitkDICOMFilesHelper.h>
 #include <mitkDICOMTagsOfInterestHelper.h>
 #include <mitkDICOMProperty.h>
 #include "legacy/mitkDicomSeriesReader.h"
 #include <mitkDICOMDCMTKTagScanner.h>
 #include <mitkLocaleSwitch.h>
 #include "mitkIPropertyProvider.h"
 #include "mitkPropertyNameHelper.h"
+#include "mitkPropertyKeyPath.h"
+#include "mitkDICOMIOMetaInformationPropertyConstants.h"
 
 #include <iostream>
 
 
 #include <itksys/SystemTools.hxx>
 #include <itksys/Directory.hxx>
 
 namespace mitk
 {
 
   BaseDICOMReaderService::BaseDICOMReaderService(const std::string& description)
     : AbstractFileReader(CustomMimeType(IOMimeTypes::DICOM_MIMETYPE()), description)
 {
 }
 
 BaseDICOMReaderService::BaseDICOMReaderService(const mitk::CustomMimeType& customType, const std::string& description)
   : AbstractFileReader(customType, description)
 {
 }
 
 void BaseDICOMReaderService::SetOnlyRegardOwnSeries(bool regard)
 {
   m_OnlyRegardOwnSeries = regard;
 }
 
 bool BaseDICOMReaderService::GetOnlyRegardOwnSeries() const
 {
   return m_OnlyRegardOwnSeries;
 }
 
 
-std::vector<itk::SmartPointer<BaseData> > BaseDICOMReaderService::Read()
+std::vector<itk::SmartPointer<BaseData> > BaseDICOMReaderService::DoRead()
 {
   std::vector<BaseData::Pointer> result;
 
 
   const std::string fileName = this->GetLocalFileName();
   //special handling of Philips 3D US DICOM.
   //Copied from DICOMSeriesReaderService
   if (DicomSeriesReader::IsPhilips3DDicom(fileName))
   {
       MITK_INFO << "it is a Philips3D US Dicom file" << std::endl;
       mitk::LocaleSwitch localeSwitch("C");
       std::locale previousCppLocale(std::cin.getloc());
       std::locale l("C");
       std::cin.imbue(l);
 
       DataNode::Pointer node = DataNode::New();
       mitk::DicomSeriesReader::StringContainer stringvec;
       stringvec.push_back(fileName);
       if (DicomSeriesReader::LoadDicomSeries(stringvec, *node))
       {
           BaseData::Pointer data = node->GetData();
           StringProperty::Pointer nameProp = StringProperty::New(itksys::SystemTools::GetFilenameName(fileName));
           data->GetPropertyList()->SetProperty("name", nameProp);
           result.push_back(data);
       }
       std::cin.imbue(previousCppLocale);
       return result;
   }
 
   //Normal DICOM handling (It wasn't a Philips 3D US)
   mitk::StringList relevantFiles = this->GetDICOMFilesInSameDirectory();
 
   if (relevantFiles.empty())
   {
       MITK_INFO << "DICOMReader service found no relevant files in specified location. No data is loaded. Location: "<<fileName;
   }
   else
   {
     bool pathIsDirectory = itksys::SystemTools::FileIsDirectory(fileName);
 
     if (!pathIsDirectory && m_OnlyRegardOwnSeries)
     {
       relevantFiles = mitk::FilterDICOMFilesForSameSeries(fileName, relevantFiles);
     }
 
     mitk::DICOMFileReader::Pointer reader = this->GetReader(relevantFiles);
 
       if(reader.IsNull())
       {
           MITK_INFO << "DICOMReader service found no suitable reader configuration for relevant files.";
       }
       else
       {
         if (!pathIsDirectory)
         { //we ensure that we only load the relevant image block files
           const auto nrOfOutputs = reader->GetNumberOfOutputs();
           for (unsigned int outputIndex = 0; outputIndex < nrOfOutputs; ++outputIndex)
           {
             const auto frameList = reader->GetOutput(outputIndex).GetImageFrameList();
 
             auto finding = std::find_if(frameList.begin(), frameList.end(), [&](const DICOMImageFrameInfo::Pointer& frame) { return frame->Filename == fileName; });
 
             if (finding != frameList.end())
             { //we have the block containing the fileName -> these are the realy relevant files.
               relevantFiles.resize(frameList.size());
               std::transform(frameList.begin(), frameList.end(), relevantFiles.begin(), [](const DICOMImageFrameInfo::Pointer& frame) { return frame->Filename; });
               break;
             }
           }
         }
           const unsigned int ntotalfiles = relevantFiles.size();
 
           for( unsigned int i=0; i< ntotalfiles; i++)
           {
             m_ReadFiles.push_back( relevantFiles.at(i) );
           }
 
           reader->SetAdditionalTagsOfInterest(mitk::GetCurrentDICOMTagsOfInterest());
           reader->SetTagLookupTableToPropertyFunctor(mitk::GetDICOMPropertyForDICOMValuesFunctor);
           reader->SetInputFiles(relevantFiles);
 
           mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New();
           scanner->AddTagPaths(reader->GetTagsOfInterest());
           scanner->SetInputFiles(relevantFiles);
           scanner->Scan();
 
           reader->SetTagCache(scanner->GetScanCache());
           reader->AnalyzeInputFiles();
           reader->LoadImages();
 
           for (unsigned int i = 0; i < reader->GetNumberOfOutputs(); ++i)
           {
             const mitk::DICOMImageBlockDescriptor& desc = reader->GetOutput(i);
             mitk::BaseData::Pointer data = desc.GetMitkImage().GetPointer();
 
             std::string nodeName = GenerateNameFromDICOMProperties(&desc);
 
             StringProperty::Pointer nameProp = StringProperty::New(nodeName);
             data->SetProperty("name", nameProp);
 
+            data->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION()), StringProperty::New(reader->GetConfigurationLabel()));
+
             result.push_back(data);
           }
       }
   }
 
   return result;
 }
 
 StringList BaseDICOMReaderService::GetDICOMFilesInSameDirectory() const
 {
   std::string fileName = this->GetLocalFileName();
 
   mitk::StringList relevantFiles = mitk::GetDICOMFilesInSameDirectory(fileName);
 
   return relevantFiles;
 }
 
 IFileReader::ConfidenceLevel BaseDICOMReaderService::GetConfidenceLevel() const
 {
   IFileReader::ConfidenceLevel abstractConfidence = AbstractFileReader::GetConfidenceLevel();
 
   if (Unsupported == abstractConfidence)
   {
     if (itksys::SystemTools::FileIsDirectory(this->GetInputLocation().c_str()))
     {
       // In principle we support dicom directories
       return Supported;
     }
   }
 
   return abstractConfidence;
 }
 
 std::string GenerateNameFromDICOMProperties(const mitk::IPropertyProvider* provider)
 {
   std::string nodeName = mitk::DataNode::NO_NAME_VALUE();
 
   auto studyProp = provider->GetConstProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str());
   if (studyProp.IsNotNull())
   {
     nodeName = studyProp->GetValueAsString();
   }
 
   auto seriesProp = provider->GetConstProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103E).c_str());
 
   if (seriesProp.IsNotNull())
   {
     if (studyProp.IsNotNull())
     {
       nodeName += " / ";
     }
     else
     {
       nodeName = "";
 
     }
     nodeName += seriesProp->GetValueAsString();
   }
 
   return nodeName;
 };
 
 }
diff --git a/Modules/DICOMReader/src/mitkDICOMFileReader.cpp b/Modules/DICOMReader/src/mitkDICOMFileReader.cpp
index 8e774692e7..1c497e6908 100644
--- a/Modules/DICOMReader/src/mitkDICOMFileReader.cpp
+++ b/Modules/DICOMReader/src/mitkDICOMFileReader.cpp
@@ -1,225 +1,227 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkDICOMFileReader.h"
 
 #include <itkGDCMImageIO.h>
 
 mitk::DICOMFileReader
 ::DICOMFileReader()
 :itk::Object()
 {
 }
 
 mitk::DICOMFileReader
 ::~DICOMFileReader()
 {
 }
 
 mitk::DICOMFileReader
 ::DICOMFileReader(const DICOMFileReader& other )
 :itk::Object()
 ,m_InputFilenames( other.m_InputFilenames )
 ,m_Outputs( other.m_Outputs )
 ,m_ConfigLabel( other.m_ConfigLabel )
 ,m_ConfigDescription( other.m_ConfigDescription )
 {
 }
 
 mitk::DICOMFileReader&
 mitk::DICOMFileReader
 ::operator=(const DICOMFileReader& other)
 {
   if (this != &other)
   {
     m_InputFilenames = other.m_InputFilenames;
     m_Outputs = other.m_Outputs;
     m_ConfigLabel = other.m_ConfigLabel;
     m_ConfigDescription = other.m_ConfigDescription;
+    m_AdditionalTagsOfInterest = other.m_AdditionalTagsOfInterest;
+    m_TagLookupTableToPropertyFunctor = other.m_TagLookupTableToPropertyFunctor;
   }
   return *this;
 }
 
 void
 mitk::DICOMFileReader
 ::SetConfigurationLabel(const std::string& label)
 {
   m_ConfigLabel = label;
   this->Modified();
 }
 
 std::string
 mitk::DICOMFileReader
 ::GetConfigurationLabel() const
 {
   return m_ConfigLabel;
 }
 
 void
 mitk::DICOMFileReader
 ::SetConfigurationDescription(const std::string& desc)
 {
   m_ConfigDescription = desc;
   this->Modified();
 }
 
 std::string
 mitk::DICOMFileReader
 ::GetConfigurationDescription() const
 {
   return m_ConfigDescription;
 }
 
 void
 mitk::DICOMFileReader
 ::SetInputFiles( const StringList& filenames)
 {
   m_InputFilenames = filenames;
   this->Modified();
 }
 
 const mitk::StringList&
 mitk::DICOMFileReader
 ::GetInputFiles() const
 {
   return m_InputFilenames;
 }
 
 unsigned int
 mitk::DICOMFileReader
 ::GetNumberOfOutputs() const
 {
   return m_Outputs.size();
 }
 
 void
 mitk::DICOMFileReader
 ::ClearOutputs()
 {
   m_Outputs.clear();
 }
 
 void
 mitk::DICOMFileReader
 ::SetNumberOfOutputs(unsigned int numberOfOutputs)
 {
   m_Outputs.resize(numberOfOutputs);
 }
 
 void
 mitk::DICOMFileReader
 ::SetOutput(unsigned int index, const mitk::DICOMImageBlockDescriptor& output)
 {
   if (index < m_Outputs.size())
   {
     m_Outputs[index] = output;
   }
   else
   {
     std::stringstream ss;
     ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)";
     throw std::invalid_argument( ss.str() );
   }
 }
 
 void
 mitk::DICOMFileReader
 ::PrintConfiguration(std::ostream& os) const
 {
   os << "---- Configuration of " << this->GetNameOfClass() <<" " << (void*)this << " ----"<< std::endl;
   this->InternalPrintConfiguration(os);
   os << "---- End of configuration ----" << std::endl;
 }
 
 
 void
 mitk::DICOMFileReader
 ::PrintOutputs(std::ostream& os, bool filenameDetails) const
 {
   os << "---- Outputs of DICOMFilereader " << (void*)this << " ----"<< std::endl;
 
   for (unsigned int o = 0; o < m_Outputs.size(); ++o)
   {
     os << "-- Output " << o << std::endl;
     const DICOMImageBlockDescriptor& block = m_Outputs[o];
     block.Print(os, filenameDetails);
   }
   os << "---- End of output list ----" << std::endl;
 }
 
 
 const mitk::DICOMImageBlockDescriptor&
 mitk::DICOMFileReader
 ::GetOutput(unsigned int index) const
 {
   if (index < m_Outputs.size())
   {
     return m_Outputs[index];
   }
   else
   {
     std::stringstream ss;
     ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)";
     throw std::invalid_argument( ss.str() );
   }
 }
 mitk::DICOMImageBlockDescriptor&
 mitk::DICOMFileReader
 ::InternalGetOutput(unsigned int index)
 {
   if (index < m_Outputs.size())
   {
     return m_Outputs[index];
   }
   else
   {
     std::stringstream ss;
     ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)";
     throw std::invalid_argument( ss.str() );
   }
 }
 
 bool
 mitk::DICOMFileReader
 ::IsDICOM(const std::string& filename)
 {
   itk::GDCMImageIO::Pointer io = itk::GDCMImageIO::New();
   return io->CanReadFile( filename.c_str() );
 }
 
 
 mitk::DICOMFileReader::AdditionalTagsMapType mitk::DICOMFileReader::GetAdditionalTagsOfInterest() const
 {
   return m_AdditionalTagsOfInterest;
 }
 
 
 void mitk::DICOMFileReader::SetAdditionalTagsOfInterest(
   const AdditionalTagsMapType& tagList)
 {
   m_AdditionalTagsOfInterest = tagList;
   this->Modified();
 }
 
 
 void mitk::DICOMFileReader::SetTagLookupTableToPropertyFunctor(
   mitk::DICOMImageBlockDescriptor::TagLookupTableToPropertyFunctor functor )
 {
   m_TagLookupTableToPropertyFunctor = functor;
   this->Modified();
 }
 
 mitk::DICOMImageBlockDescriptor::TagLookupTableToPropertyFunctor
   mitk::DICOMFileReader::GetTagLookupTableToPropertyFunctor() const
 {
   return m_TagLookupTableToPropertyFunctor;
 }
diff --git a/Modules/DICOMReader/src/mitkDICOMIOMetaInformationPropertyConstants.cpp b/Modules/DICOMReader/src/mitkDICOMIOMetaInformationPropertyConstants.cpp
new file mode 100644
index 0000000000..beecb531ed
--- /dev/null
+++ b/Modules/DICOMReader/src/mitkDICOMIOMetaInformationPropertyConstants.cpp
@@ -0,0 +1,67 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#include "mitkDICOMIOMetaInformationPropertyConstants.h"
+
+namespace mitk
+{
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_FILES()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "files" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "PixelSpacingInterpretationString" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "PixelSpacingInterpretation" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "ReaderImplementationLevelString" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "ReaderImplementationLevel" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "GantyTiltCorrected" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "3D+t" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_GDCM()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "gdcm" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_DCMTK()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "dcmtk" });
+  }
+
+  PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION()
+  {
+    return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "configuration" });
+  }
+}
diff --git a/Modules/DICOMReader/src/mitkDICOMImageBlockDescriptor.cpp b/Modules/DICOMReader/src/mitkDICOMImageBlockDescriptor.cpp
index b4244d44d2..69ca0c9109 100644
--- a/Modules/DICOMReader/src/mitkDICOMImageBlockDescriptor.cpp
+++ b/Modules/DICOMReader/src/mitkDICOMImageBlockDescriptor.cpp
@@ -1,888 +1,913 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkDICOMImageBlockDescriptor.h"
 #include "mitkStringProperty.h"
 #include "mitkLevelWindowProperty.h"
+#include "mitkPropertyKeyPath.h"
+#include "mitkDICOMIOMetaInformationPropertyConstants.h"
 #include <gdcmUIDs.h>
 #include <vector>
+#include <gdcmVersion.h>
+#include <dcmtk/config/osconfig.h>
 
 mitk::DICOMImageBlockDescriptor::DICOMImageBlockDescriptor()
 : m_ReaderImplementationLevel( SOPClassUnknown )
 , m_PropertyList( PropertyList::New() )
 , m_TagCache( nullptr )
 , m_PropertiesOutOfDate( true )
 {
   m_PropertyFunctor = &mitk::DICOMImageBlockDescriptor::GetPropertyForDICOMValues;
 }
 
 mitk::DICOMImageBlockDescriptor::~DICOMImageBlockDescriptor()
 {
 }
 
 mitk::DICOMImageBlockDescriptor::DICOMImageBlockDescriptor( const DICOMImageBlockDescriptor& other )
 : m_ImageFrameList( other.m_ImageFrameList )
 , m_MitkImage( other.m_MitkImage )
 , m_SliceIsLoaded( other.m_SliceIsLoaded )
 , m_ReaderImplementationLevel( other.m_ReaderImplementationLevel )
 , m_TiltInformation( other.m_TiltInformation )
 , m_PropertyList( other.m_PropertyList->Clone() )
 , m_TagCache( other.m_TagCache )
 , m_PropertiesOutOfDate( other.m_PropertiesOutOfDate )
 , m_AdditionalTagMap(other.m_AdditionalTagMap)
 , m_FoundAdditionalTags(other.m_FoundAdditionalTags)
 , m_PropertyFunctor(other.m_PropertyFunctor)
 {
   if ( m_MitkImage )
   {
     m_MitkImage = m_MitkImage->Clone();
   }
-
-  m_PropertyFunctor = &mitk::DICOMImageBlockDescriptor::GetPropertyForDICOMValues;
 }
 
 mitk::DICOMImageBlockDescriptor& mitk::DICOMImageBlockDescriptor::
   operator=( const DICOMImageBlockDescriptor& other )
 {
   if ( this != &other )
   {
     m_ImageFrameList            = other.m_ImageFrameList;
     m_MitkImage                 = other.m_MitkImage;
     m_SliceIsLoaded             = other.m_SliceIsLoaded;
     m_ReaderImplementationLevel = other.m_ReaderImplementationLevel;
     m_TiltInformation           = other.m_TiltInformation;
 
     m_AdditionalTagMap = other.m_AdditionalTagMap;
     m_FoundAdditionalTags = other.m_FoundAdditionalTags;
     m_PropertyFunctor = other.m_PropertyFunctor;
 
     if ( other.m_PropertyList )
     {
       m_PropertyList = other.m_PropertyList->Clone();
     }
 
     if ( other.m_MitkImage )
     {
       m_MitkImage = other.m_MitkImage->Clone();
     }
 
     m_TagCache            = other.m_TagCache;
     m_PropertiesOutOfDate = other.m_PropertiesOutOfDate;
   }
   return *this;
 }
 
 mitk::DICOMTagList mitk::DICOMImageBlockDescriptor::GetTagsOfInterest()
 {
   DICOMTagList completeList;
 
   completeList.push_back( DICOMTag( 0x0018, 0x1164 ) ); // pixel spacing
   completeList.push_back( DICOMTag( 0x0028, 0x0030 ) ); // imager pixel spacing
 
   completeList.push_back( DICOMTag( 0x0008, 0x0018 ) ); // sop instance UID
   completeList.push_back( DICOMTag( 0x0008, 0x0016 ) ); // sop class UID
 
   completeList.push_back( DICOMTag( 0x0020, 0x0011 ) ); // series number
   completeList.push_back( DICOMTag( 0x0008, 0x1030 ) ); // study description
   completeList.push_back( DICOMTag( 0x0008, 0x103e ) ); // series description
   completeList.push_back( DICOMTag( 0x0008, 0x0060 ) ); // modality
   completeList.push_back( DICOMTag( 0x0018, 0x0024 ) ); // sequence name
   completeList.push_back( DICOMTag( 0x0020, 0x0037 ) ); // image orientation
 
   completeList.push_back( DICOMTag( 0x0020, 0x1041 ) ); // slice location
   completeList.push_back( DICOMTag( 0x0020, 0x0012 ) ); // acquisition number
   completeList.push_back( DICOMTag( 0x0020, 0x0013 ) ); // instance number
   completeList.push_back( DICOMTag( 0x0020, 0x0032 ) ); // image position patient
 
   completeList.push_back( DICOMTag( 0x0028, 0x1050 ) ); // window center
   completeList.push_back( DICOMTag( 0x0028, 0x1051 ) ); // window width
   completeList.push_back( DICOMTag( 0x0008, 0x0008 ) ); // image type
   completeList.push_back( DICOMTag( 0x0028, 0x0004 ) ); // photometric interpretation
 
   return completeList;
 }
 
 
 void mitk::DICOMImageBlockDescriptor::SetAdditionalTagsOfInterest(
   const AdditionalTagsMapType& tagMap)
 {
   m_AdditionalTagMap = tagMap;
 }
 
 
 void mitk::DICOMImageBlockDescriptor::SetTiltInformation( const GantryTiltInformation& info )
 {
   m_TiltInformation = info;
 }
 
 const mitk::GantryTiltInformation mitk::DICOMImageBlockDescriptor::GetTiltInformation() const
 {
   return m_TiltInformation;
 }
 
 void mitk::DICOMImageBlockDescriptor::SetImageFrameList( const DICOMImageFrameList& framelist )
 {
   m_ImageFrameList = framelist;
   m_SliceIsLoaded.resize( framelist.size() );
   m_SliceIsLoaded.assign( framelist.size(), false );
 
   m_PropertiesOutOfDate = true;
 }
 
 const mitk::DICOMImageFrameList& mitk::DICOMImageBlockDescriptor::GetImageFrameList() const
 {
   return m_ImageFrameList;
 }
 
 void mitk::DICOMImageBlockDescriptor::SetMitkImage( Image::Pointer image )
 {
   if ( m_MitkImage != image )
   {
     if ( m_TagCache.IsExpired() )
     {
       MITK_ERROR << "Unable to describe MITK image with properties without a tag-cache object!";
       m_MitkImage = nullptr;
       return;
     }
 
     if ( m_ImageFrameList.empty() )
     {
       MITK_ERROR << "Unable to describe MITK image with properties without a frame list!";
       m_MitkImage = nullptr;
       return;
     }
 
     // Should verify that the image matches m_ImageFrameList and m_TagCache
     // however, this is hard to do without re-analyzing all
     // TODO we should at least make sure that the number of frames is identical (plus rows/columns,
     // orientation)
     //      without gantry tilt correction, we can also check image origin
 
     m_MitkImage = this->DescribeImageWithProperties( this->FixupSpacing( image ) );
   }
 }
 
 mitk::Image::Pointer mitk::DICOMImageBlockDescriptor::GetMitkImage() const
 {
   return m_MitkImage;
 }
 
 mitk::Image::Pointer mitk::DICOMImageBlockDescriptor::FixupSpacing( Image* mitkImage )
 {
   if ( mitkImage )
   {
     Vector3D imageSpacing = mitkImage->GetGeometry()->GetSpacing();
 
     ScalarType desiredSpacingX = imageSpacing[0];
     ScalarType desiredSpacingY = imageSpacing[1];
     this->GetDesiredMITKImagePixelSpacing(
       desiredSpacingX, desiredSpacingY ); // prefer pixel spacing over imager pixel spacing
 
     if ( desiredSpacingX <= 0 || desiredSpacingY <= 0 )
     {
       return mitkImage;
     }
 
     MITK_DEBUG << "Loaded image with spacing " << imageSpacing[0] << ", " << imageSpacing[1];
     MITK_DEBUG << "Found correct spacing info " << desiredSpacingX << ", " << desiredSpacingY;
 
     imageSpacing[0] = desiredSpacingX;
     imageSpacing[1] = desiredSpacingY;
     mitkImage->GetGeometry()->SetSpacing( imageSpacing );
   }
 
   return mitkImage;
 }
 void mitk::DICOMImageBlockDescriptor::SetSliceIsLoaded( unsigned int index, bool isLoaded )
 {
   if ( index < m_SliceIsLoaded.size() )
   {
     m_SliceIsLoaded[index] = isLoaded;
   }
   else
   {
     std::stringstream ss;
     ss << "Index " << index << " out of range (" << m_SliceIsLoaded.size() << " indices reserved)";
     throw std::invalid_argument( ss.str() );
   }
 }
 
 bool mitk::DICOMImageBlockDescriptor::IsSliceLoaded( unsigned int index ) const
 {
   if ( index < m_SliceIsLoaded.size() )
   {
     return m_SliceIsLoaded[index];
   }
   else
   {
     std::stringstream ss;
     ss << "Index " << index << " out of range (" << m_SliceIsLoaded.size() << " indices reserved)";
     throw std::invalid_argument( ss.str() );
   }
 }
 
 bool mitk::DICOMImageBlockDescriptor::AllSlicesAreLoaded() const
 {
   bool allLoaded = true;
   for ( auto iter = m_SliceIsLoaded.cbegin(); iter != m_SliceIsLoaded.cend(); ++iter )
   {
     allLoaded &= *iter;
   }
 
   return allLoaded;
 }
 
 /*
    PS defined      IPS defined     PS==IPS
         0               0                     --> UNKNOWN spacing, loader will invent
         0               1                     --> spacing as at detector surface
         1               0                     --> spacing as in patient
         1               1             0       --> detector surface spacing CORRECTED for geometrical
    magnifications: spacing as in patient
         1               1             1       --> detector surface spacing NOT corrected for geometrical
    magnifications: spacing as at detector
 */
 mitk::PixelSpacingInterpretation mitk::DICOMImageBlockDescriptor::GetPixelSpacingInterpretation() const
 {
   if ( m_ImageFrameList.empty() || m_TagCache.IsExpired() )
   {
     MITK_ERROR << "Invalid call to GetPixelSpacingInterpretation. Need to have initialized tag-cache!";
     return SpacingUnknown;
   }
 
   const std::string pixelSpacing       = this->GetPixelSpacing();
   const std::string imagerPixelSpacing = this->GetImagerPixelSpacing();
 
   if ( pixelSpacing.empty() )
   {
     if ( imagerPixelSpacing.empty() )
     {
       return SpacingUnknown;
     }
     else
     {
       return SpacingAtDetector;
     }
   }
   else // Pixel Spacing defined
   {
     if ( imagerPixelSpacing.empty() )
     {
       return SpacingInPatient;
     }
     else if ( pixelSpacing != imagerPixelSpacing )
     {
       return SpacingInPatient;
     }
     else
     {
       return SpacingAtDetector;
     }
   }
 }
 
 std::string mitk::DICOMImageBlockDescriptor::GetPixelSpacing() const
 {
   if ( m_ImageFrameList.empty() || m_TagCache.IsExpired() )
   {
     MITK_ERROR << "Invalid call to GetPixelSpacing. Need to have initialized tag-cache!";
     return std::string( "" );
   }
 
   static const DICOMTag tagPixelSpacing( 0x0028, 0x0030 );
   return m_TagCache.Lock()->GetTagValue( m_ImageFrameList.front(), tagPixelSpacing ).value;
 }
 
 std::string mitk::DICOMImageBlockDescriptor::GetImagerPixelSpacing() const
 {
   if ( m_ImageFrameList.empty() || m_TagCache.IsExpired() )
   {
     MITK_ERROR << "Invalid call to GetImagerPixelSpacing. Need to have initialized tag-cache!";
     return std::string( "" );
   }
 
   static const DICOMTag tagImagerPixelSpacing( 0x0018, 0x1164 );
   return m_TagCache.Lock()->GetTagValue( m_ImageFrameList.front(), tagImagerPixelSpacing ).value;
 }
 
 void mitk::DICOMImageBlockDescriptor::GetDesiredMITKImagePixelSpacing( ScalarType& spacingX,
                                                                        ScalarType& spacingY ) const
 {
   const std::string pixelSpacing = this->GetPixelSpacing();
   // preference for "in patient" pixel spacing
   if ( !DICOMStringToSpacing( pixelSpacing, spacingX, spacingY ) )
   {
     const std::string imagerPixelSpacing = this->GetImagerPixelSpacing();
     // fallback to "on detector" spacing
     if ( !DICOMStringToSpacing( imagerPixelSpacing, spacingX, spacingY ) )
     {
       // at this point we have no hints whether the spacing is correct
       // do a quick sanity check and either trust in the input or set both to 1
       // We assume neither spacing to be negative, zero or unexpectedly large for
       // medical images
       if (spacingX < mitk::eps || spacingX > 1000 || spacingY < mitk::eps || spacingY > 1000)
       {
         spacingX = spacingY = 1.0;
       }
     }
   }
 }
 
 void mitk::DICOMImageBlockDescriptor::SetProperty( const std::string& key, BaseProperty* value )
 {
   m_PropertyList->SetProperty( key, value );
 }
 
 mitk::BaseProperty* mitk::DICOMImageBlockDescriptor::GetProperty( const std::string& key ) const
 {
   this->UpdateImageDescribingProperties();
   return m_PropertyList->GetProperty( key );
 }
 
 std::string mitk::DICOMImageBlockDescriptor::GetPropertyAsString( const std::string& key ) const
 {
   this->UpdateImageDescribingProperties();
   const mitk::BaseProperty::Pointer property = m_PropertyList->GetProperty( key );
   if ( property.IsNotNull() )
   {
     return property->GetValueAsString();
   }
   else
   {
     return std::string( "" );
   }
 }
 
 void mitk::DICOMImageBlockDescriptor::SetFlag( const std::string& key, bool value )
 {
   m_PropertyList->ReplaceProperty( key, BoolProperty::New( value ) );
 }
 
 bool mitk::DICOMImageBlockDescriptor::GetFlag( const std::string& key, bool defaultValue ) const
 {
   this->UpdateImageDescribingProperties();
   BoolProperty::ConstPointer boolProp = dynamic_cast<BoolProperty*>( this->GetProperty( key ) );
   if ( boolProp.IsNotNull() )
   {
     return boolProp->GetValue();
   }
   else
   {
     return defaultValue;
   }
 }
 
 void mitk::DICOMImageBlockDescriptor::SetIntProperty( const std::string& key, int value )
 {
   m_PropertyList->ReplaceProperty( key, IntProperty::New( value ) );
 }
 
 int mitk::DICOMImageBlockDescriptor::GetIntProperty( const std::string& key, int defaultValue ) const
 {
   this->UpdateImageDescribingProperties();
   IntProperty::ConstPointer intProp = dynamic_cast<IntProperty*>( this->GetProperty( key ) );
   if ( intProp.IsNotNull() )
   {
     return intProp->GetValue();
   }
   else
   {
     return defaultValue;
   }
 }
 
 double mitk::DICOMImageBlockDescriptor::stringtodouble( const std::string& str ) const
 {
   double d;
   std::string trimmedstring( str );
   try
   {
     trimmedstring = trimmedstring.erase( trimmedstring.find_last_not_of( " \n\r\t" ) + 1 );
   }
   catch ( ... )
   {
     // no last not of
   }
 
   std::string firstcomponent( trimmedstring );
   try
   {
     firstcomponent = trimmedstring.erase( trimmedstring.find_first_of( "\\" ) );
   }
   catch ( ... )
   {
     // no last not of
   }
 
   std::istringstream converter( firstcomponent );
   if ( !firstcomponent.empty() && ( converter >> d ) && converter.eof() )
   {
     return d;
   }
   else
   {
     throw std::invalid_argument( "Argument is not a convertable number" );
   }
 }
 
 mitk::Image::Pointer mitk::DICOMImageBlockDescriptor::DescribeImageWithProperties( Image* mitkImage )
 {
   // TODO: this is a collection of properties that have been provided by the
   // legacy DicomSeriesReader.
   // We should at some point clean up this collection and name them in a more
   // consistent way!
 
   if ( !mitkImage )
     return mitkImage;
 
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_FILES()), this->GetProperty("filenamesForSlices"));
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING()),
+    StringProperty::New(PixelSpacingInterpretationToString(this->GetPixelSpacingInterpretation())));
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION()),
+    GenericProperty<PixelSpacingInterpretation>::New(this->GetPixelSpacingInterpretation()));
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING()),
+    StringProperty::New(ReaderImplementationLevelToString(m_ReaderImplementationLevel)));
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL()),
+    GenericProperty<ReaderImplementationLevel>::New(m_ReaderImplementationLevel));
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED()),
+    BoolProperty::New(this->GetTiltInformation().IsRegularGantryTilt()));
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t()), BoolProperty::New(this->GetFlag("3D+t", false)));
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_GDCM()), StringProperty::New(gdcm::Version::GetVersion()));
+  mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_DCMTK()), StringProperty::New(PACKAGE_VERSION));
+
+  // get all found additional tags of interest
+
+  for (auto tag : m_FoundAdditionalTags)
+  {
+    BaseProperty* prop = this->GetProperty(tag);
+    if (prop)
+    {
+      mitkImage->SetProperty(tag.c_str(), prop);
+    }
+  }
+
+  /////////////////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////////////////
+  //// Deprecated properties should be removed sooner then later (see above)
+  /////////////////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////////////////
+
   // first part: add some tags that describe individual slices
   // these propeties are defined at analysis time (see UpdateImageDescribingProperties())
 
   const char* propertyKeySliceLocation  = "dicom.image.0020.1041";
   const char* propertyKeyInstanceNumber = "dicom.image.0020.0013";
   const char* propertyKeySOPInstanceUID = "dicom.image.0008.0018";
 
   mitkImage->SetProperty( propertyKeySliceLocation, this->GetProperty( "sliceLocationForSlices" ) );
   mitkImage->SetProperty( propertyKeyInstanceNumber, this->GetProperty( "instanceNumberForSlices" ) );
   mitkImage->SetProperty( propertyKeySOPInstanceUID, this->GetProperty( "SOPInstanceUIDForSlices" ) );
-  mitkImage->SetProperty( "files", this->GetProperty( "filenamesForSlices" ) );
+  mitkImage->SetProperty( "files", this->GetProperty( "filenamesForSlices_deprecated" ) );
 
   // second part: add properties that describe the whole image block
   mitkImage->SetProperty( "dicomseriesreader.SOPClassUID", StringProperty::New( this->GetSOPClassUID() ) );
 
   mitkImage->SetProperty( "dicomseriesreader.SOPClass", StringProperty::New( this->GetSOPClassUIDAsName() ) );
 
   mitkImage->SetProperty(
     "dicomseriesreader.PixelSpacingInterpretationString",
     StringProperty::New( PixelSpacingInterpretationToString( this->GetPixelSpacingInterpretation() ) ) );
   mitkImage->SetProperty(
     "dicomseriesreader.PixelSpacingInterpretation",
     GenericProperty<PixelSpacingInterpretation>::New( this->GetPixelSpacingInterpretation() ) );
 
   mitkImage->SetProperty(
     "dicomseriesreader.ReaderImplementationLevelString",
     StringProperty::New( ReaderImplementationLevelToString( m_ReaderImplementationLevel ) ) );
 
   mitkImage->SetProperty( "dicomseriesreader.ReaderImplementationLevel",
                           GenericProperty<ReaderImplementationLevel>::New( m_ReaderImplementationLevel ) );
 
   mitkImage->SetProperty( "dicomseriesreader.GantyTiltCorrected",
                           BoolProperty::New( this->GetTiltInformation().IsRegularGantryTilt() ) );
 
   mitkImage->SetProperty( "dicomseriesreader.3D+t", BoolProperty::New( this->GetFlag( "3D+t", false ) ) );
 
   // level window
   const std::string windowCenter = this->GetPropertyAsString( "windowCenter" );
   const std::string windowWidth  = this->GetPropertyAsString( "windowWidth" );
   try
   {
     const double level  = stringtodouble( windowCenter );
     const double window = stringtodouble( windowWidth );
     mitkImage->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow( level, window ) ) );
   }
   catch ( ... )
   {
     // nothing, no levelwindow to be predicted...
   }
 
   const std::string modality = this->GetPropertyAsString( "modality" );
   mitkImage->SetProperty( "modality", StringProperty::New( modality ) );
 
   mitkImage->SetProperty( "dicom.pixel.PhotometricInterpretation",
                           this->GetProperty( "photometricInterpretation" ) );
   mitkImage->SetProperty( "dicom.image.imagetype", this->GetProperty( "imagetype" ) );
 
   mitkImage->SetProperty( "dicom.study.StudyDescription", this->GetProperty( "studyDescription" ) );
   mitkImage->SetProperty( "dicom.series.SeriesDescription", this->GetProperty( "seriesDescription" ) );
 
   mitkImage->SetProperty( "dicom.pixel.Rows", this->GetProperty( "rows" ) );
   mitkImage->SetProperty( "dicom.pixel.Columns", this->GetProperty( "columns" ) );
 
-  // third part: get all found additional tags of interest
-
-  for (auto tag : m_FoundAdditionalTags)
-  {
-    BaseProperty* prop = this->GetProperty(tag);
-    if (prop)
-    {
-      mitkImage->SetProperty(tag.c_str(), prop);
-    }
-  }
-
   // fourth part: get something from ImageIO. BUT this needs to be created elsewhere. or not at all!
 
   return mitkImage;
 }
 
 void mitk::DICOMImageBlockDescriptor::SetReaderImplementationLevel( const ReaderImplementationLevel& level )
 {
   m_ReaderImplementationLevel = level;
 }
 
 mitk::ReaderImplementationLevel mitk::DICOMImageBlockDescriptor::GetReaderImplementationLevel() const
 {
   return m_ReaderImplementationLevel;
 }
 
 std::string mitk::DICOMImageBlockDescriptor::GetSOPClassUID() const
 {
   if ( !m_ImageFrameList.empty() && !m_TagCache.IsExpired() )
   {
     static const DICOMTag tagSOPClassUID( 0x0008, 0x0016 );
     return m_TagCache.Lock()->GetTagValue( m_ImageFrameList.front(), tagSOPClassUID ).value;
   }
   else
   {
     MITK_ERROR
       << "Invalid call to DICOMImageBlockDescriptor::GetSOPClassUID(). Need to have initialized tag-cache!";
     return std::string( "" );
   }
 }
 
 std::string mitk::DICOMImageBlockDescriptor::GetSOPClassUIDAsName() const
 {
   if ( !m_ImageFrameList.empty() && !m_TagCache.IsExpired() )
   {
     gdcm::UIDs uidKnowledge;
     uidKnowledge.SetFromUID( this->GetSOPClassUID().c_str() );
 
     const char* name = uidKnowledge.GetName();
     if ( name )
     {
       return std::string( name );
     }
     else
     {
       return std::string( "" );
     }
   }
   else
   {
     MITK_ERROR << "Invalid call to DICOMImageBlockDescriptor::GetSOPClassUIDAsName(). Need to have "
                   "initialized tag-cache!";
     return std::string( "" );
   }
 }
 
 int mitk::DICOMImageBlockDescriptor::GetNumberOfTimeSteps() const
 {
   int result = 1;
   this->m_PropertyList->GetIntProperty("timesteps", result);
 
   return result;
 };
 
 int mitk::DICOMImageBlockDescriptor::GetNumberOfFramesPerTimeStep() const
 {
   const int numberOfTimesteps = this->GetNumberOfTimeSteps();
   int numberOfFramesPerTimestep = this->m_ImageFrameList.size() / numberOfTimesteps;
   assert(int(double((double)this->m_ImageFrameList.size() / (double)numberOfTimesteps))
     == numberOfFramesPerTimestep); // this should hold
 
   return numberOfFramesPerTimestep;
 };
 
 
 void mitk::DICOMImageBlockDescriptor::SetTagCache( DICOMTagCache* privateCache )
 {
   // this must only be used during loading and never afterwards
   m_TagCache = privateCache;
 }
 
 #define printPropertyRange( label, property_name )                                 \
   \
 {                                                                             \
     const std::string first = this->GetPropertyAsString( #property_name "First" ); \
     const std::string last  = this->GetPropertyAsString( #property_name "Last" );  \
     if ( !first.empty() || !last.empty() )                                         \
     {                                                                              \
       if ( first == last )                                                         \
       {                                                                            \
         os << "  " label ": '" << first << "'" << std::endl;                       \
       }                                                                            \
       else                                                                         \
       {                                                                            \
         os << "  " label ": '" << first << "' - '" << last << "'" << std::endl;    \
       }                                                                            \
     }                                                                              \
   \
 }
 
 #define printProperty( label, property_name )                              \
   \
 {                                                                     \
     const std::string first = this->GetPropertyAsString( #property_name ); \
     if ( !first.empty() )                                                  \
     {                                                                      \
       os << "  " label ": '" << first << "'" << std::endl;                 \
     }                                                                      \
   \
 }
 
 #define printBool( label, commands )                                           \
   \
 {                                                                         \
     os << "  " label ": '" << ( commands ? "yes" : "no" ) << "'" << std::endl; \
   \
 }
 
 
 
 
 void mitk::DICOMImageBlockDescriptor::Print(std::ostream& os, bool filenameDetails) const
 {
   os << "  Number of Frames: '" << m_ImageFrameList.size() << "'" << std::endl;
   os << "  SOP class: '" << this->GetSOPClassUIDAsName() << "'" << std::endl;
 
   printProperty( "Series Number", seriesNumber );
   printProperty( "Study Description", studyDescription );
   printProperty( "Series Description", seriesDescription );
   printProperty( "Modality", modality );
   printProperty( "Sequence Name", sequenceName );
 
   printPropertyRange( "Slice Location", sliceLocation );
   printPropertyRange( "Acquisition Number", acquisitionNumber );
   printPropertyRange( "Instance Number", instanceNumber );
   printPropertyRange( "Image Position", imagePositionPatient );
   printProperty( "Image Orientation", orientation );
 
   os << "  Pixel spacing interpretation: '"
      << PixelSpacingInterpretationToString( this->GetPixelSpacingInterpretation() ) << "'" << std::endl;
   printBool( "Gantry Tilt", this->GetTiltInformation().IsRegularGantryTilt() )
     // printBool("3D+t", this->GetFlag("3D+t",false))
 
     // os << "  MITK image loaded: '" << (this->GetMitkImage().IsNotNull() ? "yes" : "no") << "'" <<
     // std::endl;
     if ( filenameDetails )
   {
     os << "  Files in this image block:" << std::endl;
     for ( auto frameIter = m_ImageFrameList.begin(); frameIter != m_ImageFrameList.end(); ++frameIter )
     {
       os << "    " << ( *frameIter )->Filename;
       if ( ( *frameIter )->FrameNo > 0 )
       {
         os << ", " << ( *frameIter )->FrameNo;
       }
       os << std::endl;
     }
   }
 }
 
 #define storeTagValueToProperty( tag_name, tag_g, tag_e )                  \
   \
 {                                                                     \
     const DICOMTag t( tag_g, tag_e );                                      \
     const std::string tagValue = tagCache->GetTagValue( firstFrame, t ).value; \
     const_cast<DICOMImageBlockDescriptor*>( this )                         \
       ->SetProperty( #tag_name, StringProperty::New( tagValue ) );         \
   \
 }
 
 #define storeTagValueRangeToProperty( tag_name, tag_g, tag_e )                  \
   \
 {                                                                          \
     const DICOMTag t( tag_g, tag_e );                                           \
     const std::string tagValueFirst = tagCache->GetTagValue( firstFrame, t ).value; \
     const std::string tagValueLast  = tagCache->GetTagValue( lastFrame, t ).value;  \
     const_cast<DICOMImageBlockDescriptor*>( this )                              \
       ->SetProperty( #tag_name "First", StringProperty::New( tagValueFirst ) ); \
     const_cast<DICOMImageBlockDescriptor*>( this )                              \
       ->SetProperty( #tag_name "Last", StringProperty::New( tagValueLast ) );   \
   \
 }
 
 
 void mitk::DICOMImageBlockDescriptor::UpdateImageDescribingProperties() const
 {
   if ( !m_PropertiesOutOfDate )
     return;
 
   if ( !m_ImageFrameList.empty() )
   {
     if ( m_TagCache.IsExpired() )
     {
       MITK_ERROR << "Invalid call to DICOMImageBlockDescriptor::UpdateImageDescribingProperties(). Need to "
                     "have initialized tag-cache!";
       return;
     }
 
     auto tagCache = m_TagCache.Lock();
 
     if (tagCache.IsNull())
     {
       MITK_ERROR << "Invalid call to DICOMImageBlockDescriptor::UpdateImageDescribingProperties(). Need to "
         "have initialized tag-cache!";
       return;
     }
 
 
     const DICOMImageFrameInfo::Pointer firstFrame = m_ImageFrameList.front();
     const DICOMImageFrameInfo::Pointer lastFrame  = m_ImageFrameList.back();
 
     // see macros above
     storeTagValueToProperty( seriesNumber, 0x0020, 0x0011 );
     storeTagValueToProperty( studyDescription, 0x0008, 0x1030 );
     storeTagValueToProperty( seriesDescription, 0x0008, 0x103e );
     storeTagValueToProperty( modality, 0x0008, 0x0060 );
     storeTagValueToProperty( sequenceName, 0x0018, 0x0024 );
     storeTagValueToProperty( orientation, 0x0020, 0x0037 );
     storeTagValueToProperty( rows, 0x0028, 0x0010 );
     storeTagValueToProperty( columns, 0x0028, 0x0011 );
 
     storeTagValueRangeToProperty( sliceLocation, 0x0020, 0x1041 );
     storeTagValueRangeToProperty( acquisitionNumber, 0x0020, 0x0012 );
     storeTagValueRangeToProperty( instanceNumber, 0x0020, 0x0013 );
     storeTagValueRangeToProperty( imagePositionPatient, 0x0020, 0x0032 );
 
     storeTagValueToProperty( windowCenter, 0x0028, 0x1050 );
     storeTagValueToProperty( windowWidth, 0x0028, 0x1051 );
     storeTagValueToProperty( imageType, 0x0008, 0x0008 );
     storeTagValueToProperty( photometricInterpretation, 0x0028, 0x0004 );
 
     // some per-image attributes
     // frames are just numbered starting from 0. timestep 1 (the second time-step) has frames starting at
     // (number-of-frames-per-timestep)
     //     std::string propertyKeySliceLocation = "dicom.image.0020.1041";
     //     std::string propertyKeyInstanceNumber = "dicom.image.0020.0013";
     //     std::string propertyKeySOPInstanceNumber = "dicom.image.0008.0018";
 
     StringLookupTable sliceLocationForSlices;
     StringLookupTable instanceNumberForSlices;
     StringLookupTable SOPInstanceUIDForSlices;
-    StringLookupTable filenamesForSlices;
+    StringLookupTable filenamesForSlices_deprecated;
+    DICOMCachedValueLookupTable filenamesForSlices;
 
     const DICOMTag tagSliceLocation( 0x0020, 0x1041 );
     const DICOMTag tagInstanceNumber( 0x0020, 0x0013 );
     const DICOMTag tagSOPInstanceNumber( 0x0008, 0x0018 );
 
     std::unordered_map<std::string, DICOMCachedValueLookupTable> additionalTagResultList;
 
     unsigned int slice(0);
     int timePoint(-1);
     const int framesPerTimeStep = this->GetNumberOfFramesPerTimeStep();
     for ( auto frameIter = m_ImageFrameList.begin(); frameIter != m_ImageFrameList.end();
           ++slice, ++frameIter )
     {
       unsigned int zSlice = slice%framesPerTimeStep;
       if ( zSlice == 0)
       {
         timePoint++;
       }
 
       const std::string sliceLocation = tagCache->GetTagValue( *frameIter, tagSliceLocation ).value;
       sliceLocationForSlices.SetTableValue( slice, sliceLocation );
 
       const std::string instanceNumber = tagCache->GetTagValue( *frameIter, tagInstanceNumber ).value;
       instanceNumberForSlices.SetTableValue( slice, instanceNumber );
 
       const std::string sopInstanceUID = tagCache->GetTagValue( *frameIter, tagSOPInstanceNumber ).value;
       SOPInstanceUIDForSlices.SetTableValue( slice, sopInstanceUID );
 
       const std::string filename = ( *frameIter )->Filename;
-      filenamesForSlices.SetTableValue( slice, filename );
+      filenamesForSlices_deprecated.SetTableValue( slice, filename );
+      filenamesForSlices.SetTableValue(slice, { static_cast<unsigned int>(timePoint), zSlice, filename });
 
       MITK_DEBUG << "Tag info for slice " << slice << ": SL '" << sliceLocation << "' IN '" << instanceNumber
                  << "' SOP instance UID '" << sopInstanceUID << "'";
 
       for (const auto& tag : m_AdditionalTagMap)
       {
         const DICOMTagCache::FindingsListType findings = tagCache->GetTagValue( *frameIter, tag.first );
         for (const auto& finding : findings)
         {
           if (finding.isValid)
           {
             std::string propKey = (tag.second.empty()) ? DICOMTagPathToPropertyName(finding.path) : tag.second;
           DICOMCachedValueInfo info{ static_cast<unsigned int>(timePoint), zSlice, finding.value };
             additionalTagResultList[propKey].SetTableValue(slice, info);
           }
         }
       }
     }
 
     // add property or properties with proper names
     auto* thisInstance = const_cast<DICOMImageBlockDescriptor*>( this );
     thisInstance->SetProperty( "sliceLocationForSlices",
                                StringLookupTableProperty::New( sliceLocationForSlices ) );
 
     thisInstance->SetProperty( "instanceNumberForSlices",
                                StringLookupTableProperty::New( instanceNumberForSlices ) );
 
     thisInstance->SetProperty( "SOPInstanceUIDForSlices",
                                StringLookupTableProperty::New( SOPInstanceUIDForSlices ) );
 
-    thisInstance->SetProperty( "filenamesForSlices", StringLookupTableProperty::New( filenamesForSlices ) );
-
+    thisInstance->SetProperty( "filenamesForSlices_deprecated", StringLookupTableProperty::New( filenamesForSlices_deprecated ) );
+    thisInstance->SetProperty("filenamesForSlices", m_PropertyFunctor(filenamesForSlices));
 
     //add properties for additional tags of interest
 
     for ( auto iter = additionalTagResultList.cbegin(); iter != additionalTagResultList.cend(); ++iter )
     {
       thisInstance->SetProperty( iter->first, m_PropertyFunctor( iter->second ) );
       thisInstance->m_FoundAdditionalTags.insert(m_FoundAdditionalTags.cend(),iter->first);
     }
 
     m_PropertiesOutOfDate = false;
   }
 }
 
 
 mitk::BaseProperty::Pointer
 mitk::DICOMImageBlockDescriptor::GetPropertyForDICOMValues(const DICOMCachedValueLookupTable& cacheLookupTable)
 {
   const auto& lookupTable = cacheLookupTable.GetLookupTable();
   typedef std::pair<int, DICOMCachedValueInfo> PairType;
   if ( std::adjacent_find(
          lookupTable.cbegin(),
          lookupTable.cend(),
          []( const PairType& lhs, const PairType& rhs ) { return lhs.second.Value != rhs.second.Value; } )
        == lookupTable.cend() )
   {
     return static_cast<mitk::BaseProperty::Pointer>(
       mitk::StringProperty::New(cacheLookupTable.GetTableValue(0).Value).GetPointer());
   }
 
   StringLookupTable stringTable;
   for (auto element : lookupTable)
   {
     stringTable.SetTableValue(element.first, element.second.Value);
   }
 
   return static_cast<mitk::BaseProperty::Pointer>(
     mitk::StringLookupTableProperty::New(stringTable).GetPointer());
 }
 
 
 void mitk::DICOMImageBlockDescriptor::SetTagLookupTableToPropertyFunctor( TagLookupTableToPropertyFunctor functor )
 {
   if ( functor != nullptr )
   {
     m_PropertyFunctor = functor;
   }
 }
 
 mitk::BaseProperty::ConstPointer mitk::DICOMImageBlockDescriptor::GetConstProperty(const std::string &propertyKey,
   const std::string &/*contextName*/,  bool /*fallBackOnDefaultContext*/) const
 {
   this->UpdateImageDescribingProperties();
   return m_PropertyList->GetConstProperty(propertyKey);
 };
 
 std::vector<std::string> mitk::DICOMImageBlockDescriptor::GetPropertyKeys(const std::string &/*contextName*/,  bool /*includeDefaultContext*/) const
 {
   this->UpdateImageDescribingProperties();
   return m_PropertyList->GetPropertyKeys();
 };
 
 std::vector<std::string> mitk::DICOMImageBlockDescriptor::GetPropertyContextNames() const
 {
   return std::vector<std::string>();
 };
diff --git a/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp b/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp
index 6da162eeb6..8896d2b9a9 100644
--- a/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp
+++ b/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp
@@ -1,45 +1,93 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkDICOMReaderServicesActivator.h"
 
 #include "mitkAutoSelectingDICOMReaderService.h"
 #include "mitkClassicDICOMSeriesReaderService.h"
 #include "mitkDICOMTagsOfInterestService.h"
 #include "mitkSimpleVolumeDICOMSeriesReaderService.h"
+#include "mitkCoreServices.h"
+#include "mitkPropertyPersistenceInfo.h"
+#include "mitkDICOMIOMetaInformationPropertyConstants.h"
+#include "mitkIPropertyPersistence.h"
+#include "mitkTemporoSpatialStringProperty.h"
 
 #include <usModuleContext.h>
 
+void AddPropertyPersistence(const mitk::PropertyKeyPath& propPath, bool temporoSpatial = false)
+{
+  mitk::CoreServicePointer<mitk::IPropertyPersistence> persistenceService(mitk::CoreServices::GetPropertyPersistence());
+
+  mitk::PropertyPersistenceInfo::Pointer info = mitk::PropertyPersistenceInfo::New();
+  if (propPath.IsExplicit())
+  {
+    std::string name = mitk::PropertyKeyPathToPropertyName(propPath);
+    std::string key = name;
+    std::replace(key.begin(), key.end(), '.', '_');
+    info->SetNameAndKey(name, key);
+  }
+  else
+  {
+    std::string key = mitk::PropertyKeyPathToPersistenceKeyRegEx(propPath);
+    std::string keyTemplate = mitk::PropertyKeyPathToPersistenceKeyTemplate(propPath);
+    std::string propRegEx = mitk::PropertyKeyPathToPropertyRegEx(propPath);
+    std::string propTemplate = mitk::PropertyKeyPathToPersistenceNameTemplate(propPath);
+    info->UseRegEx(propRegEx, propTemplate, key, keyTemplate);
+  }
+
+  if (temporoSpatial)
+  {
+    info->SetDeserializationFunction(mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty);
+    info->SetSerializationFunction(mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON);
+  }
+
+  persistenceService->AddInfo(info);
+}
+
 namespace mitk {
 
   void DICOMReaderServicesActivator::Load(us::ModuleContext* context)
   {
     m_AutoSelectingDICOMReader.reset(new AutoSelectingDICOMReaderService());
     m_SimpleVolumeDICOMSeriesReader.reset(new SimpleVolumeDICOMSeriesReaderService());
 
     m_DICOMTagsOfInterestService.reset(new DICOMTagsOfInterestService());
     context->RegisterService<mitk::IDICOMTagsOfInterest>(m_DICOMTagsOfInterestService.get());
 
     DICOMTagPathMapType tagmap = GetDefaultDICOMTagsOfInterest();
     for (auto tag : tagmap)
     {
       m_DICOMTagsOfInterestService->AddTagOfInterest(tag.first);
     }
+
+    //add properties that should be persistent (if possible/supported by the writer)
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t());
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION());
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK());
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_FILES(), true);
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED());
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM());
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL());
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING());
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION());
+    AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING());
+
   }
 
   void DICOMReaderServicesActivator::Unload(us::ModuleContext*)
   {
   }
 
 }
 
 US_EXPORT_MODULE_ACTIVATOR(mitk::DICOMReaderServicesActivator)
diff --git a/Modules/DICOMTesting/CMakeLists.txt b/Modules/DICOMTesting/CMakeLists.txt
index 69d2fcb943..256daf6b3b 100644
--- a/Modules/DICOMTesting/CMakeLists.txt
+++ b/Modules/DICOMTesting/CMakeLists.txt
@@ -1,41 +1,43 @@
 if(BUILD_TESTING)
 if(GDCM_DIR)
 
 # clear variables from prior files.cmake
 # Else CMake would use the content of these variables and would try to create tests (which are not present in DICOMTesting).
 set(MODULE_TESTS)
 set(MODULE_IMAGE_TESTS)
 set(MODULE_SURFACE_TESTS)
 set(MODULE_TESTIMAGE)
 set(MODULE_TESTSURFACE)
 set(MODULE_CUSTOM_TESTS)
 set(H_FILES)
 set(CPP_FILES)
 
 # now create a new module only for testing purposes
 MITK_CREATE_MODULE(
   DEPENDS MitkDICOMReader
+  PACKAGE_DEPENDS
+    PRIVATE GDCM DCMTK ITK|ITKIOGDCM
 )
 
 mitk_check_module_dependencies(MODULES MitkDICOMTesting MISSING_DEPENDENCIES_VAR _missing_deps)
 
 if(_missing_deps)
   message(STATUS "mitkDICOMTesting module helper applications won't be built. Missing: ${_missing_deps}")
 else(_missing_deps)
 
   # dumps out image information
   add_executable(DumpDICOMMitkImage src/DumpDICOMMitkImage.cpp)
   mitk_use_modules(TARGET DumpDICOMMitkImage MODULES MitkDICOMTesting)
 
   # compares dumped out image information against reference dump
   add_executable(VerifyDICOMMitkImageDump src/VerifyDICOMMitkImageDump.cpp)
   mitk_use_modules(TARGET VerifyDICOMMitkImageDump MODULES MitkDICOMTesting)
 
   set_property(TARGET DumpDICOMMitkImage VerifyDICOMMitkImageDump PROPERTY FOLDER
     "${MITK_ROOT_FOLDER}/Modules/Tests")
 
   add_subdirectory(test)
 endif()
 
 endif()
 endif()
diff --git a/Modules/DICOMTesting/include/mitkTestDICOMLoading.h b/Modules/DICOMTesting/include/mitkTestDICOMLoading.h
index f1d8cd2f56..63289abc0b 100644
--- a/Modules/DICOMTesting/include/mitkTestDICOMLoading.h
+++ b/Modules/DICOMTesting/include/mitkTestDICOMLoading.h
@@ -1,108 +1,111 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 #ifndef mitkTestDICOMLoading_h
 #define mitkTestDICOMLoading_h
 
 #include "mitkClassicDICOMSeriesReader.h"
+#include "mitkPropertyKeyPath.h"
 
 #include "MitkDICOMTestingExports.h"
 
 namespace mitk
 {
 
 class MITKDICOMTESTING_EXPORT TestDICOMLoading
 {
   public:
 
     typedef std::list<Image::Pointer> ImageList;
 
     TestDICOMLoading();
 
     ImageList
     LoadFiles( const StringList & files );
 
     Image::Pointer
     DecorateVerifyCachedImage( const StringList& files, mitk::Image::Pointer cachedImage );
 
     Image::Pointer
     DecorateVerifyCachedImage( const StringList& files, DICOMTagCache*, mitk::Image::Pointer cachedImage );
 
     /**
       \brief Dump relevant image information for later comparison.
       \sa CompareImageInformationDumps
     */
     std::string
     DumpImageInformation( const Image* image );
 
     /**
       \brief Compare two image information dumps.
       \return true, if dumps are sufficiently equal (see parameters)
       \sa DumpImageInformation
     */
     bool
     CompareImageInformationDumps( const std::string& reference,
                                   const std::string& test );
 
   private:
 
     typedef std::map<std::string,std::string> KeyValueMap;
 
     ClassicDICOMSeriesReader::Pointer
     BuildDICOMReader();
 
     void SetDefaultLocale();
 
     void ResetUserLocale();
 
     std::string ComponentTypeToString( int type );
 
     KeyValueMap ParseDump( const std::string& dump );
 
     bool CompareSpacedValueFields( const std::string& reference,
                                    const std::string& test,
                                    double eps = mitk::eps );
 
     /**
        Compress whitespace in string
        \param pString input string
        \param pFill replacement whitespace (only whitespace in string after reduction)
        \param pWhitespace characters handled as whitespace
      */
     std::string reduce(const std::string& pString,
                        const std::string& pFill = " ",
                        const std::string& pWhitespace = " \t");
 
     /**
        Remove leading and trailing whitespace
        \param pString input string
        \param pWhitespace characters handled as whitespace
     */
     std::string trim(const std::string& pString,
                      const std::string& pWhitespace = " \t");
 
     template<typename T>
     bool StringToNumber(const std::string& s, T& value)
     {
       std::stringstream stream(s);
       stream >> value;
       return (!stream.fail()) && (std::abs(value) <= std::numeric_limits<T>::max());
     }
 
+    static void AddPropertyToDump(const mitk::PropertyKeyPath& key, const mitk::Image* image, std::stringstream& result);
+
     const char* m_PreviousCLocale;
     std::locale m_PreviousCppLocale;
 
 };
 
 }
 
 #endif
 
diff --git a/Modules/DICOMTesting/src/DumpDICOMMitkImage.cpp b/Modules/DICOMTesting/src/DumpDICOMMitkImage.cpp
index 240a316037..681794ef6e 100644
--- a/Modules/DICOMTesting/src/DumpDICOMMitkImage.cpp
+++ b/Modules/DICOMTesting/src/DumpDICOMMitkImage.cpp
@@ -1,36 +1,50 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkTestDICOMLoading.h"
 #include "mitkImage.h"
 
 int main(int argc, char** argv)
 {
   mitk::TestDICOMLoading loader;
   mitk::StringList files;
 
-  for (int arg = 1; arg < argc; ++arg) files.push_back( argv[arg] );
+  if (argc < 2)
+  {
+    std::cerr << "Wrong usage of DumpDICOMMitkImage. Call it like VerifyDICOMMitkImageDump <dumpfile> <dcmfile1> [<dcmfile2> [... <dcmfileN>]].";
+    return 1;
+  }
+
+  std::string dumpPath = argv[1];
+
+  for (int arg = 2; arg < argc; ++arg) files.push_back( argv[arg] );
 
   mitk::TestDICOMLoading::ImageList images = loader.LoadFiles(files);
 
+  std::ostringstream sstream;
   // combine individual dumps in a way that VerifyDICOMMitkImageDump is able to separate again.
   // I.e.: when changing this piece of code, always change VerifyDICOMMitkImageDump, too.
   unsigned int imageCounter(0);
   for ( mitk::TestDICOMLoading::ImageList::const_iterator imageIter = images.begin();
         imageIter != images.end();
         ++imageIter )
   {
-    std::cout << "-- Image " << ++imageCounter << "\n";
-    std::cout << loader.DumpImageInformation( *imageIter ) << "\n";
+    sstream << "-- Image " << ++imageCounter << "\n";
+    sstream << loader.DumpImageInformation( *imageIter ) << "\n";
   }
+  std::cout << sstream.str();
+  std::ofstream out(dumpPath, ios::trunc | ios::out);
+  out << sstream.str();
+  out.close();
+
 }
 
diff --git a/Modules/DICOMTesting/src/mitkTestDICOMLoading.cpp b/Modules/DICOMTesting/src/mitkTestDICOMLoading.cpp
index 532204de0e..ed2c8e71b0 100644
--- a/Modules/DICOMTesting/src/mitkTestDICOMLoading.cpp
+++ b/Modules/DICOMTesting/src/mitkTestDICOMLoading.cpp
@@ -1,488 +1,572 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 //#define MBILOG_ENABLE_DEBUG
 
 #include "mitkTestDICOMLoading.h"
+#include "mitkDICOMIOMetaInformationPropertyConstants.h"
+#include "mitkDICOMProperty.h"
 
 #include <stack>
 
+#include <gdcmVersion.h>
+#include <dcmtk/config/osconfig.h>
+#include "itksys/SystemTools.hxx"
+
 mitk::TestDICOMLoading::TestDICOMLoading()
 :m_PreviousCLocale(nullptr)
 {
 }
 
 void mitk::TestDICOMLoading::SetDefaultLocale()
 {
   // remember old locale only once
   if (m_PreviousCLocale == nullptr)
   {
     m_PreviousCLocale = setlocale(LC_NUMERIC, nullptr);
 
     // set to "C"
     setlocale(LC_NUMERIC, "C");
 
     m_PreviousCppLocale = std::cin.getloc();
 
     std::locale l( "C" );
     std::cin.imbue(l);
     std::cout.imbue(l);
   }
 }
 
 void mitk::TestDICOMLoading::ResetUserLocale()
 {
   if (m_PreviousCLocale)
   {
     setlocale(LC_NUMERIC, m_PreviousCLocale);
 
     std::cin.imbue(m_PreviousCppLocale);
     std::cout.imbue(m_PreviousCppLocale);
 
     m_PreviousCLocale = nullptr;
   }
 }
 
 
 
 mitk::TestDICOMLoading::ImageList
 mitk::TestDICOMLoading
 ::LoadFiles( const StringList& files )
 {
   for (auto iter = files.begin();
        iter != files.end();
        ++iter)
   {
     MITK_DEBUG << "File " << *iter;
   }
 
   ImageList result;
 
   ClassicDICOMSeriesReader::Pointer reader = this->BuildDICOMReader();
+  reader->SetTagLookupTableToPropertyFunctor(mitk::GetDICOMPropertyForDICOMValuesFunctor);
   reader->SetInputFiles( files );
   reader->AnalyzeInputFiles();
   reader->PrintOutputs(std::cout,true);
   reader->LoadImages();
 
   unsigned int numberOfImages = reader->GetNumberOfOutputs();
   for (unsigned imageIndex = 0; imageIndex < numberOfImages; ++imageIndex)
   {
     const DICOMImageBlockDescriptor& block = reader->GetOutput(imageIndex);
     result.push_back( block.GetMitkImage() );
   }
 
   return result;
 }
 
 mitk::ClassicDICOMSeriesReader::Pointer
 mitk::TestDICOMLoading
 ::BuildDICOMReader()
 {
   ClassicDICOMSeriesReader::Pointer reader = ClassicDICOMSeriesReader::New();
   reader->SetFixTiltByShearing(true);
   return reader;
 }
 
 mitk::Image::Pointer
 mitk::TestDICOMLoading
 ::DecorateVerifyCachedImage( const StringList& files, mitk::DICOMTagCache* tagCache, mitk::Image::Pointer cachedImage )
 {
   DICOMImageBlockDescriptor block;
 
   DICOMImageFrameList framelist;
   for (auto iter = files.begin();
        iter != files.end();
        ++iter)
   {
     framelist.push_back( DICOMImageFrameInfo::New(*iter) );
   }
 
   block.SetImageFrameList( framelist );
 
   block.SetTagCache( tagCache );
   block.SetMitkImage( cachedImage ); // this should/will create a propertylist describing the image slices
   return block.GetMitkImage();
 }
 
 
 mitk::Image::Pointer
 mitk::TestDICOMLoading
 ::DecorateVerifyCachedImage( const StringList& files, mitk::Image::Pointer cachedImage )
 {
   ClassicDICOMSeriesReader::Pointer reader = this->BuildDICOMReader();
+  reader->SetTagLookupTableToPropertyFunctor(mitk::GetDICOMPropertyForDICOMValuesFunctor);
   reader->SetInputFiles( files );
   reader->AnalyzeInputFiles(); // This just creates a "tag cache and a nice DICOMImageBlockDescriptor.
                                // Both of these could also be produced in a different way. The only
                                // important thing is, that the DICOMImageBlockDescriptor knows a
                                // tag-cache object when PropertyDecorateCachedMitkImageForImageBlockDescriptor
                                // is called.
 
   if  ( reader->GetNumberOfOutputs() != 1 )
   {
     MITK_ERROR << "Reader produce " << reader->GetNumberOfOutputs() << " images instead of 1 expected..";
     return nullptr;
   }
 
   DICOMImageBlockDescriptor block = reader->GetOutput(0); // creates a block copy
   block.SetMitkImage( cachedImage ); // this should/will create a propertylist describing the image slices
   return block.GetMitkImage();
 }
 
 std::string
 mitk::TestDICOMLoading::ComponentTypeToString(int type)
 {
   if (type == itk::ImageIOBase::UCHAR)
     return "UCHAR";
   else if (type == itk::ImageIOBase::CHAR)
     return "CHAR";
   else if (type == itk::ImageIOBase::USHORT)
     return "USHORT";
   else if (type == itk::ImageIOBase::SHORT)
     return "SHORT";
   else if (type == itk::ImageIOBase::UINT)
     return "UINT";
   else if (type == itk::ImageIOBase::INT)
     return "INT";
   else if (type == itk::ImageIOBase::ULONG)
     return "ULONG";
   else if (type == itk::ImageIOBase::LONG)
     return "LONG";
   else if (type == itk::ImageIOBase::FLOAT)
     return "FLOAT";
   else if (type == itk::ImageIOBase::DOUBLE)
     return "DOUBLE";
   else
     return "UNKNOWN";
 }
 
 
 // add a line to stringstream result (see DumpImageInformation
 #define DumpLine(field, data) DumpILine(0, field, data)
 
 // add an indented(!) line to stringstream result (see DumpImageInformation
 #define DumpILine(indent, field, data) \
 { \
   std::string DumpLine_INDENT; DumpLine_INDENT.resize(indent, ' ' ); \
   result << DumpLine_INDENT << field << ": " << data << "\n"; \
 }
 
 std::string
 mitk::TestDICOMLoading::DumpImageInformation( const Image* image )
 {
   std::stringstream result;
 
   if (image == nullptr) return result.str();
 
   SetDefaultLocale();
 
   // basic image data
   DumpLine( "Pixeltype",    ComponentTypeToString(image->GetPixelType().GetComponentType()) );
   DumpLine( "BitsPerPixel", image->GetPixelType().GetBpe() );
   DumpLine( "Dimension",    image->GetDimension() );
 
   result << "Dimensions: ";
   for (unsigned int dim = 0; dim < image->GetDimension(); ++dim)
     result << image->GetDimension(dim) << " ";
   result << "\n";
 
   // geometry data
   result << "Geometry: \n";
   const TimeGeometry* timeGeometry = image->GetTimeGeometry();
   BaseGeometry* geometry = timeGeometry->GetGeometryForTimeStep(0);
   if (geometry)
   {
     AffineTransform3D* transform = geometry->GetIndexToWorldTransform();
     if (transform)
     {
       result << "  " << "Matrix: ";
       const AffineTransform3D::MatrixType& matrix = transform->GetMatrix();
       for (unsigned int i = 0; i < 3; ++i)
         for (unsigned int j = 0; j < 3; ++j)
           result << matrix[i][j] << " ";
       result << "\n";
 
       result << "  " << "Offset: ";
       const AffineTransform3D::OutputVectorType& offset = transform->GetOffset();
       for (unsigned int i = 0; i < 3; ++i)
           result << offset[i] << " ";
       result << "\n";
 
       result << "  " << "Center: ";
       const AffineTransform3D::InputPointType& center = transform->GetCenter();
       for (unsigned int i = 0; i < 3; ++i)
           result << center[i] << " ";
       result << "\n";
 
       result << "  " << "Translation: ";
       const AffineTransform3D::OutputVectorType& translation = transform->GetTranslation();
       for (unsigned int i = 0; i < 3; ++i)
           result << translation[i] << " ";
       result << "\n";
 
       result << "  " << "Scale: ";
       const double* scale = transform->GetScale();
       for (unsigned int i = 0; i < 3; ++i)
           result << scale[i] << " ";
       result << "\n";
 
       result << "  " << "Origin: ";
       const Point3D& origin = geometry->GetOrigin();
       for (unsigned int i = 0; i < 3; ++i)
           result << origin[i] << " ";
       result << "\n";
 
       result << "  " << "Spacing: ";
       const Vector3D& spacing = geometry->GetSpacing();
       for (unsigned int i = 0; i < 3; ++i)
           result << spacing[i] << " ";
       result << "\n";
 
       result << "  " << "TimeBounds: ";
       const TimeBounds timeBounds = timeGeometry->GetTimeBounds();
       for (unsigned int i = 0; i < 2; ++i)
           result << timeBounds[i] << " ";
       result << "\n";
 
 
     }
   }
 
+  // io dicom meta information
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_FILES(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK(), image, result);
+  AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM(), image, result);
+
   ResetUserLocale();
 
   return result.str();
 }
 
+void mitk::TestDICOMLoading::AddPropertyToDump(const mitk::PropertyKeyPath& key, const mitk::Image* image, std::stringstream& result)
+{
+  auto propKey = mitk::PropertyKeyPathToPropertyName(key);
+  auto prop = image->GetProperty(propKey.c_str());
+  if (prop.IsNotNull())
+  {
+    auto value = prop->GetValueAsString();
+    auto dicomProp = dynamic_cast< mitk::DICOMProperty*>(prop.GetPointer());
+    if (dicomProp != nullptr)
+    {
+      auto strippedProp = dicomProp->Clone();
+      if (key == mitk::DICOMIOMetaInformationPropertyConstants::READER_FILES())
+      {//strip dicom file information from path to ensure generalized dump files
+        auto timePoints = strippedProp->GetAvailableTimeSteps();
+        for (auto timePoint : timePoints)
+        {
+          auto slices = strippedProp->GetAvailableSlices(timePoint);
+          for (auto slice : slices)
+          {
+            auto value = strippedProp->GetValue(timePoint, slice);
+            value = itksys::SystemTools::GetFilenameName(value);
+            strippedProp->SetValue(timePoint, slice, value);
+          }
+        }
+      }
+      value = mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON(strippedProp);
+    }
+    result << propKey << ": " << value << "\n";
+  }
+}
+
 std::string
 mitk::TestDICOMLoading::trim(const std::string& pString,
                              const std::string& pWhitespace)
 {
   const size_t beginStr = pString.find_first_not_of(pWhitespace);
   if (beginStr == std::string::npos)
   {
     // no content
     return "";
   }
 
   const size_t endStr = pString.find_last_not_of(pWhitespace);
   const size_t range = endStr - beginStr + 1;
 
   return pString.substr(beginStr, range);
 }
 
 std::string
 mitk::TestDICOMLoading::reduce(const std::string& pString,
                                const std::string& pFill,
                                const std::string& pWhitespace)
 {
   // trim first
   std::string result(trim(pString, pWhitespace));
 
   // replace sub ranges
   size_t beginSpace = result.find_first_of(pWhitespace);
   while (beginSpace != std::string::npos)
   {
     const size_t endSpace =
       result.find_first_not_of(pWhitespace, beginSpace);
     const size_t range = endSpace - beginSpace;
 
     result.replace(beginSpace, range, pFill);
 
     const size_t newStart = beginSpace + pFill.length();
     beginSpace = result.find_first_of(pWhitespace, newStart);
   }
 
   return result;
 }
 
 
 bool
 mitk::TestDICOMLoading::CompareSpacedValueFields( const std::string& reference,
                                                   const std::string& test,
                                                   double /*eps*/ )
 {
   bool result(true);
 
   // tokenize string, compare each token, if possible by float comparison
   std::stringstream referenceStream(reduce(reference));
   std::stringstream testStream(reduce(test));
 
   std::string refToken;
   std::string testToken;
   while ( std::getline( referenceStream,  refToken, ' ' ) &&
           std::getline (     testStream, testToken, ' ' ) )
   {
     float refNumber;
     float testNumber;
     if ( this->StringToNumber(refToken, refNumber) )
     {
       if ( this->StringToNumber(testToken, testNumber) )
       {
         // print-out compared tokens if DEBUG output allowed
         MITK_DEBUG << "Reference Token '" << refToken << "'" << " value " << refNumber
                    << ", test Token '" << testToken << "'" << " value " << testNumber;
 
         bool old_result = result;
 
         result &= ( std::abs(refNumber - testNumber) < 0.0001f /*mitk::eps*/ );
         // log the token/number which causes the test to fail
         if( old_result != result)
         {
           MITK_ERROR << std::setprecision(16) << "Reference Token '" << refToken << "'" << " value " << refNumber
                      << ", test Token '" << testToken << "'" << " value " << testNumber;
 
           MITK_ERROR << "[FALSE] - difference: " << std::setprecision(16) <<  std::abs(refNumber - testNumber) << " EPS: " << 0.0001f; //mitk::eps;
         }
       }
       else
       {
         MITK_ERROR << refNumber << " cannot be compared to '" << testToken << "'";
       }
     }
     else
     {
       MITK_DEBUG << "Token '" << refToken << "'" << " handled as string";
       result &= refToken == testToken;
     }
   }
 
   if ( std::getline( referenceStream, refToken, ' ' ) )
   {
     MITK_ERROR << "Reference string still had values when test string was already parsed: ref '" << reference << "', test '" << test << "'";
     result = false;
   }
   else if ( std::getline( testStream, testToken, ' ' ) )
   {
     MITK_ERROR << "Test string still had values when reference string was already parsed: ref '" << reference << "', test '" << test << "'";
     result = false;
   }
 
   return result;
 }
 
 bool
 mitk::TestDICOMLoading::CompareImageInformationDumps( const std::string& referenceDump,
                                                       const std::string& testDump )
 {
   KeyValueMap reference = ParseDump(referenceDump);
   KeyValueMap test = ParseDump(testDump);
 
   bool testResult(true);
 
   // verify all expected values
   for (KeyValueMap::const_iterator refIter = reference.begin();
        refIter != reference.end();
        ++refIter)
   {
     const std::string& refKey = refIter->first;
     const std::string& refValue = refIter->second;
 
     if ( test.find(refKey) != test.end() )
     {
       const std::string& testValue = test[refKey];
+      if (refKey == mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK()))
+      { //check dcmtk version always against the current version of the system
+        bool thisTestResult = testValue == std::string(" ") + PACKAGE_VERSION;
+        testResult &= thisTestResult;
 
-      bool thisTestResult = CompareSpacedValueFields( refValue, testValue );
-      testResult &= thisTestResult;
+        MITK_DEBUG << refKey << ": '" << PACKAGE_VERSION << "' == '" << testValue << "' ? " << (thisTestResult ? "YES" : "NO");
+      }
+      else if (refKey == mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM()))
+      {//check gdcm version always against the current version of the system
+        bool thisTestResult = testValue == std::string(" ") + gdcm::Version::GetVersion();
+        testResult &= thisTestResult;
+
+        MITK_DEBUG << refKey << ": '" << gdcm::Version::GetVersion() << "' == '" << testValue << "' ? " << (thisTestResult ? "YES" : "NO");
+      }
+      else
+      {
+        bool thisTestResult = CompareSpacedValueFields(refValue, testValue);
+        testResult &= thisTestResult;
 
-      MITK_DEBUG << refKey << ": '" << refValue << "' == '" << testValue << "' ? " << (thisTestResult?"YES":"NO");
+        MITK_DEBUG << refKey << ": '" << refValue << "' == '" << testValue << "' ? " << (thisTestResult ? "YES" : "NO");
+      }
     }
     else
     {
       MITK_ERROR << "Reference dump contains a key'" << refKey << "' (value '" << refValue << "')." ;
       MITK_ERROR << "This key is expected to be generated for tests (but was not). Most probably you need to update your test data.";
       return false;
     }
   }
 
   // now check test dump does not contain any additional keys
   for (KeyValueMap::const_iterator testIter = test.begin();
        testIter != test.end();
        ++testIter)
   {
     const std::string& key = testIter->first;
     const std::string& value = testIter->second;
 
-    if ( reference.find(key) == reference.end() )
+    if (key == mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK()))
+    {//check dcmtk version always against the current version of the system
+      bool thisTestResult = value == std::string(" ")+PACKAGE_VERSION;
+      testResult &= thisTestResult;
+
+      MITK_DEBUG << key << ": '" << PACKAGE_VERSION << "' == '" << value << "' ? " << (thisTestResult ? "YES" : "NO");
+    }
+    else if (key == mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM()))
+    {//check gdcm version always against the current version of the system
+      bool thisTestResult = value == std::string(" ") + gdcm::Version::GetVersion();
+      testResult &= thisTestResult;
+
+      MITK_DEBUG << key << ": '" << gdcm::Version::GetVersion() << "' == '" << value << "' ? " << (thisTestResult ? "YES" : "NO");
+    }
+    else if ( reference.find(key) == reference.end() )
     {
       MITK_ERROR << "Test dump contains an unexpected key'" << key << "' (value '" << value << "')." ;
       MITK_ERROR << "This key is not expected. Most probably you need to update your test data.";
       return false;
     }
   }
 
   return testResult;
 }
 
 mitk::TestDICOMLoading::KeyValueMap
 mitk::TestDICOMLoading::ParseDump( const std::string& dump )
 {
   KeyValueMap parsedResult;
 
   std::string shredder(dump);
 
   std::stack<std::string> surroundingKeys;
 
   std::stack<std::string::size_type> expectedIndents;
   expectedIndents.push(0);
 
   while (true)
   {
     std::string::size_type newLinePos = shredder.find( '\n' );
     if (newLinePos == std::string::npos || newLinePos == 0) break;
 
     std::string line = shredder.substr( 0, newLinePos );
     shredder = shredder.erase( 0, newLinePos+1 );
 
     std::string::size_type keyPosition = line.find_first_not_of( ' ' );
     std::string::size_type colonPosition = line.find( ':' );
 
     std::string key = line.substr(keyPosition, colonPosition - keyPosition);
     std::string::size_type firstSpacePosition = key.find_first_of(" ");
     if (firstSpacePosition != std::string::npos)
     {
       key.erase(firstSpacePosition);
     }
 
     if ( keyPosition > expectedIndents.top() )
     {
       // more indent than before
       expectedIndents.push(keyPosition);
     }
-    else if (keyPosition == expectedIndents.top() )
+    else 
     {
       if (!surroundingKeys.empty())
       {
         surroundingKeys.pop(); // last of same length
       }
-    }
-    else
-    {
-      // less indent than before
-      do expectedIndents.pop();
-      while (expectedIndents.top() != keyPosition); // unwind until current indent is found
+
+      while (expectedIndents.top() != keyPosition)
+      {
+        expectedIndents.pop();
+        if (!surroundingKeys.empty())
+        {
+          surroundingKeys.pop();
+        }
+      }; // unwind until current indent is found
     }
 
     if (!surroundingKeys.empty())
     {
       key = surroundingKeys.top() + "." + key; // construct current key name
     }
 
     surroundingKeys.push(key); // this is the new embracing key
 
     std::string value = line.substr(colonPosition+1);
 
     MITK_DEBUG << "  Key: '" << key << "' value '" << value << "'" ;
 
     parsedResult[key] = value; // store parsing result
   }
 
   return parsedResult;
 }
 
diff --git a/Modules/DICOMTesting/test/mitkDICOMPreloadedVolumeTest.cpp b/Modules/DICOMTesting/test/mitkDICOMPreloadedVolumeTest.cpp
index 69c68e14a3..19ca2db8e3 100644
--- a/Modules/DICOMTesting/test/mitkDICOMPreloadedVolumeTest.cpp
+++ b/Modules/DICOMTesting/test/mitkDICOMPreloadedVolumeTest.cpp
@@ -1,112 +1,114 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #include "mitkTestDICOMLoading.h"
 #include "mitkTestingMacros.h"
 
 #include "mitkDICOMTagCache.h"
 
 bool CheckAllPropertiesAreInOtherList(const mitk::PropertyList* list, const mitk::PropertyList* otherList)
 {
   MITK_TEST_CONDITION_REQUIRED(list && otherList, "Comparison is passed two non-empty property lists")
 
   const mitk::PropertyList::PropertyMap* listM = list->GetMap();
   const mitk::PropertyList::PropertyMap* otherListM = otherList->GetMap();
 
   bool equal = true;
   for ( auto iter = listM->begin();
         iter != listM->end();
         ++iter )
   {
     std::string key = iter->first;
     mitk::BaseProperty* property = iter->second;
 
     auto otherEntry = otherListM->find( key );
     MITK_TEST_CONDITION( otherEntry != otherListM->end(), "  Property '" << key << "' is contained in other list" )
 
     mitk::BaseProperty* otherProperty = otherEntry->second;
-    MITK_TEST_CONDITION( equal &= (*property == *otherProperty), "  Property '" << key << "' is equal in both list" )
+    auto propEqual = (*property == *otherProperty);
+    MITK_TEST_CONDITION(propEqual, "  Property '" << key << "' is equal in both list");
+    equal &= propEqual;
   }
 
   return equal;
 }
 
 bool VerifyPropertyListsEquality(const mitk::PropertyList* testList, const mitk::PropertyList* referenceList)
 {
   bool allTestPropsInReference = CheckAllPropertiesAreInOtherList(testList, referenceList);
   MITK_TEST_CONDITION(allTestPropsInReference, "All test properties found in reference properties")
   bool allReferencePropsInTest = CheckAllPropertiesAreInOtherList(referenceList, testList);
   MITK_TEST_CONDITION(allReferencePropsInTest, "All reference properties found in test properties")
   return allTestPropsInReference && allReferencePropsInTest;
 }
 
 // !!! we expect that this tests get a list of files that load as ONE SINGLE mitk::Image!
 int mitkDICOMPreloadedVolumeTest(int argc, char** const argv)
 {
   MITK_TEST_BEGIN("DICOMPreloadedVolume")
 
   mitk::TestDICOMLoading loader;
   mitk::StringList files;
 
   // load files from commandline
   for (int arg = 1; arg < argc; ++arg)
   {
     MITK_TEST_OUTPUT(<< "Test file " << argv[arg])
     files.push_back( argv[arg] );
   }
 
 
   // verify all files are DICOM
   for (mitk::StringList::const_iterator fileIter = files.begin();
        fileIter != files.end();
        ++fileIter)
   {
     MITK_TEST_CONDITION_REQUIRED( mitk::DICOMFileReader::IsDICOM(*fileIter) , *fileIter << " is recognized as loadable DICOM object" )
   }
 
   // load for a first time
   mitk::TestDICOMLoading::ImageList images = loader.LoadFiles(files);
   MITK_TEST_OUTPUT(<< "Loaded " << images.size() << " images. Remembering properties of the first one for later comparison.")
   mitk::Image::Pointer firstImage = images.front();
 
   mitk::PropertyList::Pointer originalProperties = firstImage->GetPropertyList(); // save the original
   firstImage->SetPropertyList( mitk::PropertyList::New() ); // clear image properties
   // what about DEFAULT properties? currently ONLY nodes get default properties
 
   // load for a second time, this time provide the image volume as a pointer
   // expectation is that the reader will provide the same properties to this image (without actually loading a new mitk::Image)
 
   // !!! we expect that this tests get a list of files that load as ONE SINGLE mitk::Image!
   MITK_TEST_CONDITION_REQUIRED( images.size() == 1, "Not more than 1 images loaded." );
   // otherwise, we would need to determine the correct set of files here
   MITK_TEST_OUTPUT(<< "Generating properties via reader. Comparing new properties to previously loaded version.")
   mitk::Image::Pointer reloadedImage = loader.DecorateVerifyCachedImage(files, firstImage);
   MITK_TEST_CONDITION_REQUIRED(reloadedImage.IsNotNull(), "Reader was able to property-decorate image.");
 
   mitk::PropertyList::Pointer regeneratedProperties = reloadedImage->GetPropertyList(); // get the version of the second load attempt
 
   bool listsAreEqual = VerifyPropertyListsEquality(regeneratedProperties, originalProperties);
   MITK_TEST_CONDITION(listsAreEqual, "DICOM file reader generates a valid property list when provided a pre-loaded image");
 
 
   // test again, this time provide a tag cache.
   // expectation is, that an empty tag cache will lead to NO image
   mitk::DICOMTagCache::Pointer tagCache; // empty
   MITK_TEST_OUTPUT(<< "Generating properties via reader. Comparing new properties to previously loaded version.")
   firstImage->SetPropertyList( mitk::PropertyList::New() ); // clear image properties
   reloadedImage = loader.DecorateVerifyCachedImage(files, tagCache, firstImage);
   MITK_TEST_CONDITION_REQUIRED(reloadedImage.IsNull(), "Reader was able to detect missing tag-cache.");
 
   MITK_TEST_END()
 }
 
diff --git a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp
index a1e45309f7..7406172d13 100644
--- a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp
+++ b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp
@@ -1,168 +1,168 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #include <mitkRTDoseReaderService.h>
 
 #include <mitkLexicalCast.h>
 
 #include <mitkImageAccessByItk.h>
 #include <mitkImageCast.h>
 #include <mitkDICOMFileReaderSelector.h>
 #include <mitkDICOMFileReader.h>
 #include <mitkRTConstants.h>
 #include <mitkImageStatisticsHolder.h>
 #include <mitkDICOMTagPath.h>
 #include <mitkDICOMDCMTKTagScanner.h>
 #include <mitkDicomRTMimeTypes.h>
 #include <mitkDICOMIOHelper.h>
 
 #include <dcmtk/dcmrt/drtdose.h>
 
 #include <itkShiftScaleImageFilter.h>
 #include <itkCastImageFilter.h>
 
 namespace mitk
 {
 
   RTDoseReaderService::RTDoseReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTMimeTypes::DICOMRT_DOSE_MIMETYPE_NAME()), mitk::DicomRTMimeTypes::DICOMRT_DOSE_MIMETYPE_DESCRIPTION()) {
     m_FileReaderServiceReg = RegisterService();
   }
 
   RTDoseReaderService::RTDoseReaderService(const RTDoseReaderService& other) : mitk::AbstractFileReader(other)
   {
 
   }
 
   RTDoseReaderService::~RTDoseReaderService() {}
 
   template<typename TPixel, unsigned int VImageDimension>
   void RTDoseReaderService::MultiplyGridScaling(itk::Image<TPixel, VImageDimension>* image, float gridscale)
   {
     typedef itk::Image<Float32, VImageDimension> OutputImageType;
     typedef itk::Image<TPixel, VImageDimension> InputImageType;
 
     typedef itk::CastImageFilter<InputImageType, OutputImageType> CastFilterType;
     typedef itk::ShiftScaleImageFilter<OutputImageType, OutputImageType> ScaleFilterType;
     typename CastFilterType::Pointer castFilter = CastFilterType::New();
     typename ScaleFilterType::Pointer scaleFilter = ScaleFilterType::New();
 
     castFilter->SetInput(image);
     scaleFilter->SetInput(castFilter->GetOutput());
     scaleFilter->SetScale(gridscale);
     scaleFilter->Update();
     typename OutputImageType::Pointer scaledOutput = scaleFilter->GetOutput();
     this->scaledDoseImage = mitk::Image::New();
 
     mitk::CastToMitkImage(scaledOutput, this->scaledDoseImage);
   }
 
-  std::vector<itk::SmartPointer<BaseData> > RTDoseReaderService::Read()
+  std::vector<itk::SmartPointer<BaseData> > RTDoseReaderService::DoRead()
   {
     std::vector<itk::SmartPointer<mitk::BaseData> > result;
 
 
     mitk::IDICOMTagsOfInterest* toiSrv = GetDicomTagsOfInterestService();
 
     auto tagsOfInterest = toiSrv->GetTagsOfInterest();
 
     DICOMTagPathList tagsOfInterestList;
     for (const auto& tag : tagsOfInterest) {
       tagsOfInterestList.push_back(tag.first);
     }
 
     std::string location = GetInputLocation();
     mitk::DICOMFileReaderSelector::Pointer selector = mitk::DICOMFileReaderSelector::New();
     selector->LoadBuiltIn3DConfigs();
     selector->SetInputFiles({ location });
 
     mitk::DICOMFileReader::Pointer reader = selector->GetFirstReaderWithMinimumNumberOfOutputImages();
     reader->SetAdditionalTagsOfInterest(toiSrv->GetTagsOfInterest());
 
     reader->SetInputFiles({ location });
     reader->AnalyzeInputFiles();
     reader->LoadImages();
 
     if (reader->GetNumberOfOutputs() == 0) {
       MITK_ERROR << "Could not determine a DICOM reader for this file" << std::endl;
       return result;
     }
 
     mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New();
     scanner->SetInputFiles({ location });
     scanner->AddTagPaths(tagsOfInterestList);
     scanner->Scan();
 
     mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList();
     if (frames.empty()) {
       MITK_ERROR << "Error reading the RTDOSE file" << std::endl;
       return result;
     }
 
     const mitk::DICOMImageBlockDescriptor& desc = reader->GetOutput(0);
 
     mitk::Image::Pointer originalImage = desc.GetMitkImage();
 
     if (originalImage.IsNull())
     {
       MITK_ERROR << "Error reading the RTDOSE file in mitk::DicomFileReader" << std::endl;
       return result;
     }
 
     DcmFileFormat fileformat;
     OFCondition outp = fileformat.loadFile(location.c_str(), EXS_Unknown);
     if (outp.bad())
     {
       MITK_ERROR << "Error reading the RTDOSE file in DCMTK" << std::endl;
       return result;
     }
     DcmDataset *dataset = fileformat.getDataset();
 
     DRTDoseIOD doseObject;
     OFCondition DCMTKresult = doseObject.read(*dataset);
 
     if (DCMTKresult.bad())
     {
       MITK_ERROR << "Error reading the RTDOSE file in DCMTK" << std::endl;
       return result;
     }
 
     auto findingsGridScaling = frames.front()->GetTagValueAsString(DICOMTagPath(0x3004, 0x000e)); //(0x3004, 0x000e) is grid scaling
 
     double gridScaling;
     if (findingsGridScaling.empty()) {
       MITK_ERROR << "Could not find DoseGridScaling tag" << std::endl;
       return result;
     }
     else {
       gridScaling = boost::lexical_cast<double>(findingsGridScaling.front().value);
     }
 
     AccessByItk_1(originalImage, MultiplyGridScaling, gridScaling);
 
     auto statistics = this->scaledDoseImage->GetStatistics();
     double maxDose = statistics->GetScalarValueMax();
 
     this->scaledDoseImage->SetPropertyList(originalImage->GetPropertyList());
     this->scaledDoseImage->SetProperty(mitk::RTConstants::PRESCRIBED_DOSE_PROPERTY_NAME.c_str(), mitk::GenericProperty<double>::New(0.8*maxDose));
     auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames);
     SetProperties(this->scaledDoseImage, findings);
 
     result.push_back(this->scaledDoseImage.GetPointer());
     return result;
   }
 
   RTDoseReaderService* RTDoseReaderService::Clone() const
   {
     return new RTDoseReaderService(*this);
   }
 }
diff --git a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.h b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.h
index 112f8da28c..ad24fd6011 100644
--- a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.h
+++ b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.h
@@ -1,64 +1,66 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #ifndef mitkRTDoseReaderService_h
 #define mitkRTDoseReaderService_h
 
 #include <mitkAbstractFileReader.h>
 
 #include <usServiceRegistration.h>
 #include <mitkImage.h>
 #include <MitkDicomRTIOExports.h>
 
 namespace mitk
 {
     /**
     * \brief RTDoseReaderService reads DICOM files of modality RTDOSE.
     */
     class MITKDICOMRTIO_EXPORT RTDoseReaderService : public mitk::AbstractFileReader
     {
         public:
             RTDoseReaderService(const RTDoseReaderService& other);
             RTDoseReaderService();
 
             ~RTDoseReaderService() override;
 
             using AbstractFileReader::Read;
-            /**
-            * @brief Reads a dicom dataset from a RTDOSE file
-            * The method reads the PixelData from the DicomRT dose file and scales
-            * them with a factor for getting Gray-values instead of pixel-values.
-            * The Gray-values are stored in a mitkImage with a vtkColorTransferFunc.
-            * Relative values are used for coloring the image. The relative values are
-            * relative to a PrescriptionDose defined in the RT-Plan. If there is no
-            * RT-Plan file PrescriptionDose is set to 80% of the maximum dose.
-            */
-            std::vector<itk::SmartPointer<BaseData> > Read() override;
+
+    protected:
+      /**
+      * @brief Reads a dicom dataset from a RTDOSE file
+      * The method reads the PixelData from the DicomRT dose file and scales
+      * them with a factor for getting Gray-values instead of pixel-values.
+      * The Gray-values are stored in a mitkImage with a vtkColorTransferFunc.
+      * Relative values are used for coloring the image. The relative values are
+      * relative to a PrescriptionDose defined in the RT-Plan. If there is no
+      * RT-Plan file PrescriptionDose is set to 80% of the maximum dose.
+      */
+      std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
     private:
       RTDoseReaderService* Clone() const override;
         /**
         * \brief Scales an image with a factor
         *
         * \param gridscale the factor to scale with
         */
         template<typename TPixel, unsigned int VImageDimension>
         void MultiplyGridScaling(itk::Image< TPixel, VImageDimension>* image, float gridscale);
 
         mitk::Image::Pointer scaledDoseImage;
         us::ServiceRegistration<mitk::IFileReader> m_FileReaderServiceReg;
   };
 
 }
 
 #endif
diff --git a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp
index d5d2879a6c..c1d8686b03 100644
--- a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp
+++ b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp
@@ -1,82 +1,82 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #include <mitkRTPlanReaderService.h>
 
 #include <mitkImage.h>
 #include <mitkDICOMDCMTKTagScanner.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkDICOMIOHelper.h>
 #include <mitkDICOMTagPath.h>
 #include <mitkIDICOMTagsOfInterest.h>
 #include <mitkDICOMDatasetAccessingImageFrameInfo.h>
 #include <mitkDicomRTMimeTypes.h>
 
 
 namespace mitk
 {
 
   RTPlanReaderService::RTPlanReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTMimeTypes::DICOMRT_PLAN_MIMETYPE_NAME()), mitk::DicomRTMimeTypes::DICOMRT_PLAN_MIMETYPE_DESCRIPTION()) {
     m_FileReaderServiceReg = RegisterService();
 
   }
 
   RTPlanReaderService::RTPlanReaderService(const RTPlanReaderService& other) : mitk::AbstractFileReader(other)
   {
   }
 
   RTPlanReaderService::~RTPlanReaderService() {}
 
-  std::vector<itk::SmartPointer<BaseData> > RTPlanReaderService::Read()
+  std::vector<itk::SmartPointer<BaseData> > RTPlanReaderService::DoRead()
   {
     std::vector<itk::SmartPointer<mitk::BaseData> > result;
     auto DICOMTagsOfInterestService = GetDicomTagsOfInterestService();
     auto tagsOfInterest = DICOMTagsOfInterestService->GetTagsOfInterest();
     DICOMTagPathList tagsOfInterestList;
     for (const auto& tag : tagsOfInterest) {
       tagsOfInterestList.push_back(tag.first);
     }
 
     std::string location = GetInputLocation();
     mitk::StringList files = { location };
     mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New();
     scanner->SetInputFiles(files);
     scanner->AddTagPaths(tagsOfInterestList);
     scanner->Scan();
 
     mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList();
     if (frames.empty()) {
       MITK_ERROR << "Error reading the RTPLAN file" << std::endl;
       return result;
     }
 
     auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames);
 
     //just create empty image. No image information available in RTPLAN. But properties will be attached.
     Image::Pointer dummyImage = Image::New();
     mitk::PixelType pt = mitk::MakeScalarPixelType<int>();
     unsigned int dim[] = { 1,1};
     dummyImage->Initialize(pt, 2, dim);
     SetProperties(dummyImage, findings);
 
     result.push_back(dummyImage.GetPointer());
 
     return result;
   }
 
   RTPlanReaderService* RTPlanReaderService::Clone() const
   {
     return new RTPlanReaderService(*this);
   }
 
 }
diff --git a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.h b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.h
index dd29b2af7d..c2653f2991 100644
--- a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.h
+++ b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.h
@@ -1,61 +1,63 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #ifndef mitkRTPlanReaderService_h
 #define mitkRTPlanReaderService_h
 
 #include "mitkAbstractFileReader.h"
 
 #include <vector>
 
 #include "mitkIDICOMTagsOfInterest.h"
 #include "mitkDICOMDatasetAccessingImageFrameInfo.h"
 
 #include <usModuleContext.h>
 
 #include "MitkDicomRTIOExports.h"
 
 namespace mitk
 {
   /**
   * \brief RTPlanReaderService reads DICOM files of modality RTPLAN.
     \details The tags are defined in mitk::GetDefaultDICOMTagsOfInterest() in Module MitkDicomReader. They are stored as TemporoSpatialStringProperty.
     with the key as their respective DICOM tags.
     \note No image information is in RTPLAN.
   */
   class MITKDICOMRTIO_EXPORT RTPlanReaderService : public mitk::AbstractFileReader
   {
 
   public:
     RTPlanReaderService();
     RTPlanReaderService(const RTPlanReaderService& other);
 
     using AbstractFileReader::Read;
+
+    ~RTPlanReaderService() override;
+
+  protected:
     /**
     * \brief Reads the file (only tags).
       @details DICOMDCMTKTagScanner is used to read the tags
       \note No image information is in RTPLAN.
       \sa mitk::GetDefaultDICOMTagsOfInterest() for tags that are read
     */
-    std::vector<itk::SmartPointer<BaseData> > Read() override;
-
-    ~RTPlanReaderService() override;
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     RTPlanReaderService* Clone() const override;
 
     us::ServiceRegistration<mitk::IFileReader> m_FileReaderServiceReg;
   };
 }
 
 #endif
diff --git a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp
index ef2a5132ef..f4c4bcb794 100644
--- a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp
+++ b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp
@@ -1,288 +1,288 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkRTStructureSetReaderService.h"
 
 #include <mitkDicomRTMimeTypes.h>
 #include <mitkDICOMIOHelper.h>
 #include <mitkDICOMTagPath.h>
 #include <mitkDICOMDCMTKTagScanner.h>
 
 #include "dcmtk/dcmrt/drtstrct.h"
 
 namespace mitk
 {
   RTStructureSetReaderService::RTStructureSetReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTMimeTypes::DICOMRT_STRUCT_MIMETYPE_NAME()), mitk::DicomRTMimeTypes::DICOMRT_STRUCT_MIMETYPE_DESCRIPTION()) {
     m_FileReaderServiceReg = RegisterService();
   }
 
   RTStructureSetReaderService::RTStructureSetReaderService(const RTStructureSetReaderService& other) : mitk::AbstractFileReader(other)
   {
   }
 
   RTStructureSetReaderService::~RTStructureSetReaderService() {}
 
   RTStructureSetReaderService::RoiEntry::RoiEntry()
   {
     Number = 0;
     DisplayColor[0] = 1.0;
     DisplayColor[1] = 0.0;
     DisplayColor[2] = 0.0;
     ContourModelSet = mitk::ContourModelSet::New();
   }
 
   RTStructureSetReaderService::RoiEntry::RoiEntry(const RoiEntry& src)
   {
     Number = src.Number;
     Name = src.Name;
     Description = src.Description;
     DisplayColor[0] = src.DisplayColor[0];
     DisplayColor[1] = src.DisplayColor[1];
     DisplayColor[2] = src.DisplayColor[2];
     ContourModelSet = mitk::ContourModelSet::New();
     SetPolyData(src.ContourModelSet);
   }
 
   RTStructureSetReaderService::RoiEntry::~RoiEntry() {}
 
   RTStructureSetReaderService::RoiEntry& RTStructureSetReaderService::
     RoiEntry::operator =(const RoiEntry& src)
   {
     Number = src.Number;
     Name = src.Name;
     Description = src.Description;
     DisplayColor[0] = src.DisplayColor[0];
     DisplayColor[1] = src.DisplayColor[1];
     DisplayColor[2] = src.DisplayColor[2];
     SetPolyData(src.ContourModelSet);
     return (*this);
   }
 
   void RTStructureSetReaderService::RoiEntry::
     SetPolyData(mitk::ContourModelSet::Pointer roiPolyData)
   {
     if (roiPolyData == this->ContourModelSet)
     {
       return;
     }
 
     this->ContourModelSet = roiPolyData;
   }
 
   size_t RTStructureSetReaderService::GetNumberOfROIs() const
   {
     return this->ROISequenceVector.size();
   }
 
   RTStructureSetReaderService::RoiEntry* RTStructureSetReaderService::
     FindRoiByNumber(unsigned int roiNum)
   {
     for (unsigned int i = 0; i < this->ROISequenceVector.size(); ++i)
     {
       if (this->ROISequenceVector[i].Number == roiNum)
       {
         return &this->ROISequenceVector[i];
       }
     }
 
     return nullptr;
   }
 
-  std::vector<itk::SmartPointer<BaseData> > RTStructureSetReaderService::Read()
+  std::vector<itk::SmartPointer<BaseData> > RTStructureSetReaderService::DoRead()
   {
     std::vector<itk::SmartPointer<mitk::BaseData> > result;
 
     std::string location = GetInputLocation();
 
     auto DICOMTagsOfInterestService = GetDicomTagsOfInterestService();
     auto tagsOfInterest = DICOMTagsOfInterestService->GetTagsOfInterest();
     DICOMTagPathList tagsOfInterestList;
     for (const auto& tag : tagsOfInterest) {
       tagsOfInterestList.push_back(tag.first);
     }
 
     mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New();
     scanner->SetInputFiles({ location });
     scanner->AddTagPaths(tagsOfInterestList);
     scanner->Scan();
 
     mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList();
     if (frames.empty()) {
       MITK_ERROR << "Error reading the RTSTRUCT file" << std::endl;
       return result;
     }
 
     auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames);
 
     DcmFileFormat file;
     OFCondition output = file.loadFile(location.c_str(), EXS_Unknown);
 
     if (output.bad())
     {
       MITK_ERROR << "Can't read the file" << std::endl;
       return result;
     }
 
     DcmDataset* dataset = file.getDataset();
 
     DRTStructureSetIOD structureSetObject;
     OFCondition outp = structureSetObject.read(*dataset);
 
     if (!outp.good())
     {
       MITK_ERROR << "Error reading the file" << std::endl;
       return result;
     }
 
     DRTStructureSetROISequence& roiSequence =
       structureSetObject.getStructureSetROISequence();
 
     if (!roiSequence.gotoFirstItem().good())
     {
       MITK_ERROR << "Error reading the structure sequence" << std::endl;
       return result;
     }
 
     do
     {
       DRTStructureSetROISequence::Item& currentSequence =
         roiSequence.getCurrentItem();
 
       if (!currentSequence.isValid())
       {
         continue;
       }
 
       OFString roiName;
       OFString roiDescription;
       Sint32 roiNumber;
       RoiEntry roi;
 
       currentSequence.getROIName(roiName);
       currentSequence.getROIDescription(roiDescription);
       currentSequence.getROINumber(roiNumber);
 
       roi.Name = roiName.c_str();
       roi.Description = roiDescription.c_str();
       roi.Number = roiNumber;
 
       this->ROISequenceVector.push_back(roi);
     } while (roiSequence.gotoNextItem().good());
 
     Sint32 refRoiNumber;
     DRTROIContourSequence& roiContourSeqObject =
       structureSetObject.getROIContourSequence();
 
     if (!roiContourSeqObject.gotoFirstItem().good())
     {
       MITK_ERROR << "Error reading the contour sequence" << std::endl;
       return result;
     }
 
     do
     {
       mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New();
       DRTROIContourSequence::Item& currentRoiObject =
         roiContourSeqObject.getCurrentItem();
 
       if (!currentRoiObject.isValid())
       {
         continue;
       }
 
       currentRoiObject.getReferencedROINumber(refRoiNumber);
       DRTContourSequence& contourSeqObject =
         currentRoiObject.getContourSequence();
 
       if (contourSeqObject.getNumberOfItems() > 0 && contourSeqObject.gotoFirstItem().good())
       {
         do
         {
           DRTContourSequence::Item& contourItem =
             contourSeqObject.getCurrentItem();
 
           if (!contourItem.isValid())
           {
             continue;
           }
 
           OFString contourNumber;
           OFString numberOfPoints;
           OFVector<Float64> contourData_LPS;
           mitk::ContourModel::Pointer contourSequence =
             mitk::ContourModel::New();
 
           contourItem.getContourNumber(contourNumber);
           contourItem.getNumberOfContourPoints(numberOfPoints);
           contourItem.getContourData(contourData_LPS);
 
           for (unsigned int i = 0; i < contourData_LPS.size() / 3; i++)
           {
             mitk::Point3D point;
             point[0] = contourData_LPS.at(3 * i);
             point[1] = contourData_LPS.at(3 * i + 1);
             point[2] = contourData_LPS.at(3 * i + 2);
             contourSequence->AddVertex(point);
           }
 
           contourSequence->Close();
           contourSet->AddContourModel(contourSequence);
         } while (contourSeqObject.gotoNextItem().good());
       }
       else
       {
         MITK_WARN << "contourSeqObject has no items in sequence. Object is neglected and not read. Struct name: " << this->FindRoiByNumber(refRoiNumber)->Name << std::endl;
       }
 
       RoiEntry* refROI = this->FindRoiByNumber(refRoiNumber);
 
       if (refROI == nullptr)
       {
         MITK_ERROR << "Can not find references ROI" << std::endl;
         continue;
       }
 
       Sint32 roiColor;
 
       for (unsigned int j = 0; j < 3; j++)
       {
         currentRoiObject.getROIDisplayColor(roiColor, j);
         refROI->DisplayColor[j] = roiColor / 255.0;
       }
 
       refROI->ContourModelSet = contourSet;
       contourSet->SetProperty("name", mitk::StringProperty::New(refROI->Name));
       contourSet->SetProperty("contour.color", mitk::ColorProperty::New(
         refROI->DisplayColor[0],
         refROI->DisplayColor[1],
         refROI->DisplayColor[2]));
 
     } while (roiContourSeqObject.gotoNextItem().good());
 
     for (auto const& aROI : ROISequenceVector)
     {
       result.push_back(aROI.ContourModelSet.GetPointer());
       result.at(result.size() - 1)->SetProperty("name", aROI.ContourModelSet->GetProperty("name"));
       result.at(result.size() - 1)->SetProperty("color", aROI.ContourModelSet->GetProperty("contour.color"));
       result.at(result.size() - 1)->SetProperty("contour.color", aROI.ContourModelSet->GetProperty("contour.color"));
       SetProperties(result.at(result.size() - 1).GetPointer(), findings);
     }
 
     return result;
   }
 
   RTStructureSetReaderService* RTStructureSetReaderService::Clone() const
   {
     return new RTStructureSetReaderService(*this);
   }
 
 }
diff --git a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.h b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.h
index 8986c6366f..8fcf2e8efb 100644
--- a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.h
+++ b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.h
@@ -1,85 +1,87 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKRTSTRUCTURESETREADER_H
 #define MITKRTSTRUCTURESETREADER_H
 
 #include <mitkAbstractFileReader.h>
 
 #include "MitkDicomRTIOExports.h"
 #include <mitkContourModelSet.h>
 
 #include <usModuleContext.h>
 
 namespace mitk
 {
   class MITKDICOMRTIO_EXPORT RTStructureSetReaderService : public mitk::AbstractFileReader
   {
 
     /**
      * Represent a region of interest (ROI)
      */
     class RoiEntry
     {
     public:
       RoiEntry();
       RoiEntry(const RoiEntry& src);
       virtual ~RoiEntry();
       RoiEntry& operator=(const RoiEntry& src);
 
       void SetPolyData(ContourModelSet::Pointer roiPolyData);
 
       unsigned int Number;
       std::string  Name;
       std::string  Description;
       double       DisplayColor[3];
       mitk::ContourModelSet::Pointer ContourModelSet;
     };
 
   public:
     RTStructureSetReaderService();
     RTStructureSetReaderService(const RTStructureSetReaderService& other);
 
     ~RTStructureSetReaderService() override;
 
     /**
     * @brief Reading a RT StructureSet from the DICOM file and returns the ROIs
     * (region of interest) as a ContourModelSet. One ContourModelSet represent
     * one ROI. A ContourModelSet contains ContourModels which represent the
     * single structures.
     */
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData> > Read() override;
+
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     RTStructureSetReaderService* Clone() const override;
 
     /**
      * containing the ROIs meta information like name number and description
      */
     std::vector<RoiEntry> ROISequenceVector;
 
     /**
      * Returns the number of ROIs from the ROISequenceVector
      */
     size_t GetNumberOfROIs() const;
 
     /**
      * Returns the relevant ROI from the ROISequenceVector by its number
      */
     RoiEntry* FindRoiByNumber(unsigned int roiNum);
 
     us::ServiceRegistration<mitk::IFileReader> m_FileReaderServiceReg;
   };
 }
 
 #endif // MITKRTSTRUCTURESETREADER_H
diff --git a/Modules/IGT/DataManagement/mitkNavigationTool.cpp b/Modules/IGT/DataManagement/mitkNavigationTool.cpp
index 1af990ee8f..cbea5641c1 100644
--- a/Modules/IGT/DataManagement/mitkNavigationTool.cpp
+++ b/Modules/IGT/DataManagement/mitkNavigationTool.cpp
@@ -1,358 +1,358 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkNavigationTool.h"
 #include "mitkIGTException.h"
 #include "mitkNavigationData.h"
 #include "Poco/File.h"
 #include "mitkUnspecifiedTrackingTypeInformation.h"
 
 #include <vtkSphereSource.h>
 #include "vtkConeSource.h"
 #include "vtkLineSource.h"
 #include "vtkCylinderSource.h"
 #include "vtkTransformPolyDataFilter.h"
 #include <vtkAppendPolyData.h>
 #include "mitkTextAnnotation3D.h"
 #include "mitkManualPlacementAnnotationRenderer.h"
 #include "mitkBaseRenderer.h"
 
 mitk::NavigationTool::NavigationTool() : m_Identifier("None"),
 m_Type(mitk::NavigationTool::Unknown),
 m_CalibrationFile("none"),
 m_SerialNumber(""),
 m_TrackingDeviceType(mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName()),
 m_ToolLandmarks(mitk::PointSet::New()),
 m_ToolControlPoints(mitk::PointSet::New()),
 m_ToolAxisOrientation(mitk::Quaternion(0, 0, 0, 1))
 {
   m_ToolTipPosition[0] = 0;
   m_ToolTipPosition[1] = 0;
   m_ToolTipPosition[2] = 0;
 
   SetDefaultSurface();
 }
 
 itk::LightObject::Pointer mitk::NavigationTool::InternalClone() const
 {
   Self::Pointer tool = new Self(*this);
   tool->UnRegister();
   return tool.GetPointer();
 }
 
 mitk::NavigationTool::NavigationTool(const NavigationTool &other)
   : Superclass()
 {
   this->m_Identifier = other.m_Identifier;
   this->m_Type = other.m_Type;
   if (other.m_DataNode.IsNotNull())
   {
-    this->m_DataNode = other.m_DataNode->Clone();
+    this->m_DataNode = mitk::DataNode::New();
     this->m_DataNode->SetName(other.m_DataNode->GetName());
     if (other.m_DataNode->GetData())
     {
       this->m_DataNode->SetData(dynamic_cast<mitk::BaseData*>(other.m_DataNode->GetData()->Clone().GetPointer()));
     }
   }
 
   if (other.m_SpatialObject.IsNotNull())
     this->m_SpatialObject = other.m_SpatialObject->Clone();
   this->m_CalibrationFile = other.m_CalibrationFile;
   this->m_SerialNumber = other.m_SerialNumber;
   this->m_TrackingDeviceType = other.m_TrackingDeviceType;
   if (other.m_ToolLandmarks.IsNotNull())
     this->m_ToolLandmarks = other.m_ToolLandmarks->Clone();
   if (other.m_ToolControlPoints.IsNotNull())
     this->m_ToolControlPoints = other.m_ToolControlPoints->Clone();
   this->m_ToolTipPosition = other.m_ToolTipPosition;
   this->m_ToolAxisOrientation = other.m_ToolAxisOrientation;
 }
 
 mitk::NavigationTool::~NavigationTool()
 {
 }
 
 mitk::Point3D mitk::NavigationTool::GetToolAxis()
 {
   // The tool axis in the sensor coordinate system is defined as the negative z-axis
   mitk::Vector3D toolAxisSensorCoordinateSystem;
   mitk::FillVector3D(toolAxisSensorCoordinateSystem, 0.0, 0.0, -1.0);
   // Apply inverse tool axis transform to calculate tool axis
   vnl_vector_fixed<mitk::ScalarType,3> toolAxisVector = m_ToolAxisOrientation.inverse().rotate(toolAxisSensorCoordinateSystem.GetVnlVector());
   // Transfer to mitk::Point3D
   mitk::Point3D toolAxis;
   toolAxis[0] = toolAxisVector[0];
   toolAxis[1] = toolAxisVector[1];
   toolAxis[2] = toolAxisVector[2];
   return toolAxis;
 }
 
 void mitk::NavigationTool::SetToolAxis(mitk::Point3D toolAxis)
 {
   // The tool axis in the sensor coordinate system is defined as the negative z-axis
   mitk::Vector3D toolAxisSensorCoordinateSystem;
   mitk::FillVector3D(toolAxisSensorCoordinateSystem, 0.0, 0.0, -1.0);
   // Normalize the tool axis as obtained by a tool axis calibration
   mitk::Vector3D toolAxisFromCalibration;
   mitk::FillVector3D(toolAxisFromCalibration, toolAxis[0], toolAxis[1], toolAxis[2]);
   toolAxisFromCalibration.Normalize();
   // if tool axis to be set is different to the default tool axis (0,0,-1) calculate the tool axis orientation, otherwise set it to identity
   if (toolAxisSensorCoordinateSystem == toolAxisFromCalibration)
   {
     m_ToolAxisOrientation = mitk::Quaternion(0,0,0,1);
   }
   else
   {
     // Determine rotation angle
     mitk::ScalarType rotationAngle = acos(toolAxisSensorCoordinateSystem*toolAxisFromCalibration);
     // Determine rotation axis
     mitk::Vector3D rotationAxis = itk::CrossProduct(toolAxisSensorCoordinateSystem, toolAxisFromCalibration);
     // Calculate transform
     itk::AffineTransform<mitk::ScalarType>::Pointer sensorToToolAxisOrientation = itk::AffineTransform<mitk::ScalarType>::New();
     sensorToToolAxisOrientation->Rotate3D(rotationAxis, rotationAngle);
     // transfer to quaternion notation. Note that the vnl_quaternion expects the matrix in row major format, hence the transpose
     mitk::Quaternion toolAxisTransform(sensorToToolAxisOrientation->GetMatrix().GetVnlMatrix().transpose());
     // Update the tool axis orientation
     m_ToolAxisOrientation = toolAxisTransform;
   }
 }
 
 mitk::AffineTransform3D::Pointer mitk::NavigationTool::GetToolTipTransform()
 {
   mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New();
   returnValue->SetPosition(this->m_ToolTipPosition);
   returnValue->SetOrientation(this->m_ToolAxisOrientation);
   return returnValue->GetAffineTransform3D();
 }
 
 void mitk::NavigationTool::Graft(const DataObject *data)
 {
   // Attempt to cast data to an NavigationData
   const Self* nd;
   try
   {
     nd = dynamic_cast<const Self *>(data);
   }
   catch (...)
   {
     mitkThrowException(mitk::IGTException) << "mitk::NavigationData::Graft cannot cast "
       << typeid(data).name() << " to "
       << typeid(const Self *).name();
   }
   if (!nd)
   {
     // pointer could not be cast back down
     mitkThrowException(mitk::IGTException) << "mitk::NavigationData::Graft cannot cast "
       << typeid(data).name() << " to "
       << typeid(const Self *).name();
   }
   // Now copy anything that is needed
   m_Identifier = nd->GetIdentifier();
   m_Type = nd->GetType();
   m_DataNode->SetName(nd->GetDataNode()->GetName());
   m_DataNode->SetData(nd->GetDataNode()->GetData());
   m_SpatialObject = nd->GetSpatialObject();
   m_CalibrationFile = nd->GetCalibrationFile();
   m_SerialNumber = nd->GetSerialNumber();
   m_TrackingDeviceType = nd->GetTrackingDeviceType();
   m_ToolLandmarks = nd->GetToolLandmarks();
   m_ToolControlPoints = nd->GetToolControlPoints();
   m_ToolTipPosition = nd->GetToolTipPosition();
   m_ToolAxisOrientation = nd->GetToolAxisOrientation();
 }
 
 bool mitk::NavigationTool::IsToolTipSet()
 {
   if ((m_ToolTipPosition[0] == 0) &&
     (m_ToolTipPosition[1] == 0) &&
     (m_ToolTipPosition[2] == 0) &&
     (m_ToolAxisOrientation.x() == 0) &&
     (m_ToolAxisOrientation.y() == 0) &&
     (m_ToolAxisOrientation.z() == 0) &&
     (m_ToolAxisOrientation.r() == 1))
     return false;
   else return true;
 }
 
 void mitk::NavigationTool::SetCalibrationFile(const std::string filename)
 {
   //check if file does exist:
   if (filename == "")
   {
     m_CalibrationFile = "none";
   }
   else
   {
     Poco::File myFile(filename);
     if (myFile.exists())
       m_CalibrationFile = filename;
     else
       m_CalibrationFile = "none";
   }
 }
 
 std::string mitk::NavigationTool::GetToolName()
 {
   if (this->m_DataNode.IsNull()) { return ""; }
   else { return m_DataNode->GetName(); }
 }
 
 mitk::Surface::Pointer mitk::NavigationTool::GetToolSurface()
 {
   if (this->m_DataNode.IsNull()) { return nullptr; }
   else if (this->m_DataNode->GetData() == nullptr) { return nullptr; }
   else { return dynamic_cast<mitk::Surface*>(m_DataNode->GetData()); }
 }
 
 void mitk::NavigationTool::SetDefaultSurface()
 {
   if (m_DataNode.IsNull())
     m_DataNode = mitk::DataNode::New();
 
   mitk::Surface::Pointer mySphere = mitk::Surface::New();
 
   double axisLength = 5.;
 
   vtkSmartPointer<vtkSphereSource> vtkSphere = vtkSmartPointer<vtkSphereSource>::New();
   vtkSmartPointer<vtkConeSource> vtkCone = vtkSmartPointer<vtkConeSource>::New();
   vtkSmartPointer<vtkCylinderSource> vtkCylinder = vtkSmartPointer<vtkCylinderSource>::New();
   vtkSmartPointer<vtkPolyData> axis = vtkSmartPointer<vtkPolyData>::New();
   vtkSmartPointer<vtkLineSource> vtkLine = vtkSmartPointer<vtkLineSource>::New();
   vtkSmartPointer<vtkLineSource> vtkLine2 = vtkSmartPointer<vtkLineSource>::New();
   vtkSmartPointer<vtkLineSource> vtkLine3 = vtkSmartPointer<vtkLineSource>::New();
 
   vtkSmartPointer<vtkAppendPolyData> appendPolyData = vtkSmartPointer<vtkAppendPolyData>::New();
   vtkSmartPointer<vtkPolyData> surface = vtkSmartPointer<vtkPolyData>::New();
 
   //Y-Axis (start with y, cause cylinder is oriented in y by vtk default...)
   vtkCone->SetDirection(0, 1, 0);
   vtkCone->SetHeight(1.0);
   vtkCone->SetRadius(0.4f);
   vtkCone->SetResolution(16);
   vtkCone->SetCenter(0.0, axisLength, 0.0);
   vtkCone->Update();
 
   vtkCylinder->SetRadius(0.05);
   vtkCylinder->SetHeight(axisLength);
   vtkCylinder->SetCenter(0.0, 0.5*axisLength, 0.0);
   vtkCylinder->Update();
 
   appendPolyData->AddInputData(vtkCone->GetOutput());
   appendPolyData->AddInputData(vtkCylinder->GetOutput());
   appendPolyData->Update();
   axis->DeepCopy(appendPolyData->GetOutput());
 
   //y symbol
   vtkLine->SetPoint1(-0.5, axisLength + 2., 0.0);
   vtkLine->SetPoint2(0.0, axisLength + 1.5, 0.0);
   vtkLine->Update();
 
   vtkLine2->SetPoint1(0.5, axisLength + 2., 0.0);
   vtkLine2->SetPoint2(-0.5, axisLength + 1., 0.0);
   vtkLine2->Update();
 
   appendPolyData->AddInputData(vtkLine->GetOutput());
   appendPolyData->AddInputData(vtkLine2->GetOutput());
   appendPolyData->AddInputData(axis);
   appendPolyData->Update();
   surface->DeepCopy(appendPolyData->GetOutput());
 
   //X-axis
   vtkSmartPointer<vtkTransform> XTransform = vtkSmartPointer<vtkTransform>::New();
   XTransform->RotateZ(-90);
   vtkSmartPointer<vtkTransformPolyDataFilter> TrafoFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
   TrafoFilter->SetTransform(XTransform);
   TrafoFilter->SetInputData(axis);
   TrafoFilter->Update();
 
   //x symbol
   vtkLine->SetPoint1(axisLength + 2., -0.5, 0.0);
   vtkLine->SetPoint2(axisLength + 1., 0.5, 0.0);
   vtkLine->Update();
 
   vtkLine2->SetPoint1(axisLength + 2., 0.5, 0.0);
   vtkLine2->SetPoint2(axisLength + 1., -0.5, 0.0);
   vtkLine2->Update();
 
   appendPolyData->AddInputData(vtkLine->GetOutput());
   appendPolyData->AddInputData(vtkLine2->GetOutput());
   appendPolyData->AddInputData(TrafoFilter->GetOutput());
   appendPolyData->AddInputData(surface);
   appendPolyData->Update();
   surface->DeepCopy(appendPolyData->GetOutput());
 
   //Z-axis
   vtkSmartPointer<vtkTransform> ZTransform = vtkSmartPointer<vtkTransform>::New();
   ZTransform->RotateX(90);
   TrafoFilter->SetTransform(ZTransform);
   TrafoFilter->SetInputData(axis);
   TrafoFilter->Update();
 
   //z symbol
   vtkLine->SetPoint1(-0.5, 0.0, axisLength + 2.);
   vtkLine->SetPoint2(0.5, 0.0, axisLength + 2.);
   vtkLine->Update();
 
   vtkLine2->SetPoint1(-0.5, 0.0, axisLength + 2.);
   vtkLine2->SetPoint2(0.5, 0.0, axisLength + 1.);
   vtkLine2->Update();
 
   vtkLine3->SetPoint1(0.5, 0.0, axisLength + 1.);
   vtkLine3->SetPoint2(-0.5, 0.0, axisLength + 1.);
   vtkLine3->Update();
 
   appendPolyData->AddInputData(vtkLine->GetOutput());
   appendPolyData->AddInputData(vtkLine2->GetOutput());
   appendPolyData->AddInputData(vtkLine3->GetOutput());
   appendPolyData->AddInputData(TrafoFilter->GetOutput());
   appendPolyData->AddInputData(surface);
   appendPolyData->Update();
   surface->DeepCopy(appendPolyData->GetOutput());
 
   //Center
   vtkSphere->SetRadius(0.5f);
   vtkSphere->SetCenter(0.0, 0.0, 0.0);
   vtkSphere->Update();
 
   appendPolyData->AddInputData(vtkSphere->GetOutput());
   appendPolyData->AddInputData(surface);
   appendPolyData->Update();
   surface->DeepCopy(appendPolyData->GetOutput());
 
   //Scale
   vtkSmartPointer<vtkTransform> ScaleTransform = vtkSmartPointer<vtkTransform>::New();
   ScaleTransform->Scale(20., 20., 20.);
 
   TrafoFilter->SetTransform(ScaleTransform);
   TrafoFilter->SetInputData(surface);
   TrafoFilter->Update();
 
   mySphere->SetVtkPolyData(TrafoFilter->GetOutput());
 
   this->GetDataNode()->SetData(mySphere);
 }
 
 std::string mitk::NavigationTool::GetStringWithAllToolInformation() const
 {
   std::stringstream _info;
   _info << "  Identifier: " << this->m_Identifier << "\n"
     << "  NavigationToolType: " << m_Type << "\n"
     << "  Calibration file: " << m_CalibrationFile << "\n"
     << "  Serial number: " << m_SerialNumber << "\n"
     << "  TrackingDeviceType: " << m_TrackingDeviceType << "\n"
     << "  ToolTip Position: " << m_ToolTipPosition << "\n"
     << "  Tool Axis Orientation: " << m_ToolAxisOrientation << "\n"
     << "  Tool Axis: " <<   m_ToolAxisOrientation.inverse().rotate(vnl_vector_fixed<mitk::ScalarType,3>(0.0,0.0,-1.0))
     ;
 
   return _info.str();
 }
diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.cpp b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.cpp
index 3587fc8277..1a5362d805 100644
--- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.cpp
+++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.cpp
@@ -1,169 +1,169 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkNavigationDataReaderCSV.h"
 #include <mitkIGTMimeTypes.h>
 #include <mitkLocaleSwitch.h>
 
 // STL
 #include <fstream>
 
 
 mitk::NavigationDataReaderCSV::NavigationDataReaderCSV() : AbstractFileReader(
   mitk::IGTMimeTypes::NAVIGATIONDATASETCSV_MIMETYPE(),
   "MITK NavigationData Reader (CSV)")
 {
   RegisterService();
 }
 
 mitk::NavigationDataReaderCSV::NavigationDataReaderCSV(const mitk::NavigationDataReaderCSV& other) : AbstractFileReader(other)
 {
 }
 
 mitk::NavigationDataReaderCSV::~NavigationDataReaderCSV()
 {
 }
 
 mitk::NavigationDataReaderCSV* mitk::NavigationDataReaderCSV::Clone() const
 {
   return new NavigationDataReaderCSV(*this);
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::NavigationDataReaderCSV::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::NavigationDataReaderCSV::DoRead()
 {
   std::vector<std::string> fileContent = GetFileContentLineByLine(GetInputLocation());
   int NumOfTools = getNumberOfToolsInLine(fileContent[0]);
 
   mitk::NavigationDataSet::Pointer returnValue = mitk::NavigationDataSet::New(NumOfTools);
   std::vector<mitk::BaseData::Pointer> result;
   result.push_back(returnValue.GetPointer());
 
   // start from line 1 to leave out header
   for (unsigned int i = 1; i<fileContent.size(); i++)
   {
     returnValue->AddNavigationDatas(parseLine(fileContent[i], NumOfTools));
   }
 
   return result;
 }
 
 
 int mitk::NavigationDataReaderCSV::getNumberOfToolsInLine(std::string line)
 {
   std::vector<std::string> tokens=splitLine(line);
  int size = tokens.size();
  int NumOfTools = (size)/9;
 
  if ( (size)%9 != 0 )
  {
    MITK_ERROR("mitkNavigationDataReader") << "Illegal csv-file! Unexpected number of columns found! Assuming " << NumOfTools << " tools!";
  }
 
  return NumOfTools ;
 }
 
 std::vector<std::string> mitk::NavigationDataReaderCSV::splitLine(std::string line)
 {
    std::vector<std::string> elems;
    std::stringstream ss(line);
    std::string item;
    while (std::getline(ss, item, ';')) {
      elems.push_back(item);
    }
    return elems;
 }
 
 mitk::NavigationData::Pointer mitk::NavigationDataReaderCSV::CreateNd(std::string timestamp, std::string valid, std::string X, std::string Y, std::string Z, std::string QX, std::string QY, std::string QZ, std::string QR)
 {
   mitk::NavigationData::Pointer result= mitk::NavigationData::New();
 
   mitk::Point3D position;
   mitk::Quaternion orientation;
   bool isValid = false;
   double time;
 
   time = StringToDouble(timestamp);
 
   if (valid == "1") isValid = true;
   else isValid = false;
 
   position[0] = StringToDouble(X);
   position[1] = StringToDouble(Y);
   position[2] = StringToDouble(Z);
 
   orientation[0] = StringToDouble(QX);
   orientation[1] = StringToDouble(QY);
   orientation[2] = StringToDouble(QZ);
   orientation[3] = StringToDouble(QR);
 
   result->SetIGTTimeStamp(time);
   result->SetDataValid(isValid);
   result->SetPosition(position);
   result->SetOrientation(orientation);
   return result;
 }
 
 double mitk::NavigationDataReaderCSV::StringToDouble( const std::string& s )
 {
   std::istringstream i(s);
   double x;
     if (!(i >> x))
       return 0;
     return x;
 }
 
 std::vector<mitk::NavigationData::Pointer> mitk::NavigationDataReaderCSV::parseLine(std::string line, int NumOfTools)
 {
   std::vector<std::string> parts = splitLine(line);
   std::vector<mitk::NavigationData::Pointer> result;
 
 
 
   for (int n = 0; n < NumOfTools; n++)
   {
     mitk::NavigationData::Pointer nd;
     int offset = n * 9;
     nd = CreateNd(parts[offset], parts[offset + 1], parts[offset + 2], parts[offset + 3], parts[offset + 4], parts[offset + 5], parts[offset + 6], parts[offset + 7], parts[offset + 8]);
     result.push_back(nd);
   }
   return result;
 }
 
 
 std::vector<std::string> mitk::NavigationDataReaderCSV::GetFileContentLineByLine(std::string filename)
 {
 std::vector<std::string> readData = std::vector<std::string>();
 
 //define own locale
 mitk::LocaleSwitch localeSwitch("C");
 
 //read file
 std::ifstream file;
 file.open(filename.c_str(), std::ios::in);
 if (file.good())
     {
     //read out file
     file.seekg(0L, std::ios::beg);  // move to begin of file
     while (! file.eof())
       {
       std::string buffer;
       std::getline(file,buffer);    // read out file line by line
       if (buffer.size() > 0) readData.push_back(buffer);
 
       }
     }
 
 file.close();
 
 return readData;
 }
diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.h b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.h
index 7a9527c492..462a6b4ca1 100644
--- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.h
+++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.h
@@ -1,80 +1,80 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MITKNavigationDataReaderCSV_H_HEADER_INCLUDED_
 #define MITKNavigationDataReaderCSV_H_HEADER_INCLUDED_
 
 #include <MitkIGTIOExports.h>
 
 #include <mitkAbstractFileReader.h>
 #include <mitkNavigationDataSet.h>
 
 namespace mitk {
   /** This class reads csv logged navigation datas from the hard disc and returns
    *  the navigation data set.
    *
    *  Caution: at the moment only one navigation data is supported which means that only
    *  the data of the first navigation tool in the file is read!
    */
   class MITKIGTIO_EXPORT NavigationDataReaderCSV : public AbstractFileReader
   {
   public:
 
     NavigationDataReaderCSV();
     ~NavigationDataReaderCSV() override;
 
     /** @return Returns the NavigationDataSet of the first tool in the given file.
      *          Returns an empty NavigationDataSet if the file could not be read.
      */
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
   protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
     /**
      * /brief Creates a NavigationData Pointer based on the given Input.
      */
     mitk::NavigationData::Pointer CreateNd(std::string timestamp, std::string valid, std::string X, std::string Y, std::string Z, std::string QX, std::string QY, std::string QZ, std::string QR);
 
     /**
      * /brief Presents File Content line by line
      */
     std::vector<std::string> GetFileContentLineByLine(std::string filename);
 
     /**
      * /brief Calculates the Number of Tools based on the number of colums per line.
      */
     int getNumberOfToolsInLine(std::string line);
 
     /**
      * /brief Converts string to double returns zero if failing
      */
     std::vector<mitk::NavigationData::Pointer> parseLine(std::string line, int NumOfTools);
 
     /**
      * /brief Converts string to double returns zero if failing
      */
     double StringToDouble( const std::string& s );
 
     /**
      * /brief Split line in elemens based on a given delim
      */
     std::vector<std::string> splitLine(std::string line);
 
     NavigationDataReaderCSV(const NavigationDataReaderCSV& other);
 
     mitk::NavigationDataReaderCSV* Clone() const override;
 
   };
 }
 
 #endif // MITKNavigationDataReaderCSV_H_HEADER_INCLUDED_
diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp
index 004ed0a49a..24551b7f0a 100644
--- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp
+++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp
@@ -1,364 +1,364 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkNavigationDataReaderXML.h"
 #include <mitkIGTMimeTypes.h>
 #include <mitkLocaleSwitch.h>
 
 // Third Party
 #include <itksys/SystemTools.hxx>
 #include <fstream>
 #include <tinyxml.h>
 
 
 mitk::NavigationDataReaderXML::NavigationDataReaderXML() : AbstractFileReader(
   mitk::IGTMimeTypes::NAVIGATIONDATASETXML_MIMETYPE(),
   "MITK NavigationData Reader (XML)"), m_parentElement(nullptr), m_currentNode(nullptr)
 {
   RegisterService();
 }
 
 mitk::NavigationDataReaderXML::~NavigationDataReaderXML()
 {
 }
 
 mitk::NavigationDataReaderXML::NavigationDataReaderXML(const mitk::NavigationDataReaderXML& other) : AbstractFileReader(other), m_parentElement(nullptr), m_currentNode(nullptr)
 {
 }
 
 mitk::NavigationDataReaderXML* mitk::NavigationDataReaderXML::Clone() const
 {
   return new NavigationDataReaderXML(*this);
 }
 
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::NavigationDataReaderXML::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::NavigationDataReaderXML::DoRead()
 {
   mitk::NavigationDataSet::Pointer dataset;
   std::istream* in = GetInputStream();
   if (in == nullptr)
   {
     dataset = Read(GetInputLocation());
   } else {
     dataset = Read(in);
   }
   std::vector<mitk::BaseData::Pointer> result;
   mitk::BaseData::Pointer base = dataset.GetPointer();
   result.push_back(base);
   return result;
 }
 
 
 
 mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::Read(std::string fileName)
 {
   //define own locale
   mitk::LocaleSwitch localeSwitch("C");
 
   m_FileName = fileName;
 
   TiXmlDocument document;
   if (!document.LoadFile(fileName))
   {
     mitkThrowException(mitk::IGTIOException) << "File '" << fileName << "' could not be loaded.";
   }
 
   TiXmlElement* m_DataElem = document.FirstChildElement("Version");
   if (!m_DataElem)
   {
     // for backwards compatibility of version tag
     m_DataElem = document.FirstChildElement("Data");
     if (!m_DataElem)
     {
       mitkThrowException(mitk::IGTIOException) << "Data element not found.";
     }
 
   }
 
   if (m_DataElem->QueryIntAttribute("Ver", &m_FileVersion) != TIXML_SUCCESS)
   {
     if (m_DataElem->QueryIntAttribute("version", &m_FileVersion) != TIXML_SUCCESS)
     {
       mitkThrowException(mitk::IGTIOException) << "Version not specified in XML file.";
     }
   }
 
   if (m_FileVersion != 1)
   {
     mitkThrowException(mitk::IGTIOException) << "File format version " << m_FileVersion << " is not supported.";
   }
 
   m_parentElement = document.FirstChildElement("Data");
   if (!m_parentElement)
   {
     mitkThrowException(mitk::IGTIOException) << "Data element not found.";
   }
 
   m_parentElement->QueryIntAttribute("ToolCount", &m_NumberOfOutputs);
 
   mitk::NavigationDataSet::Pointer navigationDataSet = this->ReadNavigationDataSet();
 
   return navigationDataSet;
 }
 
 mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::Read(std::istream* stream)
 {
   //define own locale
   mitk::LocaleSwitch localeSwitch("C");
 
   // first get the file version
   m_FileVersion = this->GetFileVersion(stream);
 
   // check if we have a valid version: m_FileVersion has to be always bigger than 1 for playing
   if (m_FileVersion < 1)
   {
     StreamInvalid("Playing not possible. Invalid file version!");
     return nullptr;
   }
 
   m_NumberOfOutputs = this->GetNumberOfNavigationDatas(stream);
   if (m_NumberOfOutputs == 0) { return nullptr; }
 
   mitk::NavigationDataSet::Pointer dataSet = this->ReadNavigationDataSet();
 
   return dataSet;
 }
 
 mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::ReadNavigationDataSet()
 {
   mitk::NavigationDataSet::Pointer navigationDataSet = mitk::NavigationDataSet::New(m_NumberOfOutputs);
   mitk::NavigationData::Pointer curNavigationData;
 
   do
     {
       std::vector<mitk::NavigationData::Pointer> navDatas(m_NumberOfOutputs);
       for (int n = 0; n < m_NumberOfOutputs; ++n)
       {
         curNavigationData = this->ReadVersion1();
 
         if (curNavigationData.IsNull())
         {
           if (n != 0)
           {
             MITK_WARN("mitkNavigationDataReaderXML")
                 << "Different number of NavigationData objects for different tools. Ignoring last ones.";
           }
           break;
         }
         navDatas.at(n) = curNavigationData;
       }
 
       if (curNavigationData.IsNotNull())
       {
         navigationDataSet->AddNavigationDatas(navDatas);
       }
     }
     while (curNavigationData.IsNotNull());
 
     return navigationDataSet;
 }
 
 mitk::NavigationData::Pointer mitk::NavigationDataReaderXML::ReadVersion1()
 {
   if ( !m_parentElement )
   {
     mitkThrowException(mitk::IGTIOException) << "Reading XML is not possible. Parent element is not set.";
   }
 
   TiXmlElement* elem;
   m_currentNode = m_parentElement->IterateChildren(m_currentNode);
 
   bool delElem;
 
   if(m_currentNode)
   {
     elem = m_currentNode->ToElement();
     if(elem==nullptr)
     {
       mitkThrowException(mitk::IGTException) << "Cannot find element: Is this file damaged?";
     }
     delElem = false;
   }
 
   else
   {
     elem = new TiXmlElement("");
     delElem = true;
   }
 
 
   mitk::NavigationData::Pointer nd = this->ReadNavigationData(elem);
 
   if(delElem) { delete elem; }
 
   return nd;
 }
 
 mitk::NavigationData::Pointer mitk::NavigationDataReaderXML::ReadNavigationData(TiXmlElement* elem)
 {
   if (elem == nullptr) {mitkThrow() << "Error: Element is nullptr!";}
 
   mitk::NavigationData::Pointer nd = mitk::NavigationData::New();
 
   mitk::NavigationData::PositionType position;
   mitk::NavigationData::OrientationType orientation(0.0,0.0,0.0,0.0);
   mitk::NavigationData::TimeStampType timestamp = -1;
   mitk::NavigationData::CovarianceMatrixType matrix;
 
   bool hasPosition = true;
   bool hasOrientation = true;
   bool dataValid = false;
 
   position.Fill(0.0);
   matrix.SetIdentity();
 
   elem->QueryDoubleAttribute("Time",&timestamp);
   if (timestamp == -1)
   {
     return nullptr;  //the calling method should check the return value if it is valid/not nullptr
   }
 
   elem->QueryDoubleAttribute("X", &position[0]);
   elem->QueryDoubleAttribute("Y", &position[1]);
   elem->QueryDoubleAttribute("Z", &position[2]);
 
   elem->QueryDoubleAttribute("QX", &orientation[0]);
   elem->QueryDoubleAttribute("QY", &orientation[1]);
   elem->QueryDoubleAttribute("QZ", &orientation[2]);
   elem->QueryDoubleAttribute("QR", &orientation[3]);
 
   elem->QueryDoubleAttribute("C00", &matrix[0][0]);
   elem->QueryDoubleAttribute("C01", &matrix[0][1]);
   elem->QueryDoubleAttribute("C02", &matrix[0][2]);
   elem->QueryDoubleAttribute("C03", &matrix[0][3]);
   elem->QueryDoubleAttribute("C04", &matrix[0][4]);
   elem->QueryDoubleAttribute("C05", &matrix[0][5]);
   elem->QueryDoubleAttribute("C10", &matrix[1][0]);
   elem->QueryDoubleAttribute("C11", &matrix[1][1]);
   elem->QueryDoubleAttribute("C12", &matrix[1][2]);
   elem->QueryDoubleAttribute("C13", &matrix[1][3]);
   elem->QueryDoubleAttribute("C14", &matrix[1][4]);
   elem->QueryDoubleAttribute("C15", &matrix[1][5]);
 
   int tmpval = 0;
   elem->QueryIntAttribute("Valid", &tmpval);
   if (tmpval == 0)
     dataValid = false;
   else
     dataValid = true;
 
   tmpval = 0;
   elem->QueryIntAttribute("hO", &tmpval);
   if (tmpval == 0)
     hasOrientation = false;
   else
     hasOrientation = true;
 
   tmpval = 0;
   elem->QueryIntAttribute("hP", &tmpval);
   if (tmpval == 0)
     hasPosition = false;
   else
     hasPosition = true;
 
   nd->SetIGTTimeStamp(timestamp);
   nd->SetPosition(position);
   nd->SetOrientation(orientation);
   nd->SetCovErrorMatrix(matrix);
   nd->SetDataValid(dataValid);
   nd->SetHasOrientation(hasOrientation);
   nd->SetHasPosition(hasPosition);
 
 
   return nd;
 }
 
 // -- deprecated | begin
 unsigned int mitk::NavigationDataReaderXML::GetFileVersion(std::istream* stream)
 {
   if (stream==nullptr)
   {
     MITK_ERROR << "No input stream set!";
     mitkThrowException(mitk::IGTIOException)<<"No input stream set!";
   }
   if (!stream->good())
   {
     MITK_ERROR << "Stream is not good!";
     mitkThrowException(mitk::IGTIOException)<<"Stream is not good!";
   }
   int version = 1;
 
   auto  dec = new TiXmlDeclaration();
   *stream >> *dec;
   if(strcmp(dec->Version(),"") == 0)
   {
     MITK_ERROR << "The input stream seems to have XML incompatible format";
     mitkThrowException(mitk::IGTIOException) << "The input stream seems to have XML incompatible format";
   }
 
   m_parentElement = new TiXmlElement("");
   *stream >> *m_parentElement; //2nd line this is the file version
 
   std::string tempValue = m_parentElement->Value();
   if(tempValue != "Version")
   {
       if(tempValue == "Data"){
           m_parentElement->QueryIntAttribute("version",&version);
       }
   }
   else
   {
     m_parentElement->QueryIntAttribute("Ver",&version);
   }
 
   if (version > 0) { return version; }
   else { return 0; }
 }
 
 unsigned int mitk::NavigationDataReaderXML::GetNumberOfNavigationDatas(std::istream* stream)
 {
   if (stream == nullptr)
   {
     MITK_ERROR << "No input stream set!";
     mitkThrowException(mitk::IGTException)<<"No input stream set!";
   }
   if (!stream->good())
   {
     MITK_ERROR << "Stream not good!";
     mitkThrowException(mitk::IGTException)<<"Stream not good!";
   }
 
   //If something has changed in a future version of the XML definition e.g. navigationcount or addional parameters
   //catch this here with a select case block (see GenerateData() method)
 
   int numberOfTools = 0;
 
   std::string tempValue = m_parentElement->Value();
   if(tempValue == "Version"){
     *stream >> *m_parentElement;
   }
   m_parentElement->QueryIntAttribute("ToolCount",&numberOfTools);
 
   if (numberOfTools > 0) { return numberOfTools; }
 
   return 0;
 }
 
 void mitk::NavigationDataReaderXML::StreamInvalid(std::string message)
 {
   m_StreamEnd = true;
   m_ErrorMessage = message;
   m_StreamValid = false;
   mitkThrowException(mitk::IGTIOException) << "Invalid stream!";
 }
 // -- deprecated | end
diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h
index 5d5b5d81f4..8c6dc89b47 100644
--- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h
+++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h
@@ -1,106 +1,106 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #ifndef MITKNavigationDataReaderXML_H_HEADER_INCLUDED_
 #define MITKNavigationDataReaderXML_H_HEADER_INCLUDED_
 
 #include <MitkIGTIOExports.h>
 
 #include <mitkAbstractFileReader.h>
 #include <mitkNavigationDataSet.h>
 // includes for exceptions
 #include <mitkIGTException.h>
 #include <mitkIGTIOException.h>
 
 class TiXmlElement;
 class TiXmlNode;
 
 namespace mitk {
 
   class MITKIGTIO_EXPORT NavigationDataReaderXML : public AbstractFileReader
   {
   public:
     NavigationDataReaderXML();
     ~NavigationDataReaderXML() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
   protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
     NavigationDataReaderXML(const NavigationDataReaderXML& other);
     mitk::NavigationDataReaderXML* Clone() const override;
 
     NavigationDataSet::Pointer ReadNavigationDataSet();
 
     /**
      * \brief This method reads one line of the XML document and returns the data as a NavigationData object
      * If there is a new file version another method must be added which reads this data.
      * @throw mitk::IGTException Throws an exceptions if file is damaged.
      */
     mitk::NavigationData::Pointer ReadVersion1();
     mitk::NavigationData::Pointer ReadNavigationData(TiXmlElement* elem);
 
     std::string m_FileName;
 
     TiXmlElement* m_parentElement;
     TiXmlNode* m_currentNode;
 
     int m_FileVersion; ///< indicates which XML encoding is used
     int m_NumberOfOutputs; ///< stores the number of outputs known from the XML document
 
     // -- deprecated | begin
     //std::istream* m_Stream; ///< stores a pointer to the input stream
     bool m_StreamEnd; ///< stores if the input stream arrived at end
     bool m_StreamValid;                       ///< stores if the input stream is valid or not
     std::string m_ErrorMessage;               ///< stores the error message if the stream is invalid
 
     /**
      * \brief Creates a stream out of the filename given by the variable m_FileName.
      * The stream is then set to m_Stream.
      *
      * @throw mitk::IGTIOException Throws an exception if file does not exist
      * @throw mitk::IGTException Throws an exception if the stream is nullptr
      */
     //void CreateStreamFromFilename();
 
     /**
      * \brief Returns the file version out of the XML document.
      * @throw mitk::IGTException Throws an mitk::IGTException an exception if stream is nullptr or not good.
      * @throw mitk::IGTIOException Throws an mitk::IGTIOException if the stream has an incompatible XML format.
      */
     unsigned int GetFileVersion(std::istream* stream);
 
     /**
      * \brief Returns the number of tracked tools out of the XML document.
      * @throw Throws an exception if stream is nullptr.
      * @throw Throws an exception if the input stream has an XML incompatible format.
      */
     unsigned int GetNumberOfNavigationDatas(std::istream* stream);
 
     /**
      * @brief This is a helping method which gives an error message and throws an exception with the given message.
      *        It can be used if a stream is found to be invalid.
      *
      * @throw mitk::IGTIOException Always throws an exception.
      */
     void StreamInvalid(std::string message);  ///< help method which sets the stream invalid and displays an error
     // -- deprecated | end
   private:
     NavigationDataSet::Pointer Read(std::istream* stream);
     NavigationDataSet::Pointer Read(std::string fileName);
   };
 
 } // namespace mitk
 
 #endif // MITKNavigationDataReaderXML_H_HEADER_INCLUDED_
diff --git a/Modules/IOExt/Internal/mitkObjFileReaderService.cpp b/Modules/IOExt/Internal/mitkObjFileReaderService.cpp
index b60f99fb6d..f5c1919e3c 100644
--- a/Modules/IOExt/Internal/mitkObjFileReaderService.cpp
+++ b/Modules/IOExt/Internal/mitkObjFileReaderService.cpp
@@ -1,53 +1,53 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkObjFileReaderService.h"
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkSurface.h>
 
 // VTK
 #include <vtkOBJReader.h>
 #include <vtkSmartPointer.h>
 
 mitk::ObjFileReaderService::ObjFileReaderService()
   : AbstractFileReader(CustomMimeType(IOMimeTypes::WAVEFRONT_OBJ_MIMETYPE()), "Wavefront OBJ Reader")
 {
   this->RegisterService();
 }
 
 mitk::ObjFileReaderService::~ObjFileReaderService()
 {
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::ObjFileReaderService::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::ObjFileReaderService::DoRead()
 {
   std::vector<itk::SmartPointer<BaseData>> result;
 
   vtkSmartPointer<vtkOBJReader> reader = vtkSmartPointer<vtkOBJReader>::New();
   reader->SetFileName(GetInputLocation().c_str());
   reader->Update();
 
   if (reader->GetOutput() != nullptr)
   {
     mitk::Surface::Pointer surface = mitk::Surface::New();
     surface->SetVtkPolyData(reader->GetOutput());
     result.push_back(dynamic_cast<mitk::BaseData *>(surface.GetPointer()));
   }
   return result;
 }
 
 mitk::ObjFileReaderService *mitk::ObjFileReaderService::Clone() const
 {
   return new ObjFileReaderService(*this);
 }
diff --git a/Modules/IOExt/Internal/mitkObjFileReaderService.h b/Modules/IOExt/Internal/mitkObjFileReaderService.h
index 6a059881c8..7a3f3919b2 100644
--- a/Modules/IOExt/Internal/mitkObjFileReaderService.h
+++ b/Modules/IOExt/Internal/mitkObjFileReaderService.h
@@ -1,45 +1,47 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef ObjFileReaderService_h
 #define ObjFileReaderService_h
 
 #include <mitkAbstractFileReader.h>
 #include <mitkIOMimeTypes.h>
 
 namespace mitk
 {
   class BaseData;
 
   /**
   * @brief Used to read surfaces from Wavefront OBJ files.
   *
   * @ingroup IOExt
   */
   class ObjFileReaderService : public AbstractFileReader
   {
   public:
     ObjFileReaderService();
     ~ObjFileReaderService() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
     static mitk::CustomMimeType mimeType;
 
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     ObjFileReaderService *Clone() const override;
   };
 
 } // namespace mitk
 
 #endif /* ObjFileReaderService_h */
diff --git a/Modules/IOExt/Internal/mitkPlyFileReaderService.cpp b/Modules/IOExt/Internal/mitkPlyFileReaderService.cpp
index 8f6bf4eb1a..bb44d3ed6a 100644
--- a/Modules/IOExt/Internal/mitkPlyFileReaderService.cpp
+++ b/Modules/IOExt/Internal/mitkPlyFileReaderService.cpp
@@ -1,53 +1,53 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkPlyFileReaderService.h"
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkSurface.h>
 
 // VTK
 #include <vtkPLYReader.h>
 #include <vtkSmartPointer.h>
 
 mitk::PlyFileReaderService::PlyFileReaderService()
   : AbstractFileReader(CustomMimeType(IOMimeTypes::STANFORD_PLY_MIMETYPE()), "Stanford Triangle PLY Reader")
 {
   this->RegisterService();
 }
 
 mitk::PlyFileReaderService::~PlyFileReaderService()
 {
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::PlyFileReaderService::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::PlyFileReaderService::DoRead()
 {
   std::vector<itk::SmartPointer<BaseData>> result;
 
   vtkSmartPointer<vtkPLYReader> reader = vtkSmartPointer<vtkPLYReader>::New();
   reader->SetFileName(GetInputLocation().c_str());
   reader->Update();
 
   if (reader->GetOutput() != nullptr)
   {
     mitk::Surface::Pointer surface = mitk::Surface::New();
     surface->SetVtkPolyData(reader->GetOutput());
     result.push_back(dynamic_cast<mitk::BaseData *>(surface.GetPointer()));
   }
   return result;
 }
 
 mitk::PlyFileReaderService *mitk::PlyFileReaderService::Clone() const
 {
   return new PlyFileReaderService(*this);
 }
diff --git a/Modules/IOExt/Internal/mitkPlyFileReaderService.h b/Modules/IOExt/Internal/mitkPlyFileReaderService.h
index ac81e403e6..52c1d6b19e 100644
--- a/Modules/IOExt/Internal/mitkPlyFileReaderService.h
+++ b/Modules/IOExt/Internal/mitkPlyFileReaderService.h
@@ -1,47 +1,49 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef PlyFileReaderService_h
 #define PlyFileReaderService_h
 
 #include <mitkAbstractFileReader.h>
 #include <mitkIOMimeTypes.h>
 
 namespace mitk
 {
   class BaseData;
 
   /**
   * @brief Used to read surfaces from the PLY format.
   *
   * This reader can read binary and ASCII versions of the format transparently.
   *
   * @ingroup IOExt
   */
   class PlyFileReaderService : public AbstractFileReader
   {
   public:
     PlyFileReaderService();
     ~PlyFileReaderService() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
     static mitk::CustomMimeType mimeType;
 
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     PlyFileReaderService *Clone() const override;
   };
 
 } // namespace mitk
 
 #endif /* PlyFileReaderService_h */
diff --git a/Modules/IOExt/Internal/mitkSceneFileReader.cpp b/Modules/IOExt/Internal/mitkSceneFileReader.cpp
index 121c6a3817..62ae6221f4 100644
--- a/Modules/IOExt/Internal/mitkSceneFileReader.cpp
+++ b/Modules/IOExt/Internal/mitkSceneFileReader.cpp
@@ -1,65 +1,81 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkSceneFileReader.h"
 
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkSceneIO.h>
+#include <mitkStandaloneDataStorage.h>
 
 namespace mitk
 {
   SceneFileReader::SceneFileReader() : AbstractFileReader()
   {
     CustomMimeType mimeType(IOMimeTypes::DEFAULT_BASE_NAME() + ".scene");
     mimeType.SetComment("MITK Scene Files");
     mimeType.SetCategory("MITK Scenes");
     mimeType.AddExtension("mitk");
 
     this->SetDescription("MITK Scene Reader");
     this->SetMimeType(mimeType);
 
     this->RegisterService();
   }
 
   DataStorage::SetOfObjects::Pointer SceneFileReader::Read(DataStorage &ds)
   {
     // const DataStorage::SetOfObjects::STLContainerType& oldNodes = ds.GetAll()->CastToSTLConstContainer();
     DataStorage::SetOfObjects::ConstPointer oldNodes = ds.GetAll();
     SceneIO::Pointer sceneIO = SceneIO::New();
     sceneIO->LoadScene(this->GetLocalFileName(), &ds, false);
     DataStorage::SetOfObjects::ConstPointer newNodes = ds.GetAll();
 
     // Compute the difference
     DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New();
 
     unsigned int index = 0;
     for (DataStorage::SetOfObjects::ConstIterator iter = newNodes->Begin(), iterEnd = newNodes->End(); iter != iterEnd;
          ++iter)
     {
       if (!oldNodes->empty())
       {
         if (std::find(oldNodes->begin(), oldNodes->end(), iter.Value()) == oldNodes->end())
           result->InsertElement(index++, iter.Value());
       }
       else
       {
         result->InsertElement(index++, iter.Value());
       }
     }
 
     return result;
   }
 
-  std::vector<BaseData::Pointer> SceneFileReader::Read() { return AbstractFileReader::Read(); }
+  std::vector<BaseData::Pointer> SceneFileReader::DoRead()
+  {
+    std::vector<BaseData::Pointer> result;
+
+    DataStorage::Pointer ds = StandaloneDataStorage::New().GetPointer();
+    this->Read(*ds);
+    DataStorage::SetOfObjects::ConstPointer dataNodes = ds->GetAll();
+    for (DataStorage::SetOfObjects::ConstIterator iter = dataNodes->Begin(), iterEnd = dataNodes->End();
+      iter != iterEnd;
+      ++iter)
+    {
+      result.push_back(iter.Value()->GetData());
+    }
+    return result;
+  }
+
   SceneFileReader *SceneFileReader::Clone() const { return new SceneFileReader(*this); }
 }
diff --git a/Modules/IOExt/Internal/mitkSceneFileReader.h b/Modules/IOExt/Internal/mitkSceneFileReader.h
index e2c89774a3..efdc7c2f28 100644
--- a/Modules/IOExt/Internal/mitkSceneFileReader.h
+++ b/Modules/IOExt/Internal/mitkSceneFileReader.h
@@ -1,36 +1,38 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef SceneFileReader_H_HEADER_INCLUDED
 #define SceneFileReader_H_HEADER_INCLUDED
 
 // MITK
 #include <mitkAbstractFileReader.h>
 
 namespace mitk
 {
   class SceneFileReader : public mitk::AbstractFileReader
   {
   public:
     SceneFileReader();
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
     DataStorage::SetOfObjects::Pointer Read(DataStorage &ds) override;
 
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     SceneFileReader *Clone() const override;
   };
 
 } // namespace mitk
 
 #endif /* SceneFileReader_H_HEADER_INCLUDED_C1E7E521 */
diff --git a/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.cpp b/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.cpp
index 13481b9963..6836dd7cd1 100644
--- a/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.cpp
+++ b/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.cpp
@@ -1,88 +1,88 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 #include "mitkVtkUnstructuredGridReader.h"
 #include <mitkUnstructuredGrid.h>
 #include <vtkDataReader.h>
 #include <vtkUnstructuredGridReader.h>
 #include <vtkXMLUnstructuredGridReader.h>
 
 #include <itksys/SystemTools.hxx>
 
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 
 mitk::VtkUnstructuredGridReader::VtkUnstructuredGridReader() : AbstractFileReader()
 {
   CustomMimeType mimeType(IOMimeTypes::DEFAULT_BASE_NAME() + ".vtu");
   mimeType.SetComment("Vtk Unstructured Grid Files");
   mimeType.SetCategory("Vtk Unstructured Grid");
   mimeType.AddExtension("vtu");
   mimeType.AddExtension("vtk");
 
   this->SetDescription("Vtk Unstructured Grid Files");
   this->SetMimeType(mimeType);
 
   this->RegisterService();
 }
 
 mitk::VtkUnstructuredGridReader::~VtkUnstructuredGridReader()
 {
 }
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::VtkUnstructuredGridReader::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::VtkUnstructuredGridReader::DoRead()
 {
   MITK_INFO << "Loading "
             << " as vtk unstructured grid";
   std::vector<itk::SmartPointer<mitk::BaseData>> result;
   MITK_INFO << this->GetLocalFileName();
   std::string ext = itksys::SystemTools::GetFilenameLastExtension(GetLocalFileName().c_str());
   ext = itksys::SystemTools::LowerCase(ext);
   if (ext == ".vtk")
   {
     vtkDataReader *chooser = vtkDataReader::New();
     chooser->SetFileName(GetLocalFileName().c_str());
     if (chooser->IsFileUnstructuredGrid())
     {
       vtkUnstructuredGridReader *reader = vtkUnstructuredGridReader::New();
       reader->SetFileName(GetLocalFileName().c_str());
       reader->Update();
 
       if (reader->GetOutput() != nullptr)
       {
         mitk::UnstructuredGrid::Pointer grid = mitk::UnstructuredGrid::New();
         grid->SetVtkUnstructuredGrid(reader->GetOutput());
         result.push_back(grid.GetPointer());
       }
       reader->Delete();
     }
   }
   else if (ext == ".vtu")
   {
     vtkXMLUnstructuredGridReader *reader = vtkXMLUnstructuredGridReader::New();
     reader->SetFileName(GetLocalFileName().c_str());
     reader->Update();
 
     if (reader->GetOutput() != nullptr)
     {
       mitk::UnstructuredGrid::Pointer grid = mitk::UnstructuredGrid::New();
       grid->SetVtkUnstructuredGrid(reader->GetOutput());
       result.push_back(grid.GetPointer());
     }
     reader->Delete();
   }
   return result;
 }
 
 mitk::VtkUnstructuredGridReader *mitk::VtkUnstructuredGridReader::Clone() const
 {
   return new mitk::VtkUnstructuredGridReader(*this);
 }
diff --git a/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.h b/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.h
index 1c9fa10f9f..122a715556 100644
--- a/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.h
+++ b/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.h
@@ -1,36 +1,37 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 #ifndef VtkUnstructuredGridReader_H_HEADER_INCLUDED
 #define VtkUnstructuredGridReader_H_HEADER_INCLUDED
 
 #include <mitkAbstractFileReader.h>
 
 namespace mitk
 {
   //##Documentation
   //## @brief Reader to read unstructured grid files in vtk-format
   class VtkUnstructuredGridReader : public AbstractFileReader
   {
   public:
     VtkUnstructuredGridReader();
     ~VtkUnstructuredGridReader() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
 
   protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
     VtkUnstructuredGridReader *Clone() const override;
   };
 
 } // namespace mitk
 
 #endif /* VtkUnstructuredGridReader_H_HEADER_INCLUDED */
diff --git a/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp b/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp
index e06482a23d..164906747a 100644
--- a/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp
+++ b/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp
@@ -1,1139 +1,1139 @@
 
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 #include "mitkImageStatisticsCalculator.h"
 #include <mitkTestFixture.h>
 #include <mitkTestingMacros.h>
 #include <mitkPlanarPolygon.h>
 
 #include <mitkIOUtil.h>
 
 #include <mitkPlanarFigureMaskGenerator.h>
 #include <mitkImageMaskGenerator.h>
 #include <mitkImageStatisticsConstants.h>
 
 /**
  * \brief Test class for mitkImageStatisticsCalculator
  *
  * This test covers:
  * - instantiation of an ImageStatisticsCalculator class
  * - correctness of statistics when using PlanarFigures for masking
  */
 class mitkImageStatisticsCalculatorTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkImageStatisticsCalculatorTestSuite);
   MITK_TEST(TestUninitializedImage);
   MITK_TEST(TestCase1);
   MITK_TEST(TestCase2);
   MITK_TEST(TestCase3);
   MITK_TEST(TestCase4);
   MITK_TEST(TestCase5);
   MITK_TEST(TestCase6);
   MITK_TEST(TestCase7);
   MITK_TEST(TestCase8);
   MITK_TEST(TestCase9);
   MITK_TEST(TestCase10);
   MITK_TEST(TestCase11);
   MITK_TEST(TestCase12);
   MITK_TEST(TestPic3DCroppedNoMask);
   MITK_TEST(TestPic3DCroppedBinMask);
   MITK_TEST(TestPic3DCroppedMultilabelMask);
   MITK_TEST(TestPic3DCroppedPlanarFigure);
   MITK_TEST(TestUS4DCroppedNoMaskTimeStep1);
   MITK_TEST(TestUS4DCroppedBinMaskTimeStep1);
   MITK_TEST(TestUS4DCroppedMultilabelMaskTimeStep1);
   MITK_TEST(TestUS4DCroppedPlanarFigureTimeStep1);
   MITK_TEST(TestUS4DCroppedAllTimesteps);
   MITK_TEST(TestUS4DCropped3DMask);
   CPPUNIT_TEST_SUITE_END();
 
 public:
 
   void TestUninitializedImage();
 
   void TestCase1();
   void TestCase2();
   void TestCase3();
   void TestCase4();
   void TestCase5();
   void TestCase6();
   void TestCase7();
   void TestCase8();
   void TestCase9();
   void TestCase10();
   void TestCase11();
   void TestCase12();
 
   void TestPic3DCroppedNoMask();
   void TestPic3DCroppedBinMask();
   void TestPic3DCroppedMultilabelMask();
   void TestPic3DCroppedPlanarFigure();
 
   void TestUS4DCroppedNoMaskTimeStep1();
   void TestUS4DCroppedBinMaskTimeStep1();
   void TestUS4DCroppedMultilabelMaskTimeStep1();
   void TestUS4DCroppedPlanarFigureTimeStep1();
   void TestUS4DCroppedAllTimesteps();
   void TestUS4DCropped3DMask();
 private:
 	mitk::Image::ConstPointer m_TestImage;
 
 	mitk::Image::ConstPointer m_Pic3DCroppedImage;
 	mitk::Image::Pointer m_Pic3DCroppedBinMask;
 	mitk::Image::Pointer m_Pic3DCroppedMultilabelMask;
 	mitk::PlanarFigure::Pointer m_Pic3DCroppedPlanarFigure;
 
 	mitk::Image::ConstPointer m_US4DCroppedImage;
 	mitk::Image::Pointer m_US4DCroppedBinMask;
 	mitk::Image::Pointer m_US4DCroppedMultilabelMask;
 	mitk::Image::Pointer m_US4DCropped3DBinMask;
 	mitk::PlanarFigure::Pointer m_US4DCroppedPlanarFigure;
 
 	mitk::PlaneGeometry::Pointer m_Geometry;
 
 	// creates a polygon given a geometry and a vector of 2d points
 	mitk::PlanarPolygon::Pointer GeneratePlanarPolygon(mitk::PlaneGeometry::Pointer geometry, std::vector <mitk::Point2D> points);
 
 	// universal function to calculate statistics
 	const mitk::ImageStatisticsContainer::Pointer ComputeStatistics(mitk::Image::ConstPointer image,
 		mitk::MaskGenerator::Pointer maskGen = nullptr,
 		mitk::MaskGenerator::Pointer secondardMaskGen = nullptr,
 		unsigned short label = 1);
 
 	void VerifyStatistics(mitk::ImageStatisticsContainer::ImageStatisticsObject stats,
 		mitk::ImageStatisticsContainer::RealType testMean, mitk::ImageStatisticsContainer::RealType testSD, mitk::ImageStatisticsContainer::RealType testMedian = 0);
 
 	// T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 	void VerifyStatistics(mitk::ImageStatisticsContainer::ImageStatisticsObject stats,
 		mitk::ImageStatisticsContainer::VoxelCountType N,
 		mitk::ImageStatisticsContainer::RealType mean,
 		mitk::ImageStatisticsContainer::RealType MPP,
 		mitk::ImageStatisticsContainer::RealType skewness,
 		mitk::ImageStatisticsContainer::RealType kurtosis,
 		mitk::ImageStatisticsContainer::RealType variance,
 		mitk::ImageStatisticsContainer::RealType stdev,
 		mitk::ImageStatisticsContainer::RealType min,
 		mitk::ImageStatisticsContainer::RealType max,
 		mitk::ImageStatisticsContainer::RealType RMS,
 		mitk::ImageStatisticsContainer::IndexType minIndex,
 		mitk::ImageStatisticsContainer::IndexType maxIndex);
 };
 
 void mitkImageStatisticsCalculatorTestSuite::TestUninitializedImage()
 {
 	/*****************************
 	* loading uninitialized image to datastorage
 	******************************/
 	MITK_INFO << std::endl << "Test uninitialized image: -----------------------------------------------------------------------------------";
 	mitk::Image::Pointer image = mitk::Image::New();
 	mitk::DataNode::Pointer node = mitk::DataNode::New();
 	node->SetData(image);
 
 	mitk::ImageStatisticsCalculator::Pointer is = mitk::ImageStatisticsCalculator::New();
 	CPPUNIT_ASSERT_THROW(is->GetStatistics(), mitk::Exception);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase1()
 {
 	/*****************************
 	 * one whole white pixel
 	 * -> mean of 255 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 1:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading an mitk::Image", m_TestImage.IsNotNull());
 
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 	CPPUNIT_ASSERT_MESSAGE("Failed getting image geometry", m_Geometry.IsNotNull());
 
 	mitk::Point2D pnt1; pnt1[0] = 10.5; pnt1[1] = 3.5;
 	mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5;
 	mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5;
 	mitk::Point2D pnt4; pnt4[0] = 10.5; pnt4[1] = 4.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 255.0, 0.0, 255.0);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase2()
 {
 	/*****************************
 	 * half pixel in x-direction (white)
 	 * -> mean of 255 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 2:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 10.0; pnt1[1] = 3.5;
 	mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5;
 	mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5;
 	mitk::Point2D pnt4; pnt4[0] = 10.0; pnt4[1] = 4.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 255.0, 0.0, 255.0);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase3()
 {
 	/*****************************
 	 * half pixel in diagonal-direction (white)
 	 * -> mean of 255 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 3:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 10.5; pnt1[1] = 3.5;
 	mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5;
 	mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 255.0, 0.0, 255.0);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase4()
 {
 	/*****************************
 	 * one pixel (white) + 2 half pixels (white) + 1 half pixel (black)
 	 * -> mean of 191.25 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 4:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 1.1; pnt1[1] = 1.1;
 	mitk::Point2D pnt2; pnt2[0] = 2.0; pnt2[1] = 2.0;
 	mitk::Point2D pnt3; pnt3[0] = 3.0; pnt3[1] = 1.0;
 	mitk::Point2D pnt4; pnt4[0] = 2.0; pnt4[1] = 0.0;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 191.25, 110.41823898251593, 253.72499847412109);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase5()
 {
 	/*****************************
 	 * whole pixel (white) + half pixel (gray) in x-direction
 	 * -> mean of 191.5 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 5:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5;
 	mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5;
 	mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5;
 	mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 191.50, 63.50, 128.63499999046327);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase6()
 {
 	/*****************************
 	 * quarter pixel (black) + whole pixel (white) + half pixel (gray) in x-direction
 	 * -> mean of 191.5 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 6:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5;
 	mitk::Point2D pnt2; pnt2[0] = 9.25; pnt2[1] = 3.5;
 	mitk::Point2D pnt3; pnt3[0] = 9.25; pnt3[1] = 4.5;
 	mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 191.5, 63.50, 128.63499999046327);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase7()
 {
 	/*****************************
 	 * half pixel (black) + whole pixel (white) + half pixel (gray) in x-direction
 	 * -> mean of 127.66 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 7:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5;
 	mitk::Point2D pnt2; pnt2[0] = 9.0; pnt2[1] = 3.5;
 	mitk::Point2D pnt3; pnt3[0] = 9.0; pnt3[1] = 4.0;
 	mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.0;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 127.666666666666667, 104.10358089689113, 128.7750015258789);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase8()
 {
 	/*****************************
 	 * whole pixel (gray)
 	 * -> mean of 128 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 8:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5;
 	mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 11.5;
 	mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 11.5;
 	mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 128.0, 0.0, 128.0);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase9()
 {
 	/*****************************
 	 * whole pixel (gray) + half pixel (white) in y-direction
 	 * -> mean of 191.5 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 9:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5;
 	mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 12.0;
 	mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 12.0;
 	mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 191.5, 63.50, 128.63499999046327);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase10()
 {
 	/*****************************
 	 * 2 whole pixel (white) + 2 whole pixel (black) in y-direction
 	 * -> mean of 127.66 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 10:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5;
 	mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 13.5;
 	mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 13.5;
 	mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 127.666666666666667, 104.10358089689113, 128.7750015258789);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase11()
 {
 	/*****************************
 	 * 9 whole pixels (white) + 3 half pixels (white)
 	 * + 3 whole pixel (black) [ + 3 slightly less than half pixels (black)]
 	 * -> mean of 204.0 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 11:-----------------------------------------------------------------------------------";
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 0.5; pnt1[1] = 0.5;
 	mitk::Point2D pnt2; pnt2[0] = 3.5; pnt2[1] = 3.5;
 	mitk::Point2D pnt3; pnt3[0] = 8.4999; pnt3[1] = 3.5;
 	mitk::Point2D pnt4; pnt4[0] = 5.4999; pnt4[1] = 0.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3,pnt4 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 204.0, 102.00, 253.724998474121083);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestCase12()
 {
 	/*****************************
 	 * half pixel (white) + whole pixel (white) + half pixel (black)
 	 * -> mean of 212.66 expected
 	 ******************************/
 	MITK_INFO << std::endl << "Test case 12:-----------------------------------------------------------------------------------";
 
 	std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.nrrd");
 	m_TestImage = mitk::IOUtil::Load<mitk::Image>(filename);
 	m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0);
 
 	mitk::Point2D pnt1; pnt1[0] = 9.5; pnt1[1] = 0.5;
 	mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 2.5;
 	mitk::Point2D pnt3; pnt3[0] = 11.5; pnt3[1] = 2.5;
 	std::vector<mitk::Point2D> points{ pnt1,pnt2,pnt3 };
         auto figure = GeneratePlanarPolygon(m_Geometry, points);
 
 	mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	planFigMaskGen->SetInputImage(m_TestImage);
         planFigMaskGen->SetPlanarFigure(figure.GetPointer());
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_TestImage, planFigMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	this->VerifyStatistics(statisticsObjectTimestep0, 212.666666666666667, 59.8683741404609923, 254.36499786376954);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::TestPic3DCroppedNoMask()
 {
 	MITK_INFO << std::endl << "Test Pic3D cropped without mask:-----------------------------------------------------------------------------------";
 
 	std::string Pic3DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D_cropped.nrrd");
 	m_Pic3DCroppedImage = mitk::IOUtil::Load<mitk::Image>(Pic3DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading Pic3D_cropped", m_Pic3DCroppedImage.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 27;
 	mitk::ImageStatisticsContainer::RealType expected_mean = -564.1481481481481481;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = 113.66666666666667;
         //mitk::ImageStatisticsContainer::RealType expected_median = -825;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = 0.7120461106763573;
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1.8794464383714844;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 140541.38545953357;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 374.88849736892911;
 	mitk::ImageStatisticsContainer::RealType expected_min = -927;
 	mitk::ImageStatisticsContainer::RealType expected_max = 147;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 677.35110431630551;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 2;
 	expected_minIndex[1] = 1;
 	expected_minIndex[2] = 1;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 0;
 	expected_maxIndex[1] = 1;
 	expected_maxIndex[2] = 2;
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_Pic3DCroppedImage));
 	auto statisticsObject = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	VerifyStatistics(statisticsObject,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::TestPic3DCroppedBinMask()
 {
 	MITK_INFO << std::endl << "Test Pic3D cropped binary mask:-----------------------------------------------------------------------------------";
 
 	std::string Pic3DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D_cropped.nrrd");
 	m_Pic3DCroppedImage = mitk::IOUtil::Load<mitk::Image>(Pic3DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading Pic3D_cropped", m_Pic3DCroppedImage.IsNotNull());
 
 	std::string Pic3DCroppedBinMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D_croppedBinMask.nrrd");
 	m_Pic3DCroppedBinMask = mitk::IOUtil::Load<mitk::Image>(Pic3DCroppedBinMaskFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading Pic3D binary mask", m_Pic3DCroppedBinMask.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1.0765697398089618;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = -nan("");
 	mitk::ImageStatisticsContainer::RealType expected_max = -22;
 	mitk::ImageStatisticsContainer::RealType expected_mean = -464;
 	mitk::ImageStatisticsContainer::RealType expected_min = -846;
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 4;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 595.42631785973322;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = 0.0544059290851858;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 373.14407405183323;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 139236.50;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 1;
 	expected_minIndex[1] = 0;
 	expected_minIndex[2] = 0;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 0;
 	expected_maxIndex[1] = 0;
 	expected_maxIndex[2] = 1;
 
 	mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New();
 	imgMaskGen->SetImageMask(m_Pic3DCroppedBinMask);
 	imgMaskGen->SetInputImage(m_Pic3DCroppedImage);
 	imgMaskGen->SetTimeStep(0);
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_Pic3DCroppedImage, imgMaskGen.GetPointer(), nullptr, 1));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	VerifyStatistics(statisticsObjectTimestep0,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::TestPic3DCroppedMultilabelMask()
 {
 	MITK_INFO << std::endl << "Test Pic3D cropped multilabel mask:-----------------------------------------------------------------------------------";
 
 	std::string Pic3DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D_cropped.nrrd");
 	m_Pic3DCroppedImage = mitk::IOUtil::Load<mitk::Image>(Pic3DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading Pic3D_cropped", m_Pic3DCroppedImage.IsNotNull());
 
 	std::string Pic3DCroppedMultilabelMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D_croppedMultilabelMask.nrrd");
 	m_Pic3DCroppedMultilabelMask = mitk::IOUtil::Load<mitk::Image>(Pic3DCroppedMultilabelMaskFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading Pic3D multilabel mask", m_Pic3DCroppedMultilabelMask.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1.5;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = -nan("");
 	mitk::ImageStatisticsContainer::RealType expected_max = -22;
 	mitk::ImageStatisticsContainer::RealType expected_mean = -586.33333333333333;
 	mitk::ImageStatisticsContainer::RealType expected_min = -916;
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 3;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 710.3006405741163;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = 0.6774469597523700;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 400.92421007245525;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 160740.22222222222;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 2;
 	expected_minIndex[1] = 0;
 	expected_minIndex[2] = 1;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 0;
 	expected_maxIndex[1] = 0;
 	expected_maxIndex[2] = 1;
 
 	mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New();
 	imgMaskGen->SetImageMask(m_Pic3DCroppedMultilabelMask);
 	imgMaskGen->SetInputImage(m_Pic3DCroppedImage);
 	imgMaskGen->SetTimeStep(0);
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_Pic3DCroppedImage, imgMaskGen.GetPointer(), nullptr, 2));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	VerifyStatistics(statisticsObjectTimestep0,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::TestPic3DCroppedPlanarFigure()
 {
 	MITK_INFO << std::endl << "Test Pic3D cropped planar figure:-----------------------------------------------------------------------------------";
 
 	std::string Pic3DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D_cropped.nrrd");
 	m_Pic3DCroppedImage = mitk::IOUtil::Load<mitk::Image>(Pic3DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading Pic3D_cropped", m_Pic3DCroppedImage.IsNotNull());
 
 	std::string Pic3DCroppedPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D_croppedPF.pf");
 	m_Pic3DCroppedPlanarFigure = mitk::IOUtil::Load<mitk::PlanarFigure>(Pic3DCroppedPlanarFigureFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading Pic3D planar figure", m_Pic3DCroppedPlanarFigure.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = -nan("");
 	mitk::ImageStatisticsContainer::RealType expected_max = -67;
 	mitk::ImageStatisticsContainer::RealType expected_mean = -446;
 	mitk::ImageStatisticsContainer::RealType expected_min = -825;
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 2;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 585.28369189650243;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = 0;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 379;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 143641;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 1;
 	expected_minIndex[1] = 1;
 	expected_minIndex[2] = 1;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 0;
 	expected_maxIndex[1] = 1;
 	expected_maxIndex[2] = 1;
 
 	mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	pfMaskGen->SetInputImage(m_Pic3DCroppedImage);
 	pfMaskGen->SetPlanarFigure(m_Pic3DCroppedPlanarFigure);
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_Pic3DCroppedImage, pfMaskGen.GetPointer()));
 	auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0);
 
 	VerifyStatistics(statisticsObjectTimestep0,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::TestUS4DCroppedNoMaskTimeStep1()
 {
 	MITK_INFO << std::endl << "Test US4D cropped without mask timestep 1:-----------------------------------------------------------------------------------";
 
         std::string US4DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_cropped.nrrd");
 	m_US4DCroppedImage = mitk::IOUtil::Load<mitk::Image>(US4DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D_cropped", m_US4DCroppedImage.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1.5398359155908228;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = 157.74074074074073;
 	mitk::ImageStatisticsContainer::RealType expected_max = 199;
 	mitk::ImageStatisticsContainer::RealType expected_mean = 157.74074074074073;
 	mitk::ImageStatisticsContainer::RealType expected_min = 101;
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 27;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 160.991718213494823;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = 0.0347280313508018;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 32.189936997387058;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 1036.19204389574722;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 0;
 	expected_minIndex[1] = 2;
 	expected_minIndex[2] = 0;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 0;
 	expected_maxIndex[1] = 0;
 	expected_maxIndex[2] = 1;
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer=mitk::ImageStatisticsContainer::New();
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_US4DCroppedImage));
 	auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1);
 
 	VerifyStatistics(statisticsObjectTimestep1,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::TestUS4DCroppedBinMaskTimeStep1()
 {
 	MITK_INFO << std::endl << "Test US4D cropped with binary mask timestep 1:-----------------------------------------------------------------------------------";
 
 	std::string US4DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_cropped.nrrd");
 	m_US4DCroppedImage = mitk::IOUtil::Load<mitk::Image>(US4DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D_cropped", m_US4DCroppedImage.IsNotNull());
 
 	std::string US4DCroppedBinMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_croppedBinMask.nrrd");
 	m_US4DCroppedBinMask = mitk::IOUtil::Load<mitk::Image>(US4DCroppedBinMaskFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D binary mask", m_US4DCroppedBinMask.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1.5863739712889191;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = 166.75;
 	mitk::ImageStatisticsContainer::RealType expected_max = 199;
 	mitk::ImageStatisticsContainer::RealType expected_mean = 166.75;
 	mitk::ImageStatisticsContainer::RealType expected_min = 120;
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 4;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 169.70636405273669;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = -0.4285540263894276;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 31.538666744172936;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 994.6874999999999;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 0;
 	expected_minIndex[1] = 0;
 	expected_minIndex[2] = 2;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 1;
 	expected_maxIndex[1] = 1;
 	expected_maxIndex[2] = 1;
 
 	mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New();
 	imgMask1->SetInputImage(m_US4DCroppedImage);
 	imgMask1->SetImageMask(m_US4DCroppedBinMask);
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer=mitk::ImageStatisticsContainer::New();
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_US4DCroppedImage, imgMask1.GetPointer(), nullptr, 1));
 	auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1);
 
 	VerifyStatistics(statisticsObjectTimestep1,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::TestUS4DCroppedMultilabelMaskTimeStep1()
 {
 	MITK_INFO << std::endl << "Test US4D cropped with mulitlabel mask timestep 1:-----------------------------------------------------------------------------------";
 
 	std::string US4DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_cropped.nrrd");
 	m_US4DCroppedImage = mitk::IOUtil::Load<mitk::Image>(US4DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D_cropped", m_US4DCroppedImage.IsNotNull());
 
 	std::string US4DCroppedMultilabelMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_croppedMultilabelMask.nrrd");
 	m_US4DCroppedMultilabelMask = mitk::IOUtil::Load<mitk::Image>(US4DCroppedMultilabelMaskFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D multilabel mask", m_US4DCroppedMultilabelMask.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1.0432484564918287;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = 159.75;
 	mitk::ImageStatisticsContainer::RealType expected_max = 199;
 	mitk::ImageStatisticsContainer::RealType expected_mean = 159.75;
 	mitk::ImageStatisticsContainer::RealType expected_min = 120;
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 4;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 163.74446555532802;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = -0.004329226115093;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 35.947009611371016;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 1292.187500000000227;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 0;
 	expected_minIndex[1] = 0;
 	expected_minIndex[2] = 2;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 0;
 	expected_maxIndex[1] = 0;
 	expected_maxIndex[2] = 1;
 
 	mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New();
 	imgMask1->SetInputImage(m_US4DCroppedImage);
 	imgMask1->SetImageMask(m_US4DCroppedMultilabelMask);
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_US4DCroppedImage, imgMask1.GetPointer(), nullptr, 1));
 	auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1);
 
 	VerifyStatistics(statisticsObjectTimestep1,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::TestUS4DCroppedPlanarFigureTimeStep1()
 {
 	MITK_INFO << std::endl << "Test US4D cropped planar figure timestep 1:-----------------------------------------------------------------------------------";
 
 	std::string US4DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_cropped.nrrd");
 	m_US4DCroppedImage = mitk::IOUtil::Load<mitk::Image>(US4DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D_cropped", m_US4DCroppedImage.IsNotNull());
 
 	std::string US4DCroppedPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_croppedPF.pf");
 	m_US4DCroppedPlanarFigure = mitk::IOUtil::Load<mitk::PlanarFigure>(US4DCroppedPlanarFigureFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D planar figure", m_US4DCroppedPlanarFigure.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = 172.5;
 	mitk::ImageStatisticsContainer::RealType expected_max = 197;
 	mitk::ImageStatisticsContainer::RealType expected_mean = 172.5;
 	mitk::ImageStatisticsContainer::RealType expected_min = 148;
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 2;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 174.23116827938679;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = 0;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 24.5;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 600.25;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 2;
 	expected_minIndex[1] = 2;
 	expected_minIndex[2] = 2;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 2;
 	expected_maxIndex[1] = 2;
 	expected_maxIndex[2] = 1;
 
 	mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New();
 	pfMaskGen->SetInputImage(m_US4DCroppedImage);
 	pfMaskGen->SetPlanarFigure(m_US4DCroppedPlanarFigure);
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer;
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_US4DCroppedImage, pfMaskGen.GetPointer()));
 	auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1);
 
 	VerifyStatistics(statisticsObjectTimestep1,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestUS4DCroppedAllTimesteps()
 {
 	MITK_INFO << std::endl << "Test US4D cropped all timesteps:-----------------------------------------------------------------------------------";
 
 	std::string US4DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_cropped.nrrd");
 	m_US4DCroppedImage = mitk::IOUtil::Load<mitk::Image>(US4DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D_cropped", m_US4DCroppedImage.IsNotNull());
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer=mitk::ImageStatisticsContainer::New();
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_US4DCroppedImage));
 	for (int i = 0; i < 4; i++)
 	{
 		CPPUNIT_ASSERT_MESSAGE("Error computing statistics for multiple timestep", statisticsContainer->TimeStepExists(i));
 	}
 }
 
 void mitkImageStatisticsCalculatorTestSuite::TestUS4DCropped3DMask()
 {
 	MITK_INFO << std::endl << "Test US4D cropped with 3D binary Mask:-----------------------------------------------------------------------------------";
 
 	std::string US4DCroppedFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_cropped.nrrd");
 	m_US4DCroppedImage = mitk::IOUtil::Load<mitk::Image>(US4DCroppedFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading US4D_cropped", m_US4DCroppedImage.IsNotNull());
 
 	std::string US4DCropped3DBinMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D_cropped3DBinMask.nrrd");
 	m_US4DCropped3DBinMask = mitk::IOUtil::Load<mitk::Image>(US4DCropped3DBinMaskFile);
 	CPPUNIT_ASSERT_MESSAGE("Failed loading Pic3D binary mask", m_US4DCropped3DBinMask.IsNotNull());
 	//calculated ground truth via script
 	mitk::ImageStatisticsContainer::RealType expected_kurtosis = 1;
 	mitk::ImageStatisticsContainer::RealType expected_MPP = 198;
 	mitk::ImageStatisticsContainer::RealType expected_max = 199;
 	mitk::ImageStatisticsContainer::RealType expected_mean = 198;
 	mitk::ImageStatisticsContainer::RealType expected_min = 197;
 	mitk::ImageStatisticsContainer::VoxelCountType expected_N = 2;
 	mitk::ImageStatisticsContainer::RealType expected_RMS = 198.00252523642217;
 	mitk::ImageStatisticsContainer::RealType expected_skewness = 0;
 	mitk::ImageStatisticsContainer::RealType expected_standarddev = 1;
 	mitk::ImageStatisticsContainer::RealType expected_variance = 1;
 	mitk::ImageStatisticsContainer::IndexType expected_minIndex;
 	expected_minIndex.set_size(3);
 	expected_minIndex[0] = 1;
 	expected_minIndex[1] = 2;
 	expected_minIndex[2] = 1;
 
 	mitk::ImageStatisticsContainer::IndexType expected_maxIndex;
 	expected_maxIndex.set_size(3);
 	expected_maxIndex[0] = 1;
 	expected_maxIndex[1] = 1;
 	expected_maxIndex[2] = 1;
 
 	mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New();
 	imgMask1->SetInputImage(m_US4DCroppedImage);
 	imgMask1->SetImageMask(m_US4DCropped3DBinMask);
 
 	mitk::ImageStatisticsContainer::Pointer statisticsContainer = mitk::ImageStatisticsContainer::New();
 	CPPUNIT_ASSERT_NO_THROW(statisticsContainer = ComputeStatistics(m_US4DCroppedImage, imgMask1.GetPointer(), nullptr, 1));
 	auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1);
 
 	VerifyStatistics(statisticsObjectTimestep1,
 		expected_N,
 		expected_mean,
 		expected_MPP,
 		expected_skewness,
 		expected_kurtosis,
 		expected_variance,
 		expected_standarddev,
 		expected_min,
 		expected_max,
 		expected_RMS,
 		expected_minIndex,
 		expected_maxIndex);
 }
 
 mitk::PlanarPolygon::Pointer mitkImageStatisticsCalculatorTestSuite::GeneratePlanarPolygon(mitk::PlaneGeometry::Pointer geometry, std::vector <mitk::Point2D> points)
 {
 	mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New();
 	figure->SetPlaneGeometry(geometry);
 	figure->PlaceFigure(points[0]);
         for (unsigned int i = 1; i < points.size(); i++)
 	{
 		figure->SetControlPoint(i, points[i], true);
 	}
 	return figure;
 }
 
 const mitk::ImageStatisticsContainer::Pointer
 mitkImageStatisticsCalculatorTestSuite::ComputeStatistics(mitk::Image::ConstPointer image,
 	mitk::MaskGenerator::Pointer maskGen,
 	mitk::MaskGenerator::Pointer secondardMaskGen,
 	unsigned short label)
 {
 	mitk::ImageStatisticsCalculator::Pointer imgStatCalc = mitk::ImageStatisticsCalculator::New();
 	imgStatCalc->SetInputImage(image);
 
 	if (maskGen.IsNotNull())
 	{
 		imgStatCalc->SetMask(maskGen.GetPointer());
 		if (secondardMaskGen.IsNotNull())
 		{
 			imgStatCalc->SetSecondaryMask(secondardMaskGen.GetPointer());
 		}
 	}
 
 	return imgStatCalc->GetStatistics(label);
 }
 
 void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsContainer::ImageStatisticsObject stats,
 	mitk::ImageStatisticsContainer::RealType testMean, mitk::ImageStatisticsContainer::RealType testSD, mitk::ImageStatisticsContainer::RealType testMedian)
 {
     mitk::ImageStatisticsContainer::RealType meanObject = 0;
     mitk::ImageStatisticsContainer::RealType standardDeviationObject = 0;
     mitk::ImageStatisticsContainer::RealType medianObject = 0;
 	CPPUNIT_ASSERT_NO_THROW(meanObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::MEAN()));
 	CPPUNIT_ASSERT_NO_THROW(standardDeviationObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::STANDARDDEVIATION()));
 	CPPUNIT_ASSERT_NO_THROW(medianObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::MEDIAN()));
 	CPPUNIT_ASSERT_MESSAGE("Calculated mean grayvalue is not equal to the desired value.", std::abs(meanObject - testMean) < mitk::eps);
 	CPPUNIT_ASSERT_MESSAGE("Calculated grayvalue sd is not equal to the desired value.", std::abs(standardDeviationObject - testSD) < mitk::eps);
 	CPPUNIT_ASSERT_MESSAGE("Calculated median grayvalue is not equal to the desired value.", std::abs(medianObject - testMedian) < mitk::eps);
 }
 
 // T26098 histogram statistics need to be tested (median, uniformity, UPP, entropy)
 void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsContainer::ImageStatisticsObject stats,
 	mitk::ImageStatisticsContainer::VoxelCountType N,
 	mitk::ImageStatisticsContainer::RealType mean,
 	mitk::ImageStatisticsContainer::RealType MPP,
 	mitk::ImageStatisticsContainer::RealType skewness,
 	mitk::ImageStatisticsContainer::RealType kurtosis,
 	mitk::ImageStatisticsContainer::RealType variance,
 	mitk::ImageStatisticsContainer::RealType stdev,
 	mitk::ImageStatisticsContainer::RealType min,
 	mitk::ImageStatisticsContainer::RealType max,
 	mitk::ImageStatisticsContainer::RealType RMS,
 	mitk::ImageStatisticsContainer::IndexType minIndex,
 	mitk::ImageStatisticsContainer::IndexType maxIndex)
 {
   mitk::ImageStatisticsContainer::VoxelCountType numberOfVoxelsObject;
   mitk::ImageStatisticsContainer::RealType meanObject = 0;
   mitk::ImageStatisticsContainer::RealType mppObject = 0;
   mitk::ImageStatisticsContainer::RealType skewnessObject = 0;
   mitk::ImageStatisticsContainer::RealType kurtosisObject = 0;
   mitk::ImageStatisticsContainer::RealType varianceObject = 0;
   mitk::ImageStatisticsContainer::RealType standardDeviationObject = 0;
   mitk::ImageStatisticsContainer::RealType minObject = 0;
   mitk::ImageStatisticsContainer::RealType maxObject = 0;
   mitk::ImageStatisticsContainer::RealType rmsObject = 0;
-  mitk::ImageStatisticsContainer::IndexType minIndexObject = {0, 0, 0};
-  mitk::ImageStatisticsContainer::IndexType maxIndexObject = {0, 0, 0};
+  mitk::ImageStatisticsContainer::IndexType minIndexObject(3,0);
+  mitk::ImageStatisticsContainer::IndexType maxIndexObject(3,0);
 	CPPUNIT_ASSERT_NO_THROW(numberOfVoxelsObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::VoxelCountType>(mitk::ImageStatisticsConstants::NUMBEROFVOXELS()));
 	CPPUNIT_ASSERT_NO_THROW(meanObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::MEAN()));
 	CPPUNIT_ASSERT_NO_THROW(mppObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::MPP()));
 	CPPUNIT_ASSERT_NO_THROW(skewnessObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::SKEWNESS()));
 	CPPUNIT_ASSERT_NO_THROW(kurtosisObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::KURTOSIS()));
 	CPPUNIT_ASSERT_NO_THROW(varianceObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::VARIANCE()));
 	CPPUNIT_ASSERT_NO_THROW(standardDeviationObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::STANDARDDEVIATION()));
 	CPPUNIT_ASSERT_NO_THROW(minObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::MINIMUM()));
 	CPPUNIT_ASSERT_NO_THROW(maxObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::MAXIMUM()));
 	CPPUNIT_ASSERT_NO_THROW(rmsObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::RealType>(mitk::ImageStatisticsConstants::RMS()));
 	CPPUNIT_ASSERT_NO_THROW(minIndexObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::IndexType>(mitk::ImageStatisticsConstants::MINIMUMPOSITION()));
 	CPPUNIT_ASSERT_NO_THROW(maxIndexObject = stats.GetValueConverted<mitk::ImageStatisticsContainer::IndexType>(mitk::ImageStatisticsConstants::MAXIMUMPOSITION()));
 
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", numberOfVoxelsObject - N == 0);
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(meanObject - mean) < mitk::eps);
 	// in three test cases MPP is None because the roi has no positive pixels
 	if (!std::isnan(mppObject))
 	{
 		CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(mppObject - MPP) < mitk::eps);
 	}
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(skewnessObject - skewness) < mitk::eps);
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(kurtosisObject - kurtosis) < mitk::eps);
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(varianceObject - variance) < mitk::eps);
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(standardDeviationObject - stdev) < mitk::eps);
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(minObject - min) < mitk::eps);
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(maxObject - max) < mitk::eps);
 	CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(rmsObject - RMS) < mitk::eps);
 	for (unsigned int i = 0; i < minIndex.size(); ++i)
 	{
 		CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(minIndexObject[i] - minIndex[i]) < mitk::eps);
 	}
 	for (unsigned int i = 0; i < maxIndex.size(); ++i)
 	{
 		CPPUNIT_ASSERT_MESSAGE("Calculated value does not fit expected value", std::abs(maxIndexObject[i] - maxIndex[i]) < mitk::eps);
 	}
 }
 MITK_TEST_SUITE_REGISTRATION(mitkImageStatisticsCalculator)
diff --git a/Modules/IpPicSupportIO/Internal/mitkPicFileReader.cpp b/Modules/IpPicSupportIO/Internal/mitkPicFileReader.cpp
index 2a5c956b32..61884011f1 100644
--- a/Modules/IpPicSupportIO/Internal/mitkPicFileReader.cpp
+++ b/Modules/IpPicSupportIO/Internal/mitkPicFileReader.cpp
@@ -1,299 +1,299 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkPicFileReader.h"
 #include "mitkPicHelper.h"
 
 #include "mitkCustomMimeType.h"
 #include "mitkImageWriteAccessor.h"
 
 #include <mitkIpPic.h>
 
 
 static mitk::PixelType CastToPixelType(mitkIpPicType_t pictype, size_t bpe)
 {
   const bool isSignedIntegralType = (pictype == mitkIpPicInt);
   const bool isUnsignedIntegralType = (pictype == mitkIpPicUInt);
 
   if (isSignedIntegralType)
   {
     switch (bpe)
     {
     case sizeof(char) :
       return mitk::MakeScalarPixelType<char>();
     case sizeof(short) :
       return mitk::MakeScalarPixelType<short>();
     default:
       return mitk::MakeScalarPixelType<int>();
     }
   }
   else if (isUnsignedIntegralType)
   {
     switch (bpe)
     {
     case sizeof(unsigned char) :
       return mitk::MakeScalarPixelType<unsigned char>();
     case sizeof(unsigned short) :
       return mitk::MakeScalarPixelType<unsigned short>();
     default:
       return mitk::MakeScalarPixelType<unsigned int>();
     }
   }
   else // is floating point type
   {
     switch (bpe)
     {
     case sizeof(float) :
       return mitk::MakeScalarPixelType<float>();
     default:
       return mitk::MakeScalarPixelType<double>();
     }
   }
 }
 
 static mitk::ImageDescriptor::Pointer CastToImageDescriptor(mitkIpPicDescriptor *desc)
 {
   mitk::ImageDescriptor::Pointer imDescriptor = mitk::ImageDescriptor::New();
 
   imDescriptor->Initialize(desc->n, desc->dim);
 
   mitk::PixelType ptype = ::CastToPixelType(desc->type, (desc->bpe / 8));
   imDescriptor->AddNewChannel(ptype, "imported by pic");
 
   return imDescriptor;
 }
 
 static mitkIpPicType_t CastToIpPicType(int intype)
 {
   const bool isSignedIntegralType = (intype == itk::ImageIOBase::INT || intype == itk::ImageIOBase::SHORT ||
     intype == itk::ImageIOBase::CHAR || intype == itk::ImageIOBase::LONG);
 
   const bool isUnsignedIntegralType = (intype == itk::ImageIOBase::UINT || intype == itk::ImageIOBase::USHORT ||
     intype == itk::ImageIOBase::UCHAR || intype == itk::ImageIOBase::ULONG);
 
   const bool isFloatingPointType = (intype == itk::ImageIOBase::FLOAT || intype == itk::ImageIOBase::DOUBLE);
 
   if (isSignedIntegralType)
     return mitkIpPicInt;
   if (isUnsignedIntegralType)
     return mitkIpPicUInt;
   if (isFloatingPointType)
     return mitkIpPicFloat;
   return mitkIpPicUnknown;
 }
 
 static mitkIpPicDescriptor * CastToIpPicDescriptor(mitk::Image::Pointer refImg,
   mitk::ImageWriteAccessor *imageAccess,
   mitkIpPicDescriptor *picDesc)
 {
   const mitk::ImageDescriptor::Pointer imDesc = refImg->GetImageDescriptor();
 
   // initialize dimension information
   for (unsigned int i = 0; i < 8; i++)
   {
     picDesc->n[i] = 1;
   }
 
   // set dimension information
   picDesc->dim = refImg->GetDimension();
   memcpy(picDesc->n, imDesc->GetDimensions(), picDesc->dim * sizeof(unsigned int));
 
   picDesc->type = ::CastToIpPicType(refImg->GetPixelType().GetComponentType());
   picDesc->bpe = refImg->GetPixelType().GetBpe();
   if (imageAccess != nullptr)
   {
     picDesc->data = imageAccess->GetData();
   }
 
   return picDesc;
 }
 
 
 mitk::PicFileReader::PicFileReader() : AbstractFileReader()
 {
   CustomMimeType mimeType(this->GetMimeTypePrefix() + "mbipic");
   mimeType.AddExtension("pic");
   mimeType.AddExtension("pic.gz");
   mimeType.AddExtension("PIC");
   mimeType.AddExtension("PIC.gz");
   mimeType.SetCategory("Images");
   mimeType.SetComment("DKFZ Legacy PIC Format");
 
   this->SetMimeType(mimeType);
   this->SetDescription("DKFZ PIC");
 
   this->RegisterService();
 }
 
-std::vector<mitk::BaseData::Pointer> mitk::PicFileReader::Read()
+std::vector<mitk::BaseData::Pointer> mitk::PicFileReader::DoRead()
 {
   mitk::Image::Pointer image = this->CreateImage();
   this->FillImage(image);
   std::vector<BaseData::Pointer> result;
   result.push_back(image.GetPointer());
   return result;
 }
 
 mitk::Image::Pointer mitk::PicFileReader::CreateImage()
 {
   Image::Pointer output = Image::New();
 
   std::string fileName = this->GetLocalFileName();
 
   mitkIpPicDescriptor *header = mitkIpPicGetHeader(fileName.c_str(), nullptr);
 
   if (!header)
   {
     mitkThrow() << "File could not be read.";
   }
 
   header = mitkIpPicGetTags(fileName.c_str(), header);
 
   int channels = 1;
 
   mitkIpPicTSV_t *tsv;
   if ((tsv = mitkIpPicQueryTag(header, "SOURCE HEADER")) != nullptr)
   {
     if (tsv->n[0] > 1e+06)
     {
       mitkIpPicTSV_t *tsvSH;
       tsvSH = mitkIpPicDelTag(header, "SOURCE HEADER");
       mitkIpPicFreeTag(tsvSH);
     }
   }
   if ((tsv = mitkIpPicQueryTag(header, "ICON80x80")) != nullptr)
   {
     mitkIpPicTSV_t *tsvSH;
     tsvSH = mitkIpPicDelTag(header, "ICON80x80");
     mitkIpPicFreeTag(tsvSH);
   }
   if ((tsv = mitkIpPicQueryTag(header, "VELOCITY")) != nullptr)
   {
     ++channels;
     mitkIpPicDelTag(header, "VELOCITY");
   }
 
   if (header == nullptr || header->bpe == 0)
   {
     mitkThrow() << " Could not read file " << fileName;
   }
 
   // if pic image only 2D, the n[2] value is not initialized
   unsigned int slices = 1;
   if (header->dim == 2)
   {
     header->n[2] = slices;
   }
 
   // First initialize the geometry of the output image by the pic-header
   SlicedGeometry3D::Pointer slicedGeometry = mitk::SlicedGeometry3D::New();
   PicHelper::InitializeEvenlySpaced(header, header->n[2], slicedGeometry);
 
   // if pic image only 3D, the n[3] value is not initialized
   unsigned int timesteps = 1;
   if (header->dim > 3)
   {
     timesteps = header->n[3];
   }
 
   slicedGeometry->ImageGeometryOn();
   ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New();
   timeGeometry->Initialize(slicedGeometry, timesteps);
 
   // Cast the pic descriptor to ImageDescriptor and initialize the output
 
   output->Initialize(CastToImageDescriptor(header));
   output->SetTimeGeometry(timeGeometry);
   mitkIpPicFree(header);
 
   return output;
 }
 
 void mitk::PicFileReader::ConvertHandedness(mitkIpPicDescriptor *pic)
 {
   // left to right handed conversion
   if (pic->dim >= 3)
   {
     mitkIpPicDescriptor *slice = mitkIpPicCopyHeader(pic, nullptr);
     slice->dim = 2;
     size_t size = _mitkIpPicSize(slice);
     slice->data = malloc(size);
 
     size_t v, volumes = (pic->dim > 3 ? pic->n[3] : 1);
     size_t volume_size = size * pic->n[2];
 
     for (v = 0; v < volumes; ++v)
     {
       auto *p_first = (unsigned char *)pic->data;
       auto *p_last = (unsigned char *)pic->data;
       p_first += v * volume_size;
       p_last += size * (pic->n[2] - 1) + v * volume_size;
 
       size_t i, smid = pic->n[2] / 2;
       for (i = 0; i < smid; ++i, p_last -= size, p_first += size)
       {
         memcpy(slice->data, p_last, size);
         memcpy(p_last, p_first, size);
         memcpy(p_first, slice->data, size);
       }
     }
     mitkIpPicFree(slice);
   }
 }
 
 mitk::PicFileReader *mitk::PicFileReader::Clone() const
 {
   return new PicFileReader(*this);
 }
 
 void mitk::PicFileReader::FillImage(Image::Pointer output)
 {
   mitkIpPicDescriptor *outputPic = mitkIpPicNew();
   outputPic = CastToIpPicDescriptor(output, nullptr, outputPic);
   mitkIpPicDescriptor *pic = mitkIpPicGet(this->GetLocalFileName().c_str(), outputPic);
   // comes upside-down (in MITK coordinates) from PIC file
   ConvertHandedness(pic);
 
   mitkIpPicTSV_t *tsv;
   if ((tsv = mitkIpPicQueryTag(pic, "SOURCE HEADER")) != nullptr)
   {
     if (tsv->n[0] > 1e+06)
     {
       mitkIpPicTSV_t *tsvSH;
       tsvSH = mitkIpPicDelTag(pic, "SOURCE HEADER");
       mitkIpPicFreeTag(tsvSH);
     }
   }
   if ((tsv = mitkIpPicQueryTag(pic, "ICON80x80")) != nullptr)
   {
     mitkIpPicTSV_t *tsvSH;
     tsvSH = mitkIpPicDelTag(pic, "ICON80x80");
     mitkIpPicFreeTag(tsvSH);
   }
   if ((tsv = mitkIpPicQueryTag(pic, "VELOCITY")) != nullptr)
   {
     mitkIpPicDescriptor *header = mitkIpPicCopyHeader(pic, nullptr);
     header->data = tsv->value;
     ConvertHandedness(header);
     output->SetChannel(header->data, 1);
     header->data = nullptr;
     mitkIpPicFree(header);
     mitkIpPicDelTag(pic, "VELOCITY");
   }
 
   // Copy the memory to avoid mismatches of malloc() and delete[].
   // mitkIpPicGet will always allocate a new memory block with malloc(),
   // but MITK Images delete the data via delete[].
   output->SetImportChannel(pic->data, 0, Image::CopyMemory);
   pic->data = nullptr;
   mitkIpPicFree(pic);
 }
diff --git a/Modules/IpPicSupportIO/Internal/mitkPicFileReader.h b/Modules/IpPicSupportIO/Internal/mitkPicFileReader.h
index e22f15614f..f472490732 100644
--- a/Modules/IpPicSupportIO/Internal/mitkPicFileReader.h
+++ b/Modules/IpPicSupportIO/Internal/mitkPicFileReader.h
@@ -1,47 +1,48 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef PICFILEREADER_H_HEADER_INCLUDED_C1F48A22
 #define PICFILEREADER_H_HEADER_INCLUDED_C1F48A22
 
 #include "mitkAbstractFileReader.h"
 
 #include "mitkImage.h"
 
 #include "mitkIpPic.h"
 
 namespace mitk
 {
   //##Documentation
   //## @brief Reader to read files in DKFZ-pic-format
   class PicFileReader : public AbstractFileReader
   {
   public:
     PicFileReader();
 
     using AbstractFileReader::Read;
-    std::vector<mitk::BaseData::Pointer> Read() override;
 
   protected:
     void FillImage(Image::Pointer image);
 
     Image::Pointer CreateImage();
 
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     static void ConvertHandedness(mitkIpPicDescriptor *pic);
 
     PicFileReader *Clone() const override;
   };
 
 } // namespace mitk
 
 #endif /* PICFILEREADER_H_HEADER_INCLUDED_C1F48A22 */
diff --git a/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.cpp b/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.cpp
index 72b1e39152..8e809e044b 100644
--- a/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.cpp
+++ b/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.cpp
@@ -1,315 +1,280 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <iostream>
 #include <fstream>
 
 #include <clocale>
 
 #include "mapRegistration.h"
 #include "mapRegistrationFileWriter.h"
 #include "mapRegistrationFileReader.h"
 #include "mapLazyFileFieldKernelLoader.h"
 
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
+#include <mitkLocaleSwitch.h>
 
 #include "mitkMAPRegistrationWrapperIO.h"
 #include "mitkMAPRegistrationWrapper.h"
 
 namespace mitk
 {
 
-  /** Helper structure to change (and reset) the
-  * local settings in a function scope*/
-  struct LocaleSwitch
-  {
-    LocaleSwitch(const std::string& newLocale)
-      : m_OldLocale(std::setlocale(LC_ALL, nullptr))
-      , m_NewLocale(newLocale)
-    {
-      if (m_OldLocale == nullptr)
-      {
-        m_OldLocale = "";
-      }
-      else if (m_NewLocale != m_OldLocale)
-      {
-        // set the locale
-        if (std::setlocale(LC_ALL, m_NewLocale.c_str()) == nullptr)
-        {
-          MITK_INFO << "Could not set locale " << m_NewLocale;
-          m_OldLocale = nullptr;
-        }
-      }
-    }
-
-    ~LocaleSwitch()
-    {
-      if (m_OldLocale != nullptr && std::setlocale(LC_ALL, m_OldLocale) == nullptr)
-      {
-        MITK_INFO << "Could not reset locale " << m_OldLocale;
-      }
-    }
-
-  private:
-    const char* m_OldLocale;
-    const std::string m_NewLocale;
-  };
-
   /** Helper class that allows to use an functor in multiple combinations of
   * moving and target dimensions on a passed MAPRegistrationWrapper instance.\n
   * DimHelperSub is used DimHelper to iterate in a row of the dimension
   * combination matrix.
   */
   template< unsigned int i, unsigned int j, template < unsigned int,  unsigned int> class TFunctor>
   class DimHelperSub
   {
   public:
     static bool Execute(const mitk::MAPRegistrationWrapper* obj, const map::core::String& data)
     {
       if (TFunctor<i,j>::Execute(obj, data))
       {
         return true;
       }
       return DimHelperSub<i,j-1,TFunctor>::Execute(obj, data);
     }
   };
 
   /** Specialized template version of DimSubHelper that indicates the end
   * of the row in the dimension combination matrix, thus does nothing.
   */
   template< unsigned int i, template < unsigned int,  unsigned int> class TFunctor>
   class DimHelperSub<i,1,TFunctor >
   {
   public:
     static bool Execute(const mitk::MAPRegistrationWrapper*, const map::core::String&)
     {
       //just unwind. Go to the next "row" with DimHelper
       return false;
     }
   };
 
   /** Helper class that allows to use an functor in multiple combinations of
   * moving and target dimensions on a passed MAPRegistrationWrapper instance.\n
   * It is helpful if you want to ensure that all combinations are checked/touched
   * (e.g. 3D 3D, 3D 2D, 2D 3D, 2D 2D) without generating a large switch yard.
   * Think of n*m matrix (indicating the posible combinations). DimHelper walks from
   * one row to the next and uses DimHelperSub to iterate in a row.\n
   * For every element of the matrix the functor is executed on the passed object.
   */
   template< unsigned int i,  unsigned int j, template < unsigned int,  unsigned int> class TFunctor>
   class DimHelper{
   public:
     static bool Execute(const mitk::MAPRegistrationWrapper* obj, const map::core::String& data = "")
     {
       if (DimHelperSub<i,j,TFunctor>::Execute(obj, data))
       {
         return true;
       }
       return DimHelper<i-1,j,TFunctor>::Execute(obj, data);
     }
   };
 
   /** Specialized template version of DimHelper that indicates the end
   * of the dimension combination matrix, thus does nothing.
   */
   template< unsigned int j, template < unsigned int,  unsigned int> class TFunctor>
   class DimHelper<1,j, TFunctor >
   {
   public:
     static bool Execute(const mitk::MAPRegistrationWrapper*, const map::core::String&)
     {
       //just unwind. We are done.
       return false;
     }
   };
 
   /** Functor that checks of the dimension of the registration is supported and can
   * be written.
   */
   template<unsigned int i, unsigned int j>
   class CanWrite
   {
   public:
     static bool Execute(const mitk::MAPRegistrationWrapper* obj, const map::core::String& = "")
     {
       bool result = false;
 
       result = dynamic_cast<const map::core::Registration<i,j> *>(obj->GetRegistration()) != nullptr;
 
       return result;
     }
   };
 
   /** Functor that writes the registration to a file if it has the right dimensionality.
   */
   template<unsigned int i, unsigned int j>
   class WriteReg
   {
   public:
     static bool Execute(const mitk::MAPRegistrationWrapper* obj, const map::core::String& data)
     {
       const map::core::Registration<i,j>* pReg = dynamic_cast<const map::core::Registration<i,j>*>(obj->GetRegistration());
       if (pReg == nullptr)
       {
         return false;
       }
 
       typedef map::io::RegistrationFileWriter<i,j> WriterType;
       typename WriterType::Pointer writer = WriterType::New();
 
       writer->setExpandLazyKernels(false);
 
       try
       {
         writer->write(pReg,data);
       }
       catch (const itk::ExceptionObject& e)
       {
         std::cout << e.what() << std::endl;
         throw;
       }
 
       return true;
     }
   };
 
   MAPRegistrationWrapperIO::MAPRegistrationWrapperIO(const MAPRegistrationWrapperIO& other)
     : AbstractFileIO(other)
   {
   }
 
   MAPRegistrationWrapperIO::MAPRegistrationWrapperIO() : AbstractFileIO(mitk::MAPRegistrationWrapper::GetStaticNameOfClass())
   {
     std::string category = "MatchPoint Registration File";
     CustomMimeType customMimeType;
     customMimeType.SetCategory(category);
     customMimeType.AddExtension("mapr");
     this->AbstractFileIOWriter::SetMimeType(customMimeType);
     this->AbstractFileIOWriter::SetDescription(category);
 
     customMimeType.AddExtension("mapr.xml");
     customMimeType.AddExtension("MAPR");
     customMimeType.AddExtension("MAPR.XML");
     this->AbstractFileIOReader::SetMimeType(customMimeType);
     this->AbstractFileIOReader::SetDescription(category);
 
     this->RegisterService();
   }
 
 
   void MAPRegistrationWrapperIO::Write()
   {
     bool success = false;
     const BaseData* input = this->GetInput();
     if (input == nullptr)
     {
       mitkThrow() << "Cannot write data. Data pointer is nullptr.";
     }
 
     const mitk::MAPRegistrationWrapper* wrapper = dynamic_cast<const mitk::MAPRegistrationWrapper*>(input);
     if (wrapper == nullptr)
     {
       mitkThrow() << "Cannot write data. Data pointer is not a Registration wrapper.";
     }
 
     std::ostream* writeStream = this->GetOutputStream();
     std::string fileName = this->GetOutputLocation();
     if (writeStream)
     {
       fileName = this->GetLocalFileName();
     }
 
     // Switch the current locale to "C"
     LocaleSwitch localeSwitch("C");
 
     try
     {
       success = DimHelper<3,3,WriteReg>::Execute(wrapper, fileName);
     }
     catch (const std::exception& e)
     {
       mitkThrow() << e.what();
     }
 
     if (!success)
     {
       mitkThrow() << "Cannot write registration. Currently only registrations up to 4D are supported.";
     }
   }
 
   AbstractFileIO::ConfidenceLevel MAPRegistrationWrapperIO::GetWriterConfidenceLevel() const
   {
     const mitk::MAPRegistrationWrapper* regWrapper =  dynamic_cast<const mitk::MAPRegistrationWrapper*>(this->GetInput());
 
     if (regWrapper == nullptr)
     {
       return IFileWriter::Unsupported;
     }
 
     // Check if the registration dimension is supported
     if (! DimHelper<3,3,CanWrite>::Execute(regWrapper))
     {
       return IFileWriter::Unsupported;
     };
 
     return IFileWriter::Supported;
   }
 
-  std::vector<BaseData::Pointer >  MAPRegistrationWrapperIO::Read()
+  std::vector<BaseData::Pointer >  MAPRegistrationWrapperIO::DoRead()
   {
     std::vector<BaseData::Pointer > result;
 
     LocaleSwitch("C");
 
     std::string fileName = this->GetLocalFileName();
     if ( fileName.empty() )
     {
       mitkThrow() << "Cannot read file. Filename has not been set!";
     }
 
     /* Remove the following kernel loader provider because in MITK no lazy file loading should be used
     due to conflicts with session loading (end there usage of temporary directories)*/
     map::io::RegistrationFileReader::LoaderStackType::unregisterProvider(map::io::LazyFileFieldKernelLoader<2,2>::getStaticProviderName());
     map::io::RegistrationFileReader::LoaderStackType::unregisterProvider(map::io::LazyFileFieldKernelLoader<3,3>::getStaticProviderName());
 
     map::io::RegistrationFileReader::Pointer spReader = map::io::RegistrationFileReader::New();
     spReader->setPreferLazyLoading(true);
     map::core::RegistrationBase::Pointer spReg = spReader->read(fileName);
     mitk::MAPRegistrationWrapper::Pointer spRegWrapper = mitk::MAPRegistrationWrapper::New();
     spRegWrapper->SetRegistration(spReg);
 
     result.push_back(spRegWrapper.GetPointer());
     return result;
   }
 
   AbstractFileIO::ConfidenceLevel MAPRegistrationWrapperIO::GetReaderConfidenceLevel() const
   {
     AbstractFileIO::ConfidenceLevel result = IFileReader::Unsupported;
 
     std::string fileName = this->GetLocalFileName();
     std::ifstream in( fileName.c_str() );
     if ( in.good() )
     {
       result = IFileReader::Supported;
     }
 
     in.close();
     return result;
   }
 
   MAPRegistrationWrapperIO* MAPRegistrationWrapperIO::IOClone() const
   {
     return new MAPRegistrationWrapperIO(*this);
   }
 
 }
diff --git a/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.h b/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.h
index 62f7180a03..cf3042e9ed 100644
--- a/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.h
+++ b/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.h
@@ -1,49 +1,51 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef _MITK_MAP_REGISTRATION_WRAPPER_IO_H
 #define _MITK_MAP_REGISTRATION_WRAPPER_IO_H
 
 #include <mitkAbstractFileIO.h>
 
 #include "MitkMatchPointRegistrationExports.h"
 
 namespace mitk
 {
   /**
   * Offers IO capability for MatchPoint registration wrappers
   */
   class MAPRegistrationWrapperIO : public AbstractFileIO
   {
   public:
 
     MAPRegistrationWrapperIO();
 
     // -------------- AbstractFileReader -------------
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData> > Read() override;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
     void Write() override;
     ConfidenceLevel GetWriterConfidenceLevel() const override;
 
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     MAPRegistrationWrapperIO(const MAPRegistrationWrapperIO& other);
     MAPRegistrationWrapperIO* IOClone() const override;
   };
 
 
 } // end of namespace mitk
 
 #endif
diff --git a/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.cpp b/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.cpp
index ef826f915d..a76440f531 100644
--- a/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.cpp
+++ b/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.cpp
@@ -1,123 +1,123 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkMAPRegistrationWrapperObjectFactory.h"
 
 #include <mitkProperties.h>
 #include <mitkBaseRenderer.h>
 #include <mitkDataNode.h>
 
 #include "mitkRegistrationWrapperMapper2D.h"
 #include "mitkRegistrationWrapperMapper3D.h"
 #include "mitkMAPRegistrationWrapper.h"
 
 typedef std::multimap<std::string, std::string> MultimapType;
 
 mitk::MAPRegistrationWrapperObjectFactory::MAPRegistrationWrapperObjectFactory()
 : CoreObjectFactoryBase()
 {
   static bool alreadyDone = false;
   if (!alreadyDone)
   {
     alreadyDone = true;
   }
 
 }
 
 mitk::MAPRegistrationWrapperObjectFactory::~MAPRegistrationWrapperObjectFactory()
 {
 }
 
 mitk::Mapper::Pointer
 mitk::MAPRegistrationWrapperObjectFactory::
 CreateMapper(mitk::DataNode* node, MapperSlotId slotId)
 {
     mitk::Mapper::Pointer newMapper=nullptr;
 
     if ( slotId == mitk::BaseRenderer::Standard2D )
     {
         std::string classname("MAPRegistrationWrapper");
         if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0)
         {
           newMapper = mitk::MITKRegistrationWrapperMapper2D::New();
           newMapper->SetDataNode(node);
         }
     }
     else if ( slotId == mitk::BaseRenderer::Standard3D )
     {
       std::string classname("MAPRegistrationWrapper");
       if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0)
       {
         newMapper = mitk::MITKRegistrationWrapperMapper3D::New();
         newMapper->SetDataNode(node);
       }
     }
 
     return newMapper;
 };
 
 void mitk::MAPRegistrationWrapperObjectFactory::SetDefaultProperties(mitk::DataNode* node)
 {
   if(node==nullptr)
     return;
 
   mitk::DataNode::Pointer nodePointer = node;
 
   if(node->GetData() ==nullptr)
     return;
 
   if( dynamic_cast<mitk::MAPRegistrationWrapper*>(node->GetData())!=nullptr )
   {
     mitk::MITKRegistrationWrapperMapperBase::SetDefaultProperties(node);
   }
 }
 
 const char* mitk::MAPRegistrationWrapperObjectFactory::GetFileExtensions()
 {
   std::string fileExtension;
-  this->CreateFileExtensions(m_FileExtensionsMap, fileExtension);
+  this->CreateFileExtensions({}, fileExtension);
   return fileExtension.c_str();
 };
 
 mitk::CoreObjectFactoryBase::MultimapType mitk::MAPRegistrationWrapperObjectFactory::GetFileExtensionsMap()
 {
-  return m_FileExtensionsMap;
+  return {};
 }
 
 const char* mitk::MAPRegistrationWrapperObjectFactory::GetSaveFileExtensions()
 {
   std::string fileExtension;
-  this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension);
+  this->CreateFileExtensions({}, fileExtension);
   return fileExtension.c_str();
 }
 
 mitk::CoreObjectFactoryBase::MultimapType mitk::MAPRegistrationWrapperObjectFactory::GetSaveFileExtensionsMap()
 {
-  return m_SaveFileExtensionsMap;
+  return {};
 }
 
 struct RegisterMAPRegistrationWrapperObjectFactoryHelper{
   RegisterMAPRegistrationWrapperObjectFactoryHelper()
     : m_Factory( mitk::MAPRegistrationWrapperObjectFactory::New() )
   {
     mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory( m_Factory );
   }
 
   ~RegisterMAPRegistrationWrapperObjectFactoryHelper()
   {
     mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory( m_Factory );
   }
 
   mitk::MAPRegistrationWrapperObjectFactory::Pointer m_Factory;
 };
 
 static RegisterMAPRegistrationWrapperObjectFactoryHelper registerMITKRegistrationWrapperIOFactoryHelper;
diff --git a/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.h b/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.h
index e7e2b93140..79f9a88e16 100644
--- a/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.h
+++ b/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.h
@@ -1,67 +1,58 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #ifndef __mitkMAPRegistrationWrapperObjectFactory_h
 #define __mitkMAPRegistrationWrapperObjectFactory_h
 
 #include <mitkCoreObjectFactory.h>
 #include "MitkMatchPointRegistrationExports.h"
 
 namespace mitk {
 
 class MAPRegistrationWrapperObjectFactory : public mitk::CoreObjectFactoryBase
 {
   public:
     mitkClassMacro(MAPRegistrationWrapperObjectFactory,CoreObjectFactoryBase);
     itkFactorylessNewMacro(Self);
     itkCloneMacro(Self);
 
     ~MAPRegistrationWrapperObjectFactory() override;
 
     void SetDefaultProperties(mitk::DataNode* node) override;
 
     /**
      * @deprecatedSince{2014_10} See mitk::FileWriterRegistry and QmitkIOUtil
      */
     DEPRECATED(virtual const char* GetFileExtensions());
     /**
      * @deprecatedSince{2014_10} See mitk::FileWriterRegistry and QmitkIOUtil
      */
     DEPRECATED(virtual mitk::CoreObjectFactoryBase::MultimapType GetFileExtensionsMap());
     /**
      * @deprecatedSince{2014_10} See mitk::FileWriterRegistry and QmitkIOUtil
      */
     DEPRECATED(virtual const char* GetSaveFileExtensions());
     /**
      * @deprecatedSince{2014_10} See mitk::FileWriterRegistry and QmitkIOUtil
      */
     DEPRECATED(virtual mitk::CoreObjectFactoryBase::MultimapType GetSaveFileExtensionsMap());
 
     mitk::Mapper::Pointer CreateMapper(mitk::DataNode* node, MapperSlotId slotId) override;
 
   protected:
     MAPRegistrationWrapperObjectFactory();
-  private:
-    void CreateFileExtensionsMap();
-    std::string m_ExternalFileExtensions;
-    std::string m_InternalFileExtensions;
-    std::string m_SaveFileExtensions;
-    MultimapType m_FileExtensionsMap;
-    MultimapType m_SaveFileExtensionsMap;
-
-    itk::ObjectFactoryBase::Pointer m_RegistrationWrapperIOFactory;
 };
 
 }
 
 #endif
diff --git a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp
index acaa3bc0cb..0731005329 100644
--- a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp
+++ b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp
@@ -1,707 +1,707 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkDICOMSegmentationIO__cpp
 #define __mitkDICOMSegmentationIO__cpp
 
 #include "mitkDICOMSegmentationIO.h"
 
 #include "mitkDICOMSegIOMimeTypes.h"
 #include "mitkDICOMSegmentationConstants.h"
 #include <mitkDICOMDCMTKTagScanner.h>
 #include <mitkDICOMIOHelper.h>
 #include <mitkDICOMProperty.h>
 #include <mitkIDICOMTagsOfInterest.h>
 #include <mitkImageAccessByItk.h>
 #include <mitkImageCast.h>
 #include <mitkLocaleSwitch.h>
 #include <mitkPropertyNameHelper.h>
 
 
 // itk
 #include <itkThresholdImageFilter.h>
 
 // dcmqi
 #include <dcmqi/ImageSEGConverter.h>
 
 // us
 #include <usGetModuleContext.h>
 #include <usModuleContext.h>
 
 namespace mitk
 {
   DICOMSegmentationIO::DICOMSegmentationIO()
     : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(),
       mitk::MitkDICOMSEGIOMimeTypes::DICOMSEG_MIMETYPE_NAME(),
       "DICOM Segmentation")
   {
     AbstractFileWriter::SetRanking(10);
     AbstractFileReader::SetRanking(10);
     this->RegisterService();
 
     this->AddDICOMTagsToService();
   }
 
   void DICOMSegmentationIO::AddDICOMTagsToService()
   {
     IDICOMTagsOfInterest *toiService = GetDicomTagsOfInterestService();
     if (toiService != nullptr)
     {
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_SEQUENCE_PATH());
 
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_LABEL_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH());
 
       toiService->AddTagOfInterest(DICOMSegmentationConstants::ANATOMIC_REGION_SEQUENCE_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_VALUE_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_SCHEME_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_MEANING_PATH());
 
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENTED_PROPERTY_CATEGORY_SEQUENCE_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH());
 
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENTED_PROPERTY_TYPE_SEQUENCE_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH());
 
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENTED_PROPERTY_MODIFIER_SEQUENCE_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH());
       toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH());
     }
   }
 
   IFileIO::ConfidenceLevel DICOMSegmentationIO::GetWriterConfidenceLevel() const
   {
     if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
       return Unsupported;
 
     // Check if the input file is a segmentation
     const LabelSetImage *input = static_cast<const LabelSetImage *>(this->GetInput());
 
     if (input)
     {
       if ((input->GetDimension() != 3))
       {
         MITK_INFO << "DICOM segmentation writer is tested only with 3D images, sorry.";
         return Unsupported;
       }
 
       // Check if input file has dicom information for the referenced image (original DICOM image, e.g. CT) Still necessary, see write()
       mitk::StringLookupTableProperty::Pointer dicomFilesProp =
       dynamic_cast<mitk::StringLookupTableProperty *>(input->GetProperty("referenceFiles").GetPointer());
 
       if (dicomFilesProp.IsNotNull())
         return Supported;
     }
 
     return Unsupported;
   }
 
   void DICOMSegmentationIO::Write()
   {
     ValidateOutputLocation();
 
     mitk::LocaleSwitch localeSwitch("C");
     LocalFile localFile(this);
     const std::string path = localFile.GetFileName();
 
     auto input = dynamic_cast<const LabelSetImage *>(this->GetInput());
     if (input == nullptr)
       mitkThrow() << "Cannot write non-image data";
 
     // Get DICOM information from referenced image
     vector<std::unique_ptr<DcmDataset>> dcmDatasetsSourceImage;
     std::unique_ptr<DcmFileFormat> readFileFormat(new DcmFileFormat());
     try
     {
       // TODO: Generate dcmdataset witk DICOM tags from property list; ATM the source are the filepaths from the
       // property list
       mitk::StringLookupTableProperty::Pointer filesProp =
         dynamic_cast<mitk::StringLookupTableProperty *>(input->GetProperty("referenceFiles").GetPointer());
 
       if (filesProp.IsNull())
       {
         mitkThrow() << "No property with dicom file path.";
         return;
       }
 
       StringLookupTable filesLut = filesProp->GetValue();
       const StringLookupTable::LookupTableType &lookUpTableMap = filesLut.GetLookupTable();
 
       for (auto it : lookUpTableMap)
       {
         const char *fileName = (it.second).c_str();
         if (readFileFormat->loadFile(fileName, EXS_Unknown).good())
         {
           std::unique_ptr<DcmDataset> readDCMDataset(readFileFormat->getAndRemoveDataset());
           dcmDatasetsSourceImage.push_back(std::move(readDCMDataset));
         }
       }
     }
     catch (const std::exception &e)
     {
       MITK_ERROR << "An error occurred while getting the dicom informations: " << e.what() << endl;
       return;
     }
 
     // Iterate over all layers. For each a dcm file will be generated
     for (unsigned int layer = 0; layer < input->GetNumberOfLayers(); ++layer)
     {
       vector<itkInternalImageType::Pointer> segmentations;
 
       try
       {
         // Hack: Remove the const attribute to switch between the layer images. Normally you could get the different
         // layer images by input->GetLayerImage(layer)
         mitk::LabelSetImage *mitkLayerImage = const_cast<mitk::LabelSetImage *>(input);
         mitkLayerImage->SetActiveLayer(layer);
 
         // Cast mitk layer image to itk
         ImageToItk<itkInputImageType>::Pointer imageToItkFilter = ImageToItk<itkInputImageType>::New();
         imageToItkFilter->SetInput(mitkLayerImage);
         // Cast from original itk type to dcmqi input itk image type
         typedef itk::CastImageFilter<itkInputImageType, itkInternalImageType> castItkImageFilterType;
         castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New();
         castFilter->SetInput(imageToItkFilter->GetOutput());
         castFilter->Update();
 
         itkInternalImageType::Pointer itkLabelImage = castFilter->GetOutput();
         itkLabelImage->DisconnectPipeline();
 
         // Iterate over all labels. For each label a segmentation image will be created
         const LabelSet *labelSet = input->GetLabelSet(layer);
         auto labelIter = labelSet->IteratorConstBegin();
         // Ignore background label
         ++labelIter;
 
         for (; labelIter != labelSet->IteratorConstEnd(); ++labelIter)
         {
           // Thresold over the image with the given label value
           itk::ThresholdImageFilter<itkInternalImageType>::Pointer thresholdFilter =
             itk::ThresholdImageFilter<itkInternalImageType>::New();
           thresholdFilter->SetInput(itkLabelImage);
           thresholdFilter->ThresholdOutside(labelIter->first, labelIter->first);
           thresholdFilter->SetOutsideValue(0);
           thresholdFilter->Update();
           itkInternalImageType::Pointer segmentImage = thresholdFilter->GetOutput();
           segmentImage->DisconnectPipeline();
 
           segmentations.push_back(segmentImage);
         }
       }
       catch (const itk::ExceptionObject &e)
       {
         MITK_ERROR << e.GetDescription() << endl;
         return;
       }
 
       // Create segmentation meta information
       const std::string tmpMetaInfoFile = this->CreateMetaDataJsonFile(layer);
 
       MITK_INFO << "Writing image: " << path << std::endl;
       try
       {
         //TODO is there a better way? Interface expects a vector of raw pointer.
         vector<DcmDataset*> rawVecDataset;
         for (const auto& dcmDataSet : dcmDatasetsSourceImage)
           rawVecDataset.push_back(dcmDataSet.get());
 
         // Convert itk segmentation images to dicom image
         std::unique_ptr<dcmqi::ImageSEGConverter> converter = std::make_unique<dcmqi::ImageSEGConverter>();
-        std::unique_ptr<DcmDataset> result(converter->itkimage2dcmSegmentation(rawVecDataset, segmentations, tmpMetaInfoFile));
+        std::unique_ptr<DcmDataset> result(converter->itkimage2dcmSegmentation(rawVecDataset, segmentations, tmpMetaInfoFile, false));
 
         // Write dicom file
         DcmFileFormat dcmFileFormat(result.get());
 
         std::string filePath = path.substr(0, path.find_last_of("."));
         // If there is more than one layer, we have to write more than 1 dicom file
         if (input->GetNumberOfLayers() != 1)
           filePath = filePath + std::to_string(layer) + ".dcm";
         else
           filePath = filePath + ".dcm";
 
         dcmFileFormat.saveFile(filePath.c_str(), EXS_LittleEndianExplicit);
       }
       catch (const std::exception &e)
       {
         MITK_ERROR << "An error occurred during writing the DICOM Seg: " << e.what() << endl;
         return;
       }
     } // Write a dcm file for the next layer
   }
 
   IFileIO::ConfidenceLevel DICOMSegmentationIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
 
     const std::string fileName = this->GetLocalFileName();
 
     DcmFileFormat dcmFileFormat;
     OFCondition status = dcmFileFormat.loadFile(fileName.c_str());
 
     if (status.bad())
       return Unsupported;
 
     OFString modality;
     if (dcmFileFormat.getDataset()->findAndGetOFString(DCM_Modality, modality).good())
     {
       if (modality.compare("SEG") == 0)
         return Supported;
       else
         return Unsupported;
     }
     return Unsupported;
   }
 
-  std::vector<BaseData::Pointer> DICOMSegmentationIO::Read()
+  std::vector<BaseData::Pointer> DICOMSegmentationIO::DoRead()
   {
     mitk::LocaleSwitch localeSwitch("C");
 
     LabelSetImage::Pointer labelSetImage;
     std::vector<BaseData::Pointer> result;
 
     const std::string path = this->GetLocalFileName();
 
     MITK_INFO << "loading " << path << std::endl;
 
     if (path.empty())
       mitkThrow() << "Empty filename in mitk::ItkImageIO ";
 
     try
     {
       // Get the dcm data set from file path
       DcmFileFormat dcmFileFormat;
       OFCondition status = dcmFileFormat.loadFile(path.c_str());
       if (status.bad())
         mitkThrow() << "Can't read the input file!";
 
       DcmDataset *dataSet = dcmFileFormat.getDataset();
       if (dataSet == nullptr)
         mitkThrow() << "Can't read data from input file!";
 
       //=============================== dcmqi part ====================================
       // Read the DICOM SEG images (segItkImages) and DICOM tags (metaInfo)
       std::unique_ptr<dcmqi::ImageSEGConverter> converter = std::make_unique<dcmqi::ImageSEGConverter>();
       pair<map<unsigned, itkInternalImageType::Pointer>, string> dcmqiOutput =
         converter->dcmSegmentation2itkimage(dataSet);
 
       map<unsigned, itkInternalImageType::Pointer> segItkImages = dcmqiOutput.first;
 
       dcmqi::JSONSegmentationMetaInformationHandler metaInfo(dcmqiOutput.second.c_str());
       metaInfo.read();
 
       MITK_INFO << "Input " << metaInfo.getJSONOutputAsString();
       //===============================================================================
 
       // Get the label information from segment attributes for each itk image
       vector<map<unsigned, dcmqi::SegmentAttributes *>>::const_iterator segmentIter =
         metaInfo.segmentsAttributesMappingList.begin();
 
       // For each itk image add a layer to the LabelSetImage output
       for (auto &element : segItkImages)
       {
         // Get the labeled image and cast it to mitkImage
         typedef itk::CastImageFilter<itkInternalImageType, itkInputImageType> castItkImageFilterType;
         castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New();
         castFilter->SetInput(element.second);
         castFilter->Update();
 
         Image::Pointer layerImage;
         CastToMitkImage(castFilter->GetOutput(), layerImage);
 
         // Get pixel value of the label
         itkInternalImageType::ValueType segValue = 1;
         typedef itk::ImageRegionIterator<const itkInternalImageType> IteratorType;
         // Iterate over the image to find the pixel value of the label
         IteratorType iter(element.second, element.second->GetLargestPossibleRegion());
         iter.GoToBegin();
         while (!iter.IsAtEnd())
         {
           itkInputImageType::PixelType value = iter.Get();
           if (value != 0)
           {
             segValue = value;
             break;
           }
           ++iter;
         }
         // Get Segment information map
         map<unsigned, dcmqi::SegmentAttributes *> segmentMap = (*segmentIter);
         map<unsigned, dcmqi::SegmentAttributes *>::const_iterator segmentMapIter = (*segmentIter).begin();
         dcmqi::SegmentAttributes *segmentAttribute = (*segmentMapIter).second;
 
         OFString labelName;
 
         if (segmentAttribute->getSegmentedPropertyTypeCodeSequence() != nullptr)
         {
           segmentAttribute->getSegmentedPropertyTypeCodeSequence()->getCodeMeaning(labelName);
           if (segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence() != nullptr)
           {
             OFString modifier;
             segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence()->getCodeMeaning(modifier);
             labelName.append(" (").append(modifier).append(")");
           }
         }
         else
         {
           labelName = std::to_string(segmentAttribute->getLabelID()).c_str();
           if (labelName.empty())
             labelName = "Unnamed";
         }
 
         float tmp[3] = { 0.0, 0.0, 0.0 };
         if (segmentAttribute->getRecommendedDisplayRGBValue() != nullptr)
         {
           tmp[0] = segmentAttribute->getRecommendedDisplayRGBValue()[0] / 255.0;
           tmp[1] = segmentAttribute->getRecommendedDisplayRGBValue()[1] / 255.0;
           tmp[2] = segmentAttribute->getRecommendedDisplayRGBValue()[2] / 255.0;
         }
 
         Label *newLabel = nullptr;
         // If labelSetImage do not exists (first image)
         if (labelSetImage.IsNull())
         {
           // Initialize the labelSetImage with the read image
           labelSetImage = LabelSetImage::New();
           labelSetImage->InitializeByLabeledImage(layerImage);
           // Already a label was generated, so set the information to this
           newLabel = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer());
           newLabel->SetName(labelName.c_str());
           newLabel->SetColor(Color(tmp));
           newLabel->SetValue(segValue);
         }
         else
         {
           // Add a new layer to the labelSetImage. Background label is set automatically
           labelSetImage->AddLayer(layerImage);
 
           // Add new label
           newLabel = new Label;
           newLabel->SetName(labelName.c_str());
           newLabel->SetColor(Color(tmp));
           newLabel->SetValue(segValue);
           labelSetImage->GetLabelSet(labelSetImage->GetActiveLayer())->AddLabel(newLabel);
         }
 
         // Add some more label properties
         this->SetLabelProperties(newLabel, segmentAttribute);
         ++segmentIter;
       }
 
       labelSetImage->GetLabelSet()->SetAllLabelsVisible(true);
 
       // Add some general DICOM Segmentation properties
       mitk::IDICOMTagsOfInterest *toiSrv = GetDicomTagsOfInterestService();
       auto tagsOfInterest = toiSrv->GetTagsOfInterest();
       DICOMTagPathList tagsOfInterestList;
       for (const auto &tag : tagsOfInterest)
       {
         tagsOfInterestList.push_back(tag.first);
       }
 
       mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New();
       scanner->SetInputFiles({ GetInputLocation() });
       scanner->AddTagPaths(tagsOfInterestList);
       scanner->Scan();
 
       mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList();
       if (frames.empty())
       {
         MITK_ERROR << "Error reading the DICOM Seg file" << std::endl;
         return result;
       }
 
       auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames);
       SetProperties(labelSetImage, findings);
 
       // Set active layer to the first layer of the labelset image
       if (labelSetImage->GetNumberOfLayers() > 1 && labelSetImage->GetActiveLayer() != 0)
         labelSetImage->SetActiveLayer(0);
     }
     catch (const std::exception &e)
     {
       MITK_ERROR << "An error occurred while reading the DICOM Seg file: " << e.what();
       return result;
     }
     catch (...)
     {
       MITK_ERROR << "An error occurred in dcmqi while reading the DICOM Seg file";
       return result;
     }
 
     result.push_back(labelSetImage.GetPointer());
     return result;
   }
 
   const std::string mitk::DICOMSegmentationIO::CreateMetaDataJsonFile(int layer)
   {
     const mitk::LabelSetImage *image = dynamic_cast<const mitk::LabelSetImage *>(this->GetInput());
 
     const std::string output;
     dcmqi::JSONSegmentationMetaInformationHandler handler;
 
 
     // 1. Metadata attributes that will be listed in the resulting DICOM SEG object
     std::string contentCreatorName;
     if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0070, 0x0084).c_str(),
       contentCreatorName))
       contentCreatorName = "MITK";
     handler.setContentCreatorName(contentCreatorName);
 
     std::string clinicalTrailSeriesId;
     if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0071).c_str(),
       clinicalTrailSeriesId))
       clinicalTrailSeriesId = "Session 1";
     handler.setClinicalTrialSeriesID(clinicalTrailSeriesId);
 
     std::string clinicalTrialTimePointID;
     if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0050).c_str(),
       clinicalTrialTimePointID))
       clinicalTrialTimePointID = "0";
     handler.setClinicalTrialTimePointID(clinicalTrialTimePointID);
 
     std::string clinicalTrialCoordinatingCenterName = "";
     if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0060).c_str(),
       clinicalTrialCoordinatingCenterName))
       clinicalTrialCoordinatingCenterName = "Unknown";
     handler.setClinicalTrialCoordinatingCenterName(clinicalTrialCoordinatingCenterName);
 
     std::string seriesDescription;
     if (!image->GetPropertyList()->GetStringProperty("name", seriesDescription))
       seriesDescription = "MITK Segmentation";
     handler.setSeriesDescription(seriesDescription);
 
     handler.setSeriesNumber("0" + std::to_string(layer));
     handler.setInstanceNumber("1");
     handler.setBodyPartExamined("");
 
     const LabelSet *labelSet = image->GetLabelSet(layer);
     auto labelIter = labelSet->IteratorConstBegin();
     // Ignore background label
     ++labelIter;
 
     for (; labelIter != labelSet->IteratorConstEnd(); ++labelIter)
     {
       const Label *label = labelIter->second;
 
       if (label != nullptr)
       {
         TemporoSpatialStringProperty *segmentNumberProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentLabelProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()).c_str()));
 
         TemporoSpatialStringProperty *algorithmTypeProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentCategoryCodeValueProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentCategoryCodeSchemeProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentCategoryCodeMeaningProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentTypeCodeValueProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentTypeCodeSchemeProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentTypeCodeMeaningProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentModifierCodeValueProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentModifierCodeSchemeProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentModifierCodeMeaningProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()).c_str()));
 
         dcmqi::SegmentAttributes *segmentAttribute = nullptr;
 
         if (segmentNumberProp->GetValue() == "")
         {
           MITK_ERROR << "Something went wrong with the label ID.";
         }
         else
         {
           int labelId = std::stoi(segmentNumberProp->GetValue());
           segmentAttribute = handler.createAndGetNewSegment(labelId);
         }
         if (segmentAttribute != nullptr)
         {
           segmentAttribute->setSegmentDescription(segmentLabelProp->GetValueAsString());
           segmentAttribute->setSegmentAlgorithmType(algorithmTypeProp->GetValueAsString());
           segmentAttribute->setSegmentAlgorithmName("MITK Segmentation");
           if (segmentCategoryCodeValueProp != nullptr && segmentCategoryCodeSchemeProp != nullptr &&
             segmentCategoryCodeMeaningProp != nullptr)
             segmentAttribute->setSegmentedPropertyCategoryCodeSequence(
               segmentCategoryCodeValueProp->GetValueAsString(),
               segmentCategoryCodeSchemeProp->GetValueAsString(),
               segmentCategoryCodeMeaningProp->GetValueAsString());
           else
             // some default values
             segmentAttribute->setSegmentedPropertyCategoryCodeSequence(
               "M-01000", "SRT", "Morphologically Altered Structure");
 
           if (segmentTypeCodeValueProp != nullptr && segmentTypeCodeSchemeProp != nullptr &&
             segmentTypeCodeMeaningProp != nullptr)
           {
             segmentAttribute->setSegmentedPropertyTypeCodeSequence(segmentTypeCodeValueProp->GetValueAsString(),
               segmentTypeCodeSchemeProp->GetValueAsString(),
               segmentTypeCodeMeaningProp->GetValueAsString());
             handler.setBodyPartExamined(segmentTypeCodeMeaningProp->GetValueAsString());
           }
           else
           {
             // some default values
             segmentAttribute->setSegmentedPropertyTypeCodeSequence("M-03000", "SRT", "Mass");
             handler.setBodyPartExamined("Mass");
           }
           if (segmentModifierCodeValueProp != nullptr && segmentModifierCodeSchemeProp != nullptr &&
             segmentModifierCodeMeaningProp != nullptr)
             segmentAttribute->setSegmentedPropertyTypeModifierCodeSequence(
               segmentModifierCodeValueProp->GetValueAsString(),
               segmentModifierCodeSchemeProp->GetValueAsString(),
               segmentModifierCodeMeaningProp->GetValueAsString());
 
           Color color = label->GetColor();
           segmentAttribute->setRecommendedDisplayRGBValue(color[0] * 255, color[1] * 255, color[2] * 255);
         }
       }
     }
     return handler.getJSONOutputAsString();
   }
 
   void mitk::DICOMSegmentationIO::SetLabelProperties(mitk::Label *label, dcmqi::SegmentAttributes *segmentAttribute)
   {
     // Segment Number:Identification number of the segment.The value of Segment Number(0062, 0004) shall be unique
     // within the Segmentation instance in which it is created
     label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH()).c_str(),
       TemporoSpatialStringProperty::New(std::to_string(label->GetValue())));
 
     // Segment Label: User-defined label identifying this segment.
     label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()).c_str(),
       TemporoSpatialStringProperty::New(label->GetName()));
 
     // Segment Algorithm Type: Type of algorithm used to generate the segment.
     if (!segmentAttribute->getSegmentAlgorithmType().empty())
       label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(segmentAttribute->getSegmentAlgorithmType()));
 
     // Add Segmented Property Category Code Sequence tags
     auto categoryCodeSequence = segmentAttribute->getSegmentedPropertyCategoryCodeSequence();
     if (categoryCodeSequence != nullptr)
     {
       OFString codeValue; // (0008,0100) Code Value
       categoryCodeSequence->getCodeValue(codeValue);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeValue.c_str()));
 
       OFString codeScheme; // (0008,0102) Coding Scheme Designator
       categoryCodeSequence->getCodingSchemeDesignator(codeScheme);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeScheme.c_str()));
 
       OFString codeMeaning; // (0008,0104) Code Meaning
       categoryCodeSequence->getCodeMeaning(codeMeaning);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeMeaning.c_str()));
     }
 
     // Add Segmented Property Type Code Sequence tags
     auto typeCodeSequence = segmentAttribute->getSegmentedPropertyTypeCodeSequence();
     if (typeCodeSequence != nullptr)
     {
       OFString codeValue; // (0008,0100) Code Value
       typeCodeSequence->getCodeValue(codeValue);
       label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeValue.c_str()));
 
       OFString codeScheme; // (0008,0102) Coding Scheme Designator
       typeCodeSequence->getCodingSchemeDesignator(codeScheme);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeScheme.c_str()));
 
       OFString codeMeaning; // (0008,0104) Code Meaning
       typeCodeSequence->getCodeMeaning(codeMeaning);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeMeaning.c_str()));
     }
 
     // Add Segmented Property Type Modifier Code Sequence tags
     auto modifierCodeSequence = segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence();
     if (modifierCodeSequence != nullptr)
     {
       OFString codeValue; // (0008,0100) Code Value
       modifierCodeSequence->getCodeValue(codeValue);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeValue.c_str()));
 
       OFString codeScheme; // (0008,0102) Coding Scheme Designator
       modifierCodeSequence->getCodingSchemeDesignator(codeScheme);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeScheme.c_str()));
 
       OFString codeMeaning; // (0008,0104) Code Meaning
       modifierCodeSequence->getCodeMeaning(codeMeaning);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeMeaning.c_str()));
     }
 
     // Add Atomic RegionSequence tags
     auto atomicRegionSequence = segmentAttribute->getAnatomicRegionSequence();
     if (atomicRegionSequence != nullptr)
     {
       OFString codeValue; // (0008,0100) Code Value
       atomicRegionSequence->getCodeValue(codeValue);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_VALUE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeValue.c_str()));
 
       OFString codeScheme; // (0008,0102) Coding Scheme Designator
       atomicRegionSequence->getCodingSchemeDesignator(codeScheme);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_SCHEME_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeScheme.c_str()));
 
       OFString codeMeaning; // (0008,0104) Code Meaning
       atomicRegionSequence->getCodeMeaning(codeMeaning);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_MEANING_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeMeaning.c_str()));
     }
   }
 
   DICOMSegmentationIO *DICOMSegmentationIO::IOClone() const { return new DICOMSegmentationIO(*this); }
 } // namespace
 
 #endif //__mitkDICOMSegmentationIO__cpp
diff --git a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.h b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.h
index 5767e9f3fe..123bcb803c 100644
--- a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.h
+++ b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.h
@@ -1,62 +1,64 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkDICOMSegmentationIO_h
 #define __mitkDICOMSegmentationIO_h
 
 #include <mitkAbstractFileIO.h>
 #include <mitkLabelSetImage.h>
 
 #include <dcmqi/JSONSegmentationMetaInformationHandler.h>
 
 namespace mitk
 {
   /**
    * Read and Writes a LabelSetImage to a dcm file
    * @ingroup Process
    */
   class DICOMSegmentationIO : public mitk::AbstractFileIO
   {
   public:
     typedef mitk::LabelSetImage InputType;
     typedef itk::Image<unsigned short, 3> itkInputImageType;
     typedef itk::Image<short, 3> itkInternalImageType;
 
     DICOMSegmentationIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    /**
-     * @brief Reads a number of DICOM segmentation from the file system
-     * @return a vector of mitk::LabelSetImages
-     * @throws throws an mitk::Exception if an error ocurrs
-     */
-    std::vector<BaseData::Pointer> Read() override;
+
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
     ConfidenceLevel GetWriterConfidenceLevel() const override;
+  protected:
+    /**
+     * @brief Reads a number of DICOM segmentation from the file system
+     * @return a vector of mitk::LabelSetImages
+     * @throws throws an mitk::Exception if an error ocurrs
+     */
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     DICOMSegmentationIO *IOClone() const override;
 
     // -------------- DICOMSegmentationIO specific functions -------------
     const std::string CreateMetaDataJsonFile(int layer);
     void SetLabelProperties(Label *label, dcmqi::SegmentAttributes *segmentAttribute);
     void AddDICOMTagsToService();
   };
 } // end of namespace mitk
 
 #endif // __mitkDICOMSegmentationIO_h
diff --git a/Modules/Multilabel/autoload/IO/CMakeLists.txt b/Modules/Multilabel/autoload/IO/CMakeLists.txt
index 9c62019a54..9a0856eff7 100644
--- a/Modules/Multilabel/autoload/IO/CMakeLists.txt
+++ b/Modules/Multilabel/autoload/IO/CMakeLists.txt
@@ -1,8 +1,6 @@
 MITK_CREATE_MODULE( MultilabelIO
-  INCLUDE_DIRS
-    PRIVATE src/IO
   DEPENDS PUBLIC MitkMultilabel MitkSceneSerialization
   PACKAGE_DEPENDS
     PRIVATE ITK|ITKQuadEdgeMesh+ITKAntiAlias+ITKIONRRD
   AUTOLOAD_WITH MitkCore
 )
diff --git a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp
index 9990ea7032..9466f4a70e 100644
--- a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp
+++ b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp
@@ -1,636 +1,636 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkLabelSetImageWriter__cpp
 #define __mitkLabelSetImageWriter__cpp
 
 #include "mitkLabelSetImageIO.h"
 #include "mitkBasePropertySerializer.h"
 #include "mitkIOMimeTypes.h"
 #include "mitkImageAccessByItk.h"
 #include "mitkLabelSetIOHelper.h"
 #include "mitkLabelSetImageConverter.h"
 #include <mitkLocaleSwitch.h>
 #include <mitkArbitraryTimeGeometry.h>
 #include <mitkIPropertyPersistence.h>
 #include <mitkCoreServices.h>
 #include <mitkItkImageIO.h>
 
 // itk
 #include "itkImageFileReader.h"
 #include "itkImageFileWriter.h"
 #include "itkMetaDataDictionary.h"
 #include "itkMetaDataObject.h"
 #include "itkNrrdImageIO.h"
 
 namespace mitk
 {
 
   const char* const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type";
   const char* const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints";
   const char* const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type";
   const char* const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints";
 
   LabelSetImageIO::LabelSetImageIO()
     : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(), IOMimeTypes::NRRD_MIMETYPE(), "MITK Multilabel Image")
   {
     AbstractFileWriter::SetRanking(10);
     AbstractFileReader::SetRanking(10);
     this->RegisterService();
   }
 
   IFileIO::ConfidenceLevel LabelSetImageIO::GetWriterConfidenceLevel() const
   {
     if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
       return Unsupported;
     const auto *input = static_cast<const LabelSetImage *>(this->GetInput());
     if (input)
       return Supported;
     else
       return Unsupported;
   }
 
   void LabelSetImageIO::Write()
   {
     ValidateOutputLocation();
 
     auto input = dynamic_cast<const LabelSetImage *>(this->GetInput());
 
     mitk::LocaleSwitch localeSwitch("C");
 
     mitk::Image::Pointer inputVector = mitk::ConvertLabelSetImageToImage(input);
 
     // image write
     if (inputVector.IsNull())
     {
       mitkThrow() << "Cannot write non-image data";
     }
 
     itk::NrrdImageIO::Pointer nrrdImageIo = itk::NrrdImageIO::New();
 
     // Clone the image geometry, because we might have to change it
     // for writing purposes
     BaseGeometry::Pointer geometry = inputVector->GetGeometry()->Clone();
 
     // Check if geometry information will be lost
     if (inputVector->GetDimension() == 2 && !geometry->Is2DConvertable())
     {
       MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might "
                    "consider using Convert2Dto3DImageFilter before saving.";
 
       // set matrix to identity
       mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New();
       affTrans->SetIdentity();
       mitk::Vector3D spacing = geometry->GetSpacing();
       mitk::Point3D origin = geometry->GetOrigin();
       geometry->SetIndexToWorldTransform(affTrans);
       geometry->SetSpacing(spacing);
       geometry->SetOrigin(origin);
     }
 
     LocalFile localFile(this);
     const std::string path = localFile.GetFileName();
 
     MITK_INFO << "Writing image: " << path << std::endl;
 
     try
     {
       // Implementation of writer using itkImageIO directly. This skips the use
       // of templated itkImageFileWriter, which saves the multiplexing on MITK side.
 
       const unsigned int dimension = inputVector->GetDimension();
       const unsigned int *const dimensions = inputVector->GetDimensions();
       const mitk::PixelType pixelType = inputVector->GetPixelType();
       const mitk::Vector3D mitkSpacing = geometry->GetSpacing();
       const mitk::Point3D mitkOrigin = geometry->GetOrigin();
 
       // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin,
       // though they are not supported in MITK
       itk::Vector<double, 4u> spacing4D;
       spacing4D[0] = mitkSpacing[0];
       spacing4D[1] = mitkSpacing[1];
       spacing4D[2] = mitkSpacing[2];
       spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here
 
       itk::Vector<double, 4u> origin4D;
       origin4D[0] = mitkOrigin[0];
       origin4D[1] = mitkOrigin[1];
       origin4D[2] = mitkOrigin[2];
       origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here
 
       // Set the necessary information for imageIO
       nrrdImageIo->SetNumberOfDimensions(dimension);
       nrrdImageIo->SetPixelType(pixelType.GetPixelType());
       nrrdImageIo->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ?
                                       static_cast<itk::ImageIOBase::IOComponentType>(pixelType.GetComponentType()) :
                                       itk::ImageIOBase::UNKNOWNCOMPONENTTYPE);
       nrrdImageIo->SetNumberOfComponents(pixelType.GetNumberOfComponents());
 
       itk::ImageIORegion ioRegion(dimension);
 
       for (unsigned int i = 0; i < dimension; i++)
       {
         nrrdImageIo->SetDimensions(i, dimensions[i]);
         nrrdImageIo->SetSpacing(i, spacing4D[i]);
         nrrdImageIo->SetOrigin(i, origin4D[i]);
 
         mitk::Vector3D mitkDirection;
         mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i));
         itk::Vector<double, 4u> direction4D;
         direction4D[0] = mitkDirection[0];
         direction4D[1] = mitkDirection[1];
         direction4D[2] = mitkDirection[2];
 
         // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must
         // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix.
         if (i == 3)
         {
           direction4D[3] = 1; // homogenous component
         }
         else
         {
           direction4D[3] = 0;
         }
         vnl_vector<double> axisDirection(dimension);
         for (unsigned int j = 0; j < dimension; j++)
         {
           axisDirection[j] = direction4D[j] / spacing4D[i];
         }
         nrrdImageIo->SetDirection(i, axisDirection);
 
         ioRegion.SetSize(i, inputVector->GetLargestPossibleRegion().GetSize(i));
         ioRegion.SetIndex(i, inputVector->GetLargestPossibleRegion().GetIndex(i));
       }
 
       // use compression if available
       nrrdImageIo->UseCompressionOn();
 
       nrrdImageIo->SetIORegion(ioRegion);
       nrrdImageIo->SetFileName(path);
 
       // label set specific meta data
       char keybuffer[512];
       char valbuffer[512];
 
       sprintf(keybuffer, "modality");
       sprintf(valbuffer, "org.mitk.image.multilabel");
       itk::EncapsulateMetaData<std::string>(
         nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer));
 
       sprintf(keybuffer, "layers");
       sprintf(valbuffer, "%1d", input->GetNumberOfLayers());
       itk::EncapsulateMetaData<std::string>(
         nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer));
 
       for (unsigned int layerIdx = 0; layerIdx < input->GetNumberOfLayers(); layerIdx++)
       {
         sprintf(keybuffer, "layer_%03u", layerIdx);                    // layer idx
         sprintf(valbuffer, "%1u", input->GetNumberOfLabels(layerIdx)); // number of labels for the layer
         itk::EncapsulateMetaData<std::string>(
           nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer));
 
         auto iter = input->GetLabelSet(layerIdx)->IteratorConstBegin();
         unsigned int count(0);
         while (iter != input->GetLabelSet(layerIdx)->IteratorConstEnd())
         {
           std::unique_ptr<TiXmlDocument> document;
           document.reset(new TiXmlDocument());
 
           auto *decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc....
           document->LinkEndChild(decl);
           TiXmlElement *labelElem = mitk::LabelSetIOHelper::GetLabelAsTiXmlElement(iter->second);
           document->LinkEndChild(labelElem);
           TiXmlPrinter printer;
           printer.SetIndent("");
           printer.SetLineBreak("");
 
           document->Accept(&printer);
 
           sprintf(keybuffer, "org.mitk.label_%03u_%05u", layerIdx, count);
           itk::EncapsulateMetaData<std::string>(
             nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), printer.Str());
           ++iter;
           ++count;
         }
       }
       // end label set specific meta data
 
       // Handle time geometry
       const auto* arbitraryTG = dynamic_cast<const ArbitraryTimeGeometry*>(input->GetTimeGeometry());
       if (arbitraryTG)
       {
         itk::EncapsulateMetaData<std::string>(nrrdImageIo->GetMetaDataDictionary(),
           PROPERTY_KEY_TIMEGEOMETRY_TYPE,
           ArbitraryTimeGeometry::GetStaticNameOfClass());
 
 
         auto metaTimePoints = ConvertTimePointListToMetaDataObject(arbitraryTG);
         nrrdImageIo->GetMetaDataDictionary().Set(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, metaTimePoints);
       }
 
       // Handle properties
       mitk::PropertyList::Pointer imagePropertyList = input->GetPropertyList();
       for (const auto& property : *imagePropertyList->GetMap())
       {
         mitk::CoreServicePointer<IPropertyPersistence> propPersistenceService(mitk::CoreServices::GetPropertyPersistence());
         IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfo(property.first, GetMimeType()->GetName(), true);
 
         if (infoList.empty())
         {
           continue;
         }
 
         std::string value = infoList.front()->GetSerializationFunction()(property.second);
 
         if (value == mitk::BaseProperty::VALUE_CANNOT_BE_CONVERTED_TO_STRING)
         {
           continue;
         }
 
         std::string key = infoList.front()->GetKey();
 
         itk::EncapsulateMetaData<std::string>(nrrdImageIo->GetMetaDataDictionary(), key, value);
       }
 
       ImageReadAccessor imageAccess(inputVector);
       nrrdImageIo->Write(imageAccess.GetData());
     }
     catch (const std::exception &e)
     {
       mitkThrow() << e.what();
     }
     // end image write
   }
 
   IFileIO::ConfidenceLevel LabelSetImageIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
     const std::string fileName = this->GetLocalFileName();
     itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New();
     io->SetFileName(fileName);
     io->ReadImageInformation();
 
     itk::MetaDataDictionary imgMetaDataDictionary = io->GetMetaDataDictionary();
     std::string value("");
     itk::ExposeMetaData<std::string>(imgMetaDataDictionary, "modality", value);
     if (value.compare("org.mitk.image.multilabel") == 0)
     {
       return Supported;
     }
     else
       return Unsupported;
   }
 
-  std::vector<BaseData::Pointer> LabelSetImageIO::Read()
+  std::vector<BaseData::Pointer> LabelSetImageIO::DoRead()
   {
     mitk::LocaleSwitch localeSwitch("C");
 
     // begin regular image loading, adapted from mitkItkImageIO
     itk::NrrdImageIO::Pointer nrrdImageIO = itk::NrrdImageIO::New();
     Image::Pointer image = Image::New();
 
     const unsigned int MINDIM = 2;
     const unsigned int MAXDIM = 4;
 
     const std::string path = this->GetLocalFileName();
 
     MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << std::endl;
 
     // Check to see if we can read the file given the name or prefix
     if (path.empty())
     {
       mitkThrow() << "Empty filename in mitk::ItkImageIO ";
     }
 
     // Got to allocate space for the image. Determine the characteristics of
     // the image.
     nrrdImageIO->SetFileName(path);
     nrrdImageIO->ReadImageInformation();
 
     unsigned int ndim = nrrdImageIO->GetNumberOfDimensions();
     if (ndim < MINDIM || ndim > MAXDIM)
     {
       MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim
                 << " dimensions! Reading as 4D.";
       ndim = MAXDIM;
     }
 
     itk::ImageIORegion ioRegion(ndim);
     itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize();
     itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex();
 
     unsigned int dimensions[MAXDIM];
     dimensions[0] = 0;
     dimensions[1] = 0;
     dimensions[2] = 0;
     dimensions[3] = 0;
 
     ScalarType spacing[MAXDIM];
     spacing[0] = 1.0f;
     spacing[1] = 1.0f;
     spacing[2] = 1.0f;
     spacing[3] = 1.0f;
 
     Point3D origin;
     origin.Fill(0);
 
     unsigned int i;
     for (i = 0; i < ndim; ++i)
     {
       ioStart[i] = 0;
       ioSize[i] = nrrdImageIO->GetDimensions(i);
       if (i < MAXDIM)
       {
         dimensions[i] = nrrdImageIO->GetDimensions(i);
         spacing[i] = nrrdImageIO->GetSpacing(i);
         if (spacing[i] <= 0)
           spacing[i] = 1.0f;
       }
       if (i < 3)
       {
         origin[i] = nrrdImageIO->GetOrigin(i);
       }
     }
 
     ioRegion.SetSize(ioSize);
     ioRegion.SetIndex(ioStart);
 
     MITK_INFO << "ioRegion: " << ioRegion << std::endl;
     nrrdImageIO->SetIORegion(ioRegion);
     void *buffer = new unsigned char[nrrdImageIO->GetImageSizeInBytes()];
     nrrdImageIO->Read(buffer);
 
     image->Initialize(MakePixelType(nrrdImageIO), ndim, dimensions);
     image->SetImportChannel(buffer, 0, Image::ManageMemory);
 
     // access direction of itk::Image and include spacing
     mitk::Matrix3D matrix;
     matrix.SetIdentity();
     unsigned int j, itkDimMax3 = (ndim >= 3 ? 3 : ndim);
     for (i = 0; i < itkDimMax3; ++i)
       for (j = 0; j < itkDimMax3; ++j)
         matrix[i][j] = nrrdImageIO->GetDirection(j)[i];
 
     // re-initialize PlaneGeometry with origin and direction
     PlaneGeometry *planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0);
     planeGeometry->SetOrigin(origin);
     planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix);
 
     // re-initialize SlicedGeometry3D
     SlicedGeometry3D *slicedGeometry = image->GetSlicedGeometry(0);
     slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2));
     slicedGeometry->SetSpacing(spacing);
 
     MITK_INFO << slicedGeometry->GetCornerPoint(false, false, false);
     MITK_INFO << slicedGeometry->GetCornerPoint(true, true, true);
 
     // re-initialize TimeGeometry
     const itk::MetaDataDictionary& dictionary = nrrdImageIO->GetMetaDataDictionary();
     TimeGeometry::Pointer timeGeometry;
 
     if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE) || dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TYPE))
     { // also check for the name because of backwards compatibility. Past code version stored with the name and not with
       // the key
       itk::MetaDataObject<std::string>::ConstPointer timeGeometryTypeData;
       if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE))
       {
         timeGeometryTypeData =
           dynamic_cast<const itk::MetaDataObject<std::string>*>(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TYPE));
       }
       else
       {
         timeGeometryTypeData =
           dynamic_cast<const itk::MetaDataObject<std::string>*>(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TYPE));
       }
 
       if (timeGeometryTypeData->GetMetaDataObjectValue() == ArbitraryTimeGeometry::GetStaticNameOfClass())
       {
         MITK_INFO << "used time geometry: " << ArbitraryTimeGeometry::GetStaticNameOfClass();
         typedef std::vector<TimePointType> TimePointVector;
         TimePointVector timePoints;
 
         if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS))
         {
           timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS));
         }
         else if (dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS))
         {
           timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS));
         }
 
         if (timePoints.empty())
         {
           MITK_ERROR << "Stored timepoints are empty. Meta information seems to bee invalid. Switch to ProportionalTimeGeometry fallback";
         }
         else if (timePoints.size() - 1 != image->GetDimension(3))
         {
           MITK_ERROR << "Stored timepoints (" << timePoints.size() - 1 << ") and size of image time dimension ("
             << image->GetDimension(3) << ") do not match. Switch to ProportionalTimeGeometry fallback";
         }
         else
         {
           ArbitraryTimeGeometry::Pointer arbitraryTimeGeometry = ArbitraryTimeGeometry::New();
           TimePointVector::const_iterator pos = timePoints.begin();
           auto prePos = pos++;
 
           for (; pos != timePoints.end(); ++prePos, ++pos)
           {
             arbitraryTimeGeometry->AppendNewTimeStepClone(slicedGeometry, *prePos, *pos);
           }
 
           timeGeometry = arbitraryTimeGeometry;
         }
       }
     }
 
     if (timeGeometry.IsNull())
     { // Fallback. If no other valid time geometry has been created, create a ProportionalTimeGeometry
       MITK_INFO << "used time geometry: " << ProportionalTimeGeometry::GetStaticNameOfClass();
       ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New();
       propTimeGeometry->Initialize(slicedGeometry, image->GetDimension(3));
       timeGeometry = propTimeGeometry;
     }
 
     image->SetTimeGeometry(timeGeometry);
 
     buffer = nullptr;
     MITK_INFO << "number of image components: " << image->GetPixelType().GetNumberOfComponents();
 
     // end regular image loading
 
     LabelSetImage::Pointer output = ConvertImageToLabelSetImage(image);
 
     // get labels and add them as properties to the image
     char keybuffer[256];
 
     unsigned int numberOfLayers = GetIntByKey(dictionary, "layers");
     std::string _xmlStr;
     mitk::Label::Pointer label;
 
     for (unsigned int layerIdx = 0; layerIdx < numberOfLayers; layerIdx++)
     {
       sprintf(keybuffer, "layer_%03u", layerIdx);
       int numberOfLabels = GetIntByKey(dictionary, keybuffer);
 
       mitk::LabelSet::Pointer labelSet = mitk::LabelSet::New();
 
       for (int labelIdx = 0; labelIdx < numberOfLabels; labelIdx++)
       {
         TiXmlDocument doc;
         sprintf(keybuffer, "label_%03u_%05d", layerIdx, labelIdx);
         _xmlStr = GetStringByKey(dictionary, keybuffer);
         doc.Parse(_xmlStr.c_str());
 
         TiXmlElement *labelElem = doc.FirstChildElement("Label");
         if (labelElem == nullptr)
           mitkThrow() << "Error parsing NRRD header for mitk::LabelSetImage IO";
 
         label = mitk::LabelSetIOHelper::LoadLabelFromTiXmlDocument(labelElem);
 
         if (label->GetValue() == 0) // set exterior label is needed to hold exterior information
           output->SetExteriorLabel(label);
         labelSet->AddLabel(label);
         labelSet->SetLayer(layerIdx);
       }
       output->AddLabelSetToLayer(layerIdx, labelSet);
     }
 
     for (auto iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd;
       ++iter)
     {
       if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string))
       {
         const std::string& key = iter->first;
         std::string assumedPropertyName = key;
         std::replace(assumedPropertyName.begin(), assumedPropertyName.end(), '_', '.');
 
         std::string mimeTypeName = GetMimeType()->GetName();
 
         // Check if there is already a info for the key and our mime type.
         mitk::CoreServicePointer<IPropertyPersistence> propPersistenceService(mitk::CoreServices::GetPropertyPersistence());
         IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfoByKey(key);
 
         auto predicate = [&mimeTypeName](const PropertyPersistenceInfo::ConstPointer& x) {
           return x.IsNotNull() && x->GetMimeTypeName() == mimeTypeName;
         };
         auto finding = std::find_if(infoList.begin(), infoList.end(), predicate);
 
         if (finding == infoList.end())
         {
           auto predicateWild = [](const PropertyPersistenceInfo::ConstPointer& x) {
             return x.IsNotNull() && x->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME();
           };
           finding = std::find_if(infoList.begin(), infoList.end(), predicateWild);
         }
 
         PropertyPersistenceInfo::ConstPointer info;
 
         if (finding != infoList.end())
         {
           assumedPropertyName = (*finding)->GetName();
           info = *finding;
         }
         else
         { // we have not found anything suitable so we generate our own info
           auto newInfo = PropertyPersistenceInfo::New();
           newInfo->SetNameAndKey(assumedPropertyName, key);
           newInfo->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME());
           info = newInfo;
         }
 
         std::string value =
           dynamic_cast<itk::MetaDataObject<std::string>*>(iter->second.GetPointer())->GetMetaDataObjectValue();
 
         mitk::BaseProperty::Pointer loadedProp = info->GetDeserializationFunction()(value);
 
         output->SetProperty(assumedPropertyName.c_str(), loadedProp);
 
         // Read properties should be persisted unless they are default properties
         // which are written anyway
         bool isDefaultKey = false;
 
         for (const auto& defaultKey : m_DefaultMetaDataKeys)
         {
           if (defaultKey.length() <= assumedPropertyName.length())
           {
             // does the start match the default key
             if (assumedPropertyName.substr(0, defaultKey.length()).find(defaultKey) != std::string::npos)
             {
               isDefaultKey = true;
               break;
             }
           }
         }
 
         if (!isDefaultKey)
         {
           propPersistenceService->AddInfo(info);
         }
       }
     }
 
     MITK_INFO << "...finished!";
 
     std::vector<BaseData::Pointer> result;
     result.push_back(output.GetPointer());
     return result;
   }
 
   int LabelSetImageIO::GetIntByKey(const itk::MetaDataDictionary &dic, const std::string &str)
   {
     std::vector<std::string> imgMetaKeys = dic.GetKeys();
     std::vector<std::string>::const_iterator itKey = imgMetaKeys.begin();
     std::string metaString("");
     for (; itKey != imgMetaKeys.end(); itKey++)
     {
       itk::ExposeMetaData<std::string>(dic, *itKey, metaString);
       if (itKey->find(str.c_str()) != std::string::npos)
       {
         return atoi(metaString.c_str());
       }
     }
     return 0;
   }
 
   std::string LabelSetImageIO::GetStringByKey(const itk::MetaDataDictionary &dic, const std::string &str)
   {
     std::vector<std::string> imgMetaKeys = dic.GetKeys();
     std::vector<std::string>::const_iterator itKey = imgMetaKeys.begin();
     std::string metaString("");
     for (; itKey != imgMetaKeys.end(); itKey++)
     {
       itk::ExposeMetaData<std::string>(dic, *itKey, metaString);
       if (itKey->find(str.c_str()) != std::string::npos)
       {
         return metaString;
       }
     }
     return metaString;
   }
 
   LabelSetImageIO *LabelSetImageIO::IOClone() const { return new LabelSetImageIO(*this); }
 
   void LabelSetImageIO::InitializeDefaultMetaDataKeys()
   {
     this->m_DefaultMetaDataKeys.push_back("NRRD.space");
     this->m_DefaultMetaDataKeys.push_back("NRRD.kinds");
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE);
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS);
     this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName");
     this->m_DefaultMetaDataKeys.push_back("label_");
     this->m_DefaultMetaDataKeys.push_back("layer_");
   }
 
 } // namespace
 
 #endif //__mitkLabelSetImageWriter__cpp
diff --git a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.h b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.h
index 59277a97e5..4b079dc5e4 100644
--- a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.h
+++ b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.h
@@ -1,66 +1,68 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkLabelSetImageIO_h
 #define __mitkLabelSetImageIO_h
 
 #include <mitkAbstractFileIO.h>
 #include <mitkLabelSetImage.h>
 
 namespace mitk
 {
   /**
   * Writes a LabelSetImage to a file
   * @ingroup Process
   */
   // The export macro should be removed. Currently, the unit
   // tests directly instantiate this class.
   class LabelSetImageIO : public mitk::AbstractFileIO
   {
   public:
     typedef mitk::LabelSetImage InputType;
 
     LabelSetImageIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    /**
-    * @brief Reads a number of mitk::LabelSetImages from the file system
-    * @return a vector of mitk::LabelSetImages
-    * @throws throws an mitk::Exception if an error ocurrs during parsing the nrrd header
-    */
-    std::vector<BaseData::Pointer> Read() override;
+
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
     ConfidenceLevel GetWriterConfidenceLevel() const override;
 
     // -------------- LabelSetImageIO specific functions -------------
 
     int GetIntByKey(const itk::MetaDataDictionary &dic, const std::string &str);
     std::string GetStringByKey(const itk::MetaDataDictionary &dic, const std::string &str);
 
   protected:
+    /**
+    * @brief Reads a number of mitk::LabelSetImages from the file system
+    * @return a vector of mitk::LabelSetImages
+    * @throws throws an mitk::Exception if an error ocurrs during parsing the nrrd header
+    */
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
     // Fills the m_DefaultMetaDataKeys vector with default values
     virtual void InitializeDefaultMetaDataKeys();
 
   private:
     LabelSetImageIO *IOClone() const override;
 
     std::vector<std::string> m_DefaultMetaDataKeys;
   };
 } // end of namespace mitk
 
 #endif // __mitkLabelSetImageIO_h
diff --git a/Modules/Multilabel/mitkMultilabelObjectFactory.cpp b/Modules/Multilabel/mitkMultilabelObjectFactory.cpp
index e402aeff8b..6bce2dc1d8 100644
--- a/Modules/Multilabel/mitkMultilabelObjectFactory.cpp
+++ b/Modules/Multilabel/mitkMultilabelObjectFactory.cpp
@@ -1,124 +1,124 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkMultilabelObjectFactory.h"
 
 #include "mitkBaseRenderer.h"
 #include "mitkCoreObjectFactory.h"
 #include "mitkDataNode.h"
 #include "mitkProperties.h"
 #include <mitkCoreServices.h>
 #include <mitkIPropertyFilters.h>
 #include <mitkLabelSetImageVtkMapper2D.h>
 #include <mitkPropertyFilter.h>
 
 mitk::MultilabelObjectFactory::MultilabelObjectFactory() : CoreObjectFactoryBase()
 {
   static bool alreadyDone = false;
   if (!alreadyDone)
   {
     MITK_DEBUG << "MultilabelObjectFactory c'tor" << std::endl;
 
     CreateFileExtensionsMap();
 
     alreadyDone = true;
   }
 }
 
 mitk::MultilabelObjectFactory::~MultilabelObjectFactory()
 {
 }
 
 mitk::Mapper::Pointer mitk::MultilabelObjectFactory::CreateMapper(mitk::DataNode *node, MapperSlotId id)
 {
   mitk::Mapper::Pointer newMapper = nullptr;
   mitk::BaseData *data = node->GetData();
 
   if (id == mitk::BaseRenderer::Standard2D)
   {
     if ((dynamic_cast<mitk::LabelSetImage *>(data) != nullptr))
     {
       newMapper = mitk::LabelSetImageVtkMapper2D::New();
       newMapper->SetDataNode(node);
     }
   }
   return newMapper;
 }
 
 void mitk::MultilabelObjectFactory::SetDefaultProperties(mitk::DataNode *node)
 {
   if (node == nullptr)
     return;
 
   if (node->GetData() == nullptr)
     return;
 
   if (dynamic_cast<LabelSetImage *>(node->GetData()) != nullptr)
   {
     mitk::LabelSetImageVtkMapper2D::SetDefaultProperties(node);
 
     auto propertyFilters = CoreServices::GetPropertyFilters();
 
     if (propertyFilters != nullptr)
     {
       PropertyFilter labelSetImageFilter;
       labelSetImageFilter.AddEntry("binaryimage.hoveringannotationcolor", PropertyFilter::Blacklist);
       labelSetImageFilter.AddEntry("binaryimage.hoveringcolor", PropertyFilter::Blacklist);
       labelSetImageFilter.AddEntry("binaryimage.selectedannotationcolor", PropertyFilter::Blacklist);
       labelSetImageFilter.AddEntry("binaryimage.selectedcolor", PropertyFilter::Blacklist);
       labelSetImageFilter.AddEntry("outline binary shadow color", PropertyFilter::Blacklist);
 
       propertyFilters->AddFilter(labelSetImageFilter, "LabelSetImage");
     }
   }
 }
 
 const char *mitk::MultilabelObjectFactory::GetFileExtensions()
 {
   std::string fileExtension;
-  this->CreateFileExtensions(m_FileExtensionsMap, fileExtension);
+  this->CreateFileExtensions({}, fileExtension);
   return fileExtension.c_str();
 }
 
 mitk::CoreObjectFactoryBase::MultimapType mitk::MultilabelObjectFactory::GetFileExtensionsMap()
 {
-  return m_FileExtensionsMap;
+  return {};
 }
 
 mitk::CoreObjectFactoryBase::MultimapType mitk::MultilabelObjectFactory::GetSaveFileExtensionsMap()
 {
-  return m_SaveFileExtensionsMap;
+  return {};
 }
 
 void mitk::MultilabelObjectFactory::CreateFileExtensionsMap()
 {
 }
 
 const char *mitk::MultilabelObjectFactory::GetSaveFileExtensions()
 {
   std::string fileExtension;
-  this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension);
+  this->CreateFileExtensions({}, fileExtension);
   return fileExtension.c_str();
 }
 
 struct RegisterMultilabelObjectFactory
 {
   RegisterMultilabelObjectFactory() : m_Factory(mitk::MultilabelObjectFactory::New())
   {
     mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory(m_Factory);
   }
 
   ~RegisterMultilabelObjectFactory() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory(m_Factory); }
   mitk::MultilabelObjectFactory::Pointer m_Factory;
 };
 
 static RegisterMultilabelObjectFactory registerMultilabelObjectFactory;
diff --git a/Modules/Multilabel/mitkMultilabelObjectFactory.h b/Modules/Multilabel/mitkMultilabelObjectFactory.h
index 072f959e0e..2631cf6500 100644
--- a/Modules/Multilabel/mitkMultilabelObjectFactory.h
+++ b/Modules/Multilabel/mitkMultilabelObjectFactory.h
@@ -1,50 +1,42 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef MULTILABELOBJECTFACTORY_H_INCLUDED
 #define MULTILABELOBJECTFACTORY_H_INCLUDED
 
 #include "mitkCoreObjectFactoryBase.h"
 
 #include <mitkAbstractFileIO.h>
 
 namespace mitk
 {
   class MultilabelObjectFactory : public CoreObjectFactoryBase
   {
   public:
     mitkClassMacro(MultilabelObjectFactory, CoreObjectFactoryBase);
     itkFactorylessNewMacro(Self);
     itkCloneMacro(Self) Mapper::Pointer
       CreateMapper(mitk::DataNode *node, MapperSlotId slotId) override;
     void SetDefaultProperties(mitk::DataNode *node) override;
     const char *GetFileExtensions() override;
     mitk::CoreObjectFactoryBase::MultimapType GetFileExtensionsMap() override;
     const char *GetSaveFileExtensions() override;
     mitk::CoreObjectFactoryBase::MultimapType GetSaveFileExtensionsMap() override;
 
   protected:
     MultilabelObjectFactory();
     ~MultilabelObjectFactory() override;
     void CreateFileExtensionsMap();
-    MultimapType m_FileExtensionsMap;
-    MultimapType m_SaveFileExtensionsMap;
-
-  private:
-    itk::ObjectFactoryBase::Pointer m_LabelSetImageIOFactory;
-    itk::ObjectFactoryBase::Pointer m_LabelSetImageWriterFactory;
-
-    std::vector<mitk::AbstractFileIO *> m_FileIOs;
   };
 }
 
 #endif
diff --git a/Modules/PlanarFigure/CMakeLists.txt b/Modules/PlanarFigure/CMakeLists.txt
index 0933cc7d71..af4c93bb9c 100644
--- a/Modules/PlanarFigure/CMakeLists.txt
+++ b/Modules/PlanarFigure/CMakeLists.txt
@@ -1,7 +1,10 @@
 MITK_CREATE_MODULE(
-  INCLUDE_DIRS PRIVATE src/Algorithms src/DataManagement src/Interactions src/IO src/Rendering
-  DEPENDS MitkSceneSerializationBase MitkLegacyGL MitkAnnotation
+  INCLUDE_DIRS PRIVATE src/Algorithms src/DataManagement src/Interactions src/Rendering
+  DEPENDS MitkLegacyGL MitkAnnotation
 )
 
-add_subdirectory(test)
+add_subdirectory(autoload/IO)
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
 
diff --git a/Modules/PlanarFigure/autoload/IO/CMakeLists.txt b/Modules/PlanarFigure/autoload/IO/CMakeLists.txt
new file mode 100644
index 0000000000..bdde2f83fc
--- /dev/null
+++ b/Modules/PlanarFigure/autoload/IO/CMakeLists.txt
@@ -0,0 +1,4 @@
+MITK_CREATE_MODULE( PlanarFigureIO
+  DEPENDS MitkPlanarFigure MitkSceneSerializationBase
+  AUTOLOAD_WITH MitkCore
+)
diff --git a/Modules/PlanarFigure/autoload/IO/files.cmake b/Modules/PlanarFigure/autoload/IO/files.cmake
new file mode 100644
index 0000000000..d085b5ba90
--- /dev/null
+++ b/Modules/PlanarFigure/autoload/IO/files.cmake
@@ -0,0 +1,12 @@
+set(H_FILES
+  mitkPlanarFigureIO.h
+  mitkPlanarFigureSerializer.h
+)
+
+set(CPP_FILES
+  mitkPlanarFigureIOActivator.cpp
+  mitkPlanarFigureIO.cpp
+  mitkPlanarFigureSerializer.cpp
+  mitkPlanarFigureSubclassesSerializer.cpp
+)
+
diff --git a/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIO.cpp b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIO.cpp
new file mode 100644
index 0000000000..246a8c2843
--- /dev/null
+++ b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIO.cpp
@@ -0,0 +1,560 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#include <mitkPlanarFigureIO.h>
+
+#include "mitkCustomMimeType.h"
+#include "mitkIOMimeTypes.h"
+#include "mitkExceptionMacro.h"
+
+#include "mitkPlanarAngle.h"
+#include "mitkPlanarArrow.h"
+#include "mitkPlanarBezierCurve.h"
+#include "mitkPlanarCircle.h"
+#include "mitkPlanarCross.h"
+#include "mitkPlanarDoubleEllipse.h"
+#include "mitkPlanarEllipse.h"
+#include "mitkPlanarFourPointAngle.h"
+#include "mitkPlanarLine.h"
+#include "mitkPlanarPolygon.h"
+#include "mitkPlanarRectangle.h"
+#include "mitkPlanarSubdivisionPolygon.h"
+#include "mitkPlaneGeometry.h"
+
+#include "mitkBasePropertySerializer.h"
+
+#include <mitkLocaleSwitch.h>
+
+#include <tinyxml.h>
+
+namespace mitk
+{
+
+  PlanarFigureIO::PlanarFigureIO()
+    : AbstractFileIO(PlanarFigure::GetStaticNameOfClass())
+  {
+    std::string category = "MITK PlanarFigure File";
+    CustomMimeType customMimeType;
+    customMimeType.SetCategory(category);
+    customMimeType.AddExtension("pf");
+    this->AbstractFileIOWriter::SetMimeType(customMimeType);
+    this->AbstractFileIOWriter::SetDescription(category);
+
+    customMimeType.AddExtension("pf");
+    customMimeType.AddExtension("PF");
+    this->AbstractFileIOReader::SetMimeType(customMimeType);
+    this->AbstractFileIOReader::SetDescription(category);
+
+    AbstractFileWriter::SetRanking(10);
+    AbstractFileReader::SetRanking(10);
+    this->RegisterService();
+  }
+
+  IFileIO::ConfidenceLevel PlanarFigureIO::GetWriterConfidenceLevel() const
+  {
+    if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
+      return Unsupported;
+
+    const auto *input = static_cast<const PlanarFigure *>(this->GetInput());
+    if (input != nullptr)
+      return Supported;
+    else
+      return Unsupported;
+  }
+
+  void PlanarFigureIO::Write()
+  {
+    this->ValidateOutputLocation();
+
+    mitk::LocaleSwitch localeSwitch("C");
+
+    TiXmlDocument document;
+    auto decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc....
+    document.LinkEndChild(decl);
+
+    auto version = new TiXmlElement("Version");
+    version->SetAttribute("Writer", __FILE__);
+    version->SetAttribute("CVSRevision", "$Revision: 17055 $");
+    version->SetAttribute("FileVersion", 1);
+    document.LinkEndChild(version);
+
+    auto pf = dynamic_cast<const PlanarFigure*>(this->GetInput());
+    if (pf == nullptr)
+    {
+      mitkThrow() << "Try to safe a BaseData instance as PlanarFigure. That is not a planar figure. This should not happen and is a violated precondition. Please check the program logic.";
+    }
+
+    auto pfElement = new TiXmlElement("PlanarFigure");
+    pfElement->SetAttribute("type", pf->GetNameOfClass());
+    document.LinkEndChild(pfElement);
+
+    // Serialize property list of PlanarFigure
+    mitk::PropertyList::Pointer propertyList = pf->GetPropertyList();
+    mitk::PropertyList::PropertyMap::const_iterator it;
+    for (it = propertyList->GetMap()->begin(); it != propertyList->GetMap()->end(); ++it)
+    {
+      // Create seralizer for this property
+      const mitk::BaseProperty* prop = it->second;
+      std::string serializerName = std::string(prop->GetNameOfClass()) + "Serializer";
+      std::list<itk::LightObject::Pointer> allSerializers =
+        itk::ObjectFactoryBase::CreateAllInstance(serializerName.c_str());
+
+      if (allSerializers.size() != 1)
+      {
+        // No or too many serializer(s) found, skip this property
+        continue;
+      }
+
+      auto* serializer =
+        dynamic_cast<mitk::BasePropertySerializer*>(allSerializers.begin()->GetPointer());
+      if (serializer == nullptr)
+      {
+        // Serializer not valid; skip this property
+      }
+
+      auto keyElement = new TiXmlElement("property");
+      keyElement->SetAttribute("key", it->first);
+      keyElement->SetAttribute("type", prop->GetNameOfClass());
+
+      serializer->SetProperty(prop);
+      TiXmlElement* valueElement = nullptr;
+      try
+      {
+        valueElement = serializer->Serialize();
+      }
+      catch (...)
+      {
+      }
+
+      if (valueElement == nullptr)
+      {
+        // Serialization failed; skip this property
+        continue;
+      }
+
+      // Add value to property element
+      keyElement->LinkEndChild(valueElement);
+
+      // Append serialized property to property list
+      pfElement->LinkEndChild(keyElement);
+    }
+
+    // Serialize control points of PlanarFigure
+    auto controlPointsElement = new TiXmlElement("ControlPoints");
+    pfElement->LinkEndChild(controlPointsElement);
+    for (unsigned int i = 0; i < pf->GetNumberOfControlPoints(); i++)
+    {
+      auto vElement = new TiXmlElement("Vertex");
+      vElement->SetAttribute("id", i);
+      vElement->SetDoubleAttribute("x", pf->GetControlPoint(i)[0]);
+      vElement->SetDoubleAttribute("y", pf->GetControlPoint(i)[1]);
+      controlPointsElement->LinkEndChild(vElement);
+    }
+    auto geoElement = new TiXmlElement("Geometry");
+    const auto* planeGeo = dynamic_cast<const PlaneGeometry*>(pf->GetPlaneGeometry());
+    if (planeGeo != nullptr)
+    {
+      // Write parameters of IndexToWorldTransform of the PlaneGeometry
+      typedef mitk::Geometry3D::TransformType TransformType;
+      const TransformType* affineGeometry = planeGeo->GetIndexToWorldTransform();
+      const TransformType::ParametersType& parameters = affineGeometry->GetParameters();
+      auto vElement = new TiXmlElement("transformParam");
+      for (unsigned int i = 0; i < affineGeometry->GetNumberOfParameters(); ++i)
+      {
+        std::stringstream paramName;
+        paramName << "param" << i;
+        vElement->SetDoubleAttribute(paramName.str().c_str(), parameters.GetElement(i));
+      }
+      geoElement->LinkEndChild(vElement);
+
+      // Write bounds of the PlaneGeometry
+      typedef mitk::Geometry3D::BoundsArrayType BoundsArrayType;
+      const BoundsArrayType& bounds = planeGeo->GetBounds();
+      vElement = new TiXmlElement("boundsParam");
+      for (unsigned int i = 0; i < 6; ++i)
+      {
+        std::stringstream boundName;
+        boundName << "bound" << i;
+        vElement->SetDoubleAttribute(boundName.str().c_str(), bounds.GetElement(i));
+      }
+      geoElement->LinkEndChild(vElement);
+
+      // Write spacing and origin of the PlaneGeometry
+      Vector3D spacing = planeGeo->GetSpacing();
+      Point3D origin = planeGeo->GetOrigin();
+      geoElement->LinkEndChild(this->CreateXMLVectorElement("Spacing", spacing));
+      geoElement->LinkEndChild(this->CreateXMLVectorElement("Origin", origin));
+
+      pfElement->LinkEndChild(geoElement);
+    }
+
+    if (this->GetOutputStream() != nullptr)
+    {
+      *(this->GetOutputStream()) << document;
+    }
+    else
+    {
+      if (document.SaveFile(this->GetOutputLocation()) == false)
+      {
+        MITK_ERROR << "Could not write planar figures to " << this->GetOutputLocation() << "\nTinyXML reports '" << document.ErrorDesc()
+          << "'";
+        throw std::ios_base::failure("Error during writing of planar figure xml file.");
+      }
+    }
+  }
+
+  TiXmlElement* mitk::PlanarFigureIO::CreateXMLVectorElement(const char* name, itk::FixedArray<mitk::ScalarType, 3> v)
+  {
+    auto vElement = new TiXmlElement(name);
+    vElement->SetDoubleAttribute("x", v.GetElement(0));
+    vElement->SetDoubleAttribute("y", v.GetElement(1));
+    vElement->SetDoubleAttribute("z", v.GetElement(2));
+    return vElement;
+  }
+
+  IFileIO::ConfidenceLevel PlanarFigureIO::GetReaderConfidenceLevel() const
+  {
+    if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
+      return Unsupported;
+
+    return Supported;
+    //Remark: The original reader code assumed that al pf files can be read.
+    //So no content checking was done. Thus was not implemented while refactoring
+    //to services yet. But I think it would make sense.
+  }
+
+  std::vector<BaseData::Pointer> PlanarFigureIO::DoRead()
+  {
+    mitk::LocaleSwitch localeSwitch("C");
+
+    std::vector<BaseData::Pointer> results;
+
+    TiXmlDocument document;
+
+    if (this->GetInputStream() != nullptr)
+    {
+      std::string s(std::istreambuf_iterator<char>(*(this->GetInputStream())), {});
+      document.Parse(s.c_str());
+      //Remark: didn't use *(this->GetInputStream()) >> document;
+      //because our PlanarFigure files version 1 are illformed (multiple top level elements)
+      //and therefor tinyxml does not read them completly when streamed directly.
+      //only the first (version element) is read.
+    }
+    else
+    {
+      if (!document.LoadFile(this->GetInputLocation()))
+      {
+        MITK_ERROR << "Could not open/read/parse " << this->GetInputLocation() << ". TinyXML reports: '" << document.ErrorDesc()
+          << "'. "
+          << "The error occurred in row " << document.ErrorRow() << ", column " << document.ErrorCol() << ".";
+        return {};
+      }
+    }
+
+    int fileVersion = 1;
+    TiXmlElement* versionObject = document.FirstChildElement("Version");
+    if (versionObject != nullptr)
+    {
+      if (versionObject->QueryIntAttribute("FileVersion", &fileVersion) != TIXML_SUCCESS)
+      {
+        MITK_WARN << this->GetInputLocation() << " does not contain version information! Trying version 1 format." << std::endl;
+      }
+    }
+    else
+    {
+      MITK_WARN << this->GetInputLocation() << " does not contain version information! Trying version 1 format." << std::endl;
+    }
+    if (fileVersion !=
+      1) // add file version selection and version specific file parsing here, if newer file versions are created
+    {
+      MITK_WARN << "File version > 1 is not supported by this reader.";
+      return {};
+    }
+
+    /* file version 1 reader code */
+    for (TiXmlElement* pfElement = document.FirstChildElement("PlanarFigure"); pfElement != nullptr;
+      pfElement = pfElement->NextSiblingElement("PlanarFigure"))
+    {
+      std::string type = pfElement->Attribute("type");
+
+      mitk::PlanarFigure::Pointer planarFigure = nullptr;
+      if (type == "PlanarAngle")
+      {
+        planarFigure = mitk::PlanarAngle::New();
+      }
+      else if (type == "PlanarCircle")
+      {
+        planarFigure = mitk::PlanarCircle::New();
+      }
+      else if (type == "PlanarEllipse")
+      {
+        planarFigure = mitk::PlanarEllipse::New();
+      }
+      else if (type == "PlanarCross")
+      {
+        planarFigure = mitk::PlanarCross::New();
+      }
+      else if (type == "PlanarFourPointAngle")
+      {
+        planarFigure = mitk::PlanarFourPointAngle::New();
+      }
+      else if (type == "PlanarLine")
+      {
+        planarFigure = mitk::PlanarLine::New();
+      }
+      else if (type == "PlanarPolygon")
+      {
+        planarFigure = mitk::PlanarPolygon::New();
+      }
+      else if (type == "PlanarSubdivisionPolygon")
+      {
+        planarFigure = mitk::PlanarSubdivisionPolygon::New();
+      }
+      else if (type == "PlanarRectangle")
+      {
+        planarFigure = mitk::PlanarRectangle::New();
+      }
+      else if (type == "PlanarArrow")
+      {
+        planarFigure = mitk::PlanarArrow::New();
+      }
+      else if (type == "PlanarDoubleEllipse")
+      {
+        planarFigure = mitk::PlanarDoubleEllipse::New();
+      }
+      else if (type == "PlanarBezierCurve")
+      {
+        planarFigure = mitk::PlanarBezierCurve::New();
+      }
+      else
+      {
+        // unknown type
+        MITK_WARN << "encountered unknown planar figure type '" << type << "'. Skipping this element.";
+        continue;
+      }
+
+      // Read properties of the planar figure
+      for (TiXmlElement* propertyElement = pfElement->FirstChildElement("property"); propertyElement != nullptr;
+        propertyElement = propertyElement->NextSiblingElement("property"))
+      {
+        const char* keya = propertyElement->Attribute("key");
+        const std::string key(keya ? keya : "");
+
+        const char* typea = propertyElement->Attribute("type");
+        const std::string type(typea ? typea : "");
+
+        // hand propertyElement to specific reader
+        std::stringstream propertyDeserializerClassName;
+        propertyDeserializerClassName << type << "Serializer";
+
+        const std::list<itk::LightObject::Pointer> readers =
+          itk::ObjectFactoryBase::CreateAllInstance(propertyDeserializerClassName.str().c_str());
+        if (readers.size() < 1)
+        {
+          MITK_ERROR << "No property reader found for " << type;
+        }
+        if (readers.size() > 1)
+        {
+          MITK_WARN << "Multiple property readers found for " << type << ". Using arbitrary first one.";
+        }
+
+        for (auto iter = readers.cbegin(); iter != readers.cend(); ++iter)
+        {
+          if (auto* reader = dynamic_cast<BasePropertySerializer*>(iter->GetPointer()))
+          {
+            const BaseProperty::Pointer property = reader->Deserialize(propertyElement->FirstChildElement());
+            if (property.IsNotNull())
+            {
+              planarFigure->GetPropertyList()->ReplaceProperty(key, property);
+            }
+            else
+            {
+              MITK_ERROR << "There were errors while loading property '" << key << "' of type " << type
+                << ". Your data may be corrupted";
+            }
+            break;
+          }
+        }
+      }
+
+      // If we load a planarFigure, it has definitely been placed correctly.
+      // If we do not set this property here, we cannot load old planarFigures
+      // without messing up the interaction (PF-Interactor needs this property.
+      planarFigure->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
+
+      // Which features (length or circumference etc) a figure has is decided by whether it is closed or not
+      // the function SetClosed has to be called in case of PlanarPolygons to ensure they hold the correct feature
+      auto* planarPolygon = dynamic_cast<PlanarPolygon*>(planarFigure.GetPointer());
+      if (planarPolygon != nullptr)
+      {
+        bool isClosed = false;
+        planarFigure->GetPropertyList()->GetBoolProperty("closed", isClosed);
+        planarPolygon->SetClosed(isClosed);
+      }
+
+      // Read geometry of containing plane
+      TiXmlElement* geoElement = pfElement->FirstChildElement("Geometry");
+      if (geoElement != nullptr)
+      {
+        try
+        {
+          // Create plane geometry
+          mitk::PlaneGeometry::Pointer planeGeo = mitk::PlaneGeometry::New();
+
+          // Extract and set plane transform parameters
+          const DoubleList transformList =
+            this->GetDoubleAttributeListFromXMLNode(geoElement->FirstChildElement("transformParam"), "param", 12);
+
+          typedef mitk::BaseGeometry::TransformType TransformType;
+          TransformType::ParametersType parameters;
+          parameters.SetSize(12);
+
+          unsigned int i;
+          DoubleList::const_iterator it;
+          for (it = transformList.cbegin(), i = 0; it != transformList.cend(); ++it, ++i)
+          {
+            parameters.SetElement(i, *it);
+          }
+
+          typedef mitk::BaseGeometry::TransformType TransformType;
+          TransformType::Pointer affineGeometry = TransformType::New();
+          affineGeometry->SetParameters(parameters);
+          planeGeo->SetIndexToWorldTransform(affineGeometry);
+
+          // Extract and set plane bounds
+          const DoubleList boundsList =
+            this->GetDoubleAttributeListFromXMLNode(geoElement->FirstChildElement("boundsParam"), "bound", 6);
+
+          typedef mitk::BaseGeometry::BoundsArrayType BoundsArrayType;
+
+          BoundsArrayType bounds;
+          for (it = boundsList.cbegin(), i = 0; it != boundsList.cend(); ++it, ++i)
+          {
+            bounds[i] = *it;
+          }
+
+          planeGeo->SetBounds(bounds);
+
+          // Extract and set spacing and origin
+          const Vector3D spacing = this->GetVectorFromXMLNode(geoElement->FirstChildElement("Spacing"));
+          planeGeo->SetSpacing(spacing);
+
+          const Point3D origin = this->GetPointFromXMLNode(geoElement->FirstChildElement("Origin"));
+          planeGeo->SetOrigin(origin);
+          planarFigure->SetPlaneGeometry(planeGeo);
+        }
+        catch (...)
+        {
+        }
+      }
+      TiXmlElement* cpElement = pfElement->FirstChildElement("ControlPoints");
+      bool first = true;
+      if (cpElement != nullptr)
+        for (TiXmlElement* vertElement = cpElement->FirstChildElement("Vertex"); vertElement != nullptr;
+          vertElement = vertElement->NextSiblingElement("Vertex"))
+      {
+        int id = 0;
+        mitk::Point2D::ValueType x = 0.0;
+        mitk::Point2D::ValueType y = 0.0;
+        if (vertElement->QueryIntAttribute("id", &id) == TIXML_WRONG_TYPE)
+          return{}; // TODO: can we do a better error handling?
+        if (vertElement->QueryDoubleAttribute("x", &x) == TIXML_WRONG_TYPE)
+          return{}; // TODO: can we do a better error handling?
+        if (vertElement->QueryDoubleAttribute("y", &y) == TIXML_WRONG_TYPE)
+          return{}; // TODO: can we do a better error handling?
+        Point2D p;
+        p.SetElement(0, x);
+        p.SetElement(1, y);
+        if (first == true) // needed to set m_FigurePlaced to true
+        {
+          planarFigure->PlaceFigure(p);
+          first = false;
+        }
+        planarFigure->SetControlPoint(id, p, true);
+      }
+
+      // Calculate feature quantities of this PlanarFigure
+      planarFigure->EvaluateFeatures();
+
+      // Make sure that no control point is currently selected
+      planarFigure->DeselectControlPoint();
+
+      if (planarFigure.IsNotNull())
+      {
+        results.emplace_back(planarFigure);
+      }
+    }
+
+    return results;
+  }
+
+  mitk::PlanarFigureIO::DoubleList mitk::PlanarFigureIO::GetDoubleAttributeListFromXMLNode(
+    TiXmlElement* e, const char* attributeNameBase, unsigned int count)
+  {
+    DoubleList list;
+
+    if (e == nullptr)
+      throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
+
+    for (unsigned int i = 0; i < count; ++i)
+    {
+      mitk::ScalarType p(-1.0);
+      std::stringstream attributeName;
+      attributeName << attributeNameBase << i;
+
+      if (e->QueryDoubleAttribute(attributeName.str().c_str(), &p) == TIXML_WRONG_TYPE)
+        throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
+      list.push_back(p);
+    }
+
+    return list;
+  }
+
+  mitk::Point3D mitk::PlanarFigureIO::GetPointFromXMLNode(TiXmlElement* e)
+  {
+    if (e == nullptr)
+      throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
+    mitk::Point3D point;
+    mitk::ScalarType p(-1.0);
+    if (e->QueryDoubleAttribute("x", &p) == TIXML_WRONG_TYPE)
+      throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
+    point.SetElement(0, p);
+    if (e->QueryDoubleAttribute("y", &p) == TIXML_WRONG_TYPE)
+      throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
+    point.SetElement(1, p);
+    if (e->QueryDoubleAttribute("z", &p) == TIXML_WRONG_TYPE)
+      throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
+    point.SetElement(2, p);
+    return point;
+  }
+
+  mitk::Vector3D mitk::PlanarFigureIO::GetVectorFromXMLNode(TiXmlElement* e)
+  {
+    if (e == nullptr)
+      throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
+    mitk::Vector3D vector;
+    mitk::ScalarType p(-1.0);
+    if (e->QueryDoubleAttribute("x", &p) == TIXML_WRONG_TYPE)
+      throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
+    vector.SetElement(0, p);
+    if (e->QueryDoubleAttribute("y", &p) == TIXML_WRONG_TYPE)
+      throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
+    vector.SetElement(1, p);
+    if (e->QueryDoubleAttribute("z", &p) == TIXML_WRONG_TYPE)
+      throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
+    vector.SetElement(2, p);
+    return vector;
+  }
+
+  PlanarFigureIO *PlanarFigureIO::IOClone() const { return new PlanarFigureIO(*this); }
+
+} // namespace
diff --git a/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIO.h b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIO.h
new file mode 100644
index 0000000000..215ca99134
--- /dev/null
+++ b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIO.h
@@ -0,0 +1,92 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#ifndef MITK_PLANAR_FIGURE_IO_H
+#define MITK_PLANAR_FIGURE_IO_H
+
+#include <mitkAbstractFileIO.h>
+#include <mitkPlanarFigure.h>
+
+class TiXmlElement;
+
+namespace mitk
+{
+  /**
+  * Reads/Writes a PlanarFigure to a file
+  * @ingroup Process
+  */
+  class PlanarFigureIO : public mitk::AbstractFileIO
+  {
+  public:
+    typedef mitk::PlanarFigure InputType;
+
+    PlanarFigureIO();
+
+    // -------------- AbstractFileReader -------------
+
+    using AbstractFileReader::Read;
+
+    ConfidenceLevel GetReaderConfidenceLevel() const override;
+
+    // -------------- AbstractFileWriter -------------
+
+    void Write() override;
+    ConfidenceLevel GetWriterConfidenceLevel() const override;
+
+  protected:
+    /**
+    * @brief Reads a number of mitk::PlanarFigures from the file system
+    * @return a vector of mitk::PlanarFigures
+    * @throws throws an mitk::Exception if an error ocurrs during parsing the nrrd header
+    */
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
+    using DoubleList = std::list<double>;
+    /**
+    * \brief parses the element for the attributes name0 to nameN, where "name" and the number of attributes
+    * to read are passed as argument. Returns a list of double vales.
+    * \param[in] e the TiXmlElement that will be parsed
+    * \param[in] attributeNameBase the basic name of the parameters
+    * \param[in] count the number of parameters
+    * \return returns a mitk::Point3D with the values x,y,z
+    */
+    DoubleList GetDoubleAttributeListFromXMLNode(TiXmlElement* e, const char* attributeNameBase, unsigned int count);
+
+    /**
+    * \brief parses the element for the attributes x,y,z and returns a mitk::Vector3D filled with these values
+    * \param[in] e the TiXmlElement that will be parsed
+    * \return returns a mitk::Vector3D with the values x,y,z
+    */
+    static mitk::Vector3D GetVectorFromXMLNode(TiXmlElement* e);
+
+    /**
+    * \brief parses the element for the attributes x,y,z and returns a mitk::Point3D filled with these values
+    * \param[in] e the TiXmlElement that will be parsed
+    * \return returns a mitk::Point3D with the values x,y,z
+    */
+    static mitk::Point3D GetPointFromXMLNode(TiXmlElement* e);
+
+    /**Documentation
+    * \brief creates a TinyXML element that contains x, y, and z values
+    *
+    * \param[in] name the name of the XML element
+    * \param[in] v the vector or point that contains the x, y and z values
+    * \return returns a TiXmlElement named name and three attributes x, y and z.
+    */
+    static TiXmlElement* CreateXMLVectorElement(const char* name, itk::FixedArray<mitk::ScalarType, 3> v);
+
+  private:
+    PlanarFigureIO *IOClone() const override;
+  };
+} // end of namespace mitk
+
+#endif // MITK_PLANAR_FIGURE_IO_H
diff --git a/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIOActivator.cpp b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIOActivator.cpp
new file mode 100644
index 0000000000..4c509d33b9
--- /dev/null
+++ b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureIOActivator.cpp
@@ -0,0 +1,44 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#include <usGetModuleContext.h>
+#include <usModule.h>
+#include <usModuleActivator.h>
+#include <usModuleContext.h>
+
+#include "mitkPlanarFigureIO.h"
+
+namespace mitk
+{
+  /**
+  \brief Registers IO services for PlanarFigure module.
+  */
+  class PlanarFigureIOModuleActivator : public us::ModuleActivator
+  {
+    std::vector<AbstractFileIO *> m_FileIOs;
+
+  public:
+    void Load(us::ModuleContext * /*context*/) override
+    {
+      m_FileIOs.push_back(new PlanarFigureIO());
+    }
+    void Unload(us::ModuleContext *) override
+    {
+      for (auto &elem : m_FileIOs)
+      {
+        delete elem;
+      }
+    }
+  };
+}
+
+US_EXPORT_MODULE_ACTIVATOR(mitk::PlanarFigureIOModuleActivator)
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureSerializer.cpp b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureSerializer.cpp
similarity index 87%
rename from Modules/PlanarFigure/src/IO/mitkPlanarFigureSerializer.cpp
rename to Modules/PlanarFigure/autoload/IO/mitkPlanarFigureSerializer.cpp
index 3cb1fb983b..d9e932a10e 100644
--- a/Modules/PlanarFigure/src/IO/mitkPlanarFigureSerializer.cpp
+++ b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureSerializer.cpp
@@ -1,62 +1,60 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkPlanarFigureSerializer.h"
 #include "mitkPlanarFigure.h"
-#include "mitkPlanarFigureWriter.h"
+
+#include <mitkIOUtil.h>
 
 #include <itksys/SystemTools.hxx>
 
 MITK_REGISTER_SERIALIZER(PlanarFigureSerializer)
 
 mitk::PlanarFigureSerializer::PlanarFigureSerializer()
 {
 }
 
 mitk::PlanarFigureSerializer::~PlanarFigureSerializer()
 {
 }
 
 std::string mitk::PlanarFigureSerializer::Serialize()
 {
   const auto *pf = dynamic_cast<const PlanarFigure *>(m_Data.GetPointer());
   if (pf == nullptr)
   {
     MITK_ERROR << " Object at " << (const void *)this->m_Data
                << " is not an mitk::PlanarFigure. Cannot serialize as PlanarFigure.";
     return "";
   }
 
   std::string filename(this->GetUniqueFilenameInWorkingDirectory());
   filename += "_";
   filename += m_FilenameHint;
   filename += ".pf";
 
   std::string fullname(m_WorkingDirectory);
   fullname += "/";
   fullname += itksys::SystemTools::ConvertToOutputPath(filename.c_str());
 
   try
   {
-    PlanarFigureWriter::Pointer writer = PlanarFigureWriter::New();
-    writer->SetFileName(fullname);
-    writer->SetInput(const_cast<PlanarFigure *>(pf));
-    writer->Write();
+    mitk::IOUtil::Save(pf, fullname);
   }
   catch (std::exception &e)
   {
     MITK_ERROR << " Error serializing object at " << (const void *)this->m_Data << " to " << fullname << ": "
                << e.what();
     return "";
   }
   return filename;
 }
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureSerializer.h b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureSerializer.h
similarity index 100%
rename from Modules/PlanarFigure/src/IO/mitkPlanarFigureSerializer.h
rename to Modules/PlanarFigure/autoload/IO/mitkPlanarFigureSerializer.h
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureSubclassesSerializer.cpp b/Modules/PlanarFigure/autoload/IO/mitkPlanarFigureSubclassesSerializer.cpp
similarity index 100%
rename from Modules/PlanarFigure/src/IO/mitkPlanarFigureSubclassesSerializer.cpp
rename to Modules/PlanarFigure/autoload/IO/mitkPlanarFigureSubclassesSerializer.cpp
diff --git a/Modules/PlanarFigure/files.cmake b/Modules/PlanarFigure/files.cmake
index dc4d3b3be2..321b93d75a 100644
--- a/Modules/PlanarFigure/files.cmake
+++ b/Modules/PlanarFigure/files.cmake
@@ -1,37 +1,31 @@
 file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
 
 set(CPP_FILES
   Algorithms/mitkExtrudePlanarFigureFilter.cpp
   Algorithms/mitkImageToPlanarFigureFilter.cpp
   Algorithms/mitkPlanarFigureObjectFactory.cpp
   Algorithms/mitkPlanarFigureSource.cpp
   Algorithms/mitkPlanarFigureToPlanarFigureFilter.cpp
   DataManagement/mitkPlanarAngle.cpp
   DataManagement/mitkPlanarBezierCurve.cpp
   DataManagement/mitkPlanarCircle.cpp
   DataManagement/mitkPlanarDoubleEllipse.cpp
   DataManagement/mitkPlanarEllipse.cpp
   DataManagement/mitkPlanarCross.cpp
   DataManagement/mitkPlanarFigure.cpp
   DataManagement/mitkPlanarFourPointAngle.cpp
   DataManagement/mitkPlanarLine.cpp
   DataManagement/mitkPlanarArrow.cpp
   DataManagement/mitkPlanarPolygon.cpp
   DataManagement/mitkPlanarSubdivisionPolygon.cpp
   DataManagement/mitkPlanarRectangle.cpp
   DataManagement/mitkPlanarFigureControlPointStyleProperty.cpp
-  IO/mitkPlanarFigureIOFactory.cpp
-  IO/mitkPlanarFigureReader.cpp
-  IO/mitkPlanarFigureWriter.cpp
-  IO/mitkPlanarFigureWriterFactory.cpp
-  IO/mitkPlanarFigureSerializer.cpp
-  IO/mitkPlanarFigureSubclassesSerializer.cpp
   Interactions/mitkPlanarFigureInteractor.cpp
   Rendering/mitkPlanarFigureMapper2D.cpp
   Rendering/mitkPlanarFigureVtkMapper3D.cpp
 )
 
 set(RESOURCE_FILES
   Interactions/PlanarFigureConfig.xml
   Interactions/PlanarFigureInteraction.xml
 )
diff --git a/Modules/PlanarFigure/include/mitkPlanarFigureObjectFactory.h b/Modules/PlanarFigure/include/mitkPlanarFigureObjectFactory.h
index d524154b3f..5bfb6260bb 100644
--- a/Modules/PlanarFigure/include/mitkPlanarFigureObjectFactory.h
+++ b/Modules/PlanarFigure/include/mitkPlanarFigureObjectFactory.h
@@ -1,56 +1,48 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef PLANARFIGUREOBJECTFACTORY_H_INCLUDED
 #define PLANARFIGUREOBJECTFACTORY_H_INCLUDED
 
 #include "mitkCoreObjectFactoryBase.h"
 #include <MitkPlanarFigureExports.h>
 
 namespace mitk
 {
   class MITKPLANARFIGURE_EXPORT PlanarFigureObjectFactory : public CoreObjectFactoryBase
   {
   public:
     mitkClassMacro(PlanarFigureObjectFactory, CoreObjectFactoryBase);
     itkFactorylessNewMacro(Self);
     itkCloneMacro(Self);
 
       ~PlanarFigureObjectFactory() override;
 
     Mapper::Pointer CreateMapper(mitk::DataNode *node, MapperSlotId slotId) override;
 
     void SetDefaultProperties(mitk::DataNode *node) override;
 
     const char *GetFileExtensions() override;
 
     mitk::CoreObjectFactoryBase::MultimapType GetFileExtensionsMap() override;
 
     const char *GetSaveFileExtensions() override;
 
     mitk::CoreObjectFactoryBase::MultimapType GetSaveFileExtensionsMap() override;
 
-    DEPRECATED(void RegisterIOFactories());
-
   protected:
     PlanarFigureObjectFactory();
     void CreateFileExtensionsMap();
-    MultimapType m_FileExtensionsMap;
-    MultimapType m_SaveFileExtensionsMap;
-
-  private:
-    itk::ObjectFactoryBase::Pointer m_PlanarFigureIOFactory;
-    itk::ObjectFactoryBase::Pointer m_PlanarFigureWriterFactory;
   };
 }
 
 #endif // PLANARFIGUREOBJECTFACTORY_H_INCLUDED
diff --git a/Modules/PlanarFigure/include/mitkPlanarFigureReader.h b/Modules/PlanarFigure/include/mitkPlanarFigureReader.h
deleted file mode 100644
index c565b99055..0000000000
--- a/Modules/PlanarFigure/include/mitkPlanarFigureReader.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*============================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center (DKFZ)
-All rights reserved.
-
-Use of this source code is governed by a 3-clause BSD license that can be
-found in the LICENSE file.
-
-============================================================================*/
-
-#ifndef _MITK_PlanarFigureReader__H_
-#define _MITK_PlanarFigureReader__H_
-
-#include "mitkFileReader.h"
-#include "mitkPlanarFigureSource.h"
-#include <MitkPlanarFigureExports.h>
-
-#include <list>
-
-class TiXmlElement;
-namespace mitk
-{
-  /**
-   * @brief reads xml representations of mitk::PlanarFigure from a file
-   *
-   * Reader for xml files containing one or multiple xml represenations of
-   * mitk::PlanarFigure. If multiple mitk::PlanarFigure are stored in one file,
-   * these are assigned to multiple outputs of the filter.
-   * @ingroup MitkPlanarFigureModule
-  */
-  class MITKPLANARFIGURE_EXPORT PlanarFigureReader : public PlanarFigureSource, public FileReader
-  {
-  public:
-    mitkClassMacro(PlanarFigureReader, FileReader);
-
-    itkFactorylessNewMacro(Self);
-
-    itkCloneMacro(Self);
-
-      /**
-       * @brief Sets the filename of the file to be read
-       * @param _arg the filename of the point set xml-file
-       */
-      itkSetStringMacro(FileName);
-
-    /**
-     * @brief Returns the filename of the point set xml-file.
-     * @returns the filename of the point set xml-file.
-     */
-    itkGetStringMacro(FileName);
-
-    /**
-     * @warning multiple load not (yet) supported
-     */
-    itkSetStringMacro(FilePrefix);
-
-    /**
-     * @warning multiple load not (yet) supported
-     */
-    itkGetStringMacro(FilePrefix);
-
-    /**
-     * @warning multiple load not (yet) supported
-     */
-    itkSetStringMacro(FilePattern);
-
-    /**
-     * @warning multiple load not (yet) supported
-     */
-    itkGetStringMacro(FilePattern);
-
-    static bool CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern);
-
-    /**
-     * @returns whether the last read attempt was successful or not.
-     */
-    itkGetConstMacro(Success, bool);
-
-  protected:
-    typedef std::list<double> DoubleList;
-
-    /**
-     * Constructor
-     */
-    PlanarFigureReader();
-
-    /**
-     * Virtual destructor
-     */
-    ~PlanarFigureReader() override;
-
-    /**
-     * Actually reads the point sets from the given file
-     */
-    void GenerateData() override;
-
-    /**
-     * Does nothing in the current implementation
-     */
-    void GenerateOutputInformation() override;
-
-    /**
-     * Resizes the output-objects according to the given number.
-     * @param num the new number of output objects.
-     */
-    virtual void ResizeOutputs(const unsigned int &num);
-
-    /**
-     * Checks if the given file has appropriate
-     * read access.
-     * @returns true if the file exists and may be read
-     *          or false otherwise.
-     */
-    virtual int CanReadFile(const char *name);
-
-    /**
-    * \brief parses the element for the attributes x,y,z and returns a mitk::Vector3D filled with these values
-    * \param[in] e the TiXmlElement that will be parsed
-    * \return returns a mitk::Vector3D with the values x,y,z
-    */
-    mitk::Vector3D GetVectorFromXMLNode(TiXmlElement *e);
-
-    /**
-    * \brief parses the element for the attributes x,y,z and returns a mitk::Point3D filled with these values
-    * \param[in] e the TiXmlElement that will be parsed
-    * \return returns a mitk::Point3D with the values x,y,z
-    */
-    mitk::Point3D GetPointFromXMLNode(TiXmlElement *e);
-
-    /**
-    * \brief parses the element for the attributes name0 to nameN, where "name" and the number of attributes
-    * to read are passed as argument. Returns a list of double vales.
-    * \param[in] e the TiXmlElement that will be parsed
-    * \param[in] attributeNameBase the basic name of the parameters
-    * \param[in] count the number of parameters
-    * \return returns a mitk::Point3D with the values x,y,z
-    */
-    DoubleList GetDoubleAttributeListFromXMLNode(TiXmlElement *e, const char *attributeNameBase, unsigned int count);
-
-    std::string m_FileName;
-    std::string m_FilePrefix;
-    std::string m_FilePattern;
-    bool m_Success;
-  };
-}
-#endif
diff --git a/Modules/PlanarFigure/include/mitkPlanarFigureWriter.h b/Modules/PlanarFigure/include/mitkPlanarFigureWriter.h
deleted file mode 100644
index ff4fc6476e..0000000000
--- a/Modules/PlanarFigure/include/mitkPlanarFigureWriter.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*============================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center (DKFZ)
-All rights reserved.
-
-Use of this source code is governed by a 3-clause BSD license that can be
-found in the LICENSE file.
-
-============================================================================*/
-
-#ifndef _MITK_PlanarFigure_WRITER__H_
-#define _MITK_PlanarFigure_WRITER__H_
-
-#include <MitkPlanarFigureExports.h>
-#include <itkProcessObject.h>
-#include <mitkFileWriterWithInformation.h>
-#include <mitkPlanarFigure.h>
-
-class TiXmlElement;
-namespace mitk
-{
-  /**
-  * @brief XML-based writer for mitk::PlanarFigures
-  *
-  * XML-based writer for mitk::PlanarFigures.
-  * @ingroup MitkPlanarFigureModule
-  */
-  class MITKPLANARFIGURE_EXPORT PlanarFigureWriter : public mitk::FileWriterWithInformation
-  {
-  public:
-    mitkClassMacro(PlanarFigureWriter, mitk::FileWriter);
-
-    mitkWriterMacro;
-
-    itkFactorylessNewMacro(Self);
-
-    itkCloneMacro(Self);
-
-      typedef mitk::PlanarFigure InputType;
-
-    typedef InputType::Pointer InputTypePointer;
-
-    /**
-    * Sets the filename of the file to write.
-    * @param FileName the name of the file to write.
-    */
-    itkSetStringMacro(FileName);
-
-    /**
-    * @returns the name of the file to be written to disk.
-    */
-    itkGetStringMacro(FileName);
-
-    /**
-    * @warning multiple write not (yet) supported
-    */
-    itkSetStringMacro(FilePrefix);
-
-    /**
-    * @warning multiple write not (yet) supported
-    */
-    itkGetStringMacro(FilePrefix);
-
-    /**
-    * @warning multiple write not (yet) supported
-    */
-    itkSetStringMacro(FilePattern);
-
-    /**
-    * @warning multiple write not (yet) supported
-    */
-    itkGetStringMacro(FilePattern);
-
-    using Superclass::SetInput;
-
-    /**
-    * Sets the 0'th input object for the filter.
-    * @param input the first input for the filter.
-    */
-    void SetInput(InputType *input);
-
-    /**
-    * Sets the n'th input object for the filter. If num is
-    * larger than GetNumberOfInputs() the number of inputs is
-    * resized appropriately.
-    * @param input the n'th input for the filter.
-    */
-    void SetInput(const unsigned int &num, InputType *input);
-
-    /**
-    * @returns the 0'th input object of the filter.
-    */
-    PlanarFigure *GetInput();
-
-    /**
-    * @param num the index of the desired output object.
-    * @returns the n'th input object of the filter.
-    */
-    PlanarFigure *GetInput(const unsigned int &num);
-
-    /**
-    * @brief Return the possible file extensions for the data type associated with the writer
-    */
-    std::vector<std::string> GetPossibleFileExtensions() override;
-
-    /**
-    * @brief Return the extension to be added to the filename.
-    */
-    std::string GetFileExtension() override;
-
-    /**
-    * @brief Check if the Writer can write the Content of the
-    */
-    bool CanWriteDataType(DataNode *) override;
-
-    /**
-    * @brief Return the MimeType of the saved File.
-    */
-    std::string GetWritenMIMEType() override;
-
-    /**
-    * @brief Set the DataTreenode as Input. Important: The Writer always have a SetInput-Function.
-    */
-    virtual void SetInput(DataNode *);
-
-    std::string GetSupportedBaseData() const override;
-
-    /**
-    * @returns whether the last write attempt was successful or not.
-    */
-    itkGetConstMacro(Success, bool);
-
-    const char *GetDefaultFilename() override { return "PlanarFigure.pf"; }
-    const char *GetFileDialogPattern() override { return "Planar Figure Files (*.pf)"; }
-    const char *GetDefaultExtension() override { return ".pf"; }
-    bool CanWriteBaseDataType(BaseData::Pointer data) override
-    {
-      return dynamic_cast<mitk::PlanarFigure *>(data.GetPointer());
-    }
-    void DoWrite(BaseData::Pointer data) override
-    {
-      if (CanWriteBaseDataType(data))
-      {
-        this->SetInput(dynamic_cast<mitk::PlanarFigure *>(data.GetPointer()));
-        this->Update();
-      }
-    }
-
-    /**
-    @brief CAUTION: It's up to the user to call this function to release the
-    memory buffer after use in case the file writer has written to its memory array.
-    See mitkFileWriter base class. */
-    void ReleaseMemory() override;
-
-  protected:
-    /**
-    * Constructor.
-    */
-    PlanarFigureWriter();
-
-    /**
-    * Virtual destructor.
-    */
-    ~PlanarFigureWriter() override;
-
-    /**
-    * Writes the a .pf file in xml format that contains all input planar figures
-    */
-    void GenerateData() override;
-
-    /**
-    * Resizes the number of inputs of the writer.
-    * The inputs are initialized by empty PlanarFigures
-    * @param num the new number of inputs
-    */
-    virtual void ResizeInputs(const unsigned int &num);
-
-    /**Documentation
-    * \brief creates a TinyXML element that contains x, y, and z values
-    *
-    * \param[in] name the name of the XML element
-    * \param[in] v the vector or point that contains the x, y and z values
-    * \return returns a TiXmlElement named name and three attributes x, y and z.
-    */
-    TiXmlElement *CreateXMLVectorElement(const char *name, itk::FixedArray<mitk::ScalarType, 3> v);
-
-    std::string m_FileName;
-    std::string m_FilePrefix;
-    std::string m_FilePattern;
-    std::string m_Extension;
-    std::string m_MimeType;
-    bool m_Success;
-  };
-}
-
-#endif
diff --git a/Modules/PlanarFigure/src/Algorithms/mitkPlanarFigureObjectFactory.cpp b/Modules/PlanarFigure/src/Algorithms/mitkPlanarFigureObjectFactory.cpp
index ab07c731b3..6ab9c276c3 100644
--- a/Modules/PlanarFigure/src/Algorithms/mitkPlanarFigureObjectFactory.cpp
+++ b/Modules/PlanarFigure/src/Algorithms/mitkPlanarFigureObjectFactory.cpp
@@ -1,136 +1,117 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkPlanarFigureObjectFactory.h"
-#include "mitkPlanarFigureWriter.h"
 
 #include "mitkCoreObjectFactory.h"
 
 #include "mitkPlanarFigure.h"
-#include "mitkPlanarFigureIOFactory.h"
 #include "mitkPlanarFigureMapper2D.h"
 #include "mitkPlanarFigureVtkMapper3D.h"
-#include "mitkPlanarFigureWriterFactory.h"
 #include "mitkVtkGLMapperWrapper.h"
 
 typedef std::multimap<std::string, std::string> MultimapType;
 
 mitk::PlanarFigureObjectFactory::PlanarFigureObjectFactory()
-  : m_PlanarFigureIOFactory(PlanarFigureIOFactory::New().GetPointer()),
-    m_PlanarFigureWriterFactory(PlanarFigureWriterFactory::New().GetPointer())
 {
   static bool alreadyDone = false;
   if (!alreadyDone)
   {
-    itk::ObjectFactoryBase::RegisterFactory(m_PlanarFigureIOFactory);
-    itk::ObjectFactoryBase::RegisterFactory(m_PlanarFigureWriterFactory);
-
-    m_FileWriters.push_back(PlanarFigureWriter::New().GetPointer());
-
     CreateFileExtensionsMap();
 
     alreadyDone = true;
   }
 }
 
 mitk::PlanarFigureObjectFactory::~PlanarFigureObjectFactory()
 {
-  itk::ObjectFactoryBase::UnRegisterFactory(m_PlanarFigureWriterFactory);
-  itk::ObjectFactoryBase::UnRegisterFactory(m_PlanarFigureIOFactory);
 }
 
 mitk::Mapper::Pointer mitk::PlanarFigureObjectFactory::CreateMapper(mitk::DataNode *node, MapperSlotId id)
 {
   mitk::Mapper::Pointer newMapper = nullptr;
   mitk::BaseData *data = node->GetData();
 
   if (dynamic_cast<PlanarFigure *>(data) != nullptr)
   {
     if (id == mitk::BaseRenderer::Standard2D)
     {
       newMapper = mitk::PlanarFigureMapper2D::New();
       newMapper->SetDataNode(node);
     }
     else if (id == mitk::BaseRenderer::Standard3D)
     {
       newMapper = mitk::PlanarFigureVtkMapper3D::New();
       newMapper->SetDataNode(node);
     }
   }
 
   return newMapper;
 }
 
 void mitk::PlanarFigureObjectFactory::SetDefaultProperties(mitk::DataNode *node)
 {
   if (node == nullptr)
   {
     return;
   }
 
   mitk::DataNode::Pointer nodePointer = node;
 
   mitk::PlanarFigure::Pointer pf = dynamic_cast<mitk::PlanarFigure *>(node->GetData());
   if (pf.IsNotNull())
   {
     mitk::PlanarFigureMapper2D::SetDefaultProperties(node);
     mitk::PlanarFigureVtkMapper3D::SetDefaultProperties(node);
     node->AddProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0), nullptr, true);
     node->AddProperty("opacity", mitk::FloatProperty::New(0.8), nullptr, true);
   }
 }
 
 const char *mitk::PlanarFigureObjectFactory::GetFileExtensions()
 {
   return "";
 }
 
 mitk::CoreObjectFactoryBase::MultimapType mitk::PlanarFigureObjectFactory::GetFileExtensionsMap()
 {
-  return m_FileExtensionsMap;
+  return {};
 }
 
 const char *mitk::PlanarFigureObjectFactory::GetSaveFileExtensions()
 {
-  // return ";;Planar Figures (*.pf)";  // for mitk::PlanarFigure and derived classes
   std::string fileExtension;
-  this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension);
+  this->CreateFileExtensions({}, fileExtension);
   return fileExtension.c_str();
 };
 
 mitk::CoreObjectFactoryBase::MultimapType mitk::PlanarFigureObjectFactory::GetSaveFileExtensionsMap()
 {
-  return m_SaveFileExtensionsMap;
+  return {};
 }
 
 void mitk::PlanarFigureObjectFactory::CreateFileExtensionsMap()
-{
-  m_FileExtensionsMap.insert(std::pair<std::string, std::string>("*.pf", "Planar Figure Files"));
-  m_SaveFileExtensionsMap.insert(std::pair<std::string, std::string>("*.pf", "Planar Figure Files"));
-}
-
-void mitk::PlanarFigureObjectFactory::RegisterIOFactories()
 {
 }
 
 struct RegisterPlanarFigureObjectFactory
 {
   RegisterPlanarFigureObjectFactory() : m_Factory(mitk::PlanarFigureObjectFactory::New())
   {
     mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory(m_Factory);
   }
 
   ~RegisterPlanarFigureObjectFactory() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory(m_Factory); }
   mitk::PlanarFigureObjectFactory::Pointer m_Factory;
 };
 
 static RegisterPlanarFigureObjectFactory registerPlanarFigureObjectFactory;
diff --git a/Modules/PlanarFigure/src/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/src/DataManagement/mitkPlanarFigure.cpp
index d135f3e58a..eb64366acd 100644
--- a/Modules/PlanarFigure/src/DataManagement/mitkPlanarFigure.cpp
+++ b/Modules/PlanarFigure/src/DataManagement/mitkPlanarFigure.cpp
@@ -1,781 +1,781 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkPlanarFigure.h"
 #include "mitkPlaneGeometry.h"
 #include <mitkProperties.h>
 #include <mitkProportionalTimeGeometry.h>
 
 #include <algorithm>
 
 mitk::PlanarFigure::PlanarFigure()
   : m_SelectedControlPoint(-1),
     m_PreviewControlPointVisible(false),
     m_FigurePlaced(false),
     m_PlaneGeometry(nullptr),
     m_PolyLineUpToDate(false),
     m_HelperLinesUpToDate(false),
     m_FeaturesUpToDate(false),
     m_FeaturesMTime(0)
 {
   m_HelperPolyLinesToBePainted = BoolContainerType::New();
 
   m_DisplaySize.first = 0.0;
   m_DisplaySize.second = 0;
 
   this->SetProperty("closed", mitk::BoolProperty::New(false));
 
   // Currently only single-time-step geometries are supported
   this->InitializeTimeGeometry(1);
 }
 
 mitk::PlanarFigure::PlanarFigure(const Self &other)
   : BaseData(other),
     m_ControlPoints(other.m_ControlPoints),
     m_NumberOfControlPoints(other.m_NumberOfControlPoints),
     m_SelectedControlPoint(other.m_SelectedControlPoint),
     m_PolyLines(other.m_PolyLines),
     m_HelperPolyLines(other.m_HelperPolyLines),
     m_PreviewControlPoint(other.m_PreviewControlPoint),
     m_PreviewControlPointVisible(other.m_PreviewControlPointVisible),
     m_FigurePlaced(other.m_FigurePlaced),
-    m_PlaneGeometry(other.m_PlaneGeometry), // do not clone since SetPlaneGeometry() doesn't clone either
     m_PolyLineUpToDate(other.m_PolyLineUpToDate),
     m_HelperLinesUpToDate(other.m_HelperLinesUpToDate),
     m_FeaturesUpToDate(other.m_FeaturesUpToDate),
     m_Features(other.m_Features),
     m_FeaturesMTime(other.m_FeaturesMTime),
     m_DisplaySize(other.m_DisplaySize)
 {
   m_HelperPolyLinesToBePainted = BoolContainerType::New();
   for (unsigned long i = 0; i < other.m_HelperPolyLinesToBePainted->Size(); ++i)
   {
     m_HelperPolyLinesToBePainted->InsertElement(i, other.m_HelperPolyLinesToBePainted->GetElement(i));
   }
+  m_PlaneGeometry = dynamic_cast<PlaneGeometry*>(GetGeometry(0));
 }
 
 void mitk::PlanarFigure::SetPlaneGeometry(mitk::PlaneGeometry *geometry)
 {
   this->SetGeometry(geometry);
   m_PlaneGeometry = dynamic_cast<PlaneGeometry *>(GetGeometry(0)); // geometry;
 }
 
 const mitk::PlaneGeometry *mitk::PlanarFigure::GetPlaneGeometry() const
 {
   return m_PlaneGeometry;
 }
 
 bool mitk::PlanarFigure::IsClosed() const
 {
   mitk::BoolProperty *closed = dynamic_cast<mitk::BoolProperty *>(this->GetProperty("closed").GetPointer());
   if (closed != nullptr)
   {
     return closed->GetValue();
   }
   return false;
 }
 
 void mitk::PlanarFigure::PlaceFigure(const mitk::Point2D &point)
 {
   for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i)
   {
     m_ControlPoints.push_back(this->ApplyControlPointConstraints(i, point));
   }
 
   m_FigurePlaced = true;
   m_SelectedControlPoint = 1;
 }
 
 bool mitk::PlanarFigure::AddControlPoint(const mitk::Point2D &point, int position)
 {
   // if we already have the maximum number of control points, do nothing
   if (m_NumberOfControlPoints < this->GetMaximumNumberOfControlPoints())
   {
     // if position has not been defined or position would be the last control point, just append the new one
     // we also append a new point if we click onto the line between the first two control-points if the second
     // control-point is selected
     // -> special case for PlanarCross
     if (position == -1 || position > (int)m_NumberOfControlPoints - 1 || (position == 1 && m_SelectedControlPoint == 2))
     {
       if (m_ControlPoints.size() > this->GetMaximumNumberOfControlPoints() - 1)
       {
         // get rid of deprecated control points in the list. This is necessary
         // as ::ResetNumberOfControlPoints() only sets the member, does not resize the list!
         m_ControlPoints.resize(this->GetNumberOfControlPoints());
       }
 
       m_ControlPoints.push_back(this->ApplyControlPointConstraints(m_NumberOfControlPoints, point));
       m_SelectedControlPoint = m_NumberOfControlPoints;
     }
     else
     {
       // insert the point at the given position and set it as selected point
       auto iter = m_ControlPoints.begin() + position;
       m_ControlPoints.insert(iter, this->ApplyControlPointConstraints(position, point));
       for (unsigned int i = 0; i < m_ControlPoints.size(); ++i)
       {
         if (point == m_ControlPoints.at(i))
         {
           m_SelectedControlPoint = i;
         }
       }
     }
 
     // polylines & helperpolylines need to be repainted
     m_PolyLineUpToDate = false;
     m_HelperLinesUpToDate = false;
     m_FeaturesUpToDate = false;
 
     // one control point more
     ++m_NumberOfControlPoints;
     return true;
   }
   else
   {
     return false;
   }
 }
 
 bool mitk::PlanarFigure::SetControlPoint(unsigned int index, const Point2D &point, bool createIfDoesNotExist)
 {
   bool controlPointSetCorrectly = false;
   if (createIfDoesNotExist)
   {
     if (m_NumberOfControlPoints <= index)
     {
       m_ControlPoints.push_back(this->ApplyControlPointConstraints(index, point));
       m_NumberOfControlPoints++;
     }
     else
     {
       m_ControlPoints.at(index) = this->ApplyControlPointConstraints(index, point);
     }
     controlPointSetCorrectly = true;
   }
   else if (index < m_NumberOfControlPoints)
   {
     m_ControlPoints.at(index) = this->ApplyControlPointConstraints(index, point);
     controlPointSetCorrectly = true;
   }
   else
   {
     return false;
   }
 
   if (controlPointSetCorrectly)
   {
     m_PolyLineUpToDate = false;
     m_HelperLinesUpToDate = false;
     m_FeaturesUpToDate = false;
   }
 
   return controlPointSetCorrectly;
 }
 
 bool mitk::PlanarFigure::SetCurrentControlPoint(const Point2D &point)
 {
   if ((m_SelectedControlPoint < 0) || (m_SelectedControlPoint >= (int)m_NumberOfControlPoints))
   {
     return false;
   }
 
   return this->SetControlPoint(m_SelectedControlPoint, point, false);
 }
 
 unsigned int mitk::PlanarFigure::GetNumberOfControlPoints() const
 {
   return m_NumberOfControlPoints;
 }
 
 bool mitk::PlanarFigure::SelectControlPoint(unsigned int index)
 {
   if (index < this->GetNumberOfControlPoints())
   {
     m_SelectedControlPoint = index;
     return true;
   }
   else
   {
     return false;
   }
 }
 
 bool mitk::PlanarFigure::DeselectControlPoint()
 {
   bool wasSelected = (m_SelectedControlPoint != -1);
 
   m_SelectedControlPoint = -1;
 
   return wasSelected;
 }
 
 void mitk::PlanarFigure::SetPreviewControlPoint(const Point2D &point)
 {
   m_PreviewControlPoint = point;
   m_PreviewControlPointVisible = true;
 }
 
 void mitk::PlanarFigure::ResetPreviewContolPoint()
 {
   m_PreviewControlPointVisible = false;
 }
 
 mitk::Point2D mitk::PlanarFigure::GetPreviewControlPoint() const
 {
   return m_PreviewControlPoint;
 }
 
 bool mitk::PlanarFigure::IsPreviewControlPointVisible() const
 {
   return m_PreviewControlPointVisible;
 }
 
 mitk::Point2D mitk::PlanarFigure::GetControlPoint(unsigned int index) const
 {
   if (index < m_NumberOfControlPoints)
   {
     return m_ControlPoints.at(index);
   }
 
   itkExceptionMacro(<< "GetControlPoint(): Invalid index!");
 }
 
 mitk::Point3D mitk::PlanarFigure::GetWorldControlPoint(unsigned int index) const
 {
   Point3D point3D;
   if ((m_PlaneGeometry != nullptr) && (index < m_NumberOfControlPoints))
   {
     m_PlaneGeometry->Map(m_ControlPoints.at(index), point3D);
     return point3D;
   }
 
   itkExceptionMacro(<< "GetWorldControlPoint(): Invalid index!");
 }
 
 const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index)
 {
   mitk::PlanarFigure::PolyLineType polyLine;
   if (index > m_PolyLines.size() || !m_PolyLineUpToDate)
   {
     this->GeneratePolyLine();
     m_PolyLineUpToDate = true;
   }
 
   return m_PolyLines.at(index);
 }
 
 const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) const
 {
   return m_PolyLines.at(index);
 }
 
 void mitk::PlanarFigure::ClearPolyLines()
 {
   for (std::vector<PolyLineType>::size_type i = 0; i < m_PolyLines.size(); i++)
   {
     m_PolyLines.at(i).clear();
   }
   m_PolyLineUpToDate = false;
 }
 
 const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetHelperPolyLine(unsigned int index,
                                                                              double mmPerDisplayUnit,
                                                                              unsigned int displayHeight)
 {
   mitk::PlanarFigure::PolyLineType helperPolyLine;
   if (index < m_HelperPolyLines.size())
   {
     // m_HelperLinesUpToDate does not cover changes in zoom-level, so we have to check previous values of the
     // two parameters as well
     if (!m_HelperLinesUpToDate || m_DisplaySize.first != mmPerDisplayUnit || m_DisplaySize.second != displayHeight)
     {
       this->GenerateHelperPolyLine(mmPerDisplayUnit, displayHeight);
       m_HelperLinesUpToDate = true;
 
       // store these parameters to be able to check next time if somebody zoomed in or out
       m_DisplaySize.first = mmPerDisplayUnit;
       m_DisplaySize.second = displayHeight;
     }
 
     helperPolyLine = m_HelperPolyLines.at(index);
   }
 
   return helperPolyLine;
 }
 
 void mitk::PlanarFigure::ClearHelperPolyLines()
 {
   for (std::vector<PolyLineType>::size_type i = 0; i < m_HelperPolyLines.size(); i++)
   {
     m_HelperPolyLines.at(i).clear();
   }
   m_HelperLinesUpToDate = false;
 }
 
 /** \brief Returns the number of features available for this PlanarFigure
 * (such as, radius, area, ...). */
 unsigned int mitk::PlanarFigure::GetNumberOfFeatures() const
 {
   return m_Features.size();
 }
 
 int mitk::PlanarFigure::GetControlPointForPolylinePoint(int indexOfPolylinePoint, int /*polyLineIndex*/) const
 {
   return indexOfPolylinePoint;
 }
 
 const char *mitk::PlanarFigure::GetFeatureName(unsigned int index) const
 {
   if (index < m_Features.size())
   {
     return m_Features[index].Name.c_str();
   }
   else
   {
     return nullptr;
   }
 }
 
 const char *mitk::PlanarFigure::GetFeatureUnit(unsigned int index) const
 {
   if (index < m_Features.size())
   {
     return m_Features[index].Unit.c_str();
   }
   else
   {
     return nullptr;
   }
 }
 
 double mitk::PlanarFigure::GetQuantity(unsigned int index) const
 {
   if (index < m_Features.size())
   {
     return m_Features[index].Quantity;
   }
   else
   {
     return 0.0;
   }
 }
 
 bool mitk::PlanarFigure::IsFeatureActive(unsigned int index) const
 {
   if (index < m_Features.size())
   {
     return m_Features[index].Active;
   }
   else
   {
     return false;
   }
 }
 
 bool mitk::PlanarFigure::IsFeatureVisible(unsigned int index) const
 {
   if (index < m_Features.size())
   {
     return m_Features[index].Visible;
   }
   else
   {
     return false;
   }
 }
 
 void mitk::PlanarFigure::SetFeatureVisible(unsigned int index, bool visible)
 {
   if (index < m_Features.size())
   {
     m_Features[index].Visible = visible;
   }
 }
 
 void mitk::PlanarFigure::EvaluateFeatures()
 {
   if (!m_FeaturesUpToDate || !m_PolyLineUpToDate)
   {
     if (!m_PolyLineUpToDate)
     {
       this->GeneratePolyLine();
     }
 
     this->EvaluateFeaturesInternal();
 
     m_FeaturesUpToDate = true;
   }
 }
 
 void mitk::PlanarFigure::UpdateOutputInformation()
 {
   // Bounds are NOT calculated here, since the PlaneGeometry defines a fixed
   // frame (= bounds) for the planar figure.
   Superclass::UpdateOutputInformation();
   this->GetTimeGeometry()->Update();
 }
 
 void mitk::PlanarFigure::SetRequestedRegionToLargestPossibleRegion()
 {
 }
 
 bool mitk::PlanarFigure::RequestedRegionIsOutsideOfTheBufferedRegion()
 {
   return false;
 }
 
 bool mitk::PlanarFigure::VerifyRequestedRegion()
 {
   return true;
 }
 
 void mitk::PlanarFigure::SetRequestedRegion(const itk::DataObject * /*data*/)
 {
 }
 
 void mitk::PlanarFigure::ResetNumberOfControlPoints(int numberOfControlPoints)
 {
   // DO NOT resize the list here, will cause crash!!
   m_NumberOfControlPoints = numberOfControlPoints;
 }
 
 mitk::Point2D mitk::PlanarFigure::ApplyControlPointConstraints(unsigned int /*index*/, const Point2D &point)
 {
   if (m_PlaneGeometry == nullptr)
   {
     return point;
   }
 
   Point2D indexPoint;
   m_PlaneGeometry->WorldToIndex(point, indexPoint);
 
   BoundingBox::BoundsArrayType bounds = m_PlaneGeometry->GetBounds();
   if (indexPoint[0] < bounds[0])
   {
     indexPoint[0] = bounds[0];
   }
   if (indexPoint[0] > bounds[1])
   {
     indexPoint[0] = bounds[1];
   }
   if (indexPoint[1] < bounds[2])
   {
     indexPoint[1] = bounds[2];
   }
   if (indexPoint[1] > bounds[3])
   {
     indexPoint[1] = bounds[3];
   }
 
   Point2D constrainedPoint;
   m_PlaneGeometry->IndexToWorld(indexPoint, constrainedPoint);
 
   return constrainedPoint;
 }
 
 unsigned int mitk::PlanarFigure::AddFeature(const char *featureName, const char *unitName)
 {
   unsigned int index = m_Features.size();
 
   Feature newFeature(featureName, unitName);
   m_Features.push_back(newFeature);
 
   return index;
 }
 
 void mitk::PlanarFigure::SetFeatureName(unsigned int index, const char *featureName)
 {
   if (index < m_Features.size())
   {
     m_Features[index].Name = featureName;
   }
 }
 
 void mitk::PlanarFigure::SetFeatureUnit(unsigned int index, const char *unitName)
 {
   if (index < m_Features.size())
   {
     m_Features[index].Unit = unitName;
   }
 }
 
 void mitk::PlanarFigure::SetQuantity(unsigned int index, double quantity)
 {
   if (index < m_Features.size())
   {
     m_Features[index].Quantity = quantity;
   }
 }
 
 void mitk::PlanarFigure::ActivateFeature(unsigned int index)
 {
   if (index < m_Features.size())
   {
     m_Features[index].Active = true;
   }
 }
 
 void mitk::PlanarFigure::DeactivateFeature(unsigned int index)
 {
   if (index < m_Features.size())
   {
     m_Features[index].Active = false;
   }
 }
 
 void mitk::PlanarFigure::InitializeTimeGeometry(unsigned int timeSteps)
 {
   mitk::PlaneGeometry::Pointer geometry2D = mitk::PlaneGeometry::New();
   geometry2D->Initialize();
 
   // The geometry is propagated automatically to all time steps,
   // if EvenlyTimed is true...
   ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New();
   timeGeometry->Initialize(geometry2D, timeSteps);
   SetTimeGeometry(timeGeometry);
 }
 
 void mitk::PlanarFigure::PrintSelf(std::ostream &os, itk::Indent indent) const
 {
   Superclass::PrintSelf(os, indent);
   os << indent << this->GetNameOfClass() << ":\n";
 
   if (this->IsClosed())
     os << indent << "This figure is closed\n";
   else
     os << indent << "This figure is not closed\n";
   os << indent << "Minimum number of control points: " << this->GetMinimumNumberOfControlPoints() << std::endl;
   os << indent << "Maximum number of control points: " << this->GetMaximumNumberOfControlPoints() << std::endl;
   os << indent << "Current number of control points: " << this->GetNumberOfControlPoints() << std::endl;
   os << indent << "Control points:" << std::endl;
 
   for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i)
   {
     // os << indent.GetNextIndent() << i << ": " << m_ControlPoints->ElementAt( i ) << std::endl;
     os << indent.GetNextIndent() << i << ": " << m_ControlPoints.at(i) << std::endl;
   }
   os << indent << "Geometry:\n";
   this->GetPlaneGeometry()->Print(os, indent.GetNextIndent());
 }
 
 unsigned short mitk::PlanarFigure::GetPolyLinesSize()
 {
   if (!m_PolyLineUpToDate)
   {
     this->GeneratePolyLine();
     m_PolyLineUpToDate = true;
   }
   return m_PolyLines.size();
 }
 
 unsigned short mitk::PlanarFigure::GetHelperPolyLinesSize() const
 {
   return m_HelperPolyLines.size();
 }
 
 bool mitk::PlanarFigure::IsHelperToBePainted(unsigned int index) const
 {
   return m_HelperPolyLinesToBePainted->GetElement(index);
 }
 
 bool mitk::PlanarFigure::ResetOnPointSelect()
 {
   return false;
 }
 
 bool mitk::PlanarFigure::ResetOnPointSelectNeeded() const
 {
   return false;
 }
 
 void mitk::PlanarFigure::RemoveControlPoint(unsigned int index)
 {
   if (index > m_ControlPoints.size())
     return;
 
   if ((m_ControlPoints.size() - 1) < this->GetMinimumNumberOfControlPoints())
     return;
 
   ControlPointListType::iterator iter;
   iter = m_ControlPoints.begin() + index;
 
   m_ControlPoints.erase(iter);
 
   m_PolyLineUpToDate = false;
   m_HelperLinesUpToDate = false;
   m_FeaturesUpToDate = false;
 
   --m_NumberOfControlPoints;
 }
 
 void mitk::PlanarFigure::RemoveLastControlPoint()
 {
   RemoveControlPoint(m_ControlPoints.size() - 1);
 }
 
 void mitk::PlanarFigure::SetNumberOfPolyLines(unsigned int numberOfPolyLines)
 {
   m_PolyLines.resize(numberOfPolyLines);
 }
 
 void mitk::PlanarFigure::SetNumberOfHelperPolyLines(unsigned int numberOfHerlperPolyLines)
 {
   m_HelperPolyLines.resize(numberOfHerlperPolyLines);
 }
 
 void mitk::PlanarFigure::AppendPointToPolyLine(unsigned int index, PolyLineElement element)
 {
   if (index < m_PolyLines.size())
   {
     m_PolyLines[index].push_back(element);
     m_PolyLineUpToDate = false;
   }
   else
   {
     MITK_ERROR << "Tried to add point to PolyLine " << index + 1 << ", although only " << m_PolyLines.size()
                << " exists";
   }
 }
 
 void mitk::PlanarFigure::AppendPointToHelperPolyLine(unsigned int index, PolyLineElement element)
 {
   if (index < m_HelperPolyLines.size())
   {
     m_HelperPolyLines[index].push_back(element);
     m_HelperLinesUpToDate = false;
   }
   else
   {
     MITK_ERROR << "Tried to add point to HelperPolyLine " << index + 1 << ", although only " << m_HelperPolyLines.size()
                << " exists";
   }
 }
 
 bool mitk::PlanarFigure::Equals(const mitk::PlanarFigure &other) const
 {
   // check geometries
   if (this->GetPlaneGeometry() && other.GetPlaneGeometry())
   {
     if (!Equal(*(this->GetPlaneGeometry()), *(other.GetPlaneGeometry()), mitk::eps, true))
     {
       return false;
     }
   }
   else
   {
     MITK_ERROR << "Geometry is not equal";
     return false;
   }
 
   // check isPlaced member
   if (this->m_FigurePlaced != other.m_FigurePlaced)
   {
     MITK_ERROR << "Is_Placed is not equal";
     return false;
   }
 
   // check closed property
   if (this->IsClosed() != other.IsClosed())
   {
     MITK_ERROR << "Is_closed is not equal";
     return false;
   }
 
   // check poly lines
   if (this->m_PolyLines.size() != other.m_PolyLines.size())
   {
     return false;
   }
   else
   {
     auto itThis = this->m_PolyLines.begin();
     auto itEnd = this->m_PolyLines.end();
     auto itOther = other.m_PolyLines.begin();
 
     while (itThis != itEnd)
     {
       if (itThis->size() != itOther->size())
         return false;
       else
       {
         auto itLineThis = itThis->begin();
         auto itLineEnd = itThis->end();
         auto itLineOther = itOther->begin();
 
         while (itLineThis != itLineEnd)
         {
           Point2D p1 = *itLineThis;
           Point2D p2 = *itLineOther;
           ScalarType delta = fabs(p1[0] - p2[0]) + fabs(p1[1] - p2[1]);
           if (delta > .001)
           {
             MITK_ERROR << "Poly line is not equal";
             MITK_ERROR << p1 << "/" << p2;
             return false;
           }
 
           ++itLineThis;
           ++itLineOther;
         }
       }
       ++itThis;
       ++itOther;
     }
   }
 
   // check features
   if (this->GetNumberOfFeatures() != other.GetNumberOfFeatures())
   {
     MITK_ERROR << "Number of Features is Different";
     return false;
   }
   else
   {
     auto itThis = m_Features.begin();
     auto itEnd = m_Features.end();
     auto itOther = other.m_Features.begin();
 
     while (itThis != itEnd)
     {
       if ((itThis->Quantity - itOther->Quantity) > .001)
       {
         MITK_ERROR << "Quantity is Different" << itThis->Quantity << "/" << itOther->Quantity;
         return false;
       }
       if (itThis->Unit.compare(itOther->Unit) != 0)
       {
         MITK_ERROR << "Unit is Different" << itThis->Unit << "/" << itOther->Unit;
         return false;
       }
       if (itThis->Name.compare(itOther->Name) != 0)
       {
         MITK_ERROR << "Name of Measure is Different " << itThis->Name << "/ " << itOther->Name;
         ;
         return false;
       }
 
       ++itThis;
       ++itOther;
     }
   }
 
   return true;
 }
 
 bool mitk::Equal(const mitk::PlanarFigure &leftHandSide,
                  const mitk::PlanarFigure &rightHandSide,
                  ScalarType /*eps*/,
                  bool /*verbose*/)
 {
   // FIXME: use eps and verbose
   return leftHandSide.Equals(rightHandSide);
 }
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureIOFactory.cpp b/Modules/PlanarFigure/src/IO/mitkPlanarFigureIOFactory.cpp
deleted file mode 100644
index 9c6d67781c..0000000000
--- a/Modules/PlanarFigure/src/IO/mitkPlanarFigureIOFactory.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*============================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center (DKFZ)
-All rights reserved.
-
-Use of this source code is governed by a 3-clause BSD license that can be
-found in the LICENSE file.
-
-============================================================================*/
-
-#include "mitkPlanarFigureIOFactory.h"
-#include "mitkIOAdapter.h"
-#include "mitkPlanarFigureReader.h"
-
-#include "itkVersion.h"
-
-namespace mitk
-{
-  PlanarFigureIOFactory::PlanarFigureIOFactory()
-  {
-    this->RegisterOverride("mitkIOAdapter",
-                           "mitkPlanarFigureReader",
-                           "mitk PlanarFigure IO",
-                           true,
-                           itk::CreateObjectFunction<IOAdapter<PlanarFigureReader>>::New());
-  }
-
-  PlanarFigureIOFactory::~PlanarFigureIOFactory() {}
-  const char *PlanarFigureIOFactory::GetITKSourceVersion() const { return ITK_SOURCE_VERSION; }
-  const char *PlanarFigureIOFactory::GetDescription() const
-  {
-    return "PlanarFigure IO Factory, allows the loading of .pf files";
-  }
-
-} // end namespace mitk
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureIOFactory.h b/Modules/PlanarFigure/src/IO/mitkPlanarFigureIOFactory.h
deleted file mode 100644
index f7f3b161ef..0000000000
--- a/Modules/PlanarFigure/src/IO/mitkPlanarFigureIOFactory.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*============================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center (DKFZ)
-All rights reserved.
-
-Use of this source code is governed by a 3-clause BSD license that can be
-found in the LICENSE file.
-
-============================================================================*/
-#ifndef __mitkPlanarFigureIOFactory_h
-#define __mitkPlanarFigureIOFactory_h
-
-#ifdef _MSC_VER
-#pragma warning(disable : 4786)
-#endif
-
-#include "itkObjectFactoryBase.h"
-#include "mitkBaseData.h"
-
-namespace mitk
-{
-  //##Documentation
-  //## @brief Create instances of PlanarFigureReader objects using an object factory.
-  //##
-  //## @ingroup MitkPlanarFigureModule
-  class PlanarFigureIOFactory : public itk::ObjectFactoryBase
-  {
-  public:
-    /** Standard class typedefs. */
-    typedef PlanarFigureIOFactory Self;
-    typedef itk::ObjectFactoryBase Superclass;
-    typedef itk::SmartPointer<Self> Pointer;
-    typedef itk::SmartPointer<const Self> ConstPointer;
-
-    /** Class methods used to interface with the registered factories. */
-    const char *GetITKSourceVersion(void) const override;
-    const char *GetDescription(void) const override;
-
-    /** Method for class instantiation. */
-    itkFactorylessNewMacro(Self);
-    static PlanarFigureIOFactory *FactoryNew() { return new PlanarFigureIOFactory; }
-    /** Run-time type information (and related methods). */
-    itkTypeMacro(PlanarFigureIOFactory, ObjectFactoryBase);
-
-    /**
-     * Register one factory of this type
-     * \deprecatedSince{2013_09}
-     */
-    DEPRECATED(static void RegisterOneFactory(void))
-    {
-      PlanarFigureIOFactory::Pointer PlanarFigureIOFactory = PlanarFigureIOFactory::New();
-      ObjectFactoryBase::RegisterFactory(PlanarFigureIOFactory);
-    }
-
-  protected:
-    PlanarFigureIOFactory();
-    ~PlanarFigureIOFactory() override;
-
-  private:
-    PlanarFigureIOFactory(const Self &); // purposely not implemented
-    void operator=(const Self &);        // purposely not implemented
-  };
-
-} // end namespace mitk
-
-#endif
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureReader.cpp b/Modules/PlanarFigure/src/IO/mitkPlanarFigureReader.cpp
deleted file mode 100644
index 5aa97568cc..0000000000
--- a/Modules/PlanarFigure/src/IO/mitkPlanarFigureReader.cpp
+++ /dev/null
@@ -1,438 +0,0 @@
-/*============================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center (DKFZ)
-All rights reserved.
-
-Use of this source code is governed by a 3-clause BSD license that can be
-found in the LICENSE file.
-
-============================================================================*/
-
-#include "mitkPlanarFigureReader.h"
-
-#include "mitkPlanarAngle.h"
-#include "mitkPlanarArrow.h"
-#include "mitkPlanarBezierCurve.h"
-#include "mitkPlanarCircle.h"
-#include "mitkPlanarCross.h"
-#include "mitkPlanarDoubleEllipse.h"
-#include "mitkPlanarEllipse.h"
-#include "mitkPlanarFourPointAngle.h"
-#include "mitkPlanarLine.h"
-#include "mitkPlanarPolygon.h"
-#include "mitkPlanarRectangle.h"
-#include "mitkPlanarSubdivisionPolygon.h"
-#include "mitkPlaneGeometry.h"
-
-#include "mitkBasePropertySerializer.h"
-#include <mitkLocaleSwitch.h>
-
-#include <itksys/SystemTools.hxx>
-#include <tinyxml.h>
-
-mitk::PlanarFigureReader::PlanarFigureReader()
-  : PlanarFigureSource(), FileReader(), m_FileName(""), m_FilePrefix(""), m_FilePattern(""), m_Success(false)
-{
-  this->SetNumberOfRequiredOutputs(1);
-  this->SetNumberOfIndexedOutputs(1);
-  this->SetNthOutput(0, this->MakeOutput(0));
-
-  m_CanReadFromMemory = true;
-
-  // this->Modified();
-  // this->GetOutput()->Modified();
-  // this->GetOutput()->ReleaseData();
-}
-
-mitk::PlanarFigureReader::~PlanarFigureReader()
-{
-}
-
-void mitk::PlanarFigureReader::GenerateData()
-{
-  mitk::LocaleSwitch localeSwitch("C");
-  m_Success = false;
-  this->SetNumberOfIndexedOutputs(0); // reset all outputs, we add new ones depending on the file content
-
-  TiXmlDocument document;
-
-  if (m_ReadFromMemory)
-  {
-    if (m_MemoryBuffer == nullptr || m_MemorySize == 0)
-    {
-      // check
-      itkWarningMacro(<< "Sorry, memory buffer has not been set!");
-      return;
-    }
-    if (m_MemoryBuffer[m_MemorySize - 1] == '\0')
-    {
-      document.Parse(m_MemoryBuffer);
-    }
-    else
-    {
-      auto tmpArray = new char[(int)m_MemorySize + 1];
-      tmpArray[m_MemorySize] = '\0';
-      memcpy(tmpArray, m_MemoryBuffer, m_MemorySize);
-
-      document.Parse(m_MemoryBuffer);
-
-      delete[] tmpArray;
-    }
-  }
-  else
-  {
-    if (m_FileName.empty())
-    {
-      itkWarningMacro(<< "Sorry, filename has not been set!");
-      return;
-    }
-    if (this->CanReadFile(m_FileName.c_str()) == false)
-    {
-      itkWarningMacro(<< "Sorry, can't read file " << m_FileName << "!");
-      return;
-    }
-    if (!document.LoadFile(m_FileName))
-    {
-      MITK_ERROR << "Could not open/read/parse " << m_FileName << ". TinyXML reports: '" << document.ErrorDesc()
-                 << "'. "
-                 << "The error occurred in row " << document.ErrorRow() << ", column " << document.ErrorCol() << ".";
-      return;
-    }
-  }
-
-  int fileVersion = 1;
-  TiXmlElement *versionObject = document.FirstChildElement("Version");
-  if (versionObject != nullptr)
-  {
-    if (versionObject->QueryIntAttribute("FileVersion", &fileVersion) != TIXML_SUCCESS)
-    {
-      MITK_WARN << m_FileName << " does not contain version information! Trying version 1 format." << std::endl;
-    }
-  }
-  else
-  {
-    MITK_WARN << m_FileName << " does not contain version information! Trying version 1 format." << std::endl;
-  }
-  if (fileVersion !=
-      1) // add file version selection and version specific file parsing here, if newer file versions are created
-  {
-    MITK_WARN << "File version > 1 is not supported by this reader.";
-    return;
-  }
-
-  /* file version 1 reader code */
-  for (TiXmlElement *pfElement = document.FirstChildElement("PlanarFigure"); pfElement != nullptr;
-       pfElement = pfElement->NextSiblingElement("PlanarFigure"))
-  {
-    std::string type = pfElement->Attribute("type");
-
-    mitk::PlanarFigure::Pointer planarFigure = nullptr;
-    if (type == "PlanarAngle")
-    {
-      planarFigure = mitk::PlanarAngle::New();
-    }
-    else if (type == "PlanarCircle")
-    {
-      planarFigure = mitk::PlanarCircle::New();
-    }
-    else if (type == "PlanarEllipse")
-    {
-      planarFigure = mitk::PlanarEllipse::New();
-    }
-    else if (type == "PlanarCross")
-    {
-      planarFigure = mitk::PlanarCross::New();
-    }
-    else if (type == "PlanarFourPointAngle")
-    {
-      planarFigure = mitk::PlanarFourPointAngle::New();
-    }
-    else if (type == "PlanarLine")
-    {
-      planarFigure = mitk::PlanarLine::New();
-    }
-    else if (type == "PlanarPolygon")
-    {
-      planarFigure = mitk::PlanarPolygon::New();
-    }
-    else if (type == "PlanarSubdivisionPolygon")
-    {
-      planarFigure = mitk::PlanarSubdivisionPolygon::New();
-    }
-    else if (type == "PlanarRectangle")
-    {
-      planarFigure = mitk::PlanarRectangle::New();
-    }
-    else if (type == "PlanarArrow")
-    {
-      planarFigure = mitk::PlanarArrow::New();
-    }
-    else if (type == "PlanarDoubleEllipse")
-    {
-      planarFigure = mitk::PlanarDoubleEllipse::New();
-    }
-    else if (type == "PlanarBezierCurve")
-    {
-      planarFigure = mitk::PlanarBezierCurve::New();
-    }
-    else
-    {
-      // unknown type
-      MITK_WARN << "encountered unknown planar figure type '" << type << "'. Skipping this element.";
-      continue;
-    }
-
-    // Read properties of the planar figure
-    for (TiXmlElement *propertyElement = pfElement->FirstChildElement("property"); propertyElement != nullptr;
-         propertyElement = propertyElement->NextSiblingElement("property"))
-    {
-      const char *keya = propertyElement->Attribute("key");
-      const std::string key(keya ? keya : "");
-
-      const char *typea = propertyElement->Attribute("type");
-      const std::string type(typea ? typea : "");
-
-      // hand propertyElement to specific reader
-      std::stringstream propertyDeserializerClassName;
-      propertyDeserializerClassName << type << "Serializer";
-
-      const std::list<itk::LightObject::Pointer> readers =
-        itk::ObjectFactoryBase::CreateAllInstance(propertyDeserializerClassName.str().c_str());
-      if (readers.size() < 1)
-      {
-        MITK_ERROR << "No property reader found for " << type;
-      }
-      if (readers.size() > 1)
-      {
-        MITK_WARN << "Multiple property readers found for " << type << ". Using arbitrary first one.";
-      }
-
-      for (auto iter = readers.cbegin(); iter != readers.cend(); ++iter)
-      {
-        if (auto *reader = dynamic_cast<BasePropertySerializer *>(iter->GetPointer()))
-        {
-          const BaseProperty::Pointer property = reader->Deserialize(propertyElement->FirstChildElement());
-          if (property.IsNotNull())
-          {
-            planarFigure->GetPropertyList()->ReplaceProperty(key, property);
-          }
-          else
-          {
-            MITK_ERROR << "There were errors while loading property '" << key << "' of type " << type
-                       << ". Your data may be corrupted";
-          }
-          break;
-        }
-      }
-    }
-
-    // If we load a planarFigure, it has definitely been placed correctly.
-    // If we do not set this property here, we cannot load old planarFigures
-    // without messing up the interaction (PF-Interactor needs this property.
-    planarFigure->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-
-    // Which features (length or circumference etc) a figure has is decided by whether it is closed or not
-    // the function SetClosed has to be called in case of PlanarPolygons to ensure they hold the correct feature
-    auto *planarPolygon = dynamic_cast<PlanarPolygon *>(planarFigure.GetPointer());
-    if (planarPolygon != nullptr)
-    {
-      bool isClosed = false;
-      planarFigure->GetPropertyList()->GetBoolProperty("closed", isClosed);
-      planarPolygon->SetClosed(isClosed);
-    }
-
-    // Read geometry of containing plane
-    TiXmlElement *geoElement = pfElement->FirstChildElement("Geometry");
-    if (geoElement != nullptr)
-    {
-      try
-      {
-        // Create plane geometry
-        mitk::PlaneGeometry::Pointer planeGeo = mitk::PlaneGeometry::New();
-
-        // Extract and set plane transform parameters
-        const DoubleList transformList =
-          this->GetDoubleAttributeListFromXMLNode(geoElement->FirstChildElement("transformParam"), "param", 12);
-
-        typedef mitk::BaseGeometry::TransformType TransformType;
-        TransformType::ParametersType parameters;
-        parameters.SetSize(12);
-
-        unsigned int i;
-        DoubleList::const_iterator it;
-        for (it = transformList.cbegin(), i = 0; it != transformList.cend(); ++it, ++i)
-        {
-          parameters.SetElement(i, *it);
-        }
-
-        typedef mitk::BaseGeometry::TransformType TransformType;
-        TransformType::Pointer affineGeometry = TransformType::New();
-        affineGeometry->SetParameters(parameters);
-        planeGeo->SetIndexToWorldTransform(affineGeometry);
-
-        // Extract and set plane bounds
-        const DoubleList boundsList =
-          this->GetDoubleAttributeListFromXMLNode(geoElement->FirstChildElement("boundsParam"), "bound", 6);
-
-        typedef mitk::BaseGeometry::BoundsArrayType BoundsArrayType;
-
-        BoundsArrayType bounds;
-        for (it = boundsList.cbegin(), i = 0; it != boundsList.cend(); ++it, ++i)
-        {
-          bounds[i] = *it;
-        }
-
-        planeGeo->SetBounds(bounds);
-
-        // Extract and set spacing and origin
-        const Vector3D spacing = this->GetVectorFromXMLNode(geoElement->FirstChildElement("Spacing"));
-        planeGeo->SetSpacing(spacing);
-
-        const Point3D origin = this->GetPointFromXMLNode(geoElement->FirstChildElement("Origin"));
-        planeGeo->SetOrigin(origin);
-        planarFigure->SetPlaneGeometry(planeGeo);
-      }
-      catch (...)
-      {
-      }
-    }
-    TiXmlElement *cpElement = pfElement->FirstChildElement("ControlPoints");
-    bool first = true;
-    if (cpElement != nullptr)
-      for (TiXmlElement *vertElement = cpElement->FirstChildElement("Vertex"); vertElement != nullptr;
-           vertElement = vertElement->NextSiblingElement("Vertex"))
-      {
-        int id = 0;
-        mitk::Point2D::ValueType x = 0.0;
-        mitk::Point2D::ValueType y = 0.0;
-        if (vertElement->QueryIntAttribute("id", &id) == TIXML_WRONG_TYPE)
-          return; // TODO: can we do a better error handling?
-        if (vertElement->QueryDoubleAttribute("x", &x) == TIXML_WRONG_TYPE)
-          return; // TODO: can we do a better error handling?
-        if (vertElement->QueryDoubleAttribute("y", &y) == TIXML_WRONG_TYPE)
-          return; // TODO: can we do a better error handling?
-        Point2D p;
-        p.SetElement(0, x);
-        p.SetElement(1, y);
-        if (first == true) // needed to set m_FigurePlaced to true
-        {
-          planarFigure->PlaceFigure(p);
-          first = false;
-        }
-        planarFigure->SetControlPoint(id, p, true);
-      }
-
-    // Calculate feature quantities of this PlanarFigure
-    planarFigure->EvaluateFeatures();
-
-    // Make sure that no control point is currently selected
-    planarFigure->DeselectControlPoint();
-
-    // \TODO: what about m_FigurePlaced and m_SelectedControlPoint ??
-    this->SetNthOutput(this->GetNumberOfOutputs(), planarFigure); // add planarFigure as new output of this filter
-  }
-
-  m_Success = true;
-}
-
-mitk::Point3D mitk::PlanarFigureReader::GetPointFromXMLNode(TiXmlElement *e)
-{
-  if (e == nullptr)
-    throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
-  mitk::Point3D point;
-  mitk::ScalarType p(-1.0);
-  if (e->QueryDoubleAttribute("x", &p) == TIXML_WRONG_TYPE)
-    throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
-  point.SetElement(0, p);
-  if (e->QueryDoubleAttribute("y", &p) == TIXML_WRONG_TYPE)
-    throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
-  point.SetElement(1, p);
-  if (e->QueryDoubleAttribute("z", &p) == TIXML_WRONG_TYPE)
-    throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
-  point.SetElement(2, p);
-  return point;
-}
-
-mitk::Vector3D mitk::PlanarFigureReader::GetVectorFromXMLNode(TiXmlElement *e)
-{
-  if (e == nullptr)
-    throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
-  mitk::Vector3D vector;
-  mitk::ScalarType p(-1.0);
-  if (e->QueryDoubleAttribute("x", &p) == TIXML_WRONG_TYPE)
-    throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
-  vector.SetElement(0, p);
-  if (e->QueryDoubleAttribute("y", &p) == TIXML_WRONG_TYPE)
-    throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
-  vector.SetElement(1, p);
-  if (e->QueryDoubleAttribute("z", &p) == TIXML_WRONG_TYPE)
-    throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
-  vector.SetElement(2, p);
-  return vector;
-}
-
-mitk::PlanarFigureReader::DoubleList mitk::PlanarFigureReader::GetDoubleAttributeListFromXMLNode(
-  TiXmlElement *e, const char *attributeNameBase, unsigned int count)
-{
-  DoubleList list;
-
-  if (e == nullptr)
-    throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
-
-  for (unsigned int i = 0; i < count; ++i)
-  {
-    mitk::ScalarType p(-1.0);
-    std::stringstream attributeName;
-    attributeName << attributeNameBase << i;
-
-    if (e->QueryDoubleAttribute(attributeName.str().c_str(), &p) == TIXML_WRONG_TYPE)
-      throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
-    list.push_back(p);
-  }
-
-  return list;
-}
-
-void mitk::PlanarFigureReader::GenerateOutputInformation()
-{
-}
-
-int mitk::PlanarFigureReader::CanReadFile(const char *name)
-{
-  if (std::string(name).empty())
-    return false;
-
-  return (itksys::SystemTools::LowerCase(itksys::SystemTools::GetFilenameLastExtension(name)) ==
-          ".pf"); // assume, we can read all .pf files
-
-  // TiXmlDocument document(name);
-  // if (document.LoadFile() == false)
-  //  return false;
-  // return (document.FirstChildElement("PlanarFigure") != nullptr);
-}
-
-bool mitk::PlanarFigureReader::CanReadFile(const std::string filename, const std::string, const std::string)
-{
-  if (filename.empty())
-    return false;
-
-  return (itksys::SystemTools::LowerCase(itksys::SystemTools::GetFilenameLastExtension(filename)) ==
-          ".pf"); // assume, we can read all .pf files
-
-  // TiXmlDocument document(filename);
-  // if (document.LoadFile() == false)
-  //  return false;
-  // return (document.FirstChildElement("PlanarFigure") != nullptr);
-}
-
-void mitk::PlanarFigureReader::ResizeOutputs(const unsigned int &num)
-{
-  unsigned int prevNum = this->GetNumberOfOutputs();
-  this->SetNumberOfIndexedOutputs(num);
-  for (unsigned int i = prevNum; i < num; ++i)
-  {
-    this->SetNthOutput(i, this->MakeOutput(i).GetPointer());
-  }
-}
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriter.cpp b/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriter.cpp
deleted file mode 100644
index ceec5adfb9..0000000000
--- a/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriter.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-/*============================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center (DKFZ)
-All rights reserved.
-
-Use of this source code is governed by a 3-clause BSD license that can be
-found in the LICENSE file.
-
-============================================================================*/
-
-#include "mitkPlanarFigureWriter.h"
-#include "mitkBasePropertySerializer.h"
-#include "mitkPlaneGeometry.h"
-#include <tinyxml.h>
-
-mitk::PlanarFigureWriter::PlanarFigureWriter()
-  : m_FileName(""),
-    m_FilePrefix(""),
-    m_FilePattern(""),
-    m_Extension(".pf"),
-    m_MimeType("application/MITK.PlanarFigure"),
-    m_Success(false)
-{
-  this->SetNumberOfRequiredInputs(1);
-  this->SetNumberOfIndexedOutputs(0);
-  // this->SetNthOutput( 0, mitk::PlanarFigure::New().GetPointer() );
-
-  m_CanWriteToMemory = true;
-}
-
-mitk::PlanarFigureWriter::~PlanarFigureWriter()
-{
-}
-
-void mitk::PlanarFigureWriter::GenerateData()
-{
-  m_Success = false;
-
-  if (!m_WriteToMemory && m_FileName.empty())
-  {
-    MITK_ERROR << "Could not write planar figures. File name is invalid";
-    throw std::invalid_argument("file name is empty");
-  }
-
-  TiXmlDocument document;
-  auto decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc....
-  document.LinkEndChild(decl);
-
-  auto version = new TiXmlElement("Version");
-  version->SetAttribute("Writer", __FILE__);
-  version->SetAttribute("CVSRevision", "$Revision: 17055 $");
-  version->SetAttribute("FileVersion", 1);
-  document.LinkEndChild(version);
-
-  /* create xml element for each input */
-  for (unsigned int i = 0; i < this->GetNumberOfInputs(); ++i)
-  {
-    // Create root element for this PlanarFigure
-    InputType::Pointer pf = this->GetInput(i);
-    if (pf.IsNull())
-      continue;
-    auto pfElement = new TiXmlElement("PlanarFigure");
-    pfElement->SetAttribute("type", pf->GetNameOfClass());
-    document.LinkEndChild(pfElement);
-
-    if (pf->GetNumberOfControlPoints() == 0)
-      continue;
-
-    // PlanarFigure::VertexContainerType* vertices = pf->GetControlPoints();
-    // if (vertices == nullptr)
-    //  continue;
-
-    // Serialize property list of PlanarFigure
-    mitk::PropertyList::Pointer propertyList = pf->GetPropertyList();
-    mitk::PropertyList::PropertyMap::const_iterator it;
-    for (it = propertyList->GetMap()->begin(); it != propertyList->GetMap()->end(); ++it)
-    {
-      // Create seralizer for this property
-      const mitk::BaseProperty *prop = it->second;
-      std::string serializerName = std::string(prop->GetNameOfClass()) + "Serializer";
-      std::list<itk::LightObject::Pointer> allSerializers =
-        itk::ObjectFactoryBase::CreateAllInstance(serializerName.c_str());
-
-      if (allSerializers.size() != 1)
-      {
-        // No or too many serializer(s) found, skip this property
-        continue;
-      }
-
-      auto *serializer =
-        dynamic_cast<mitk::BasePropertySerializer *>(allSerializers.begin()->GetPointer());
-      if (serializer == nullptr)
-      {
-        // Serializer not valid; skip this property
-      }
-
-      auto keyElement = new TiXmlElement("property");
-      keyElement->SetAttribute("key", it->first);
-      keyElement->SetAttribute("type", prop->GetNameOfClass());
-
-      serializer->SetProperty(prop);
-      TiXmlElement *valueElement = nullptr;
-      try
-      {
-        valueElement = serializer->Serialize();
-      }
-      catch (...)
-      {
-      }
-
-      if (valueElement == nullptr)
-      {
-        // Serialization failed; skip this property
-        continue;
-      }
-
-      // Add value to property element
-      keyElement->LinkEndChild(valueElement);
-
-      // Append serialized property to property list
-      pfElement->LinkEndChild(keyElement);
-    }
-
-    // Serialize control points of PlanarFigure
-    auto controlPointsElement = new TiXmlElement("ControlPoints");
-    pfElement->LinkEndChild(controlPointsElement);
-    for (unsigned int i = 0; i < pf->GetNumberOfControlPoints(); i++)
-    {
-      auto vElement = new TiXmlElement("Vertex");
-      vElement->SetAttribute("id", i);
-      vElement->SetDoubleAttribute("x", pf->GetControlPoint(i)[0]);
-      vElement->SetDoubleAttribute("y", pf->GetControlPoint(i)[1]);
-      controlPointsElement->LinkEndChild(vElement);
-    }
-    auto geoElement = new TiXmlElement("Geometry");
-    const auto *planeGeo = dynamic_cast<const PlaneGeometry *>(pf->GetPlaneGeometry());
-    if (planeGeo != nullptr)
-    {
-      // Write parameters of IndexToWorldTransform of the PlaneGeometry
-      typedef mitk::Geometry3D::TransformType TransformType;
-      const TransformType *affineGeometry = planeGeo->GetIndexToWorldTransform();
-      const TransformType::ParametersType &parameters = affineGeometry->GetParameters();
-      auto vElement = new TiXmlElement("transformParam");
-      for (unsigned int i = 0; i < affineGeometry->GetNumberOfParameters(); ++i)
-      {
-        std::stringstream paramName;
-        paramName << "param" << i;
-        vElement->SetDoubleAttribute(paramName.str().c_str(), parameters.GetElement(i));
-      }
-      geoElement->LinkEndChild(vElement);
-
-      // Write bounds of the PlaneGeometry
-      typedef mitk::Geometry3D::BoundsArrayType BoundsArrayType;
-      const BoundsArrayType &bounds = planeGeo->GetBounds();
-      vElement = new TiXmlElement("boundsParam");
-      for (unsigned int i = 0; i < 6; ++i)
-      {
-        std::stringstream boundName;
-        boundName << "bound" << i;
-        vElement->SetDoubleAttribute(boundName.str().c_str(), bounds.GetElement(i));
-      }
-      geoElement->LinkEndChild(vElement);
-
-      // Write spacing and origin of the PlaneGeometry
-      Vector3D spacing = planeGeo->GetSpacing();
-      Point3D origin = planeGeo->GetOrigin();
-      geoElement->LinkEndChild(this->CreateXMLVectorElement("Spacing", spacing));
-      geoElement->LinkEndChild(this->CreateXMLVectorElement("Origin", origin));
-
-      pfElement->LinkEndChild(geoElement);
-    }
-  }
-
-  if (m_WriteToMemory)
-  {
-    // Declare a printer
-    TiXmlPrinter printer;
-    // attach it to the document you want to convert in to a std::string
-    document.Accept(&printer);
-
-    // Create memory buffer and print tinyxmldocument there...
-    m_MemoryBufferSize = printer.Size() + 1;
-    m_MemoryBuffer = new char[m_MemoryBufferSize];
-    strcpy(m_MemoryBuffer, printer.CStr());
-  }
-  else
-  {
-    if (document.SaveFile(m_FileName) == false)
-    {
-      MITK_ERROR << "Could not write planar figures to " << m_FileName << "\nTinyXML reports '" << document.ErrorDesc()
-                 << "'";
-      throw std::ios_base::failure("Error during writing of planar figure xml file.");
-    }
-  }
-  m_Success = true;
-}
-
-void mitk::PlanarFigureWriter::ReleaseMemory()
-{
-  if (m_MemoryBuffer != nullptr)
-  {
-    delete[] m_MemoryBuffer;
-  }
-}
-
-TiXmlElement *mitk::PlanarFigureWriter::CreateXMLVectorElement(const char *name, itk::FixedArray<mitk::ScalarType, 3> v)
-{
-  auto vElement = new TiXmlElement(name);
-  vElement->SetDoubleAttribute("x", v.GetElement(0));
-  vElement->SetDoubleAttribute("y", v.GetElement(1));
-  vElement->SetDoubleAttribute("z", v.GetElement(2));
-  return vElement;
-}
-
-void mitk::PlanarFigureWriter::ResizeInputs(const unsigned int &num)
-{
-  // unsigned int prevNum = this->GetNumberOfInputs();
-  this->SetNumberOfIndexedInputs(num);
-  // for ( unsigned int i = prevNum; i < num; ++i )
-  //{
-  //  this->SetNthInput( i, mitk::PlanarFigure::New().GetPointer() );
-  //}
-}
-
-void mitk::PlanarFigureWriter::SetInput(InputType *PlanarFigure)
-{
-  this->ProcessObject::SetNthInput(0, PlanarFigure);
-}
-
-void mitk::PlanarFigureWriter::SetInput(const unsigned int &id, InputType *PlanarFigure)
-{
-  if (id >= this->GetNumberOfInputs())
-    this->ResizeInputs(id + 1);
-  this->ProcessObject::SetNthInput(id, PlanarFigure);
-}
-
-mitk::PlanarFigure *mitk::PlanarFigureWriter::GetInput()
-{
-  if (this->GetNumberOfInputs() < 1)
-    return nullptr;
-  else
-    return dynamic_cast<InputType *>(this->GetInput(0));
-}
-
-mitk::PlanarFigure *mitk::PlanarFigureWriter::GetInput(const unsigned int &num)
-{
-  return dynamic_cast<InputType *>(this->ProcessObject::GetInput(num));
-}
-
-bool mitk::PlanarFigureWriter::CanWriteDataType(DataNode *input)
-{
-  if (input == nullptr)
-    return false;
-
-  mitk::BaseData *data = input->GetData();
-  if (data == nullptr)
-    return false;
-
-  mitk::PlanarFigure::Pointer PlanarFigure = dynamic_cast<mitk::PlanarFigure *>(data);
-  if (PlanarFigure.IsNull())
-    return false;
-  // add code for special subclasses here
-  return true;
-}
-
-void mitk::PlanarFigureWriter::SetInput(DataNode *input)
-{
-  if (this->CanWriteDataType(input))
-    this->ProcessObject::SetNthInput(0, dynamic_cast<mitk::PlanarFigure *>(input->GetData()));
-}
-
-std::string mitk::PlanarFigureWriter::GetSupportedBaseData() const
-{
-  return PlanarFigure::GetStaticNameOfClass();
-}
-
-std::string mitk::PlanarFigureWriter::GetWritenMIMEType()
-{
-  return m_MimeType;
-}
-
-std::vector<std::string> mitk::PlanarFigureWriter::GetPossibleFileExtensions()
-{
-  std::vector<std::string> possibleFileExtensions;
-  possibleFileExtensions.push_back(m_Extension);
-  return possibleFileExtensions;
-}
-
-std::string mitk::PlanarFigureWriter::GetFileExtension()
-{
-  return m_Extension;
-}
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriterFactory.cpp b/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriterFactory.cpp
deleted file mode 100644
index 2b1ee14b9e..0000000000
--- a/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriterFactory.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*============================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center (DKFZ)
-All rights reserved.
-
-Use of this source code is governed by a 3-clause BSD license that can be
-found in the LICENSE file.
-
-============================================================================*/
-
-#include "mitkPlanarFigureWriterFactory.h"
-
-#include "itkCreateObjectFunction.h"
-#include "itkVersion.h"
-
-#include <mitkPlanarFigureWriter.h>
-
-namespace mitk
-{
-  template <class T>
-  class CreatePlanarFigureWriter : public itk::CreateObjectFunctionBase
-  {
-  public:
-    /** Standard class typedefs. */
-    typedef CreatePlanarFigureWriter Self;
-    typedef itk::SmartPointer<Self> Pointer;
-
-    /** Methods from itk:LightObject. */
-    itkFactorylessNewMacro(Self) LightObject::Pointer CreateObject() override
-    {
-      typename T::Pointer p = T::New();
-      p->Register();
-      return p.GetPointer();
-    }
-
-  protected:
-    CreatePlanarFigureWriter() {}
-    ~CreatePlanarFigureWriter() override {}
-  private:
-    CreatePlanarFigureWriter(const Self &); // purposely not implemented
-    void operator=(const Self &);           // purposely not implemented
-  };
-
-  PlanarFigureWriterFactory::PlanarFigureWriterFactory()
-  {
-    this->RegisterOverride("IOWriter",
-                           "PlanarFigureWriter",
-                           "PlanarFigure xml Writer",
-                           true,
-                           mitk::CreatePlanarFigureWriter<mitk::PlanarFigureWriter>::New());
-  }
-
-  PlanarFigureWriterFactory::~PlanarFigureWriterFactory() {}
-  itk::ObjectFactoryBase::Pointer PlanarFigureWriterFactory::GetInstance()
-  {
-    static itk::ObjectFactoryBase::Pointer factory(mitk::PlanarFigureWriterFactory::New().GetPointer());
-    return factory;
-  }
-
-  void PlanarFigureWriterFactory::RegisterOneFactory(void)
-  {
-    if (GetInstance()->GetReferenceCount() == 1)
-    {
-      ObjectFactoryBase::RegisterFactory(GetInstance().GetPointer());
-    }
-  }
-
-  void PlanarFigureWriterFactory::UnRegisterOneFactory(void)
-  {
-    ObjectFactoryBase::UnRegisterFactory(GetInstance().GetPointer());
-  }
-
-  const char *PlanarFigureWriterFactory::GetITKSourceVersion() const { return ITK_SOURCE_VERSION; }
-  const char *PlanarFigureWriterFactory::GetDescription() const { return "PlanarFigureWriterFactory"; }
-} // end namespace mitk
diff --git a/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriterFactory.h b/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriterFactory.h
deleted file mode 100644
index b0f8d30e96..0000000000
--- a/Modules/PlanarFigure/src/IO/mitkPlanarFigureWriterFactory.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*============================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center (DKFZ)
-All rights reserved.
-
-Use of this source code is governed by a 3-clause BSD license that can be
-found in the LICENSE file.
-
-============================================================================*/
-
-#ifndef PLANARFIGURE_WRITERFACTORY_H_HEADER_INCLUDED
-#define PLANARFIGURE_WRITERFACTORY_H_HEADER_INCLUDED
-
-#include "itkObjectFactoryBase.h"
-#include "mitkBaseData.h"
-
-namespace mitk
-{
-  class PlanarFigureWriterFactory : public itk::ObjectFactoryBase
-  {
-  public:
-    mitkClassMacroItkParent(mitk::PlanarFigureWriterFactory, itk::ObjectFactoryBase);
-
-      /** Class methods used to interface with the registered factories. */
-      const char *GetITKSourceVersion(void) const override;
-    const char *GetDescription(void) const override;
-
-    /** Method for class instantiation. */
-    itkFactorylessNewMacro(Self);
-
-      /**
-       * Register one factory of this type
-       * \deprecatedSince{2013_09}
-       */
-      DEPRECATED(static void RegisterOneFactory(void));
-
-    /**
-     * UnRegister one factory of this type
-     * \deprecatedSince{2013_09}
-     */
-    DEPRECATED(static void UnRegisterOneFactory(void));
-
-  protected:
-    PlanarFigureWriterFactory();
-    ~PlanarFigureWriterFactory() override;
-
-  private:
-    PlanarFigureWriterFactory(const Self &); // purposely not implemented
-    void operator=(const Self &);            // purposely not implemented
-
-    static itk::ObjectFactoryBase::Pointer GetInstance();
-  };
-
-} // end namespace mitk
-
-#endif // PLANARFIGURE_WRITERFACTORY_H_HEADER_INCLUDED
diff --git a/Modules/PlanarFigure/test/mitkPlanarFigureIOTest.cpp b/Modules/PlanarFigure/test/mitkPlanarFigureIOTest.cpp
index e24ed0bfef..40fd836151 100644
--- a/Modules/PlanarFigure/test/mitkPlanarFigureIOTest.cpp
+++ b/Modules/PlanarFigure/test/mitkPlanarFigureIOTest.cpp
@@ -1,592 +1,510 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkTestingMacros.h"
 
 #include "mitkPlanarAngle.h"
 #include "mitkPlanarCircle.h"
 #include "mitkPlanarCross.h"
 #include "mitkPlanarFourPointAngle.h"
 #include "mitkPlanarLine.h"
 #include "mitkPlanarPolygon.h"
 #include "mitkPlanarRectangle.h"
 #include "mitkPlanarSubdivisionPolygon.h"
 
-#include "mitkPlanarFigureReader.h"
-#include "mitkPlanarFigureWriter.h"
-
 #include "mitkPlaneGeometry.h"
 
-#include <itksys/SystemTools.hxx>
+#include "mitkGeometry3D.h"
+#include "mitkAbstractFileIO.h"
+#include "mitkFileReaderRegistry.h"
+#include "mitkFileWriterRegistry.h"
+#include "mitkIOUtil.h"
 
-static mitk::PlanarFigure::Pointer Clone(mitk::PlanarFigure::Pointer original)
-{
-  return original->Clone();
-}
+#include <itksys/SystemTools.hxx>
 
 /** \brief Helper class for testing PlanarFigure reader and writer classes. */
 class PlanarFigureIOTestClass
 {
 public:
-  typedef std::list<mitk::PlanarFigure::Pointer> PlanarFigureList;
-  typedef std::vector<mitk::PlanarFigureWriter::Pointer> PlanarFigureToMemoryWriterList;
+  typedef std::map<const std::string, mitk::PlanarFigure::Pointer> PlanarFigureMap;
+  typedef std::map<const std::string, std::string> PlanarFigureToStreamMap;
 
-  static PlanarFigureList CreatePlanarFigures()
+  static PlanarFigureMap CreatePlanarFigures()
   {
-    PlanarFigureList planarFigures;
+    PlanarFigureMap planarFigures;
 
     // Create PlaneGeometry on which to place the PlanarFigures
     mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New();
     planeGeometry->InitializeStandardPlane(100.0, 100.0);
 
     // Create a few sample points for PlanarFigure placement
     mitk::Point2D p0;
     p0[0] = 20.0;
     p0[1] = 20.0;
     mitk::Point2D p1;
     p1[0] = 80.0;
     p1[1] = 80.0;
     mitk::Point2D p2;
     p2[0] = 90.0;
     p2[1] = 10.0;
     mitk::Point2D p3;
     p3[0] = 10.0;
     p3[1] = 90.0;
 
     // Create PlanarAngle
     mitk::PlanarAngle::Pointer planarAngle = mitk::PlanarAngle::New();
     planarAngle->SetPlaneGeometry(planeGeometry);
     planarAngle->PlaceFigure(p0);
     planarAngle->SetCurrentControlPoint(p1);
     planarAngle->AddControlPoint(p2);
     planarAngle->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarAngle.GetPointer());
+    planarFigures.emplace("planarAngle",planarAngle.GetPointer());
 
     // Create PlanarCircle
     mitk::PlanarCircle::Pointer planarCircle = mitk::PlanarCircle::New();
     planarCircle->SetPlaneGeometry(planeGeometry);
     planarCircle->PlaceFigure(p0);
     planarCircle->SetCurrentControlPoint(p1);
     planarCircle->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarCircle.GetPointer());
+    planarFigures.emplace("planarCircle",planarCircle.GetPointer());
 
     // Create PlanarCross
     mitk::PlanarCross::Pointer planarCross = mitk::PlanarCross::New();
     planarCross->SetSingleLineMode(false);
     planarCross->SetPlaneGeometry(planeGeometry);
     planarCross->PlaceFigure(p0);
     planarCross->SetCurrentControlPoint(p1);
     planarCross->AddControlPoint(p2);
     planarCross->AddControlPoint(p3);
     planarCross->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarCross.GetPointer());
+    planarFigures.emplace("planarCross",planarCross.GetPointer());
 
     // Create PlanarFourPointAngle
     mitk::PlanarFourPointAngle::Pointer planarFourPointAngle = mitk::PlanarFourPointAngle::New();
     planarFourPointAngle->SetPlaneGeometry(planeGeometry);
     planarFourPointAngle->PlaceFigure(p0);
     planarFourPointAngle->SetCurrentControlPoint(p1);
     planarFourPointAngle->AddControlPoint(p2);
     planarFourPointAngle->AddControlPoint(p3);
     planarFourPointAngle->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarFourPointAngle.GetPointer());
+    planarFigures.emplace("planarFourPointAngle",planarFourPointAngle.GetPointer());
 
     // Create PlanarLine
     mitk::PlanarLine::Pointer planarLine = mitk::PlanarLine::New();
     planarLine->SetPlaneGeometry(planeGeometry);
     planarLine->PlaceFigure(p0);
     planarLine->SetCurrentControlPoint(p1);
     planarLine->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarLine.GetPointer());
+    planarFigures.emplace("planarLine",planarLine.GetPointer());
 
     // Create PlanarPolygon
     mitk::PlanarPolygon::Pointer planarPolygon = mitk::PlanarPolygon::New();
     planarPolygon->SetClosed(false);
     planarPolygon->SetPlaneGeometry(planeGeometry);
     planarPolygon->PlaceFigure(p0);
     planarPolygon->SetCurrentControlPoint(p1);
     planarPolygon->AddControlPoint(p2);
     planarPolygon->AddControlPoint(p3);
     planarPolygon->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarPolygon.GetPointer());
+    planarFigures.emplace("planarPolygon",planarPolygon.GetPointer());
 
     // Create PlanarSubdivisionPolygon
     mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon = mitk::PlanarSubdivisionPolygon::New();
     planarSubdivisionPolygon->SetClosed(false);
     planarSubdivisionPolygon->SetPlaneGeometry(planeGeometry);
     planarSubdivisionPolygon->PlaceFigure(p0);
     planarSubdivisionPolygon->SetCurrentControlPoint(p1);
     planarSubdivisionPolygon->AddControlPoint(p2);
     planarSubdivisionPolygon->AddControlPoint(p3);
     planarSubdivisionPolygon->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarSubdivisionPolygon.GetPointer());
+    planarFigures.emplace("planarSubdivisionPolygon",planarSubdivisionPolygon.GetPointer());
 
     // Create PlanarRectangle
     mitk::PlanarRectangle::Pointer planarRectangle = mitk::PlanarRectangle::New();
     planarRectangle->SetPlaneGeometry(planeGeometry);
     planarRectangle->PlaceFigure(p0);
     planarRectangle->SetCurrentControlPoint(p1);
     planarRectangle->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarRectangle.GetPointer());
+    planarFigures.emplace("planarRectangle",planarRectangle.GetPointer());
 
     // create preciseGeometry which is using float coordinates
     mitk::PlaneGeometry::Pointer preciseGeometry = mitk::PlaneGeometry::New();
     mitk::Vector3D right;
     right[0] = 0.0;
     right[1] = 1.23456;
     right[2] = 0.0;
 
     mitk::Vector3D down;
     down[0] = 1.23456;
     down[1] = 0.0;
     down[2] = 0.0;
 
     mitk::Vector3D spacing;
     spacing[0] = 0.0123456;
     spacing[1] = 0.0123456;
     spacing[2] = 1.123456;
     preciseGeometry->InitializeStandardPlane(right, down, &spacing);
 
     // convert points into the precise coordinates
     mitk::Point2D p0precise;
     p0precise[0] = p0[0] * spacing[0];
     p0precise[1] = p0[1] * spacing[1];
     mitk::Point2D p1precise;
     p1precise[0] = p1[0] * spacing[0];
     p1precise[1] = p1[1] * spacing[1];
     mitk::Point2D p2precise;
     p2precise[0] = p2[0] * spacing[0];
     p2precise[1] = p2[1] * spacing[1];
     mitk::Point2D p3precise;
     p3precise[0] = p3[0] * spacing[0];
     p3precise[1] = p3[1] * spacing[1];
 
     // Now all PlanarFigures are create using the precise Geometry
     // Create PlanarCross
     mitk::PlanarCross::Pointer nochncross = mitk::PlanarCross::New();
     nochncross->SetSingleLineMode(false);
     nochncross->SetPlaneGeometry(preciseGeometry);
     nochncross->PlaceFigure(p0precise);
     nochncross->SetCurrentControlPoint(p1precise);
     nochncross->AddControlPoint(p2precise);
     nochncross->AddControlPoint(p3precise);
     nochncross->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(nochncross.GetPointer());
+    planarFigures.emplace("nochncross", nochncross.GetPointer());
 
     // Create PlanarAngle
     mitk::PlanarAngle::Pointer planarAnglePrecise = mitk::PlanarAngle::New();
     planarAnglePrecise->SetPlaneGeometry(preciseGeometry);
     planarAnglePrecise->PlaceFigure(p0precise);
     planarAnglePrecise->SetCurrentControlPoint(p1precise);
     planarAnglePrecise->AddControlPoint(p2precise);
     planarAnglePrecise->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarAnglePrecise.GetPointer());
+    planarFigures.emplace("planarAnglePrecise",planarAnglePrecise.GetPointer());
 
     // Create PlanarCircle
     mitk::PlanarCircle::Pointer planarCirclePrecise = mitk::PlanarCircle::New();
     planarCirclePrecise->SetPlaneGeometry(preciseGeometry);
     planarCirclePrecise->PlaceFigure(p0precise);
     planarCirclePrecise->SetCurrentControlPoint(p1precise);
     planarCirclePrecise->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarCirclePrecise.GetPointer());
+    planarFigures.emplace("planarCirclePrecise",planarCirclePrecise.GetPointer());
 
     // Create PlanarFourPointAngle
     mitk::PlanarFourPointAngle::Pointer planarFourPointAnglePrecise = mitk::PlanarFourPointAngle::New();
     planarFourPointAnglePrecise->SetPlaneGeometry(preciseGeometry);
     planarFourPointAnglePrecise->PlaceFigure(p0precise);
     planarFourPointAnglePrecise->SetCurrentControlPoint(p1precise);
     planarFourPointAnglePrecise->AddControlPoint(p2precise);
     planarFourPointAnglePrecise->AddControlPoint(p3precise);
     planarFourPointAnglePrecise->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarFourPointAnglePrecise.GetPointer());
+    planarFigures.emplace("planarFourPointAnglePrecise",planarFourPointAnglePrecise.GetPointer());
 
     // Create PlanarLine
     mitk::PlanarLine::Pointer planarLinePrecise = mitk::PlanarLine::New();
     planarLinePrecise->SetPlaneGeometry(preciseGeometry);
     planarLinePrecise->PlaceFigure(p0precise);
     planarLinePrecise->SetCurrentControlPoint(p1precise);
     planarLinePrecise->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarLinePrecise.GetPointer());
+    planarFigures.emplace("planarLinePrecise",planarLinePrecise.GetPointer());
 
     // Create PlanarPolygon
     mitk::PlanarPolygon::Pointer planarPolygonPrecise = mitk::PlanarPolygon::New();
     planarPolygonPrecise->SetClosed(false);
     planarPolygonPrecise->SetPlaneGeometry(preciseGeometry);
     planarPolygonPrecise->PlaceFigure(p0precise);
     planarPolygonPrecise->SetCurrentControlPoint(p1precise);
     planarPolygonPrecise->AddControlPoint(p2precise);
     planarPolygonPrecise->AddControlPoint(p3precise);
     planarPolygonPrecise->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarPolygonPrecise.GetPointer());
+    planarFigures.emplace("planarPolygonPrecise",planarPolygonPrecise.GetPointer());
 
     // Create PlanarSubdivisionPolygon
     mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygonPrecise = mitk::PlanarSubdivisionPolygon::New();
     planarSubdivisionPolygonPrecise->SetClosed(false);
     planarSubdivisionPolygonPrecise->SetPlaneGeometry(preciseGeometry);
     planarSubdivisionPolygonPrecise->PlaceFigure(p0precise);
     planarSubdivisionPolygonPrecise->SetCurrentControlPoint(p1precise);
     planarSubdivisionPolygonPrecise->AddControlPoint(p2precise);
     planarSubdivisionPolygonPrecise->AddControlPoint(p3precise);
     planarSubdivisionPolygonPrecise->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarSubdivisionPolygonPrecise.GetPointer());
+    planarFigures.emplace("planarSubdivisionPolygonPrecise",planarSubdivisionPolygonPrecise.GetPointer());
 
     // Create PlanarRectangle
     mitk::PlanarRectangle::Pointer planarRectanglePrecise = mitk::PlanarRectangle::New();
     planarRectanglePrecise->SetPlaneGeometry(preciseGeometry);
     planarRectanglePrecise->PlaceFigure(p0precise);
     planarRectanglePrecise->SetCurrentControlPoint(p1precise);
     planarRectanglePrecise->GetPropertyList()->SetBoolProperty("initiallyplaced", true);
-    planarFigures.push_back(planarRectanglePrecise.GetPointer());
+    planarFigures.emplace("planarRectanglePrecise",planarRectanglePrecise.GetPointer());
 
     return planarFigures;
   }
 
-  static PlanarFigureList CreateDeepCopiedPlanarFigures(PlanarFigureList original)
+  static PlanarFigureMap CreateClonedPlanarFigures(PlanarFigureMap original)
   {
-    PlanarFigureList copiedPlanarFigures;
-
-    PlanarFigureList::iterator it1;
+    PlanarFigureMap copiedPlanarFigures;
 
-    for (it1 = original.begin(); it1 != original.end(); ++it1)
+    for (const auto& pf : original)
     {
-      mitk::PlanarFigure::Pointer copiedFigure = (*it1)->Clone();
+      mitk::PlanarFigure::Pointer copiedFigure = pf.second->Clone();
 
-      copiedPlanarFigures.push_back(copiedFigure);
+      copiedPlanarFigures[pf.first] = copiedFigure;
     }
     return copiedPlanarFigures;
   }
 
-  static PlanarFigureList CreateClonedPlanarFigures(PlanarFigureList original)
-  {
-    PlanarFigureList clonedPlanarFigures;
-    clonedPlanarFigures.resize(original.size());
-    std::transform(original.begin(), original.end(), clonedPlanarFigures.begin(), Clone);
-    return clonedPlanarFigures;
-  }
-
-  static void VerifyPlanarFigures(PlanarFigureList &planarFigures1, PlanarFigureList &planarFigures2)
+  static void VerifyPlanarFigures(PlanarFigureMap &referencePfs, PlanarFigureMap &testPfs)
   {
-    PlanarFigureList::iterator it1, it2;
+    PlanarFigureMap::iterator it1, it2;
 
     int i = 0;
-    for (it1 = planarFigures1.begin(); it1 != planarFigures1.end(); ++it1)
+    for (it1 = referencePfs.begin(); it1 != referencePfs.end(); ++it1)
     {
       bool planarFigureFound = false;
       int j = 0;
-      for (it2 = planarFigures2.begin(); it2 != planarFigures2.end(); ++it2)
+      for (it2 = testPfs.begin(); it2 != testPfs.end(); ++it2)
       {
         // Compare PlanarFigures (returns false if different types)
-        if (ComparePlanarFigures(*it1, *it2))
+        if (ComparePlanarFigures(it1->second, it2->second))
         {
           planarFigureFound = true;
         }
         ++j;
       }
 
       // Test if (at least) on PlanarFigure of the first type was found in the second list
       MITK_TEST_CONDITION_REQUIRED(planarFigureFound,
-                                   "Testing if " << (*it1)->GetNameOfClass() << " has a counterpart " << i);
+                                   "Testing if " << it1->second->GetNameOfClass() << " has a counterpart " << i);
       ++i;
     }
   }
 
-  static bool ComparePlanarFigures(mitk::PlanarFigure *figure1, mitk::PlanarFigure *figure2)
+  static bool ComparePlanarFigures(const mitk::PlanarFigure *referencePf, const mitk::PlanarFigure *testPf)
   {
     // Test if PlanarFigures are of same type; otherwise return
-    if (strcmp(figure1->GetNameOfClass(), figure2->GetNameOfClass()) != 0)
+    if (strcmp(referencePf->GetNameOfClass(), testPf->GetNameOfClass()) != 0)
     {
       return false;
     }
 
-    if (strcmp(figure1->GetNameOfClass(), "PlanarCross") == 0)
+    if (strcmp(referencePf->GetNameOfClass(), "PlanarCross") == 0)
     {
       std::cout << "Planar Cross Found" << std::endl;
     }
 
     // Test for equal number of control points
-    if (figure1->GetNumberOfControlPoints() != figure2->GetNumberOfControlPoints())
+    if (referencePf->GetNumberOfControlPoints() != testPf->GetNumberOfControlPoints())
     {
       return false;
     }
 
     // Test if all control points are equal
-    for (unsigned int i = 0; i < figure1->GetNumberOfControlPoints(); ++i)
+    for (unsigned int i = 0; i < referencePf->GetNumberOfControlPoints(); ++i)
     {
-      mitk::Point2D point1 = figure1->GetControlPoint(i);
-      mitk::Point2D point2 = figure2->GetControlPoint(i);
+      mitk::Point2D point1 = referencePf->GetControlPoint(i);
+      mitk::Point2D point2 = testPf->GetControlPoint(i);
 
       if (point1.EuclideanDistanceTo(point2) >= mitk::eps)
       {
         return false;
       }
     }
 
     // Test for equal number of properties
     typedef mitk::PropertyList::PropertyMap PropertyMap;
-    const PropertyMap *properties1 = figure1->GetPropertyList()->GetMap();
-    const PropertyMap *properties2 = figure2->GetPropertyList()->GetMap();
-
-    if (properties1->size() != properties2->size())
-    {
-      return false;
-    }
+    const PropertyMap *refProperties = referencePf->GetPropertyList()->GetMap();
+    const PropertyMap *testProperties = testPf->GetPropertyList()->GetMap();
 
     MITK_INFO << "List 1:";
-    for (auto i1 = properties1->begin(); i1 != properties1->end(); ++i1)
+    for (auto i1 = refProperties->begin(); i1 != refProperties->end(); ++i1)
     {
       std::cout << i1->first << std::endl;
     }
 
     MITK_INFO << "List 2:";
-    for (auto i2 = properties2->begin(); i2 != properties2->end(); ++i2)
+    for (auto i2 = testProperties->begin(); i2 != testProperties->end(); ++i2)
     {
       std::cout << i2->first << std::endl;
     }
 
     MITK_INFO << "-------";
 
-    // Test if all properties are equal
-    if (!std::equal(properties1->begin(), properties1->end(), properties2->begin(), PropertyMapEntryCompare()))
+    //remark test planar figures may have additional properties
+    //(e.g. reader meta information), but they are not relevant
+    //for the test. Only check of all properties of the reference
+    //are present and correct.
+    for (const auto prop : *refProperties)
     {
-      return false;
+      auto finding = testProperties->find(prop.first);
+      if (finding == testProperties->end())
+      {
+        return false;
+      }
+
+      MITK_INFO << "Comparing " << prop.first << "(" << prop.second->GetValueAsString() << ") and " << finding->first
+        << "(" << finding->second->GetValueAsString() << ")";
+      // Compare property objects contained in the map entries (see mitk::PropertyList)
+      if (!(*(prop.second) == *(finding->second))) return false;
     }
 
     // Test if Geometry is equal
-    const auto *planeGeometry1 = dynamic_cast<const mitk::PlaneGeometry *>(figure1->GetPlaneGeometry());
-    const auto *planeGeometry2 = dynamic_cast<const mitk::PlaneGeometry *>(figure2->GetPlaneGeometry());
+    const auto *planeGeometry1 = dynamic_cast<const mitk::PlaneGeometry *>(referencePf->GetPlaneGeometry());
+    const auto *planeGeometry2 = dynamic_cast<const mitk::PlaneGeometry *>(testPf->GetPlaneGeometry());
 
     // Test Geometry transform parameters
     typedef mitk::Geometry3D::TransformType TransformType;
     const TransformType *affineGeometry1 = planeGeometry1->GetIndexToWorldTransform();
     const TransformType::ParametersType &parameters1 = affineGeometry1->GetParameters();
     const TransformType::ParametersType &parameters2 = planeGeometry2->GetIndexToWorldTransform()->GetParameters();
     for (unsigned int i = 0; i < affineGeometry1->GetNumberOfParameters(); ++i)
     {
       if (fabs(parameters1.GetElement(i) - parameters2.GetElement(i)) >= mitk::eps)
       {
         return false;
       }
     }
 
     // Test Geometry bounds
     typedef mitk::Geometry3D::BoundsArrayType BoundsArrayType;
     const BoundsArrayType &bounds1 = planeGeometry1->GetBounds();
     const BoundsArrayType &bounds2 = planeGeometry2->GetBounds();
     for (unsigned int i = 0; i < 6; ++i)
     {
       if (fabs(bounds1.GetElement(i) - bounds2.GetElement(i)) >= mitk::eps)
       {
         return false;
       };
     }
 
     // Test Geometry spacing and origin
     mitk::Vector3D spacing1 = planeGeometry1->GetSpacing();
     mitk::Vector3D spacing2 = planeGeometry2->GetSpacing();
     if ((spacing1 - spacing2).GetNorm() >= mitk::eps)
     {
       return false;
     }
 
     mitk::Point3D origin1 = planeGeometry1->GetOrigin();
     mitk::Point3D origin2 = planeGeometry2->GetOrigin();
 
     if (origin1.EuclideanDistanceTo(origin2) >= mitk::eps)
     {
       return false;
     }
     return true;
   }
 
-  static void SerializePlanarFigures(PlanarFigureList &planarFigures, std::string &fileName)
+  static PlanarFigureToStreamMap SerializePlanarFiguresToMemoryBuffers(PlanarFigureMap &planarFigures)
   {
-    // std::string  sceneFileName = Poco::Path::temp() + /*Poco::Path::separator() +*/ "scene.zip";
-    std::cout << "File name: " << fileName << std::endl;
-
-    mitk::PlanarFigureWriter::Pointer writer = mitk::PlanarFigureWriter::New();
-    writer->SetFileName(fileName.c_str());
+    PlanarFigureToStreamMap pfMemoryStreams;
 
-    unsigned int i;
-    PlanarFigureList::iterator it;
-    for (it = planarFigures.begin(), i = 0; it != planarFigures.end(); ++it, ++i)
+    for (const auto& pf : planarFigures)
     {
-      writer->SetInput(i, *it);
+      mitk::FileWriterRegistry writerRegistry;
+      auto writers = writerRegistry.GetWriters(pf.second.GetPointer(), "");
+
+      std::ostringstream stream;
+      writers[0]->SetOutputStream("",&stream);
+      writers[0]->SetInput(pf.second);
+      writers[0]->Write();
+      pfMemoryStreams.emplace(pf.first, stream.str());
     }
 
-    writer->Update();
-
-    MITK_TEST_CONDITION_REQUIRED(writer->GetSuccess(), "Testing if writing was successful");
+    return pfMemoryStreams;
   }
 
-  static PlanarFigureList DeserializePlanarFigures(std::string &fileName)
+  static PlanarFigureMap DeserializePlanarFiguresFromMemoryBuffers(PlanarFigureToStreamMap pfMemoryStreams)
   {
-    // Read in the planar figures
-    mitk::PlanarFigureReader::Pointer reader = mitk::PlanarFigureReader::New();
-    reader->SetFileName(fileName.c_str());
-    reader->Update();
-
-    MITK_TEST_CONDITION_REQUIRED(reader->GetSuccess(), "Testing if reading was successful");
-
     // Store them in the list and return it
-    PlanarFigureList planarFigures;
-    for (unsigned int i = 0; i < reader->GetNumberOfOutputs(); ++i)
-    {
-      mitk::PlanarFigure *figure = reader->GetOutput(i);
-      planarFigures.push_back(figure);
-    }
+    PlanarFigureMap planarFigures;
 
-    return planarFigures;
-  }
+    mitk::FileReaderRegistry readerRegistry;
+    std::vector<mitk::IFileReader*> readers =
+      readerRegistry.GetReaders(mitk::FileReaderRegistry::GetMimeTypeForFile("pf"));
 
-  static PlanarFigureToMemoryWriterList SerializePlanarFiguresToMemoryBuffers(PlanarFigureList &planarFigures)
-  {
-    PlanarFigureToMemoryWriterList pfMemoryWriters;
-    unsigned int i;
-    PlanarFigureList::iterator it;
-
-    bool success = true;
-    for (it = planarFigures.begin(), i = 0; it != planarFigures.end(); ++it, ++i)
-    {
-      mitk::PlanarFigureWriter::Pointer writer = mitk::PlanarFigureWriter::New();
-      writer->SetWriteToMemory(true);
-      writer->SetInput(*it);
-      writer->Update();
-
-      pfMemoryWriters.push_back(writer);
-
-      if (!writer->GetSuccess())
-        success = false;
-    }
-
-    MITK_TEST_CONDITION_REQUIRED(success, "Testing if writing to memory buffers was successful");
-
-    return pfMemoryWriters;
-  }
-
-  static PlanarFigureList DeserializePlanarFiguresFromMemoryBuffers(PlanarFigureToMemoryWriterList pfMemoryWriters)
-  {
-    // Store them in the list and return it
-    PlanarFigureList planarFigures;
-    bool success = true;
-    for (unsigned int i = 0; i < pfMemoryWriters.size(); ++i)
+    for (const auto& pfStream : pfMemoryStreams)
     {
-      // Read in the planar figures
-      mitk::PlanarFigureReader::Pointer reader = mitk::PlanarFigureReader::New();
-      reader->SetReadFromMemory(true);
-      reader->SetMemoryBuffer(pfMemoryWriters[i]->GetMemoryPointer(), pfMemoryWriters[i]->GetMemorySize());
-      reader->Update();
-      mitk::PlanarFigure *figure = reader->GetOutput(0);
-      planarFigures.push_back(figure);
-
-      if (!reader->GetSuccess())
-        success = false;
+      std::istringstream stream;
+      stream.str(pfStream.second);
+      readers[0]->SetInput("", &stream);
+      auto pfRead = readers[0]->Read();
+      MITK_TEST_CONDITION(pfRead.size() == 1, "One planar figure should be read from stream.");
+      auto pf = dynamic_cast<mitk::PlanarFigure*>(pfRead.front().GetPointer());
+      MITK_TEST_CONDITION(pf != nullptr, "Loaded data should be a planar figure.");
+      planarFigures.emplace(pfStream.first, pf);
     }
 
-    MITK_TEST_CONDITION_REQUIRED(success, "Testing if reading was successful");
-
     return planarFigures;
   }
 
-private:
-  class PropertyMapEntryCompare
-  {
-  public:
-    bool operator()(const mitk::PropertyList::PropertyMap::value_type &entry1,
-                    const mitk::PropertyList::PropertyMap::value_type &entry2)
-    {
-      MITK_INFO << "Comparing " << entry1.first << "(" << entry1.second->GetValueAsString() << ") and " << entry2.first
-                << "(" << entry2.second->GetValueAsString() << ")";
-      // Compare property objects contained in the map entries (see mitk::PropertyList)
-      return *(entry1.second) == *(entry2.second);
-    }
-  };
-
 }; // end test helper class
 
 /** \brief Test for PlanarFigure reader and writer classes.
  *
  * The test works as follows:
  *
  * First, a number of PlanarFigure objects of different types are created and placed with
  * various control points. These objects are the serialized to file, read again from file, and
  * the retrieved objects are compared with their control points, properties, and geometry
  * information to the original PlanarFigure objects.
  */
 int mitkPlanarFigureIOTest(int /* argc */, char * /*argv*/ [])
 {
   MITK_TEST_BEGIN("PlanarFigureIO");
 
   // Create a number of PlanarFigure objects
-  PlanarFigureIOTestClass::PlanarFigureList originalPlanarFigures = PlanarFigureIOTestClass::CreatePlanarFigures();
-
-  // Create a number of "deep-copied" planar figures to test the DeepCopy function (deprecated)
-  PlanarFigureIOTestClass::PlanarFigureList copiedPlanarFigures =
-    PlanarFigureIOTestClass::CreateDeepCopiedPlanarFigures(originalPlanarFigures);
-
-  PlanarFigureIOTestClass::VerifyPlanarFigures(originalPlanarFigures, copiedPlanarFigures);
+  PlanarFigureIOTestClass::PlanarFigureMap originalPlanarFigures = PlanarFigureIOTestClass::CreatePlanarFigures();
 
   // Create a number of cloned planar figures to test the Clone function
-  PlanarFigureIOTestClass::PlanarFigureList clonedPlanarFigures =
+  PlanarFigureIOTestClass::PlanarFigureMap clonedPlanarFigures =
     PlanarFigureIOTestClass::CreateClonedPlanarFigures(originalPlanarFigures);
 
   PlanarFigureIOTestClass::VerifyPlanarFigures(originalPlanarFigures, clonedPlanarFigures);
 
-  // Write PlanarFigure objects into temp file
-  // tmpname
-  static unsigned long count = 0;
-  unsigned long n = count++;
-  std::ostringstream name;
-  for (int i = 0; i < 6; ++i)
+
+  std::map <const std::string, const std::string> pfFileNameMap;
+  for (const auto& pf : originalPlanarFigures)
   {
-    name << char('a' + (n % 26));
-    n /= 26;
+    std::string filename = mitk::IOUtil::CreateTemporaryFile(pf.first+"_XXXXXX.pf", itksys::SystemTools::GetCurrentWorkingDirectory());
+    mitk::IOUtil::Save(pf.second, filename);
+    pfFileNameMap.emplace(pf.first, filename);
   }
-  std::string myname;
-  myname.append(name.str());
-
-  std::string fileName = itksys::SystemTools::GetCurrentWorkingDirectory() + myname + ".pf";
-
-  PlanarFigureIOTestClass::SerializePlanarFigures(originalPlanarFigures, fileName);
 
   // Write PlanarFigure objects to memory buffers
-  PlanarFigureIOTestClass::PlanarFigureToMemoryWriterList writersWithMemoryBuffers =
+  PlanarFigureIOTestClass::PlanarFigureToStreamMap writersStreams =
     PlanarFigureIOTestClass::SerializePlanarFiguresToMemoryBuffers(originalPlanarFigures);
 
   // Read PlanarFigure objects from temp file
-  PlanarFigureIOTestClass::PlanarFigureList retrievedPlanarFigures =
-    PlanarFigureIOTestClass::DeserializePlanarFigures(fileName);
-
-  // Read PlanarFigure objects from memory buffers
-  PlanarFigureIOTestClass::PlanarFigureList retrievedPlanarFiguresFromMemory =
-    PlanarFigureIOTestClass::DeserializePlanarFiguresFromMemoryBuffers(writersWithMemoryBuffers);
-
-  auto it = writersWithMemoryBuffers.begin();
-  while (it != writersWithMemoryBuffers.end())
+  PlanarFigureIOTestClass::PlanarFigureMap retrievedPlanarFigures;
+  for (const auto& files : pfFileNameMap)
   {
-    (*it)->ReleaseMemory();
-    ++it;
+    auto pf = mitk::IOUtil::Load<mitk::PlanarFigure>(files.second);
+    retrievedPlanarFigures.emplace(files.first, pf);
   }
 
+  // Read PlanarFigure objects from memory buffers
+  PlanarFigureIOTestClass::PlanarFigureMap retrievedPlanarFiguresFromMemory =
+    PlanarFigureIOTestClass::DeserializePlanarFiguresFromMemoryBuffers(writersStreams);
+
   // Test if original and retrieved PlanarFigure objects are the same
   PlanarFigureIOTestClass::VerifyPlanarFigures(originalPlanarFigures, retrievedPlanarFigures);
 
   // Test if original and memory retrieved PlanarFigure objects are the same
   PlanarFigureIOTestClass::VerifyPlanarFigures(originalPlanarFigures, retrievedPlanarFiguresFromMemory);
 
   // empty the originalPlanarFigures
   originalPlanarFigures.clear();
 
-  // Test if deep-copied and retrieved PlanarFigure objects are the same
-  PlanarFigureIOTestClass::VerifyPlanarFigures(copiedPlanarFigures, retrievedPlanarFigures);
+  // Test if cloned and retrieved PlanarFigure objects are the same
+  PlanarFigureIOTestClass::VerifyPlanarFigures(clonedPlanarFigures, retrievedPlanarFigures);
 
   MITK_TEST_END()
 }
diff --git a/Modules/PlanarFigure/test/mitkPlanarFigureInteractionTest.cpp b/Modules/PlanarFigure/test/mitkPlanarFigureInteractionTest.cpp
index ed99c4df76..66852cd761 100644
--- a/Modules/PlanarFigure/test/mitkPlanarFigureInteractionTest.cpp
+++ b/Modules/PlanarFigure/test/mitkPlanarFigureInteractionTest.cpp
@@ -1,202 +1,197 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkTestingMacros.h"
 #include <mitkTestFixture.h>
 #include <mitkTestingConfig.h>
 
 #include <mitkIOUtil.h>
 #include <mitkInteractionTestHelper.h>
 #include <mitkRenderingTestHelper.h>
 #include <mitkPlanarFigureInteractor.h>
-#include <mitkPlanarFigureReader.h>
-#include <mitkPlanarFigureWriter.h>
 
 #include <mitkPlanarAngle.h>
 #include <mitkPlanarArrow.h>
 #include <mitkPlanarBezierCurve.h>
 #include <mitkPlanarCircle.h>
 #include <mitkPlanarDoubleEllipse.h>
 #include <mitkPlanarEllipse.h>
 #include <mitkPlanarFourPointAngle.h>
 #include <mitkPlanarLine.h>
 #include <mitkPlanarPolygon.h>
 #include <mitkPlanarRectangle.h>
 #include <mitkPlanarSubdivisionPolygon.h>
 
 #include <vtkDebugLeaks.h>
 
 #include "usModuleRegistry.h"
 
 class mitkPlanarFigureInteractionTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkPlanarFigureInteractionTestSuite);
   MITK_TEST(AngleInteractionCreate);
   MITK_TEST(Angle2InteractionCreate);
   MITK_TEST(BezierCurveInteractionCreate);
   MITK_TEST(CircleInteractionCreate);
   MITK_TEST(DoubleEllipseInteractionCreate);
   MITK_TEST(PlanarFourPointAngleInteractionCreate);
   MITK_TEST(PlanarLineInteractionCreate);
   MITK_TEST(PlanarPolygonInteractionCreate);
   MITK_TEST(NonClosedPlanarPolygonInteractionCreate);
   MITK_TEST(RectangleInteractionCreate);
   // BUG 19304
   // MITK_TEST(PlanarSubdivisionInteractionCreate);
 
   CPPUNIT_TEST_SUITE_END();
 
 public:
   void setUp()
   {
     /// \todo Fix leaks of vtkObjects. Bug 18095.
     vtkDebugLeaks::SetExitError(0);
   }
 
   void tearDown() {}
   void RunTest(mitk::PlanarFigure::Pointer figure, std::string interactionXmlPath, std::string referenceFigurePath)
   {
     mitk::DataNode::Pointer node;
     mitk::PlanarFigureInteractor::Pointer figureInteractor;
 
     // Create DataNode as a container for our PlanarFigure
     node = mitk::DataNode::New();
     node->SetData(figure);
 
     mitk::InteractionTestHelper interactionTestHelper(GetTestDataFilePath(interactionXmlPath));
 
     // Load a bounding image
     mitk::Image::Pointer testImage = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Pic3D.nrrd"));
     figure->SetGeometry(testImage->GetGeometry());
 
     mitk::DataNode::Pointer dn = mitk::DataNode::New();
     dn->SetData(testImage);
     interactionTestHelper.AddNodeToStorage(dn);
     interactionTestHelper.GetDataStorage()->Add(node, dn);
 
     node->SetName("PLANAR FIGURE");
     // set as selected
     node->SetSelected(true);
     node->AddProperty("selected", mitk::BoolProperty::New(true));
 
     // Load state machine
     figureInteractor = mitk::PlanarFigureInteractor::New();
     us::Module *planarFigureModule = us::ModuleRegistry::GetModule("MitkPlanarFigure");
     figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule);
     figureInteractor->SetEventConfig("PlanarFigureConfig.xml", planarFigureModule);
     figureInteractor->SetDataNode(node);
 
     // Start Interaction
     interactionTestHelper.PlaybackInteraction();
 
     // Load reference PlanarFigure
-    mitk::PlanarFigureReader::Pointer reader = mitk::PlanarFigureReader::New();
-    reader->SetFileName(GetTestDataFilePath(referenceFigurePath));
-    reader->Update();
-    mitk::PlanarFigure::Pointer reference = reader->GetOutput(0);
+    auto reference = mitk::IOUtil::Load<mitk::PlanarFigure>(GetTestDataFilePath(referenceFigurePath));
 
     // Compare figures
     MITK_ASSERT_EQUAL(figure, reference, "Compare figure with reference");
   }
 
   void AngleInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarAngle::New();
     RunTest(figure, "InteractionTestData/Interactions/Angle1.xml", "InteractionTestData/ReferenceData/Angle1.pf");
   }
 
   void Angle2InteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarAngle::New();
     RunTest(figure, "InteractionTestData/Interactions/Angle2.xml", "InteractionTestData/ReferenceData/Angle2.pf");
   }
 
   void BezierCurveInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarBezierCurve::New();
     RunTest(figure, "InteractionTestData/Interactions/Bezier.xml", "InteractionTestData/ReferenceData/Bezier.pf");
   }
 
   void CircleInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarCircle::New();
     RunTest(figure, "InteractionTestData/Interactions/Circle.xml", "InteractionTestData/ReferenceData/Circle.pf");
   }
 
   void DoubleEllipseInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarDoubleEllipse::New();
     RunTest(figure,
             "InteractionTestData/Interactions/DoubleEllipse.xml",
             "InteractionTestData/ReferenceData/DoubleEllipse.pf");
   }
 
   void PlanarSubdivisionInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarSubdivisionPolygon::New();
     RunTest(figure,
             "InteractionTestData/Interactions/SubdivisionPolygon.xml",
             "InteractionTestData/ReferenceData/SubDivision.pf");
   }
 
   void PlanarFourPointAngleInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarFourPointAngle::New();
     RunTest(figure,
             "InteractionTestData/Interactions/Planar4PointAngle.xml",
             "InteractionTestData/ReferenceData/Planar4PointAngle.pf");
   }
 
   void PlanarLineInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarLine::New();
     RunTest(figure, "InteractionTestData/Interactions/Line.xml", "InteractionTestData/ReferenceData/Line.pf");
   }
 
   void PlanarPolygonInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarPolygon::New();
     RunTest(figure, "InteractionTestData/Interactions/Polygon.xml", "InteractionTestData/ReferenceData/Polygon.pf");
   }
 
   void NonClosedPlanarPolygonInteractionCreate()
   {
     mitk::PlanarPolygon::Pointer figure;
     figure = mitk::PlanarPolygon::New();
     figure->ClosedOff();
     RunTest(
       figure.GetPointer(), "InteractionTestData/Interactions/Path.xml", "InteractionTestData/ReferenceData/Path.pf");
   }
 
   void RectangleInteractionCreate()
   {
     mitk::PlanarFigure::Pointer figure;
     figure = mitk::PlanarRectangle::New();
     RunTest(figure, "InteractionTestData/Interactions/Rectangle.xml", "InteractionTestData/ReferenceData/Rectangle.pf");
   }
 
   // this is only for the OpenGL check
   mitkPlanarFigureInteractionTestSuite() : m_RenderingTestHelper(300, 300) {}
   private:
     mitk::RenderingTestHelper m_RenderingTestHelper;
 };
 
 MITK_TEST_SUITE_REGISTRATION(mitkPlanarFigureInteraction)
diff --git a/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp b/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp
index 7b77409216..ff1ca235c1 100644
--- a/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp
+++ b/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp
@@ -1,416 +1,419 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #include "QmitkAbstractNodeSelectionWidget.h"
 #include "QmitkModelViewSelectionConnector.h"
 
 QmitkAbstractNodeSelectionWidget::QmitkAbstractNodeSelectionWidget(QWidget* parent) : QWidget(parent), m_InvalidInfo("Error. Select data."),
 m_EmptyInfo("Empty. Make a selection."), m_PopUpTitel("Select a data node"), m_PopUpHint(""),
 m_IsOptional(false), m_SelectOnlyVisibleNodes(true), m_DataStorageDeletedTag(0), m_LastEmissionAllowance(true), m_RecursionGuard(false)
 {
 }
 
 QmitkAbstractNodeSelectionWidget::~QmitkAbstractNodeSelectionWidget()
 {
   auto dataStorage = m_DataStorage.Lock();
   if (dataStorage.IsNotNull())
   {
     // remove Listener for the data storage itself
     dataStorage->RemoveObserver(m_DataStorageDeletedTag);
 
     // remove "add node listener" from data storage
     dataStorage->AddNodeEvent.RemoveListener(
       mitk::MessageDelegate1<QmitkAbstractNodeSelectionWidget, const mitk::DataNode*>(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage));
 
     // remove "remove node listener" from data storage
     dataStorage->RemoveNodeEvent.RemoveListener(
       mitk::MessageDelegate1<QmitkAbstractNodeSelectionWidget, const mitk::DataNode*>(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage));
   }
 
   for (auto& node : m_CurrentInternalSelection)
   {
     this->RemoveNodeObserver(node);
   }
 }
 
 QmitkAbstractNodeSelectionWidget::NodeList QmitkAbstractNodeSelectionWidget::GetSelectedNodes() const
 {
   return this->CompileEmitSelection();
 }
 
 QmitkAbstractNodeSelectionWidget::ConstNodeStdVector QmitkAbstractNodeSelectionWidget::GetSelectedNodesStdVector() const
 {
   auto result = this->GetSelectedNodes();
   return ConstNodeStdVector(result.begin(), result.end());
 }
 
 void QmitkAbstractNodeSelectionWidget::SetDataStorage(mitk::DataStorage* dataStorage)
 {
   if (m_DataStorage == dataStorage)
   {
     return;
   }
 
   auto oldStorage = m_DataStorage.Lock();
   if (oldStorage.IsNotNull())
   {
     // remove Listener for the data storage itself
     oldStorage->RemoveObserver(m_DataStorageDeletedTag);
 
     // remove "add node listener" from old data storage
     oldStorage->AddNodeEvent.RemoveListener(
       mitk::MessageDelegate1<QmitkAbstractNodeSelectionWidget, const mitk::DataNode*>(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage));
 
     // remove "remove node listener" from old data storage
     oldStorage->RemoveNodeEvent.RemoveListener(
       mitk::MessageDelegate1<QmitkAbstractNodeSelectionWidget, const mitk::DataNode*>(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage));
   }
 
   m_DataStorage = dataStorage;
 
   auto newStorage = m_DataStorage.Lock();
 
   if (newStorage.IsNotNull())
   {
     // add Listener for the data storage itself
     auto command = itk::SimpleMemberCommand<QmitkAbstractNodeSelectionWidget>::New();
     command->SetCallbackFunction(this, &QmitkAbstractNodeSelectionWidget::SetDataStorageDeleted);
     m_DataStorageDeletedTag = newStorage->AddObserver(itk::DeleteEvent(), command);
 
     // add "add node listener" for new data storage
     newStorage->AddNodeEvent.AddListener(
       mitk::MessageDelegate1<QmitkAbstractNodeSelectionWidget, const mitk::DataNode*>(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage));
 
     // add remove node listener for new data storage
     newStorage->RemoveNodeEvent.AddListener(
       mitk::MessageDelegate1<QmitkAbstractNodeSelectionWidget, const mitk::DataNode*>(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage));
   }
 
   this->OnDataStorageChanged();
 
   this->HandleChangeOfInternalSelection({});
 }
 
 void QmitkAbstractNodeSelectionWidget::SetNodePredicate(const mitk::NodePredicateBase* nodePredicate)
 {
   if (m_NodePredicate != nodePredicate)
   {
     m_NodePredicate = nodePredicate;
 
     this->OnNodePredicateChanged();
 
     NodeList newInternalNodes;
 
     for (auto& node : m_CurrentInternalSelection)
     {
       if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node))
       {
         newInternalNodes.append(node);
       }
     }
 
     if (!m_SelectOnlyVisibleNodes)
     {
       for (auto& node : m_CurrentExternalSelection)
       {
         if (!newInternalNodes.contains(node) && (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)))
         {
           newInternalNodes.append(node);
         }
       }
     }
 
     this->HandleChangeOfInternalSelection(newInternalNodes);
   }
 }
 
 void QmitkAbstractNodeSelectionWidget::HandleChangeOfInternalSelection(NodeList newInternalSelection)
 {
-  this->ReviseSelectionChanged(m_CurrentInternalSelection, newInternalSelection);
+  if (!EqualNodeSelections(m_CurrentInternalSelection, newInternalSelection))
+  {
+    this->ReviseSelectionChanged(m_CurrentInternalSelection, newInternalSelection);
 
-  this->SetCurrentInternalSelection(newInternalSelection);
+    this->SetCurrentInternalSelection(newInternalSelection);
 
-  this->OnInternalSelectionChanged();
+    this->OnInternalSelectionChanged();
 
-  auto newEmission = this->CompileEmitSelection();
+    auto newEmission = this->CompileEmitSelection();
 
-  this->EmitSelection(newEmission);
+    this->EmitSelection(newEmission);
 
-  this->UpdateInfo();
+    this->UpdateInfo();
+  }
 }
 
 void QmitkAbstractNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes)
 {
   if (!m_RecursionGuard)
   {
     m_CurrentExternalSelection = selectedNodes;
 
     auto dataStorage = m_DataStorage.Lock();
     NodeList newInternalSelection;
     for (auto node : selectedNodes)
     {
       if (dataStorage.IsNotNull() && dataStorage->Exists(node) && (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)))
       {
         newInternalSelection.append(node);
       }
     }
 
     this->HandleChangeOfInternalSelection(newInternalSelection);
   }
 }
 
 const mitk::NodePredicateBase* QmitkAbstractNodeSelectionWidget::GetNodePredicate() const
 {
   return m_NodePredicate;
 }
 
 QString QmitkAbstractNodeSelectionWidget::GetInvalidInfo() const
 {
   return m_InvalidInfo;
 }
 
 QString QmitkAbstractNodeSelectionWidget::GetEmptyInfo() const
 {
   return m_EmptyInfo;
 }
 
 QString QmitkAbstractNodeSelectionWidget::GetPopUpTitel() const
 {
   return m_PopUpTitel;
 }
 
 QString QmitkAbstractNodeSelectionWidget::GetPopUpHint() const
 {
   return m_PopUpHint;
 }
 
 bool QmitkAbstractNodeSelectionWidget::GetSelectionIsOptional() const
 {
   return m_IsOptional;
 }
 
 bool QmitkAbstractNodeSelectionWidget::GetSelectOnlyVisibleNodes() const
 {
   return m_SelectOnlyVisibleNodes;
 }
 
 void QmitkAbstractNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes)
 {
   if (m_SelectOnlyVisibleNodes != selectOnlyVisibleNodes)
   {
     m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes;
 
     auto newEmission = this->CompileEmitSelection();
 
     this->EmitSelection(newEmission);
   }
 }
 
 void QmitkAbstractNodeSelectionWidget::SetInvalidInfo(QString info)
 {
   m_InvalidInfo = info;
   this->UpdateInfo();
 }
 
 void QmitkAbstractNodeSelectionWidget::SetEmptyInfo(QString info)
 {
   m_EmptyInfo = info;
   this->UpdateInfo();
 }
 
 void QmitkAbstractNodeSelectionWidget::SetPopUpTitel(QString info)
 {
   m_PopUpTitel = info;
 }
 
 void QmitkAbstractNodeSelectionWidget::SetPopUpHint(QString info)
 {
   m_PopUpHint = info;
 }
 
 void QmitkAbstractNodeSelectionWidget::SetSelectionIsOptional(bool isOptional)
 {
   m_IsOptional = isOptional;
   this->UpdateInfo();
 }
 
 void QmitkAbstractNodeSelectionWidget::SetDataStorageDeleted()
 {
   this->OnDataStorageChanged();
   this->HandleChangeOfInternalSelection({});
 }
 
 void QmitkAbstractNodeSelectionWidget::ReviseSelectionChanged(const NodeList& /*oldInternalSelection*/, NodeList& /*newInternalSelection*/)
 {
 }
 
 bool QmitkAbstractNodeSelectionWidget::AllowEmissionOfSelection(const NodeList& /*emissionCandidates*/) const
 {
   return true;
 }
 
 void QmitkAbstractNodeSelectionWidget::EmitSelection(const NodeList& emissionCandidates)
 {
   m_LastEmissionAllowance = this->AllowEmissionOfSelection(emissionCandidates);
   if (m_LastEmissionAllowance && !EqualNodeSelections(m_LastEmission, emissionCandidates))
   {
     m_RecursionGuard = true;
     emit CurrentSelectionChanged(emissionCandidates);
     m_RecursionGuard = false;
     m_LastEmission = emissionCandidates;
   }
 }
 
 void QmitkAbstractNodeSelectionWidget::SetCurrentInternalSelection(NodeList selectedNodes)
 {
   for (auto& node : m_CurrentInternalSelection)
   {
     this->RemoveNodeObserver(node);
   }
 
   m_CurrentInternalSelection = selectedNodes;
 
   for (auto& node : m_CurrentInternalSelection)
   {
     this->AddNodeObserver(node);
   }
 }
 
 const QmitkAbstractNodeSelectionWidget::NodeList& QmitkAbstractNodeSelectionWidget::GetCurrentInternalSelection() const
 {
   return m_CurrentInternalSelection;
 }
 
 const QmitkAbstractNodeSelectionWidget::NodeList& QmitkAbstractNodeSelectionWidget::GetCurrentExternalSelection() const
 {
   return m_CurrentExternalSelection;
 }
 
 void QmitkAbstractNodeSelectionWidget::OnNodePredicateChanged()
 {
 }
 
 void QmitkAbstractNodeSelectionWidget::OnDataStorageChanged()
 {
 }
 
 void QmitkAbstractNodeSelectionWidget::OnInternalSelectionChanged()
 {
 }
 
 void QmitkAbstractNodeSelectionWidget::NodeAddedToStorage(const mitk::DataNode* node)
 {
   this->OnNodeAddedToStorage(node);
 }
 
 void QmitkAbstractNodeSelectionWidget::OnNodeAddedToStorage(const mitk::DataNode* /*node*/)
 {
 }
 
 void QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage(const mitk::DataNode* node)
 {
   this->OnNodeRemovedFromStorage(node);
   this->RemoveNodeFromSelection(node);
 }
 
 void QmitkAbstractNodeSelectionWidget::OnNodeRemovedFromStorage(const mitk::DataNode* /*node*/)
 {
 }
 
 QmitkAbstractNodeSelectionWidget::NodeList QmitkAbstractNodeSelectionWidget::CompileEmitSelection() const
 {
   NodeList result = m_CurrentInternalSelection;
 
   if (!m_SelectOnlyVisibleNodes)
   {
     for (auto node : m_CurrentExternalSelection)
     {
       if (!result.contains(node) && m_NodePredicate.IsNotNull() && !m_NodePredicate->CheckNode(node))
       {
         result.append(node);
       }
     }
   }
 
   return result;
 }
 
 void QmitkAbstractNodeSelectionWidget::RemoveNodeFromSelection(const mitk::DataNode* node)
 {
   auto newSelection = m_CurrentInternalSelection;
 
   auto finding = std::find(std::begin(newSelection), std::end(newSelection), node);
   
   if (finding != std::end(newSelection))
   {
     newSelection.erase(finding);
     this->HandleChangeOfInternalSelection(newSelection);
   }
 }
 
 void QmitkAbstractNodeSelectionWidget::OnNodeModified(const itk::Object * caller, const itk::EventObject & event)
 {
   if (itk::ModifiedEvent().CheckEvent(&event))
   {
     auto node = dynamic_cast<const mitk::DataNode*>(caller);
 
     if (node)
     {
       if (m_NodePredicate.IsNotNull() && !m_NodePredicate->CheckNode(node))
       {
         this->RemoveNodeFromSelection(node);
       }
       else
       {
         auto oldAllowance = m_LastEmissionAllowance;
         auto newEmission = this->CompileEmitSelection();
         auto nonConstNode = const_cast<mitk::DataNode*>(node);
         if (newEmission.contains(nonConstNode) && (oldAllowance != this->AllowEmissionOfSelection(newEmission)))
         {
           this->EmitSelection(newEmission);
           this->UpdateInfo();
         }
       }
     }
   }
 }
 
 void QmitkAbstractNodeSelectionWidget::AddNodeObserver(mitk::DataNode* node)
 {
   if (node)
   {
     auto modifiedCommand = itk::MemberCommand<QmitkAbstractNodeSelectionWidget>::New();
     modifiedCommand->SetCallbackFunction(this, &QmitkAbstractNodeSelectionWidget::OnNodeModified);
 
     auto nodeModifiedObserverTag = node->AddObserver(itk::ModifiedEvent(), modifiedCommand);
 
     m_NodeObserverTags.insert(std::make_pair(node, nodeModifiedObserverTag));
   }
 }
 
 void QmitkAbstractNodeSelectionWidget::RemoveNodeObserver(mitk::DataNode* node)
 {
   if (node)
   {
     auto finding = m_NodeObserverTags.find(node);
     if (finding != std::end(m_NodeObserverTags))
     {
       node->RemoveObserver(finding->second);
     }
     else
     {
       MITK_ERROR << "Selection widget is in a wrong state. A node should be removed from the internal selection but seems to have no observer. Node:" << node;
     }
     m_NodeObserverTags.erase(node);
   }
 }
diff --git a/Modules/QtWidgets/test/CMakeLists.txt b/Modules/QtWidgets/test/CMakeLists.txt
index fe9484dd12..b7ff9b62be 100644
--- a/Modules/QtWidgets/test/CMakeLists.txt
+++ b/Modules/QtWidgets/test/CMakeLists.txt
@@ -1,9 +1,9 @@
 MITK_CREATE_MODULE_TESTS()
 
 if(UNIX AND NOT APPLE)
-  set(qt_platform "-platform minimal")
+  set(qt_platform -platform minimal)
 else()
   unset(qt_platform)
 endif()
 
 mitkAddCustomModuleTest(QmitkAbstractNodeSelectionWidgetTest QmitkAbstractNodeSelectionWidgetTest ${qt_platform})
diff --git a/Modules/QtWidgetsExt/CMakeLists.txt b/Modules/QtWidgetsExt/CMakeLists.txt
index 5fc72f81b0..c2e295c41b 100644
--- a/Modules/QtWidgetsExt/CMakeLists.txt
+++ b/Modules/QtWidgetsExt/CMakeLists.txt
@@ -1,6 +1,6 @@
 MITK_CREATE_MODULE(
-  DEPENDS MitkAlgorithmsExt MitkQtWidgets
+  DEPENDS MitkAlgorithmsExt MitkQtWidgets PRIVATE MitkSceneSerializationBase
   PACKAGE_DEPENDS
     PUBLIC Qwt CTK|CTKWidgets
     PRIVATE Qt5|Concurrent+Svg+Xml
 )
diff --git a/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp
index 922415e67b..45483cc16a 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp
+++ b/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp
@@ -1,948 +1,956 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 #include "QmitkAdaptiveRegionGrowingToolGUI.h"
 
 #include <qmessagebox.h>
 
 #include "mitkITKImageImport.h"
 #include "mitkImageAccessByItk.h"
 #include "mitkImageTimeSelector.h"
 #include "mitkNodePredicateDataType.h"
 #include "mitkProperties.h"
 #include "mitkTransferFunctionProperty.h"
 
 #include "mitkImageStatisticsHolder.h"
 
 #include "itkMaskImageFilter.h"
 #include "itkNumericTraits.h"
 #include <itkBinaryThresholdImageFilter.h>
 #include <itkConnectedAdaptiveThresholdImageFilter.h>
 #include <itkImageIterator.h>
 #include <itkMinimumMaximumImageCalculator.h>
 
 #include "QmitkConfirmSegmentationDialog.h"
 #include "itkOrImageFilter.h"
 #include "mitkImageCast.h"
 
 #include "mitkImagePixelReadAccessor.h"
 #include "mitkPixelTypeMultiplex.h"
 
 #include "mitkImageCast.h"
 
 MITK_TOOL_GUI_MACRO(, QmitkAdaptiveRegionGrowingToolGUI, "")
 
 QmitkAdaptiveRegionGrowingToolGUI::QmitkAdaptiveRegionGrowingToolGUI(QWidget *parent)
   : QmitkToolGUI(),
     m_DataStorage(nullptr),
     m_UseVolumeRendering(false),
     m_UpdateSuggestedThreshold(true),
     m_SuggestedThValue(0.0)
 {
   this->setParent(parent);
 
   m_Controls.setupUi(this);
 
   m_Controls.m_ThresholdSlider->setDecimals(1);
   m_Controls.m_ThresholdSlider->setSpinBoxAlignment(Qt::AlignVCenter);
 
   m_Controls.m_PreviewSlider->setEnabled(false);
   m_Controls.m_PreviewSlider->setSingleStep(0.5);
   // Not yet available
   // m_Controls.m_PreviewSlider->InvertedAppearance(true);
 
   //3D preview doesn't work: T24430. Postponed until reimplementation of segmentation
   m_Controls.m_cbVolumeRendering->setVisible(false);
 
   this->CreateConnections();
   this->SetDataNodeNames("labeledRGSegmentation", "RGResult", "RGFeedbackSurface", "maskedSegmentation");
 
   connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *)));
 }
 
 QmitkAdaptiveRegionGrowingToolGUI::~QmitkAdaptiveRegionGrowingToolGUI()
 {
   // Removing the observer of the PointSet node
   if (m_RegionGrow3DTool->GetPointSetNode().IsNotNull())
   {
     m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetAddObserverTag);
     m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetMoveObserverTag);
   }
   this->RemoveHelperNodes();
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::OnNewToolAssociated(mitk::Tool *tool)
 {
   m_RegionGrow3DTool = dynamic_cast<mitk::AdaptiveRegionGrowingTool *>(tool);
   if (m_RegionGrow3DTool.IsNotNull())
   {
     SetInputImageNode(this->m_RegionGrow3DTool->GetReferenceData());
     this->m_DataStorage = this->m_RegionGrow3DTool->GetDataStorage();
     this->EnableControls(true);
 
     // Watch for point added or modified
     itk::SimpleMemberCommand<QmitkAdaptiveRegionGrowingToolGUI>::Pointer pointAddedCommand =
       itk::SimpleMemberCommand<QmitkAdaptiveRegionGrowingToolGUI>::New();
     pointAddedCommand->SetCallbackFunction(this, &QmitkAdaptiveRegionGrowingToolGUI::OnPointAdded);
     m_PointSetAddObserverTag =
       m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver(mitk::PointSetAddEvent(), pointAddedCommand);
     m_PointSetMoveObserverTag =
       m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver(mitk::PointSetMoveEvent(), pointAddedCommand);
   }
   else
   {
     this->EnableControls(false);
   }
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::RemoveHelperNodes()
 {
   mitk::DataNode::Pointer imageNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
   if (imageNode.IsNotNull())
   {
     m_DataStorage->Remove(imageNode);
   }
 
   mitk::DataNode::Pointer maskedSegmentationNode = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION);
   if (maskedSegmentationNode.IsNotNull())
   {
     m_DataStorage->Remove(maskedSegmentationNode);
   }
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::CreateConnections()
 {
   // Connecting GUI components
   connect((QObject *)(m_Controls.m_pbRunSegmentation), SIGNAL(clicked()), this, SLOT(RunSegmentation()));
   connect(m_Controls.m_PreviewSlider, SIGNAL(valueChanged(double)), this, SLOT(ChangeLevelWindow(double)));
   connect((QObject *)(m_Controls.m_pbConfirmSegementation), SIGNAL(clicked()), this, SLOT(ConfirmSegmentation()));
   connect(
     m_Controls.m_ThresholdSlider, SIGNAL(maximumValueChanged(double)), this, SLOT(SetUpperThresholdValue(double)));
   connect(
     m_Controls.m_ThresholdSlider, SIGNAL(minimumValueChanged(double)), this, SLOT(SetLowerThresholdValue(double)));
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::SetDataNodeNames(std::string labledSegmentation,
                                                          std::string binaryImage,
                                                          std::string surface,
                                                          std::string maskedSegmentation)
 {
   m_NAMEFORLABLEDSEGMENTATIONIMAGE = labledSegmentation;
   m_NAMEFORBINARYIMAGE = binaryImage;
   m_NAMEFORSURFACE = surface;
   m_NAMEFORMASKEDSEGMENTATION = maskedSegmentation;
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::SetDataStorage(mitk::DataStorage *dataStorage)
 {
   m_DataStorage = dataStorage;
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::SetInputImageNode(mitk::DataNode *node)
 {
   m_InputImageNode = node;
   mitk::Image *inputImage = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
   if (inputImage)
   {
     mitk::ScalarType max = inputImage->GetStatistics()->GetScalarValueMax();
     mitk::ScalarType min = inputImage->GetStatistics()->GetScalarValueMin();
     m_Controls.m_ThresholdSlider->setMaximum(max);
     m_Controls.m_ThresholdSlider->setMinimum(min);
     // Just for initialization
     m_Controls.m_ThresholdSlider->setMaximumValue(max);
     m_Controls.m_ThresholdSlider->setMinimumValue(min);
   }
 }
 
 template <typename TPixel>
-static void AccessPixel(mitk::PixelType /*ptype*/, const mitk::Image::Pointer im, mitk::Point3D p, int &val)
+static void AccessPixel(mitk::PixelType /*ptype*/, mitk::Image* im, mitk::Point3D p, int& val)
+{
+  mitk::ImagePixelReadAccessor<TPixel, 3> access(im);
+  val = access.GetPixelByWorldCoordinates(p);
+}
+
+/**Overloaded const verison*/
+template <typename TPixel>
+static void AccessPixel(mitk::PixelType /*ptype*/, const mitk::Image* im, mitk::Point3D p, int& val)
 {
   mitk::ImagePixelReadAccessor<TPixel, 3> access(im);
   val = access.GetPixelByWorldCoordinates(p);
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::OnPointAdded()
 {
   if (m_RegionGrow3DTool.IsNull())
     return;
 
   mitk::DataNode *node = m_RegionGrow3DTool->GetPointSetNode();
 
   if (node != nullptr)
   {
     mitk::PointSet::Pointer pointSet = dynamic_cast<mitk::PointSet *>(node->GetData());
 
     if (pointSet.IsNull())
     {
       QMessageBox::critical(nullptr, "QmitkAdaptiveRegionGrowingToolGUI", "PointSetNode does not contain a pointset");
       return;
     }
 
     m_Controls.m_lblSetSeedpoint->setText("");
 
-    mitk::Image *image = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
+    const mitk::Image *image = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
 
     mitk::Point3D seedPoint =
       pointSet
         ->GetPointSet(
           mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget0"))->GetTimeStep())
         ->GetPoints()
         ->ElementAt(0);
 
     if (image->GetGeometry()->IsInside(seedPoint))
       mitkPixelTypeMultiplex3(
         AccessPixel, image->GetChannelDescriptor().GetPixelType(), image, seedPoint, m_SeedpointValue) else return;
 
     /* In this case the seedpoint is placed e.g. in the lung or bronchialtree
      * The lowerFactor sets the windowsize depending on the regiongrowing direction
      */
     m_CurrentRGDirectionIsUpwards = true;
     if (m_SeedpointValue < -500)
     {
       m_CurrentRGDirectionIsUpwards = false;
     }
 
     // Initializing the region by the area around the seedpoint
     m_SeedPointValueMean = 0;
 
     itk::Index<3> currentIndex, runningIndex;
     mitk::ScalarType pixelValues[125];
     unsigned int pos(0);
 
     image->GetGeometry(0)->WorldToIndex(seedPoint, currentIndex);
     runningIndex = currentIndex;
 
     for (int i = runningIndex[0] - 2; i <= runningIndex[0] + 2; i++)
     {
       for (int j = runningIndex[1] - 2; j <= runningIndex[1] + 2; j++)
       {
         for (int k = runningIndex[2] - 2; k <= runningIndex[2] + 2; k++)
         {
           currentIndex[0] = i;
           currentIndex[1] = j;
           currentIndex[2] = k;
 
           if (image->GetGeometry()->IsIndexInside(currentIndex))
           {
             int component = 0;
             m_InputImageNode->GetIntProperty("Image.Displayed Component", component);
             mitkPixelTypeMultiplex4(mitk::FastSinglePixelAccess,
                                     image->GetChannelDescriptor().GetPixelType(),
                                     image,
                                     nullptr,
                                     currentIndex,
                                     pixelValues[pos]);
 
             pos++;
           }
           else
           {
             pixelValues[pos] = std::numeric_limits<long>::min();
             pos++;
           }
         }
       }
     }
 
     // Now calculation mean of the pixelValues
     // Now calculation mean of the pixelValues
     unsigned int numberOfValues(0);
     for (auto &pixelValue : pixelValues)
     {
       if (pixelValue > std::numeric_limits<long>::min())
       {
         m_SeedPointValueMean += pixelValue;
         numberOfValues++;
       }
     }
     m_SeedPointValueMean = m_SeedPointValueMean / numberOfValues;
 
     mitk::ScalarType var = 0;
     if (numberOfValues > 1)
     {
       for (auto &pixelValue : pixelValues)
       {
         if (pixelValue > std::numeric_limits<mitk::ScalarType>::min())
         {
           var += (pixelValue - m_SeedPointValueMean) * (pixelValue - m_SeedPointValueMean);
         }
       }
       var /= numberOfValues - 1;
     }
     mitk::ScalarType stdDev = sqrt(var);
 
     /*
      * Here the upper- and lower threshold is calculated:
      * The windowSize is 20% of the maximum range of the intensity values existing in the current image
      * If the RG direction is upwards the lower TH is meanSeedValue-0.15*windowSize and upper TH is
      * meanSeedValue+0.85*windowsSize
      * if the RG direction is downwards the lower TH is meanSeedValue-0.85*windowSize and upper TH is
      * meanSeedValue+0.15*windowsSize
     */
     mitk::ScalarType min = image->GetStatistics()->GetScalarValueMin();
     mitk::ScalarType max = image->GetStatistics()->GetScalarValueMax();
     mitk::ScalarType windowSize = max - min;
 
     windowSize = 0.15 * windowSize;
 
     if (m_CurrentRGDirectionIsUpwards)
     {
       m_LOWERTHRESHOLD = m_SeedPointValueMean - stdDev;
       m_UPPERTHRESHOLD = m_SeedpointValue + windowSize;
       if (m_UPPERTHRESHOLD > max)
         m_UPPERTHRESHOLD = max;
       m_Controls.m_ThresholdSlider->setMaximumValue(m_UPPERTHRESHOLD);
       m_Controls.m_ThresholdSlider->setMinimumValue(m_LOWERTHRESHOLD);
     }
     else
     {
       m_UPPERTHRESHOLD = m_SeedPointValueMean;
       if (m_SeedpointValue > m_SeedPointValueMean)
         m_UPPERTHRESHOLD = m_SeedpointValue;
       m_LOWERTHRESHOLD = m_SeedpointValue - windowSize;
       if (m_LOWERTHRESHOLD < min)
         m_LOWERTHRESHOLD = min;
       m_Controls.m_ThresholdSlider->setMinimumValue(m_LOWERTHRESHOLD);
       m_Controls.m_ThresholdSlider->setMaximumValue(m_UPPERTHRESHOLD);
     }
   }
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::RunSegmentation()
 {
   if (m_InputImageNode.IsNull())
   {
     QMessageBox::information(nullptr, "Adaptive Region Growing functionality", "Please specify the image in Datamanager!");
     return;
   }
 
   mitk::DataNode::Pointer node = m_RegionGrow3DTool->GetPointSetNode();
 
   if (node.IsNull())
   {
     QMessageBox::information(nullptr, "Adaptive Region Growing functionality", "Please insert a seed point inside the "
                                                                             "image.\n\nFirst press the \"Define Seed "
                                                                             "Point\" button,\nthen click left mouse "
                                                                             "button inside the image.");
     return;
   }
 
   // safety if no pointSet or pointSet empty
   mitk::PointSet::Pointer seedPointSet = dynamic_cast<mitk::PointSet *>(node->GetData());
   if (seedPointSet.IsNull())
   {
     m_Controls.m_pbRunSegmentation->setEnabled(true);
     QMessageBox::information(
       nullptr, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point.");
     return;
   }
 
   int timeStep =
     mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget0"))->GetTimeStep();
 
   if (!(seedPointSet->GetSize(timeStep)))
   {
     m_Controls.m_pbRunSegmentation->setEnabled(true);
     QMessageBox::information(
       nullptr, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point.");
     return;
   }
 
   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
 
   mitk::PointSet::PointType seedPoint = seedPointSet->GetPointSet(timeStep)->GetPoints()->Begin().Value();
 
   mitk::Image::Pointer orgImage = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
 
   if (orgImage.IsNotNull())
   {
     if (orgImage->GetDimension() == 4)
     {
       mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
       timeSelector->SetInput(orgImage);
       timeSelector->SetTimeNr(timeStep);
       timeSelector->UpdateLargestPossibleRegion();
       mitk::Image *timedImage = timeSelector->GetOutput();
       AccessByItk_2(timedImage, StartRegionGrowing, timedImage->GetGeometry(), seedPoint);
     }
     else if (orgImage->GetDimension() == 3)
     {
       // QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); //set the cursor to waiting
       AccessByItk_2(orgImage, StartRegionGrowing, orgImage->GetGeometry(), seedPoint);
       // QApplication::restoreOverrideCursor();//reset cursor
     }
     else
     {
       QApplication::restoreOverrideCursor(); // reset cursor
       QMessageBox::information(
         nullptr, "Adaptive Region Growing functionality", "Only images of dimension 3 or 4 can be processed!");
       return;
     }
   }
   EnableControls(true); // Segmentation ran successfully, so enable all controls.
   node->SetVisibility(true);
   QApplication::restoreOverrideCursor(); // reset cursor
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void QmitkAdaptiveRegionGrowingToolGUI::StartRegionGrowing(itk::Image<TPixel, VImageDimension> *itkImage,
                                                            mitk::BaseGeometry *imageGeometry,
                                                            mitk::PointSet::PointType seedPoint)
 {
   typedef itk::Image<TPixel, VImageDimension> InputImageType;
   typedef typename InputImageType::IndexType IndexType;
   typedef itk::ConnectedAdaptiveThresholdImageFilter<InputImageType, InputImageType> RegionGrowingFilterType;
   typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New();
   typedef itk::BinaryThresholdImageFilter<InputImageType, InputImageType> ThresholdFilterType;
   typedef itk::MaskImageFilter<InputImageType, InputImageType, InputImageType> MaskImageFilterType;
 
   if (!imageGeometry->IsInside(seedPoint))
   {
     QApplication::restoreOverrideCursor(); // reset cursor to be able to click ok with the regular mouse cursor
     QMessageBox::information(nullptr,
                              "Segmentation functionality",
                              "The seed point is outside of the image! Please choose a position inside the image!");
     return;
   }
 
   IndexType seedIndex;
   imageGeometry->WorldToIndex(seedPoint, seedIndex); // convert world coordinates to image indices
 
   if (m_SeedpointValue > m_UPPERTHRESHOLD || m_SeedpointValue < m_LOWERTHRESHOLD)
   {
     QApplication::restoreOverrideCursor(); // reset cursor to be able to click ok with the regular mouse cursor
     QMessageBox::information(
       nullptr,
       "Segmentation functionality",
       "The seed point is outside the defined thresholds! Please set a new seed point or adjust the thresholds.");
     MITK_INFO << "Mean: " << m_SeedPointValueMean;
     return;
   }
 
   // Setting the direction of the regiongrowing. For dark structures e.g. the lung the regiongrowing
   // is performed starting at the upper value going to the lower one
   regionGrower->SetGrowingDirectionIsUpwards(m_CurrentRGDirectionIsUpwards);
   regionGrower->SetInput(itkImage);
   regionGrower->AddSeed(seedIndex);
   // In some cases we have to subtract 1 for the lower threshold and add 1 to the upper.
   // Otherwise no region growing is done. Maybe a bug in the ConnectiveAdaptiveThresholdFilter
   regionGrower->SetLower(m_LOWERTHRESHOLD - 1);
   regionGrower->SetUpper(m_UPPERTHRESHOLD + 1);
 
   try
   {
     regionGrower->Update();
   }
   catch (itk::ExceptionObject &exc)
   {
     QMessageBox errorInfo;
     errorInfo.setWindowTitle("Adaptive RG Segmentation Functionality");
     errorInfo.setIcon(QMessageBox::Critical);
     errorInfo.setText("An error occurred during region growing!");
     errorInfo.setDetailedText(exc.what());
     errorInfo.exec();
     return; // can't work
   }
   catch (...)
   {
     QMessageBox::critical(nullptr, "Adaptive RG Segmentation Functionality", "An error occurred during region growing!");
     return;
   }
 
   mitk::Image::Pointer resultImage = mitk::ImportItkImage(regionGrower->GetOutput())->Clone();
   // initialize slider
   m_Controls.m_PreviewSlider->setMinimum(m_LOWERTHRESHOLD);
 
   mitk::ScalarType max = m_SeedpointValue + resultImage->GetStatistics()->GetScalarValueMax();
   if (max < m_UPPERTHRESHOLD)
     m_Controls.m_PreviewSlider->setMaximum(max);
   else
     m_Controls.m_PreviewSlider->setMaximum(m_UPPERTHRESHOLD);
 
   this->m_DetectedLeakagePoint = regionGrower->GetLeakagePoint();
 
   if (m_CurrentRGDirectionIsUpwards)
   {
     m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean - 1);
   }
   else
   {
     m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean + 1);
   }
   this->m_SliderInitialized = true;
 
   // create new node and then delete the old one if there is one
   mitk::DataNode::Pointer newNode = mitk::DataNode::New();
   newNode->SetData(resultImage);
 
   // set some properties
   newNode->SetProperty("name", mitk::StringProperty::New(m_NAMEFORLABLEDSEGMENTATIONIMAGE));
   newNode->SetProperty("helper object", mitk::BoolProperty::New(true));
   newNode->SetProperty("color", mitk::ColorProperty::New(0.0, 1.0, 0.0));
   newNode->SetProperty("layer", mitk::IntProperty::New(1));
   newNode->SetProperty("opacity", mitk::FloatProperty::New(0.7));
 
   // delete the old image, if there was one:
   mitk::DataNode::Pointer binaryNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
   m_DataStorage->Remove(binaryNode);
 
   // now add result to data tree
   m_DataStorage->Add(newNode, m_InputImageNode);
 
   typename InputImageType::Pointer inputImageItk;
   mitk::CastToItkImage<InputImageType>(resultImage, inputImageItk);
   // volume rendering preview masking
   typename ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New();
   thresholdFilter->SetInput(inputImageItk);
   thresholdFilter->SetInsideValue(1);
   thresholdFilter->SetOutsideValue(0);
 
   double sliderVal = this->m_Controls.m_PreviewSlider->value();
   if (m_CurrentRGDirectionIsUpwards)
   {
     thresholdFilter->SetLowerThreshold(sliderVal);
     thresholdFilter->SetUpperThreshold(itk::NumericTraits<TPixel>::max());
   }
   else
   {
     thresholdFilter->SetLowerThreshold(itk::NumericTraits<TPixel>::min());
     thresholdFilter->SetUpperThreshold(sliderVal);
   }
   thresholdFilter->SetInPlace(false);
 
   typename MaskImageFilterType::Pointer maskFilter = MaskImageFilterType::New();
   maskFilter->SetInput(inputImageItk);
   maskFilter->SetInPlace(false);
   maskFilter->SetMaskImage(thresholdFilter->GetOutput());
   maskFilter->SetOutsideValue(0);
   maskFilter->UpdateLargestPossibleRegion();
 
   mitk::Image::Pointer mitkMask;
   mitk::CastToMitkImage<InputImageType>(maskFilter->GetOutput(), mitkMask);
   mitk::DataNode::Pointer maskedNode = mitk::DataNode::New();
   maskedNode->SetData(mitkMask);
 
   // set some properties
   maskedNode->SetProperty("name", mitk::StringProperty::New(m_NAMEFORMASKEDSEGMENTATION));
   maskedNode->SetProperty("helper object", mitk::BoolProperty::New(true));
   maskedNode->SetProperty("color", mitk::ColorProperty::New(0.0, 1.0, 0.0));
   maskedNode->SetProperty("layer", mitk::IntProperty::New(1));
   maskedNode->SetProperty("opacity", mitk::FloatProperty::New(0.0));
 
   // delete the old image, if there was one:
   mitk::DataNode::Pointer deprecatedMask = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION);
   m_DataStorage->Remove(deprecatedMask);
 
   // now add result to data tree
   m_DataStorage->Add(maskedNode, m_InputImageNode);
 
   this->InitializeLevelWindow();
 
   if (m_UseVolumeRendering)
     this->EnableVolumeRendering(true);
 
   m_UpdateSuggestedThreshold = true; // reset first stored threshold value
   // Setting progress to finished
   mitk::ProgressBar::GetInstance()->Progress(357);
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::InitializeLevelWindow()
 {
   // get the preview from the datatree
   mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
 
   mitk::LevelWindow tempLevelWindow;
   newNode->GetLevelWindow(tempLevelWindow, nullptr, "levelwindow");
 
   mitk::ScalarType *level = new mitk::ScalarType(0.0);
   mitk::ScalarType *window = new mitk::ScalarType(1.0);
 
   int upper;
   if (m_CurrentRGDirectionIsUpwards)
   {
     upper = m_UPPERTHRESHOLD - m_SeedpointValue;
   }
   else
   {
     upper = m_SeedpointValue - m_LOWERTHRESHOLD;
   }
 
   tempLevelWindow.SetRangeMinMax(mitk::ScalarType(0), mitk::ScalarType(upper));
 
   // get the suggested threshold from the detected leakage-point and adjust the slider
 
   if (m_CurrentRGDirectionIsUpwards)
   {
     this->m_Controls.m_PreviewSlider->setValue(m_SeedpointValue);
     *level = m_UPPERTHRESHOLD - (m_SeedpointValue) + 0.5;
   }
   else
   {
     this->m_Controls.m_PreviewSlider->setValue(m_SeedpointValue);
     *level = (m_SeedpointValue)-m_LOWERTHRESHOLD + 0.5;
   }
 
   tempLevelWindow.SetLevelWindow(*level, *window);
   newNode->SetLevelWindow(tempLevelWindow, nullptr, "levelwindow");
   // update the widgets
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 
   m_SliderInitialized = true;
 
   // inquiry need to fix bug#1828
   static int lastSliderPosition = 0;
   if ((this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1) == lastSliderPosition)
   {
     this->ChangeLevelWindow(lastSliderPosition);
   }
   lastSliderPosition = this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1;
 
   if (m_UseVolumeRendering)
     this->UpdateVolumeRenderingThreshold((int)(*level + 0.5)); // lower threshold for labeled image
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::ChangeLevelWindow(double newValue)
 {
   if (m_SliderInitialized)
   {
     // do nothing, if no preview exists
     mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
     if (newNode.IsNull())
       return;
 
     mitk::LevelWindow tempLevelWindow;
 
     newNode->GetLevelWindow(tempLevelWindow, nullptr, "levelwindow"); // get the levelWindow associated with the preview
 
     mitk::ScalarType level; // = this->m_UPPERTHRESHOLD - newValue + 0.5;
     mitk::ScalarType *window = new mitk::ScalarType(1);
 
     // adjust the levelwindow according to the position of the slider (newvalue)
     if (m_CurrentRGDirectionIsUpwards)
     {
       level = m_UPPERTHRESHOLD - newValue + 0.5;
       tempLevelWindow.SetLevelWindow(level, *window);
     }
     else
     {
       level = newValue - m_LOWERTHRESHOLD + 0.5;
       tempLevelWindow.SetLevelWindow(level, *window);
     }
 
     newNode->SetLevelWindow(tempLevelWindow, nullptr, "levelwindow");
 
     if (m_UseVolumeRendering)
       this->UpdateVolumeRenderingThreshold((int)(level - 0.5)); // lower threshold for labeled image
 
     newNode->SetVisibility(true);
     mitk::RenderingManager::GetInstance()->RequestUpdateAll();
   }
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::DecreaseSlider()
 {
   // moves the slider one step to the left, when the "-"-button is pressed
   if (this->m_Controls.m_PreviewSlider->value() != this->m_Controls.m_PreviewSlider->minimum())
   {
     int newValue = this->m_Controls.m_PreviewSlider->value() - 1;
     this->ChangeLevelWindow(newValue);
     this->m_Controls.m_PreviewSlider->setValue(newValue);
   }
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::IncreaseSlider()
 {
   // moves the slider one step to the right, when the "+"-button is pressed
   if (this->m_Controls.m_PreviewSlider->value() != this->m_Controls.m_PreviewSlider->maximum())
   {
     int newValue = this->m_Controls.m_PreviewSlider->value() + 1;
     this->ChangeLevelWindow(newValue);
     this->m_Controls.m_PreviewSlider->setValue(newValue);
   }
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::ConfirmSegmentation()
 {
   // get image node
   if (m_InputImageNode.IsNull())
   {
     QMessageBox::critical(nullptr, "Adaptive region growing functionality", "Please specify the image in Datamanager!");
     return;
   }
   // get image data
   mitk::Image::Pointer orgImage = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
   if (orgImage.IsNull())
   {
     QMessageBox::critical(nullptr, "Adaptive region growing functionality", "No Image found!");
     return;
   }
   // get labeled segmentation
   mitk::Image::Pointer labeledSeg =
     (mitk::Image *)m_DataStorage->GetNamedObject<mitk::Image>(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
   if (labeledSeg.IsNull())
   {
     QMessageBox::critical(nullptr, "Adaptive region growing functionality", "No Segmentation Preview found!");
     return;
   }
 
   mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
   if (newNode.IsNull())
     return;
 
   QmitkConfirmSegmentationDialog dialog;
   QString segName = QString::fromStdString(m_RegionGrow3DTool->GetCurrentSegmentationName());
 
   dialog.SetSegmentationName(segName);
   int result = dialog.exec();
 
   switch (result)
   {
     case QmitkConfirmSegmentationDialog::CREATE_NEW_SEGMENTATION:
       m_RegionGrow3DTool->SetOverwriteExistingSegmentation(false);
       break;
     case QmitkConfirmSegmentationDialog::OVERWRITE_SEGMENTATION:
       m_RegionGrow3DTool->SetOverwriteExistingSegmentation(true);
       break;
     case QmitkConfirmSegmentationDialog::CANCEL_SEGMENTATION:
       return;
   }
 
   mitk::Image::Pointer img = dynamic_cast<mitk::Image *>(newNode->GetData());
   AccessByItk(img, ITKThresholding);
 
   // disable volume rendering preview after the segmentation node was created
   this->EnableVolumeRendering(false);
   newNode->SetVisibility(false);
   m_Controls.m_cbVolumeRendering->setChecked(false);
   // TODO disable slider etc...
 
   if (m_RegionGrow3DTool.IsNotNull())
   {
     m_RegionGrow3DTool->ConfirmSegmentation();
   }
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void QmitkAdaptiveRegionGrowingToolGUI::ITKThresholding(itk::Image<TPixel, VImageDimension> *itkImage)
 {
   mitk::Image::Pointer originalSegmentation =
     dynamic_cast<mitk::Image *>(this->m_RegionGrow3DTool->GetTargetSegmentationNode()->GetData());
 
   int timeStep =
     mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget0"))->GetTimeStep();
 
   if (originalSegmentation)
   {
     typedef itk::Image<TPixel, VImageDimension> InputImageType;
     typedef itk::Image<mitk::Tool::DefaultSegmentationDataType, VImageDimension> SegmentationType;
 
     // select single 3D volume if we have more than one time step
     typename SegmentationType::Pointer originalSegmentationInITK = SegmentationType::New();
     if (originalSegmentation->GetTimeGeometry()->CountTimeSteps() > 1)
     {
       mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
       timeSelector->SetInput(originalSegmentation);
       timeSelector->SetTimeNr(timeStep);
       timeSelector->UpdateLargestPossibleRegion();
       CastToItkImage(timeSelector->GetOutput(), originalSegmentationInITK);
     }
     else // use original
     {
       CastToItkImage(originalSegmentation, originalSegmentationInITK);
     }
 
     // Fill current preiview image in segmentation image
     originalSegmentationInITK->FillBuffer(0);
     itk::ImageRegionIterator<SegmentationType> itOutput(originalSegmentationInITK,
                                                         originalSegmentationInITK->GetLargestPossibleRegion());
     itk::ImageRegionIterator<InputImageType> itInput(itkImage, itkImage->GetLargestPossibleRegion());
     itOutput.GoToBegin();
     itInput.GoToBegin();
 
     // calculate threhold from slider value
     int currentTreshold = 0;
     if (m_CurrentRGDirectionIsUpwards)
     {
       currentTreshold = m_UPPERTHRESHOLD - m_Controls.m_PreviewSlider->value() + 1;
     }
     else
     {
       currentTreshold = m_Controls.m_PreviewSlider->value() - m_LOWERTHRESHOLD;
     }
 
     // iterate over image and set pixel in segmentation according to thresholded labeled image
     while (!itOutput.IsAtEnd() && !itInput.IsAtEnd())
     {
       // Use threshold slider to determine if pixel is set to 1
       if (itInput.Value() != 0 && itInput.Value() >= static_cast<typename itk::ImageRegionIterator<InputImageType>::PixelType>(currentTreshold))
       {
         itOutput.Set(1);
       }
 
       ++itOutput;
       ++itInput;
     }
 
     // combine current working segmentation image with our region growing result
     originalSegmentation->SetVolume((void *)(originalSegmentationInITK->GetPixelContainer()->GetBufferPointer()),
                                     timeStep);
 
     originalSegmentation->Modified();
     mitk::RenderingManager::GetInstance()->RequestUpdateAll();
   }
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::EnableControls(bool enable)
 {
   if (m_RegionGrow3DTool.IsNull())
     return;
 
   // Check if seed point is already set, if not leave RunSegmentation disabled
   // if even m_DataStorage is nullptr leave node nullptr
   mitk::DataNode::Pointer node = m_RegionGrow3DTool->GetPointSetNode();
   if (node.IsNull())
   {
     this->m_Controls.m_pbRunSegmentation->setEnabled(false);
   }
   else
   {
     this->m_Controls.m_pbRunSegmentation->setEnabled(enable);
   }
 
   // Check if a segmentation exists, if not leave segmentation dependent disabled.
   // if even m_DataStorage is nullptr leave node nullptr
   node = m_DataStorage ? m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE) : nullptr;
   if (node.IsNull())
   {
     this->m_Controls.m_PreviewSlider->setEnabled(false);
     this->m_Controls.m_pbConfirmSegementation->setEnabled(false);
   }
   else
   {
     this->m_Controls.m_PreviewSlider->setEnabled(enable);
     this->m_Controls.m_pbConfirmSegementation->setEnabled(enable);
   }
 
   this->m_Controls.m_cbVolumeRendering->setEnabled(enable);
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::EnableVolumeRendering(bool enable)
 {
   mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION);
 
   if (node.IsNull())
     return;
 
   if (enable)
   {
     node->SetBoolProperty("volumerendering", enable);
     node->SetBoolProperty("volumerendering.uselod", true);
   }
   else
   {
     node->SetBoolProperty("volumerendering", enable);
   }
 
   double val = this->m_Controls.m_PreviewSlider->value();
   this->ChangeLevelWindow(val);
 
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::UpdateVolumeRenderingThreshold(int)
 {
   typedef short PixelType;
   typedef itk::Image<PixelType, 3> InputImageType;
   typedef itk::BinaryThresholdImageFilter<InputImageType, InputImageType> ThresholdFilterType;
   typedef itk::MaskImageFilter<InputImageType, InputImageType, InputImageType> MaskImageFilterType;
 
   mitk::DataNode::Pointer grownImageNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
   mitk::Image::Pointer grownImage = dynamic_cast<mitk::Image *>(grownImageNode->GetData());
 
   if (!grownImage)
   {
     MITK_ERROR << "Missing data node for labeled segmentation image.";
     return;
   }
 
   InputImageType::Pointer itkGrownImage;
   mitk::CastToItkImage(grownImage, itkGrownImage);
 
   ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New();
   thresholdFilter->SetInput(itkGrownImage);
   thresholdFilter->SetInPlace(false);
 
   double sliderVal = this->m_Controls.m_PreviewSlider->value();
   PixelType threshold = itk::NumericTraits<PixelType>::min();
   if (m_CurrentRGDirectionIsUpwards)
   {
     threshold = static_cast<PixelType>(m_UPPERTHRESHOLD - sliderVal + 0.5);
 
     thresholdFilter->SetLowerThreshold(threshold);
     thresholdFilter->SetUpperThreshold(itk::NumericTraits<PixelType>::max());
   }
   else
   {
     threshold = sliderVal - m_LOWERTHRESHOLD + 0.5;
 
     thresholdFilter->SetLowerThreshold(itk::NumericTraits<PixelType>::min());
     thresholdFilter->SetUpperThreshold(threshold);
   }
   thresholdFilter->UpdateLargestPossibleRegion();
 
   MaskImageFilterType::Pointer maskFilter = MaskImageFilterType::New();
   maskFilter->SetInput(itkGrownImage);
   maskFilter->SetInPlace(false);
   maskFilter->SetMaskImage(thresholdFilter->GetOutput());
   maskFilter->SetOutsideValue(0);
   maskFilter->UpdateLargestPossibleRegion();
 
   mitk::Image::Pointer mitkMaskedImage;
   mitk::CastToMitkImage<InputImageType>(maskFilter->GetOutput(), mitkMaskedImage);
   mitk::DataNode::Pointer maskNode = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION);
   maskNode->SetData(mitkMaskedImage);
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::UseVolumeRendering(bool on)
 {
   m_UseVolumeRendering = on;
 
   this->EnableVolumeRendering(on);
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::SetLowerThresholdValue(double lowerThreshold)
 {
   m_LOWERTHRESHOLD = lowerThreshold;
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::SetUpperThresholdValue(double upperThreshold)
 {
   m_UPPERTHRESHOLD = upperThreshold;
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::Deactivated()
 {
   // make the segmentation preview node invisible
   mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
   if (node.IsNotNull())
   {
     node->SetVisibility(false);
   }
 
   // disable volume rendering preview after the segmentation node was created
   this->EnableVolumeRendering(false);
   m_Controls.m_cbVolumeRendering->setChecked(false);
 }
 
 void QmitkAdaptiveRegionGrowingToolGUI::Activated()
 {
 }
diff --git a/Modules/TubeGraph/include/mitkTubeGraphIO.h b/Modules/TubeGraph/include/mitkTubeGraphIO.h
index 0124cbcd3b..b4a0b0afea 100644
--- a/Modules/TubeGraph/include/mitkTubeGraphIO.h
+++ b/Modules/TubeGraph/include/mitkTubeGraphIO.h
@@ -1,69 +1,71 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef _MITK_TUBE_GRAPH_IO_H_
 #define _MITK_TUBE_GRAPH_IO_H_
 
 #include <mitkAbstractFileIO.h>
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 
 #include "mitkTubeGraph.h"
 
 class TiXmlElement;
 
 namespace mitk
 {
   /**
   * @brief reader and writer for xml representations of mitk::TubeGraph
   *
   * @ingroup IO
   */
   class TubeGraphIO : public mitk::AbstractFileIO
   {
   public:
     TubeGraphIO();
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
-    std::vector<BaseData::Pointer> Read() override;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
     ConfidenceLevel GetWriterConfidenceLevel() const override;
 
     static CustomMimeType TUBEGRAPH_MIMETYPE() // tsf
     {
       CustomMimeType mimeType(TUBEGRAPH_MIMETYPE_NAME());
       mimeType.AddExtension("tsf");
       mimeType.SetCategory("Graphs");
       mimeType.SetComment("MITK Tube Graph Structure File");
       return mimeType;
     }
     static std::string TUBEGRAPH_MIMETYPE_NAME()
     {
       static std::string name = mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".graphs.tubular-sructure";
       return name;
     }
 
+  protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
   private:
     TubeGraphIO *IOClone() const override;
     TubeGraphIO(const TubeGraphIO &other);
     const BoundingBox::Pointer ComputeBoundingBox(TubeGraph::Pointer graph) const;
   };
 }
 
 #endif //_MITK_SURFACE_VTK_IO_H_
diff --git a/Modules/TubeGraph/src/IO/mitkTubeGraphIO.cpp b/Modules/TubeGraph/src/IO/mitkTubeGraphIO.cpp
index c313192ff3..9d764365d5 100644
--- a/Modules/TubeGraph/src/IO/mitkTubeGraphIO.cpp
+++ b/Modules/TubeGraph/src/IO/mitkTubeGraphIO.cpp
@@ -1,593 +1,593 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkTubeGraphIO.h"
 
 #include "mitkCircularProfileTubeElement.h"
 #include "mitkTubeGraphDefinitions.h"
 #include "mitkTubeGraphProperty.h"
 
 #include <mitkIOMimeTypes.h>
 
 #include <tinyxml.h>
 
 #include <vtkMatrix4x4.h>
 
 #include <itksys/SystemTools.hxx>
 
 namespace mitk
 {
   TubeGraphIO::TubeGraphIO(const TubeGraphIO &other) : AbstractFileIO(other) {}
   TubeGraphIO::TubeGraphIO()
     : AbstractFileIO(
         mitk::TubeGraph::GetStaticNameOfClass(), mitk::TubeGraphIO::TUBEGRAPH_MIMETYPE(), "Tube Graph Structure File")
   {
     this->RegisterService();
   }
 
-  std::vector<BaseData::Pointer> TubeGraphIO::Read()
+  std::vector<BaseData::Pointer> TubeGraphIO::DoRead()
   {
     std::locale::global(std::locale("C"));
 
     std::vector<itk::SmartPointer<mitk::BaseData>> result;
 
     InputStream stream(this);
 
     TiXmlDocument doc;
     stream >> doc;
     if (!doc.Error())
     {
       TubeGraph::Pointer newTubeGraph = TubeGraph::New();
 
       TiXmlHandle hDoc(&doc);
       TiXmlElement *pElem;
       TiXmlHandle hRoot(nullptr);
 
       pElem = hDoc.FirstChildElement().Element();
 
       // save this for later
       hRoot = TiXmlHandle(pElem);
 
       pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_GEOMETRY).Element();
 
       // read geometry
       mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
       geometry->Initialize();
 
       // read origin
       mitk::Point3D origin;
       double temp = 0;
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_ORIGIN_X, &temp);
       origin[0] = temp;
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_ORIGIN_Y, &temp);
       origin[1] = temp;
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_ORIGIN_Z, &temp);
       origin[2] = temp;
       geometry->SetOrigin(origin);
 
       // read spacing
       Vector3D spacing;
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_SPACING_X, &temp);
       spacing.SetElement(0, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_SPACING_Y, &temp);
       spacing.SetElement(1, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_SPACING_Z, &temp);
       spacing.SetElement(2, temp);
       geometry->SetSpacing(spacing);
 
       // read transform
       vtkMatrix4x4 *m = vtkMatrix4x4::New();
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_XX, &temp);
       m->SetElement(0, 0, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_XY, &temp);
       m->SetElement(1, 0, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_XZ, &temp);
       m->SetElement(2, 0, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_YX, &temp);
       m->SetElement(0, 1, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_YY, &temp);
       m->SetElement(1, 1, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_YZ, &temp);
       m->SetElement(2, 1, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZX, &temp);
       m->SetElement(0, 2, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZY, &temp);
       m->SetElement(1, 2, temp);
       pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZZ, &temp);
       m->SetElement(2, 2, temp);
 
       m->SetElement(0, 3, origin[0]);
       m->SetElement(1, 3, origin[1]);
       m->SetElement(2, 3, origin[2]);
       m->SetElement(3, 3, 1);
       geometry->SetIndexToWorldTransformByVtkMatrix(m);
 
       geometry->SetImageGeometry(false);
 
       // read tube graph
 
       // read vertices
       pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_VERTICES).Element();
       if (pElem != nullptr)
       {
         // walk through the vertices
         for (TiXmlElement *vertexElement = pElem->FirstChildElement(); vertexElement != nullptr; vertexElement = vertexElement->NextSiblingElement())
         {
           int vertexID(0);
           mitk::Point3D coordinate;
           coordinate.Fill(0.0);
           double diameter(0);
 
           vertexElement->Attribute(mitk::TubeGraphDefinitions::XML_VERTEX_ID, &vertexID);
 
           TiXmlElement *tubeElement = vertexElement->FirstChildElement();
 
           tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_X, &temp);
           coordinate[0] = temp;
           tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Y, &temp);
           coordinate[1] = temp;
           tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Z, &temp);
           coordinate[2] = temp;
           tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, &diameter);
 
           mitk::TubeGraphVertex vertexData;
           auto *newElement = new mitk::CircularProfileTubeElement(coordinate, diameter);
           vertexData.SetTubeElement(newElement);
 
           mitk::TubeGraph::VertexDescriptorType newVertex = newTubeGraph->AddVertex(vertexData);
           if (static_cast<int>(newVertex) != vertexID)
           {
             MITK_ERROR << "Aborting tube graph creation, different vertex ids.";
             return result;
             ;
           }
         }
       }
 
       // read edges
       pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_EDGES).Element();
       if (pElem != nullptr)
       {
         // walk through the edges
         auto edgeElement = pElem->FirstChildElement();
         for ( ; edgeElement != nullptr; edgeElement = edgeElement->NextSiblingElement())
         {
           int edgeID(0), edgeSourceID(0), edgeTargetID(0);
           mitk::Point3D coordinate;
           double diameter(0);
 
           edgeElement->Attribute(mitk::TubeGraphDefinitions::XML_EDGE_ID, &edgeID);
           edgeElement->Attribute(mitk::TubeGraphDefinitions::XML_EDGE_SOURCE_ID, &edgeSourceID);
           edgeElement->Attribute(mitk::TubeGraphDefinitions::XML_EDGE_TARGET_ID, &edgeTargetID);
 
           mitk::TubeGraphEdge edgeData;
 
           for (TiXmlElement *tubeElement = edgeElement->FirstChildElement(mitk::TubeGraphDefinitions::XML_ELEMENT); tubeElement != nullptr; tubeElement = tubeElement->NextSiblingElement())
           {
             tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_X, &temp);
             coordinate[0] = temp;
             tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Y, &temp);
             coordinate[1] = temp;
             tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Z, &temp);
             coordinate[2] = temp;
             tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, &diameter);
 
             auto *newElement = new mitk::CircularProfileTubeElement(coordinate, diameter);
 
             edgeData.AddTubeElement(newElement);
           }
           try
           {
             newTubeGraph->AddEdge(edgeSourceID, edgeTargetID, edgeData);
           }
           catch (const std::runtime_error &error)
           {
             MITK_ERROR << error.what();
             return result;
           }
         }
       }
 
       // Compute bounding box
       BoundingBox::Pointer bb = this->ComputeBoundingBox(newTubeGraph);
       geometry->SetBounds(bb->GetBounds());
 
       MITK_INFO << "Tube Graph read";
       MITK_INFO << "Edge numb:" << newTubeGraph->GetNumberOfEdges()
                 << " Vertices: " << newTubeGraph->GetNumberOfVertices();
 
       MITK_INFO << "Reading tube graph property";
       mitk::TubeGraphProperty::Pointer newProperty = mitk::TubeGraphProperty::New();
 
       // read label groups
       pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_LABELGROUPS).Element();
       if (pElem != nullptr)
       {
         // walk through the label groups
         for (TiXmlElement *labelGroupElement = pElem->FirstChildElement(); labelGroupElement != nullptr; labelGroupElement = labelGroupElement->NextSiblingElement())
         {
           auto *newLabelGroup = new mitk::TubeGraphProperty::LabelGroup();
           const char *labelGroupName;
 
           labelGroupName =
             labelGroupElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_LABELGROUP_NAME.c_str());
           if (labelGroupName)
             newLabelGroup->labelGroupName = labelGroupName;
 
           for (TiXmlElement *labelElement = labelGroupElement->FirstChildElement(mitk::TubeGraphDefinitions::XML_LABEL); labelElement != nullptr; labelElement = labelElement->NextSiblingElement())
           {
             auto *newLabel = new mitk::TubeGraphProperty::LabelGroup::Label();
             const char *labelName;
             bool isVisible = true;
             Color color;
 
             labelName = labelElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_LABEL_NAME.c_str());
             if (labelName)
               newLabel->labelName = labelName;
 
             labelElement->Attribute(mitk::TubeGraphDefinitions::XML_LABEL_VISIBILITY, &temp);
             if (temp == 0)
               isVisible = false;
             else
               isVisible = true;
             labelElement->Attribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_R, &temp);
             color[0] = temp;
             labelElement->Attribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_G, &temp);
             color[1] = temp;
             labelElement->Attribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_B, &temp);
             color[2] = temp;
 
             newLabel->isVisible = isVisible;
             newLabel->labelColor = color;
             newLabelGroup->labels.push_back(newLabel);
           }
           newProperty->AddLabelGroup(newLabelGroup, newProperty->GetLabelGroups().size());
         }
       }
       // read attributations
       pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_ATTRIBUTIONS).Element();
       if (pElem != nullptr)
       {
         std::map<TubeGraphProperty::TubeToLabelGroupType, std::string> tubeToLabelsMap;
         for (TiXmlElement *tubeToLabelElement = pElem->FirstChildElement(); tubeToLabelElement != nullptr; tubeToLabelElement = tubeToLabelElement->NextSiblingElement())
         {
           TubeGraph::TubeDescriptorType tube;
           auto *labelGroup = new mitk::TubeGraphProperty::LabelGroup();
           auto *label = new mitk::TubeGraphProperty::LabelGroup::Label();
 
           tubeToLabelElement->Attribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_1, &temp);
           tube.first = temp;
           tubeToLabelElement->Attribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_2, &temp);
           tube.second = temp;
           const char *labelGroupName =
             tubeToLabelElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_LABELGROUP_NAME.c_str());
           if (labelGroupName)
             labelGroup = newProperty->GetLabelGroupByName(labelGroupName);
 
           const char *labelName =
             tubeToLabelElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_LABEL_NAME.c_str());
           if (labelName)
             label = newProperty->GetLabelByName(labelGroup, labelName);
 
           if (tube != TubeGraph::ErrorId && labelGroup != nullptr && label != nullptr)
           {
             TubeGraphProperty::TubeToLabelGroupType tubeToLabelGroup(tube, labelGroupName);
             tubeToLabelsMap.insert(
               std::pair<TubeGraphProperty::TubeToLabelGroupType, std::string>(tubeToLabelGroup, labelName));
           }
         }
         if (tubeToLabelsMap.size() > 0)
           newProperty->SetTubesToLabels(tubeToLabelsMap);
       }
       // read annotations
       pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_ANNOTATIONS).Element();
       if (pElem != nullptr)
       {
         for (TiXmlElement *annotationElement = pElem->FirstChildElement(); annotationElement != nullptr; annotationElement = annotationElement->NextSiblingElement())
         {
           auto *annotation = new mitk::TubeGraphProperty::Annotation();
           std::string annotationName;
           std::string annotationDescription;
           TubeGraph::TubeDescriptorType tube;
 
           annotationName =
             annotationElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_ANNOTATION_NAME.c_str());
           annotation->name = annotationName;
 
           annotationDescription =
             annotationElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_ANNOTATION_DESCRIPTION.c_str());
           annotation->description = annotationDescription;
 
           annotationElement->Attribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_1, &temp);
           tube.first = temp;
           annotationElement->Attribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_2, &temp);
           tube.second = temp;
 
           if (tube != TubeGraph::ErrorId)
           {
             annotation->tube = tube;
             newProperty->AddAnnotation(annotation);
           }
         }
       }
 
       MITK_INFO << "Tube Graph Property read";
 
       newTubeGraph->SetGeometry(geometry);
       newTubeGraph->SetProperty("Tube Graph.Visualization Information", newProperty);
       result.push_back(newTubeGraph.GetPointer());
     }
 
     else
     {
       mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": "
                   << doc.ErrorDesc();
     }
     return result;
   }
 
   AbstractFileIO::ConfidenceLevel TubeGraphIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
     return Supported;
   }
 
   void TubeGraphIO::Write()
   {
     OutputStream out(this);
 
     if (!out.good())
     {
       mitkThrow() << "Stream not good.";
     }
 
     std::locale previousLocale(out.getloc());
     std::locale I("C");
     out.imbue(I);
 
     const auto *tubeGraph = dynamic_cast<const mitk::TubeGraph *>(this->GetInput());
     // Get geometry of the tube graph
     mitk::Geometry3D::Pointer geometry = dynamic_cast<mitk::Geometry3D *>(tubeGraph->GetGeometry());
     // Get property of the tube graph
     mitk::TubeGraphProperty::Pointer tubeGraphProperty = dynamic_cast<mitk::TubeGraphProperty *>(
       tubeGraph->GetProperty("Tube Graph.Visualization Information").GetPointer());
     // Create XML document
     TiXmlDocument documentXML;
     { // Begin document
       auto *declXML = new TiXmlDeclaration("1.0", "", "");
       documentXML.LinkEndChild(declXML);
 
       auto *mainXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_TUBEGRAPH_FILE);
       mainXML->SetAttribute(mitk::TubeGraphDefinitions::XML_FILE_VERSION, mitk::TubeGraphDefinitions::VERSION_STRING);
       documentXML.LinkEndChild(mainXML);
 
       auto *geometryXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_GEOMETRY);
       { // begin geometry
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_XX, geometry->GetMatrixColumn(0)[0]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_XY, geometry->GetMatrixColumn(0)[1]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_XZ, geometry->GetMatrixColumn(0)[2]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_YX, geometry->GetMatrixColumn(1)[0]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_YY, geometry->GetMatrixColumn(1)[1]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_YZ, geometry->GetMatrixColumn(1)[2]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZX, geometry->GetMatrixColumn(2)[0]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZY, geometry->GetMatrixColumn(2)[1]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZZ, geometry->GetMatrixColumn(2)[2]);
 
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ORIGIN_X, geometry->GetOrigin()[0]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ORIGIN_Y, geometry->GetOrigin()[1]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ORIGIN_Z, geometry->GetOrigin()[2]);
 
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_SPACING_X, geometry->GetSpacing()[0]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_SPACING_Y, geometry->GetSpacing()[1]);
         geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_SPACING_Z, geometry->GetSpacing()[2]);
 
       } // end geometry
       mainXML->LinkEndChild(geometryXML);
 
       auto *verticesXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_VERTICES);
       { // begin vertices section
         std::vector<mitk::TubeGraphVertex> vertexVector = tubeGraph->GetVectorOfAllVertices();
         for (unsigned int index = 0; index < vertexVector.size(); index++)
         {
           auto *vertexXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_VERTEX);
           vertexXML->SetAttribute(mitk::TubeGraphDefinitions::XML_VERTEX_ID,
                                   tubeGraph->GetVertexDescriptor(vertexVector[index]));
           // element of each vertex
           const mitk::TubeElement *element = vertexVector[index].GetTubeElement();
           auto *elementXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ELEMENT);
           elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_X,
                                          element->GetCoordinates().GetElement(0));
           elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Y,
                                          element->GetCoordinates().GetElement(1));
           elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Z,
                                          element->GetCoordinates().GetElement(2));
           if (dynamic_cast<const mitk::CircularProfileTubeElement *>(element))
             elementXML->SetDoubleAttribute(
               mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER,
               (dynamic_cast<const mitk::CircularProfileTubeElement *>(element))->GetDiameter());
           else
             elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, 2);
 
           vertexXML->LinkEndChild(elementXML);
 
           verticesXML->LinkEndChild(vertexXML);
         }
       } // end vertices section
       mainXML->LinkEndChild(verticesXML);
 
       auto *edgesXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_EDGES);
       { // begin edges section
         std::vector<mitk::TubeGraphEdge> edgeVector = tubeGraph->GetVectorOfAllEdges();
         for (unsigned int index = 0; index < edgeVector.size(); index++)
         {
           auto *edgeXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_EDGE);
           edgeXML->SetAttribute(mitk::TubeGraphDefinitions::XML_EDGE_ID, index);
           std::pair<mitk::TubeGraphVertex, mitk::TubeGraphVertex> soureTargetPair =
             tubeGraph->GetVerticesOfAnEdge(tubeGraph->GetEdgeDescriptor(edgeVector[index]));
           edgeXML->SetAttribute(mitk::TubeGraphDefinitions::XML_EDGE_SOURCE_ID,
                                 tubeGraph->GetVertexDescriptor(soureTargetPair.first));
           edgeXML->SetAttribute(mitk::TubeGraphDefinitions::XML_EDGE_TARGET_ID,
                                 tubeGraph->GetVertexDescriptor(soureTargetPair.second));
 
           // begin elements of the edge
           std::vector<mitk::TubeElement *> elementVector = edgeVector[index].GetElementVector();
           for (unsigned int elementIndex = 0; elementIndex < elementVector.size(); elementIndex++)
           {
             auto *elementXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ELEMENT);
             elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_X,
                                            elementVector[elementIndex]->GetCoordinates().GetElement(0));
             elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Y,
                                            elementVector[elementIndex]->GetCoordinates().GetElement(1));
             elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Z,
                                            elementVector[elementIndex]->GetCoordinates().GetElement(2));
             if (dynamic_cast<const mitk::CircularProfileTubeElement *>(elementVector[elementIndex]))
               elementXML->SetDoubleAttribute(
                 mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER,
                 (dynamic_cast<const mitk::CircularProfileTubeElement *>(elementVector[elementIndex]))->GetDiameter());
             else
               elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, 2);
             edgeXML->LinkEndChild(elementXML);
             // elementsXML->LinkEndChild(elementXML);
           }
           edgesXML->LinkEndChild(edgeXML);
         }
       } // end edges section
       mainXML->LinkEndChild(edgesXML);
 
       auto *labelGroupsXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_LABELGROUPS);
       { // begin label group  section
         std::vector<TubeGraphProperty::LabelGroup *> labelGroupVector = tubeGraphProperty->GetLabelGroups();
         for (unsigned int index = 0; index < labelGroupVector.size(); index++)
         {
           auto *labelGroupXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_LABELGROUP);
           labelGroupXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABELGROUP_NAME,
                                       labelGroupVector[index]->labelGroupName);
           // begin labels of the label group
           std::vector<TubeGraphProperty::LabelGroup::Label *> labelVector = labelGroupVector[index]->labels;
           for (unsigned int labelIndex = 0; labelIndex < labelVector.size(); labelIndex++)
           {
             auto *labelXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_LABEL);
             labelXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABEL_NAME, labelVector[labelIndex]->labelName);
             labelXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABEL_VISIBILITY,
                                    labelVector[labelIndex]->isVisible);
             labelXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_R,
                                          labelVector[labelIndex]->labelColor[0]);
             labelXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_G,
                                          labelVector[labelIndex]->labelColor[1]);
             labelXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_B,
                                          labelVector[labelIndex]->labelColor[2]);
             labelGroupXML->LinkEndChild(labelXML);
           }
           labelGroupsXML->LinkEndChild(labelGroupXML);
         }
       } // end labe group section
       mainXML->LinkEndChild(labelGroupsXML);
 
       auto *attributionsXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ATTRIBUTIONS);
       { // begin attributions section
         std::map<mitk::TubeGraphProperty::TubeToLabelGroupType, std::string> tubeToLabelGroup =
           tubeGraphProperty->GetTubesToLabels();
         for (auto it =
                tubeToLabelGroup.begin();
              it != tubeToLabelGroup.end();
              it++)
         {
           auto *attributXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ATTRIBUTION);
           attributXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_1, it->first.first.first);
           attributXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_2, it->first.first.second);
           attributXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABELGROUP_NAME, it->first.second);
           attributXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABEL_NAME, it->second);
           attributionsXML->LinkEndChild(attributXML);
         }
 
       } // end attributions section
       mainXML->LinkEndChild(attributionsXML);
 
       auto *annotationsXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ANNOTATIONS);
       { // begin annotations section
         std::vector<mitk::TubeGraphProperty::Annotation *> annotations = tubeGraphProperty->GetAnnotations();
         for (unsigned int index = 0; index < annotations.size(); index++)
         {
           auto *annotationXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ANNOTATION);
           annotationXML->SetAttribute(mitk::TubeGraphDefinitions::XML_ANNOTATION_NAME, annotations[index]->name);
           annotationXML->SetAttribute(mitk::TubeGraphDefinitions::XML_ANNOTATION_DESCRIPTION,
                                       annotations[index]->description);
           annotationXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_1, annotations[index]->tube.first);
           annotationXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_2, annotations[index]->tube.second);
 
           annotationsXML->LinkEndChild(annotationXML);
         }
       } // end annotations section
       mainXML->LinkEndChild(annotationsXML);
     } // end document
 
     TiXmlPrinter printer;
     printer.SetStreamPrinting();
     documentXML.Accept(&printer);
     out << printer.Str();
   }
 
   AbstractFileIO::ConfidenceLevel TubeGraphIO::GetWriterConfidenceLevel() const
   {
     if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
       return Unsupported;
     return Supported;
   }
 
   TubeGraphIO *TubeGraphIO::IOClone() const { return new TubeGraphIO(*this); }
 }
 
 const mitk::BoundingBox::Pointer mitk::TubeGraphIO::ComputeBoundingBox(mitk::TubeGraph::Pointer graph) const
 {
   BoundingBox::Pointer boundingBox = BoundingBox::New();
   BoundingBox::PointIdentifier pointid = 0;
   BoundingBox::PointsContainer::Pointer pointscontainer = BoundingBox::PointsContainer::New();
 
   ScalarType nullpoint[] = {0, 0, 0};
   BoundingBox::PointType p(nullpoint);
 
   // traverse the tree and add each point to the pointscontainer
 
   mitk::Point3D pos;
 
   std::vector<mitk::TubeGraphVertex> vertexVector = graph->GetVectorOfAllVertices();
   for (auto vertex = vertexVector.begin(); vertex != vertexVector.end();
        ++vertex)
   {
     pos = vertex->GetTubeElement()->GetCoordinates();
     p[0] = pos[0];
     p[1] = pos[1];
     p[2] = pos[2];
     pointscontainer->InsertElement(pointid++, p);
   }
 
   std::vector<mitk::TubeGraphEdge> edgeVector = graph->GetVectorOfAllEdges();
 
   for (auto edge = edgeVector.begin(); edge != edgeVector.end(); ++edge)
   {
     std::vector<mitk::TubeElement *> allElements = edge->GetElementVector();
     for (unsigned int index = 0; index < edge->GetNumberOfElements(); index++)
     {
       pos = allElements[index]->GetCoordinates();
       p[0] = pos[0];
       p[1] = pos[1];
       p[2] = pos[2];
       pointscontainer->InsertElement(pointid++, p);
     }
   }
 
   boundingBox->SetPoints(pointscontainer);
   boundingBox->ComputeBoundingBox();
 
   return boundingBox;
 }
diff --git a/Modules/US/CMakeLists.txt b/Modules/US/CMakeLists.txt
index 5add219afe..d45cfcac5f 100644
--- a/Modules/US/CMakeLists.txt
+++ b/Modules/US/CMakeLists.txt
@@ -1,16 +1,16 @@
 MITK_CREATE_MODULE(
   SUBPROJECTS
   INCLUDE_DIRS USControlInterfaces USFilters USModel
   INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL}
-  PACKAGE_DEPENDS Poco
+  PACKAGE_DEPENDS Poco PRIVATE tinyxml
   DEPENDS MitkOpenCVVideoSupport MitkQtWidgetsExt MitkIGTBase MitkOpenIGTLink
 )
 
 ## create US config
 #CONFIGURE_FILE(mitkUSConfig.h.in ${PROJECT_BINARY_DIR}/mitkUSConfig.h @ONLY)
 
 ADD_SUBDIRECTORY(USHardwareTelemed)
 ADD_SUBDIRECTORY(USHardwareDiPhAS)
 ADD_SUBDIRECTORY(USNavigation)
 
 ADD_SUBDIRECTORY(Testing)
diff --git a/Modules/US/USModel/mitkUSDeviceReaderXML.cpp b/Modules/US/USModel/mitkUSDeviceReaderXML.cpp
index 4295678f0e..250b7af835 100644
--- a/Modules/US/USModel/mitkUSDeviceReaderXML.cpp
+++ b/Modules/US/USModel/mitkUSDeviceReaderXML.cpp
@@ -1,204 +1,204 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkUSDeviceReaderWriterConstants.h"
 #include "mitkUSDeviceReaderXML.h"
 #include <mitkIGTMimeTypes.h>
 #include <mitkLocaleSwitch.h>
 
 #include <mitkUSVideoDevice.h>
 
 // Third Party
 #include <itksys/SystemTools.hxx>
 #include <fstream>
 #include <tinyxml.h>
 
 mitk::USDeviceReaderXML::USDeviceReaderXML() : AbstractFileReader(
   mitk::IGTMimeTypes::USDEVICEINFORMATIONXML_MIMETYPE(),
   "MITK USDevice Reader (XML)"), m_Filename("")
 {
   RegisterService();
 }
 
 mitk::USDeviceReaderXML::~USDeviceReaderXML()
 {
 }
 
 mitk::USDeviceReaderXML::USDeviceConfigData &mitk::USDeviceReaderXML::GetUSDeviceConfigData()
 {
   return m_DeviceConfig;
 }
 
 mitk::USDeviceReaderXML::USDeviceReaderXML(const mitk::USDeviceReaderXML& other) : AbstractFileReader(other)
 {
 }
 
 mitk::USDeviceReaderXML* mitk::USDeviceReaderXML::Clone() const
 {
   return new USDeviceReaderXML(*this);
 }
 
 
 
 
-std::vector<itk::SmartPointer<mitk::BaseData>> mitk::USDeviceReaderXML::Read()
+std::vector<itk::SmartPointer<mitk::BaseData>> mitk::USDeviceReaderXML::DoRead()
 {
   MITK_WARN << "This method is not implemented. \
   Please use the method ReadUltrasoundDeviceConfiguration() instead.";
   std::vector<mitk::BaseData::Pointer> result;
   return result;
 }
 
 bool mitk::USDeviceReaderXML::ReadUltrasoundDeviceConfiguration()
 {
   MITK_INFO << "Try to start reading xml device configuration...";
   if (m_Filename == "")
   {
     MITK_WARN << "Cannot read file - empty filename!";
     return false;
   }
 
   TiXmlDocument document(m_Filename);
   if (!document.LoadFile())
   {
     MITK_ERROR << "Error when opening and reading file :" << m_Filename;
     return false;
   }
 
   TiXmlHandle documentHandle(&document);
   TiXmlElement* ultrasoundDeviceTag = documentHandle.FirstChildElement(TAG_ULTRASOUNDDEVICE).ToElement();
   if (ultrasoundDeviceTag == nullptr)
   {
     MITK_ERROR << "Error parsing the file :" << m_Filename << std::endl << "Wrong xml format structure.";
     return false;
   }
 
   //Extract attribute information of the ULTRASOUNDDEVICE-Tag:
   this->ExtractAttributeInformationOfUltrasoundDeviceTag(ultrasoundDeviceTag);
 
   TiXmlElement* generalSettingsTag = documentHandle.FirstChildElement(TAG_ULTRASOUNDDEVICE).FirstChildElement(TAG_GENERALSETTINGS).ToElement();
   if (generalSettingsTag == nullptr)
   {
     MITK_ERROR << "Error parsing the GENERALSETTINGS-Tag in the file :" << m_Filename;
     return false;
   }
 
   //Extract attribute information of the GENERALSETTINGS-Tag:
   this->ExtractAttributeInformationOfGeneralSettingsTag(generalSettingsTag);
 
   TiXmlElement* probesTag = documentHandle.FirstChildElement(TAG_ULTRASOUNDDEVICE).FirstChildElement(TAG_PROBES).ToElement();
   if (probesTag == nullptr)
   {
     MITK_ERROR << "Error: PROBES-Tag was not found in the file :" << m_Filename << "Therefore, creating default probe.";
     //Create default ultrasound probe:
     mitk::USProbe::Pointer ultrasoundProbeDefault = mitk::USProbe::New();
     ultrasoundProbeDefault->SetName("default");
     ultrasoundProbeDefault->SetDepth(0);
     m_DeviceConfig.probes.push_back(ultrasoundProbeDefault);
     return true;
   }
 
   //Extract all saved and configured probes of the USDevice:
   for (TiXmlElement* probeTag = probesTag->FirstChildElement(TAG_PROBE);
     probeTag != nullptr; probeTag = probeTag->NextSiblingElement())
   {
     this->ExtractProbe(probeTag);
   }
   return true;
 }
 
 void mitk::USDeviceReaderXML::SetFilename(std::string filename)
 {
   m_Filename = filename;
 }
 
 void mitk::USDeviceReaderXML::ExtractAttributeInformationOfUltrasoundDeviceTag(TiXmlElement *ultrasoundTag)
 {
   ultrasoundTag->QueryDoubleAttribute(ATTR_FILEVERS, &m_DeviceConfig.fileversion);
   ultrasoundTag->QueryStringAttribute(ATTR_TYPE, &m_DeviceConfig.deviceType);
   ultrasoundTag->QueryStringAttribute(ATTR_NAME, &m_DeviceConfig.deviceName);
   ultrasoundTag->QueryStringAttribute(ATTR_MANUFACTURER, &m_DeviceConfig.manufacturer);
   ultrasoundTag->QueryStringAttribute(ATTR_MODEL, &m_DeviceConfig.model);
   ultrasoundTag->QueryStringAttribute(ATTR_COMMENT, &m_DeviceConfig.comment);
   ultrasoundTag->QueryIntAttribute(ATTR_IMAGESTREAMS, &m_DeviceConfig.numberOfImageStreams);
   ultrasoundTag->QueryStringAttribute(ATTR_HOST, &m_DeviceConfig.host);
   ultrasoundTag->QueryIntAttribute(ATTR_PORT, &m_DeviceConfig.port);
   ultrasoundTag->QueryBoolAttribute(ATTR_SERVER, &m_DeviceConfig.server);
 }
 
 void mitk::USDeviceReaderXML::ExtractAttributeInformationOfGeneralSettingsTag(TiXmlElement *generalSettingsTag)
 {
   generalSettingsTag->QueryBoolAttribute(ATTR_GREYSCALE, &m_DeviceConfig.useGreyscale);
   generalSettingsTag->QueryBoolAttribute(ATTR_RESOLUTIONOVERRIDE, &m_DeviceConfig.useResolutionOverride);
   generalSettingsTag->QueryIntAttribute(ATTR_RESOLUTIONHEIGHT, &m_DeviceConfig.resolutionHeight);
   generalSettingsTag->QueryIntAttribute(ATTR_RESOLUTIONWIDTH, &m_DeviceConfig.resolutionWidth);
   generalSettingsTag->QueryIntAttribute(ATTR_SOURCEID, &m_DeviceConfig.sourceID);
   generalSettingsTag->QueryStringAttribute(ATTR_FILEPATH, &m_DeviceConfig.filepathVideoSource);
   generalSettingsTag->QueryIntAttribute(ATTR_OPENCVPORT, &m_DeviceConfig.opencvPort);
 }
 
 void mitk::USDeviceReaderXML::ExtractProbe(TiXmlElement *probeTag)
 {
   mitk::USProbe::Pointer ultrasoundProbe = mitk::USProbe::New();
   std::string probeName;
   probeTag->QueryStringAttribute(ATTR_NAME, &probeName);
   ultrasoundProbe->SetName(probeName);
 
   TiXmlElement* depthsTag = probeTag->FirstChildElement(TAG_DEPTHS);
   if (depthsTag != nullptr)
   {
     for (TiXmlElement* depthTag = depthsTag->FirstChildElement(TAG_DEPTH);
       depthTag != nullptr; depthTag = depthTag->NextSiblingElement())
     {
       int depth = 0;
       mitk::Vector3D spacing;
       spacing[0] = 1;
       spacing[1] = 1;
       spacing[2] = 1;
 
       depthTag->QueryIntAttribute(ATTR_DEPTH, &depth);
 
       TiXmlElement* spacingTag = depthTag->FirstChildElement(TAG_SPACING);
       if (spacingTag != nullptr)
       {
         spacingTag->QueryDoubleAttribute(ATTR_X, &spacing[0]);
         spacingTag->QueryDoubleAttribute(ATTR_Y, &spacing[1]);
       }
 
       ultrasoundProbe->SetDepthAndSpacing(depth, spacing);
     }
   }
   else
   {
     MITK_ERROR << "Error: DEPTHS-Tag was not found in the file :" << m_Filename
       << "Therefore, creating default depth [0] and spacing [1,1,1] for the probe.";
     ultrasoundProbe->SetDepth(0);
   }
 
   unsigned int croppingTop = 0;
   unsigned int croppingBottom = 0;
   unsigned int croppingLeft = 0;
   unsigned int croppingRight = 0;
 
   TiXmlElement* croppingTag = probeTag->FirstChildElement(TAG_CROPPING);
   if (croppingTag != nullptr)
   {
     croppingTag->QueryUnsignedAttribute(ATTR_TOP, &croppingTop);
     croppingTag->QueryUnsignedAttribute(ATTR_BOTTOM, &croppingBottom);
     croppingTag->QueryUnsignedAttribute(ATTR_LEFT, &croppingLeft);
     croppingTag->QueryUnsignedAttribute(ATTR_RIGHT, &croppingRight);
   }
 
   ultrasoundProbe->SetProbeCropping(croppingTop, croppingBottom, croppingLeft, croppingRight);
   m_DeviceConfig.probes.push_back(ultrasoundProbe);
 }
diff --git a/Modules/US/USModel/mitkUSDeviceReaderXML.h b/Modules/US/USModel/mitkUSDeviceReaderXML.h
index 74d3d76b9f..a81663d7c2 100644
--- a/Modules/US/USModel/mitkUSDeviceReaderXML.h
+++ b/Modules/US/USModel/mitkUSDeviceReaderXML.h
@@ -1,101 +1,103 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #ifndef mitkUSDeviceReaderXML_H_HEADER_INCLUDED_
 #define mitkUSDeviceReaderXML_H_HEADER_INCLUDED_
 
 #include <MitkUSExports.h>
 
 #include <mitkAbstractFileReader.h>
 #include <mitkUSProbe.h>
 
 class TiXmlElement;
 class TiXmlNode;
 
 namespace mitk {
 
   class MITKUS_EXPORT USDeviceReaderXML : public AbstractFileReader
   {
   public:
     USDeviceReaderXML();
     ~USDeviceReaderXML() override;
 
     using AbstractFileReader::Read;
-    std::vector<itk::SmartPointer<BaseData>> Read() override;
+
     bool ReadUltrasoundDeviceConfiguration();
 
     void SetFilename(std::string filename);
 
     typedef struct USDeviceConfigData_
     {
       double fileversion;
       std::string deviceType;
       std::string deviceName;
       std::string manufacturer;
       std::string model;
       std::string comment;
       std::string host;
       int port;
       bool server;
       int numberOfImageStreams;
 
       bool useGreyscale;
       bool useResolutionOverride;
       int resolutionWidth;
       int resolutionHeight;
       int sourceID;
       std::string filepathVideoSource;
       int opencvPort;
 
       std::vector <mitk::USProbe::Pointer> probes;
 
       USDeviceConfigData_()
         : fileversion(0), deviceType("Unknown"), deviceName("Unknown"),
           manufacturer("Unknown"), comment(""), host("localhost"),
           port(18944), server(false), numberOfImageStreams(1),
           useGreyscale(true), useResolutionOverride(true),
           resolutionWidth(640), resolutionHeight(480), sourceID(0),
           filepathVideoSource(""), opencvPort(0)
         { };
 
     }USDeviceConfigData;
 
     USDeviceConfigData &GetUSDeviceConfigData();
 
   protected:
+    std::vector<itk::SmartPointer<BaseData>> DoRead() override;
+
     USDeviceReaderXML(const USDeviceReaderXML& other);
     mitk::USDeviceReaderXML* Clone() const override;
 
     /**
     * \brief Extracts all stored attribute information of the ULTRASOUNDDEVICE-Tag.
     */
     void ExtractAttributeInformationOfUltrasoundDeviceTag(TiXmlElement *element);
 
     /**
     * \brief Extracts all stored attribute information of the GENERALSETTINGS-Tag.
     */
     void ExtractAttributeInformationOfGeneralSettingsTag(TiXmlElement *element);
 
     /**
     * \brief Extracts all stored information of a single ultrasound probe.
     */
     void ExtractProbe(TiXmlElement *element);
 
   private:
     std::string m_Filename;
     USDeviceConfigData m_DeviceConfig;
   };
 
 } // namespace mitk
 
 #endif // mitkUSDeviceReaderXML_H_HEADER_INCLUDED_
diff --git a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUltrasoundCalibration.cpp b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUltrasoundCalibration.cpp
index a47d8aedf0..c8502054a3 100644
--- a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUltrasoundCalibration.cpp
+++ b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUltrasoundCalibration.cpp
@@ -1,1398 +1,1398 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // Blueberry
 #include <berryISelectionService.h>
 #include <berryIWorkbenchWindow.h>
 
 // Qmitk
 #include "QmitkUltrasoundCalibration.h"
 #include <QTimer>
 
 // Qt
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QTextStream>
 #include <QmitkServiceListWidget.h>
 
 // MITK
 #include <mitkVector.h>
 #include "mitkIOUtil.h"
 #include "mitkIRenderingManager.h"
 #include <mitkBaseData.h>
 #include <mitkImageGenerator.h>
 #include <mitkNodePredicateDataType.h>
 #include <mitkNodePredicateNot.h>
 #include <mitkNodePredicateProperty.h>
 #include <mitkPointSet.h>
 #include <mitkPointSetDataInteractor.h>
 #include <mitkPointSetShapeProperty.h>
 #include <mitkSceneIO.h>
 
 // us
 #include <usServiceReference.h>
 
 // VTK
 #include <vtkLandmarkTransform.h>
 #include <vtkMatrix4x4.h>
 #include <vtkPlane.h>
 #include <vtkPoints.h>
 #include <vtkSphereSource.h>
 #include <vtkTransform.h>
 
 #include <vtkVertexGlyphFilter.h>
 
 #include "internal/org_mbi_gui_qt_usnavigation_Activator.h"
 
 // sleep headers
 #include <chrono>
 #include <thread>
 
 const std::string QmitkUltrasoundCalibration::VIEW_ID = "org.mitk.views.ultrasoundcalibration";
 
 QmitkUltrasoundCalibration::QmitkUltrasoundCalibration()
   : m_PhantomConfigurationPointSet(nullptr),
     m_USDeviceChanged(this, &QmitkUltrasoundCalibration::OnUSDepthChanged)
 {
   ctkPluginContext *pluginContext = mitk::PluginActivator::GetContext();
 
   if (pluginContext)
   {
     // to be notified about service event of an USDevice
     pluginContext->connectServiceListener(this,
                                           "OnDeviceServiceEvent",
                                           QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" +
                                                                  us_service_interface_iid<mitk::USDevice>() + ")"));
   }
 }
 
 QmitkUltrasoundCalibration::~QmitkUltrasoundCalibration()
 {
   m_Controls.m_CombinedModalityManagerWidget->blockSignals(true);
   mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality;
   combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality();
   if (combinedModality.IsNotNull())
   {
     combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_USDeviceChanged);
   }
   m_Timer->stop();
 
   this->OnStopCalibrationProcess();
 
   this->OnStopPlusCalibration();
 
   mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path");
   if (node.IsNotNull())
     this->GetDataStorage()->Remove(node);
 
   this->GetDataStorage()->Remove(m_VerificationReferencePointsDataNode);
 
   delete m_Timer;
 
   // remove observer for phantom-based point adding
   m_CalibPointsImage->RemoveAllObservers();
 }
 
 void QmitkUltrasoundCalibration::SetFocus()
 {
   m_Controls.m_ToolBox->setFocus();
 }
 
 void QmitkUltrasoundCalibration::CreateQtPartControl(QWidget *parent)
 {
   // create GUI widgets from the Qt Designer's .ui file
   m_Controls.setupUi(parent);
 
   m_Controls.m_CombinedModalityManagerWidget->SetCalibrationLoadedNecessary(false);
 
   m_Timer = new QTimer(this);
   m_StreamingTimer = new QTimer(this);
 
   m_Controls.m_SpacingBtnFreeze->setEnabled(true);
   m_Controls.m_SpacingAddPoint->setEnabled(false);
   m_Controls.m_CalculateSpacing->setEnabled(false);
 
   m_SpacingPointsCount = 0;
   m_SpacingPoints = mitk::PointSet::New();
   m_SpacingNode = mitk::DataNode::New();
   m_SpacingNode->SetName("Spacing Points");
   m_SpacingNode->SetData(this->m_SpacingPoints);
   this->GetDataStorage()->Add(m_SpacingNode);
 
   // Pointset for Calibration Points
   m_CalibPointsTool = mitk::PointSet::New();
 
   // Pointset for Worldpoints
   m_CalibPointsImage = mitk::PointSet::New();
 
   m_CalibPointsCount = 0;
 
   // Evaluation Pointsets (Non-Visualized)
   m_EvalPointsImage = mitk::PointSet::New();
   m_EvalPointsTool = mitk::PointSet::New();
   m_EvalPointsProjected = mitk::PointSet::New();
 
   // Neelde Projection Filter
   m_NeedleProjectionFilter = mitk::NeedleProjectionFilter::New();
 
   // Tracking Status Widgets
   m_Controls.m_CalibTrackingStatus->ShowStatusLabels();
   m_Controls.m_EvalTrackingStatus->ShowStatusLabels();
 
   // General & Device Selection
   connect(m_Timer, SIGNAL(timeout()), this, SLOT(Update()));
 
   // Calibration
   connect(m_Controls.m_CalibBtnFreeze, SIGNAL(clicked()), this, SLOT(SwitchFreeze())); // Freeze
   connect(m_Controls.m_CalibBtnAddPoint,
           SIGNAL(clicked()),
           this,
           SLOT(OnAddCalibPoint())); // Tracking & Image Points (Calibration)
   connect(m_Controls.m_CalibBtnCalibrate, SIGNAL(clicked()), this, SLOT(OnCalibration())); // Perform Calibration
   // Phantom-based calibration
   connect(m_Controls.m_CalibBtnLoadPhantomConfiguration,
           SIGNAL(clicked()),
           this,
           SLOT(OnLoadPhantomConfiguration())); // Phantom configuration
   connect(m_Controls.m_CalibBtnMatchAnnotationToPhantomConfiguration,
           SIGNAL(clicked()),
           this,
           SLOT(OnMatchAnnotationToPhantomConfiguration()));
   connect(m_Controls.m_CalibBtnMoveUp, SIGNAL(clicked()), this, SLOT(OnMovePhantomAnnotationsUp()));
   connect(m_Controls.m_CalibBtnMoveDown, SIGNAL(clicked()), this, SLOT(OnMovePhantomAnnotationsDown()));
   connect(m_Controls.m_CalibBtnMoveLeft, SIGNAL(clicked()), this, SLOT(OnMovePhantomAnnotationsLeft()));
   connect(m_Controls.m_CalibBtnMoveRight, SIGNAL(clicked()), this, SLOT(OnMovePhantomAnnotationsRight()));
   connect(m_Controls.m_CalibBtnRotateRight, SIGNAL(clicked()), this, SLOT(OnRotatePhantomAnnotationsRight()));
   connect(m_Controls.m_CalibBtnRotateLeft, SIGNAL(clicked()), this, SLOT(OnRotatePhantomAnnotationsLeft()));
 
   connect(m_Controls.m_CalibBtnPerformPhantomCalibration,
           SIGNAL(clicked()),
           this,
           SLOT(OnPhantomBasedCalibration())); // Perform phantom-based calibration
   connect(m_Controls.m_CalibBtnSavePhantomCalibration,
           SIGNAL(clicked()),
           this,
           SLOT(OnSaveCalibration())); // Save phantom-based calibration
 
   // Evaluation
   connect(m_Controls.m_EvalBtnStep1, SIGNAL(clicked()), this, SLOT(OnAddEvalProjectedPoint())); // Needle Projection
   connect(m_Controls.m_EvalBtnStep2, SIGNAL(clicked()), this, SLOT(SwitchFreeze()));            // Freeze
   connect(m_Controls.m_EvalBtnStep3,
           SIGNAL(clicked()),
           this,
           SLOT(OnAddEvalTargetPoint())); // Tracking & Image Points (Evaluation)
   connect(m_Controls.m_EvalBtnSave, SIGNAL(clicked()), this, SLOT(OnSaveEvaluation())); // Save Evaluation Results
   connect(m_Controls.m_CalibBtnSaveCalibration,
           SIGNAL(clicked()),
           this,
           SLOT(OnSaveCalibration()));                                       // Save Evaluation Results
   connect(m_Controls.m_BtnReset, SIGNAL(clicked()), this, SLOT(OnReset())); // Reset Pointsets
 
   // PLUS Calibration
   connect(m_Controls.m_GetCalibrationFromPLUS, SIGNAL(clicked()), this, SLOT(OnGetPlusCalibration()));
   connect(m_Controls.m_StartStreaming, SIGNAL(clicked()), this, SLOT(OnStartStreaming()));
   connect(m_StreamingTimer, SIGNAL(timeout()), this, SLOT(OnStreamingTimerTimeout()));
   connect(m_Controls.m_StopPlusCalibration, SIGNAL(clicked()), this, SLOT(OnStopPlusCalibration()));
   connect(m_Controls.m_SavePlusCalibration, SIGNAL(clicked()), this, SLOT(OnSaveCalibration()));
   connect(this, SIGNAL(NewConnectionSignal()), this, SLOT(OnNewConnection()));
 
   // Determine Spacing for Calibration of USVideoDevice
   connect(m_Controls.m_SpacingBtnFreeze, SIGNAL(clicked()), this, SLOT(OnFreezeClicked()));
   connect(m_Controls.m_SpacingAddPoint, SIGNAL(clicked()), this, SLOT(OnAddSpacingPoint()));
   connect(m_Controls.m_CalculateSpacing, SIGNAL(clicked()), this, SLOT(OnCalculateSpacing()));
 
   connect(m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalReadyForNextStep()), this, SLOT(OnDeviceSelected()));
   connect(m_Controls.m_CombinedModalityManagerWidget,
           SIGNAL(SignalNoLongerReadyForNextStep()),
           this,
           SLOT(OnDeviceDeselected()));
   connect(m_Controls.m_StartCalibrationButton, SIGNAL(clicked()), this, SLOT(OnStartCalibrationProcess()));
   connect(m_Controls.m_StartPlusCalibrationButton, SIGNAL(clicked()), this, SLOT(OnStartPlusCalibration()));
   connect(m_Controls.m_CalibBtnRestartCalibration, SIGNAL(clicked()), this, SLOT(OnReset()));
   connect(m_Controls.m_CalibBtnStopCalibration, SIGNAL(clicked()), this, SLOT(OnStopCalibrationProcess()));
 
   connect(m_Controls.m_AddReferencePoints, SIGNAL(clicked()), this, SLOT(OnAddCurrentTipPositionToReferencePoints()));
   connect(m_Controls.m_AddCurrentPointerTipForVerification,
           SIGNAL(clicked()),
           this,
           SLOT(OnAddCurrentTipPositionForVerification()));
   connect(m_Controls.m_StartVerification, SIGNAL(clicked()), this, SLOT(OnStartVerification()));
 
   // initialize data storage combo box
   m_Controls.m_ReferencePointsComboBox->SetDataStorage(this->GetDataStorage());
   m_Controls.m_ReferencePointsComboBox->SetAutoSelectNewItems(true);
   m_Controls.m_ReferencePointsComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet"));
 
   // initialize point list widget
   if (m_VerificationReferencePoints.IsNull())
   {
     m_VerificationReferencePoints = mitk::PointSet::New();
   }
   if (m_VerificationReferencePointsDataNode.IsNull())
   {
     m_VerificationReferencePointsDataNode = mitk::DataNode::New();
     m_VerificationReferencePointsDataNode->SetName("US Verification Reference Points");
     m_VerificationReferencePointsDataNode->SetData(m_VerificationReferencePoints);
     this->GetDataStorage()->Add(m_VerificationReferencePointsDataNode);
   }
   m_Controls.m_ReferencePointsPointListWidget->SetPointSetNode(m_VerificationReferencePointsDataNode);
 
   m_Controls.m_ToolBox->setCurrentIndex(0);
 }
 
 void QmitkUltrasoundCalibration::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/,
                                                     const QList<mitk::DataNode::Pointer> & /*nodes*/)
 {
 }
 
 void QmitkUltrasoundCalibration::OnTabSwitch(int index)
 {
   switch (index)
   {
     case 0:
       if (m_Controls.m_ToolBox->isItemEnabled(1) || m_Controls.m_ToolBox->isItemEnabled(2))
       {
         this->OnStopCalibrationProcess();
       }
       break;
     default:;
   }
 }
 
 void QmitkUltrasoundCalibration::OnDeviceSelected()
 {
   mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality;
   combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality();
   if (combinedModality.IsNotNull())
   {
     combinedModality->GetUltrasoundDevice()->AddPropertyChangedListener(m_USDeviceChanged);
 
     m_Controls.m_StartCalibrationButton->setEnabled(true);
     m_Controls.m_StartPlusCalibrationButton->setEnabled(true);
     m_Controls.m_ToolBox->setItemEnabled(1, true);
     m_Controls.m_ToolBox->setItemEnabled(2, true);
   }
 }
 
 void QmitkUltrasoundCalibration::OnDeviceDeselected()
 {
   mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality;
   combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality();
   if (combinedModality.IsNotNull())
   {
     combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_USDeviceChanged);
   }
   m_Controls.m_StartCalibrationButton->setEnabled(false);
   m_Controls.m_StartPlusCalibrationButton->setEnabled(false);
   m_Controls.m_ToolBox->setCurrentIndex(0);
   m_Controls.m_ToolBox->setItemEnabled(1, false);
   m_Controls.m_ToolBox->setItemEnabled(2, false);
 }
 
 void QmitkUltrasoundCalibration::OnAddCurrentTipPositionToReferencePoints()
 {
   if (m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource().IsNull() ||
       (m_Controls.m_VerificationPointerChoser->GetSelectedToolID() == -1))
   {
     MITK_WARN << "No tool selected, aborting";
     return;
   }
   mitk::NavigationData::Pointer currentPointerData =
     m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource()->GetOutput(
       m_Controls.m_VerificationPointerChoser->GetSelectedToolID());
   mitk::Point3D currentTipPosition = currentPointerData->GetPosition();
   m_VerificationReferencePoints->InsertPoint(m_VerificationReferencePoints->GetSize(), currentTipPosition);
 }
 
 void QmitkUltrasoundCalibration::OnStartVerification()
 {
   m_currentPoint = 0;
   mitk::PointSet::Pointer selectedPointSet =
     dynamic_cast<mitk::PointSet *>(m_Controls.m_ReferencePointsComboBox->GetSelectedNode()->GetData());
   m_Controls.m_CurrentPointLabel->setText("Point " + QString::number(m_currentPoint) + " of " +
                                           QString::number(selectedPointSet->GetSize()));
   m_allErrors = std::vector<double>();
   m_allReferencePoints = std::vector<mitk::Point3D>();
   for (int i = 0; i < selectedPointSet->GetSize(); i++)
   {
     m_allReferencePoints.push_back(selectedPointSet->GetPoint(i));
   }
 }
 
 void QmitkUltrasoundCalibration::OnAddCurrentTipPositionForVerification()
 {
   if (m_currentPoint == -1)
   {
     MITK_WARN << "Cannot add point";
     return;
   }
   if (m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource().IsNull() ||
       (m_Controls.m_VerificationPointerChoser->GetSelectedToolID() == -1))
   {
     MITK_WARN << "No tool selected, aborting";
     return;
   }
   mitk::NavigationData::Pointer currentPointerData =
     m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource()->GetOutput(
       m_Controls.m_VerificationPointerChoser->GetSelectedToolID());
   mitk::Point3D currentTipPosition = currentPointerData->GetPosition();
 
   double currentError = m_allReferencePoints.at(m_currentPoint).EuclideanDistanceTo(currentTipPosition);
   MITK_INFO << "Current Error: " << currentError << " mm";
   m_allErrors.push_back(currentError);
 
   if (++m_currentPoint < static_cast<int>(m_allReferencePoints.size()))
   {
     m_Controls.m_CurrentPointLabel->setText("Point " + QString::number(m_currentPoint) + " of " +
                                             QString::number(m_allReferencePoints.size()));
   }
   else
   {
     m_currentPoint = -1;
     double meanError = 0;
     for (std::size_t i = 0; i < m_allErrors.size(); ++i)
     {
       meanError += m_allErrors[i];
     }
     meanError /= m_allErrors.size();
 
     QString result = "Finished verification! \n Verification of " + QString::number(m_allErrors.size()) +
                      " points, mean error: " + QString::number(meanError) + " mm";
     m_Controls.m_ResultsTextEdit->setText(result);
     MITK_INFO << result.toStdString();
   }
 }
 
 void QmitkUltrasoundCalibration::OnStartCalibrationProcess()
 {
   // US Image Stream
-  m_Node = this->GetDataStorage()->GetNamedNode("US Viewing Stream - Image 0")->Clone();
+  m_Node = dynamic_cast<mitk::DataNode*>(this->GetDataStorage()->GetNamedNode("US Viewing Stream - Image 0")->CreateAnother().GetPointer());
   m_Node->SetName("US Calibration Viewing Stream");
   this->GetDataStorage()->Add(m_Node);
 
   // data node for calibration point set
   m_CalibNode = mitk::DataNode::New();
   m_CalibNode->SetName("Tool Calibration Points");
   m_CalibNode->SetData(this->m_CalibPointsTool);
   this->GetDataStorage()->Add(m_CalibNode);
 
   // data node for world point set
   m_WorldNode = mitk::DataNode::New();
   m_WorldNode->SetName("Image Calibration Points");
   m_WorldNode->SetData(this->m_CalibPointsImage);
   this->GetDataStorage()->Add(m_WorldNode);
 
   m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality();
   m_CombinedModality->SetCalibration(mitk::AffineTransform3D::New()); // dummy calibration because without a calibration
                                                                       // the comined modality was laggy (maybe a bug?)
   if (m_CombinedModality.IsNull())
   {
     return;
   }
 
   m_Tracker = m_CombinedModality->GetNavigationDataSource();
 
   // Construct Pipeline
   this->m_NeedleProjectionFilter->SetInput(0, m_Tracker->GetOutput(0));
 
   QApplication::setOverrideCursor(Qt::WaitCursor);
   // make sure that the combined modality is in connected state before using it
   if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Connected)
   {
     m_CombinedModality->GetUltrasoundDevice()->Connect();
   }
   if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Activated)
   {
     m_CombinedModality->GetUltrasoundDevice()->Activate();
   }
   QApplication::restoreOverrideCursor();
 
   this->SwitchFreeze();
 
   // Trigger the ProbeChanged method for initializing/updating the spacing of the ultrasound image correctly
   std::string probeName = m_CombinedModality->GetUltrasoundDevice()->GetCurrentProbe()->GetName();
   m_CombinedModality->GetUltrasoundDevice()->ProbeChanged(probeName);
 
   mitk::DataNode::Pointer usNode = this->GetDataStorage()->GetNamedNode("US Viewing Stream - Image 0");
   if (usNode.IsNotNull())
   {
     this->GetDataStorage()->Remove(usNode);
   }
 
   // Todo: Maybe display this elsewhere
   this->ShowNeedlePath();
 
   // Switch active tab to Calibration page
   m_Controls.m_ToolBox->setItemEnabled(1, true);
   m_Controls.m_ToolBox->setCurrentIndex(1);
 }
 
 void QmitkUltrasoundCalibration::OnStartPlusCalibration()
 {
   if (m_CombinedModality.IsNull())
   {
     m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality();
     if (m_CombinedModality.IsNull())
     {
       return;
     } // something went wrong, there is no combined modality
   }
 
   // setup server to send UltrasoundImages to PLUS
   mitk::IGTLServer::Pointer m_USServer = mitk::IGTLServer::New(true);
   m_USServer->SetName("EchoTrack Image Source");
   m_USServer->SetHostname("127.0.0.1");
   m_USServer->SetPortNumber(18944);
 
   m_USMessageProvider = mitk::IGTLMessageProvider::New();
   m_USMessageProvider->SetIGTLDevice(m_USServer);
   m_USMessageProvider->SetFPS(5);
 
   m_USImageToIGTLMessageFilter = mitk::ImageToIGTLMessageFilter::New();
   m_USImageToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetUltrasoundDevice());
   m_USImageToIGTLMessageFilter->SetName("USImage Filter");
 
   // setup server to send TrackingData to PLUS
   m_TrackingServer = mitk::IGTLServer::New(true);
   m_TrackingServer->SetName("EchoTrack Tracking Source");
   m_TrackingServer->SetHostname("127.0.0.1");
   m_TrackingServer->SetPortNumber(18945);
 
   m_TrackingMessageProvider = mitk::IGTLMessageProvider::New();
   m_TrackingMessageProvider->SetIGTLDevice(m_TrackingServer);
   m_TrackingMessageProvider->SetFPS(5);
 
   m_TrackingToIGTLMessageFilter = mitk::NavigationDataToIGTLMessageFilter::New();
   m_TrackingToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetTrackingDeviceDataSource());
   m_TrackingToIGTLMessageFilter->SetName("Tracker Filter");
 
   typedef itk::SimpleMemberCommand<QmitkUltrasoundCalibration> CurCommandType;
 
   CurCommandType::Pointer newConnectionCommand = CurCommandType::New();
   newConnectionCommand->SetCallbackFunction(this, &QmitkUltrasoundCalibration::OnPlusConnected);
   this->m_NewConnectionObserverTag =
     this->m_TrackingServer->AddObserver(mitk::NewClientConnectionEvent(), newConnectionCommand);
 
   // Open connections of both servers
   if (m_USServer->OpenConnection())
   {
     MITK_INFO << "US Server opened its connection successfully";
     m_USServer->StartCommunication();
   }
   else
   {
     MITK_INFO << "US Server could not open its connection";
   }
   if (m_TrackingServer->OpenConnection())
   {
     MITK_INFO << "Tracking Server opened its connection successfully";
     m_TrackingServer->StartCommunication();
   }
   else
   {
     MITK_INFO << "Tracking Server could not open its connection";
   }
   if (m_USMessageProvider->IsCommunicating() && m_TrackingMessageProvider->IsCommunicating())
   {
     m_Controls.m_StartPlusCalibrationButton->setEnabled(false);
     m_Controls.m_GetCalibrationFromPLUS->setEnabled(true);
     m_Controls.m_StartStreaming->setEnabled(false);
     m_Controls.m_SavePlusCalibration->setEnabled(false);
     m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : green; }");
     m_Controls.m_SetupStatus->setText("Setup successfull you can now connect PLUS");
   }
   else
   {
     m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : red; }");
     m_Controls.m_SetupStatus->setText("Something went wrong. Please try again");
   }
 }
 
 void QmitkUltrasoundCalibration::OnStopPlusCalibration()
 {
   // closing all server and clients when PlusCalibration is finished
   if (m_USMessageProvider.IsNotNull())
   {
     if (m_USMessageProvider->IsStreaming())
     {
       m_USMessageProvider->StopStreamingOfSource(m_USImageToIGTLMessageFilter);
     }
   }
   if (m_TrackingMessageProvider.IsNotNull())
   {
     if (m_TrackingMessageProvider->IsStreaming())
     {
       m_TrackingMessageProvider->StopStreamingOfSource(m_TrackingToIGTLMessageFilter);
     }
   }
   if (m_USServer.IsNotNull())
   {
     m_USServer->CloseConnection();
   }
   if (m_TrackingServer.IsNotNull())
   {
     m_TrackingServer->CloseConnection();
   }
   if (m_TransformClient.IsNotNull())
   {
     m_TransformClient->CloseConnection();
   }
   m_Controls.m_GotCalibrationLabel->setText("");
   m_Controls.m_ConnectionStatus->setText("");
   m_Controls.m_SetupStatus->setText("");
   m_Controls.m_StartPlusCalibrationButton->setEnabled(true);
   m_StreamingTimer->stop();
   delete m_StreamingTimer;
 }
 
 void QmitkUltrasoundCalibration::OnPlusConnected()
 {
   emit NewConnectionSignal();
 }
 
 void QmitkUltrasoundCalibration::OnNewConnection()
 {
   m_Controls.m_StartStreaming->setEnabled(true);
   m_Controls.m_ConnectionStatus->setStyleSheet("QLabel { color : green; }");
   m_Controls.m_ConnectionStatus->setText("Connection successfull you can now start streaming");
 }
 
 void QmitkUltrasoundCalibration::OnStreamingTimerTimeout()
 {
   m_USMessageProvider->Update();
   m_TrackingMessageProvider->Update();
 }
 
 void QmitkUltrasoundCalibration::OnStartStreaming()
 {
   m_USMessageProvider->StartStreamingOfSource(m_USImageToIGTLMessageFilter, 5);
   m_TrackingMessageProvider->StartStreamingOfSource(m_TrackingToIGTLMessageFilter, 5);
   m_Controls.m_StartStreaming->setEnabled(false);
   m_Controls.m_ConnectionStatus->setText("");
   m_StreamingTimer->start((1.0 / 5.0 * 1000.0));
 }
 
 void QmitkUltrasoundCalibration::OnGetPlusCalibration()
 {
   m_TransformClient = mitk::IGTLClient::New(true);
   m_TransformClient->SetHostname("127.0.0.1");
   m_TransformClient->SetPortNumber(18946);
   m_TransformDeviceSource = mitk::IGTLDeviceSource::New();
   m_TransformDeviceSource->SetIGTLDevice(m_TransformClient);
   m_TransformDeviceSource->Connect();
   if (m_TransformDeviceSource->IsConnected())
   {
     MITK_INFO << "successfully connected";
     m_TransformDeviceSource->StartCommunication();
     if (m_TransformDeviceSource->IsCommunicating())
     {
       MITK_INFO << "communication started";
       mitk::IGTLMessage::Pointer receivedMessage;
       bool condition = false;
       igtl::Matrix4x4 transformPLUS;
       while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid()))
       {
         std::this_thread::sleep_for(std::chrono::milliseconds(50));
         m_TransformDeviceSource->Update();
         receivedMessage = m_TransformDeviceSource->GetOutput();
         igtl::TransformMessage::Pointer msg =
           dynamic_cast<igtl::TransformMessage *>(m_TransformDeviceSource->GetOutput()->GetMessage().GetPointer());
         if (msg == nullptr || msg.IsNull())
         {
           MITK_INFO << "Received message could not be casted to TransformMessage. Skipping...";
           continue;
         }
         else
         {
           if (std::strcmp(msg->GetDeviceName(), "ImageToTracker") != 0)
           {
             MITK_INFO << "Was not Image to Tracker Transform. Skipping...";
             continue;
           }
           else
           {
             msg->GetMatrix(transformPLUS);
             condition = true;
             break;
           }
         }
       }
       if (condition)
       {
         this->ProcessPlusCalibration(transformPLUS);
       }
       else
       {
         m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }");
         m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again");
       }
     }
     else
     {
       MITK_INFO << " no connection";
       m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }");
       m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again");
     }
   }
   else
   {
     m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }");
     m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again");
   }
 }
 
 void QmitkUltrasoundCalibration::ProcessPlusCalibration(igtl::Matrix4x4 &imageToTracker)
 {
   mitk::AffineTransform3D::Pointer imageToTrackerTransform = mitk::AffineTransform3D::New();
   itk::Matrix<mitk::ScalarType, 3, 3> rotationFloat = itk::Matrix<mitk::ScalarType, 3, 3>();
   itk::Vector<mitk::ScalarType, 3> translationFloat = itk::Vector<mitk::ScalarType, 3>();
 
   rotationFloat[0][0] = imageToTracker[0][0];
   rotationFloat[0][1] = imageToTracker[0][1];
   rotationFloat[0][2] = imageToTracker[0][2];
   rotationFloat[1][0] = imageToTracker[1][0];
   rotationFloat[1][1] = imageToTracker[1][1];
   rotationFloat[1][2] = imageToTracker[1][2];
   rotationFloat[2][0] = imageToTracker[2][0];
   rotationFloat[2][1] = imageToTracker[2][1];
   rotationFloat[2][2] = imageToTracker[2][2];
   translationFloat[0] = imageToTracker[0][3];
   translationFloat[1] = imageToTracker[1][3];
   translationFloat[2] = imageToTracker[2][3];
 
   imageToTrackerTransform->SetTranslation(translationFloat);
   imageToTrackerTransform->SetMatrix(rotationFloat);
 
   m_CombinedModality->SetCalibration(imageToTrackerTransform);
   m_Controls.m_ToolBox->setItemEnabled(2, true);
   m_Controls.m_SavePlusCalibration->setEnabled(true);
   m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : green; }");
   m_Controls.m_GotCalibrationLabel->setText("Recieved Calibration from PLUS you can now save it");
 }
 
 void QmitkUltrasoundCalibration::OnStopCalibrationProcess()
 {
   this->ClearTemporaryMembers();
 
   m_Timer->stop();
 
   this->GetDataStorage()->Remove(m_Node);
   m_Node = nullptr;
 
   this->GetDataStorage()->Remove(m_CalibNode);
   m_CalibNode = nullptr;
 
   this->GetDataStorage()->Remove(m_WorldNode);
   m_WorldNode = nullptr;
 
   m_Controls.m_ToolBox->setCurrentIndex(0);
 }
 
 void QmitkUltrasoundCalibration::OnDeviceServiceEvent(const ctkServiceEvent event)
 {
   if (m_CombinedModality.IsNull() || event.getType() != ctkServiceEvent::MODIFIED)
   {
     return;
   }
 
   ctkServiceReference service = event.getServiceReference();
 
   QString curDepth =
     service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH)).toString();
   if (m_CurrentDepth != curDepth)
   {
     m_CurrentDepth = curDepth;
     this->OnReset();
   }
 }
 
 void QmitkUltrasoundCalibration::OnAddCalibPoint()
 {
   mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition();
 
   this->m_CalibPointsImage->InsertPoint(m_CalibPointsCount, world);
   this->m_CalibPointsTool->InsertPoint(m_CalibPointsCount, this->m_FreezePoint);
 
   QString text = text.number(m_CalibPointsCount + 1);
   text = "Point " + text;
   this->m_Controls.m_CalibPointList->addItem(text);
 
   m_CalibPointsCount++;
   SwitchFreeze();
 }
 
 void QmitkUltrasoundCalibration::OnCalibration()
 {
   if (m_CombinedModality.IsNull())
   {
     return;
   }
 
   // Compute transformation
   vtkSmartPointer<vtkLandmarkTransform> transform = vtkSmartPointer<vtkLandmarkTransform>::New();
 
   transform->SetSourceLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints());
   transform->SetTargetLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsTool)->GetPoints());
 
   if (!m_CombinedModality->GetIsTrackedUltrasoundActive())
   {
     if (m_Controls.m_ScaleTransform->isChecked())
     {
       transform->SetModeToSimilarity();
     } // use affine transform
     else
     {
       transform->SetModeToRigidBody();
     } // use similarity transform: scaling is not touched
     MITK_INFO << "TEST";
   }
   else
   {
     transform->SetModeToRigidBody(); // use similarity transform: scaling is not touched
   }
 
   transform->Modified();
   transform->Update();
 
   // Convert from vtk to itk data types
   itk::Matrix<mitk::ScalarType, 3, 3> rotationFloat = itk::Matrix<mitk::ScalarType, 3, 3>();
   itk::Vector<mitk::ScalarType, 3> translationFloat = itk::Vector<mitk::ScalarType, 3>();
   vtkSmartPointer<vtkMatrix4x4> m = transform->GetMatrix();
   rotationFloat[0][0] = m->GetElement(0, 0);
   rotationFloat[0][1] = m->GetElement(0, 1);
   rotationFloat[0][2] = m->GetElement(0, 2);
   rotationFloat[1][0] = m->GetElement(1, 0);
   rotationFloat[1][1] = m->GetElement(1, 1);
   rotationFloat[1][2] = m->GetElement(1, 2);
   rotationFloat[2][0] = m->GetElement(2, 0);
   rotationFloat[2][1] = m->GetElement(2, 1);
   rotationFloat[2][2] = m->GetElement(2, 2);
   translationFloat[0] = m->GetElement(0, 3);
   translationFloat[1] = m->GetElement(1, 3);
   translationFloat[2] = m->GetElement(2, 3);
 
   mitk::PointSet::Pointer ImagePointsTransformed = m_CalibPointsImage->Clone();
   this->ApplyTransformToPointSet(ImagePointsTransformed, transform);
   mitk::DataNode::Pointer CalibPointsImageTransformed =
     this->GetDataStorage()->GetNamedNode("Calibration Points Image (Transformed)");
   if (CalibPointsImageTransformed.IsNull())
   {
     CalibPointsImageTransformed = mitk::DataNode::New();
     CalibPointsImageTransformed->SetName("Calibration Points Image (Transformed)");
     this->GetDataStorage()->Add(CalibPointsImageTransformed);
   }
   CalibPointsImageTransformed->SetData(ImagePointsTransformed);
 
   // Set new calibration transform
   m_Transformation = mitk::AffineTransform3D::New();
   m_Transformation->SetTranslation(translationFloat);
   m_Transformation->SetMatrix(rotationFloat);
   MITK_INFO << "New Calibration transform: " << m_Transformation;
 
   mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast<mitk::SlicedGeometry3D *>(m_Node->GetData()->GetGeometry());
 
   mitk::PlaneGeometry::Pointer plane = const_cast<mitk::PlaneGeometry *>(sliced3d->GetPlaneGeometry(0));
 
   plane->SetIndexToWorldTransform(m_Transformation);
 
   // Save to US-Device
   m_CombinedModality->SetCalibration(m_Transformation);
   m_Controls.m_ToolBox->setItemEnabled(2, true);
 
   // Save to NeedleProjectionFilter
   m_NeedleProjectionFilter->SetTargetPlane(m_Transformation);
 
   // Update Calibration FRE
   m_CalibrationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New();
   mitk::PointSet::Pointer p1 =
     this->m_CalibPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems
 
   // Create point set with transformed image calibration points for
   // calculating the difference of image calibration and tool
   // calibration points in one geometry space
   mitk::PointSet::Pointer p2 = mitk::PointSet::New();
   int n = 0;
   for (mitk::PointSet::PointsConstIterator it = m_CalibPointsImage->Begin(); it != m_CalibPointsImage->End(); ++it, ++n)
   {
     p2->InsertPoint(n, m_Transformation->TransformPoint(it->Value()));
   }
 
   m_CalibrationStatistics->SetPointSets(p1, p2);
   // QString text = text.number(m_CalibrationStatistics->GetRMS());
   QString text = QString::number(ComputeFRE(m_CalibPointsImage, m_CalibPointsTool, transform));
   MITK_INFO << "Calibration FRE: " << text.toStdString().c_str();
   m_Controls.m_EvalLblCalibrationFRE->setText(text);
 
   m_Node->SetStringProperty("Calibration FRE", text.toStdString().c_str());
   // Enable Button to save Calibration
   m_Controls.m_CalibBtnSaveCalibration->setEnabled(true);
 }
 
 void QmitkUltrasoundCalibration::OnLoadPhantomConfiguration()
 {
   // clear all data
   ClearTemporaryMembers();
   // reset UI
   m_Controls.m_CalibBtnMatchAnnotationToPhantomConfiguration->setEnabled(false);
   m_Controls.m_RefinePhantomAnnotationsGroupBox->setEnabled(false);
   m_Controls.m_CalibBtnPerformPhantomCalibration->setEnabled(false);
   m_Controls.m_CalibBtnSavePhantomCalibration->setEnabled(false);
 
   // open phantom configuration
   QString fileName = QFileDialog::getOpenFileName(nullptr, "Load phantom configuration", "", "*.mps");
 
   // dialog closed or selection canceled
   if (fileName.isNull())
   {
     return;
   }
 
   m_PhantomConfigurationPointSet = dynamic_cast<mitk::PointSet *>(mitk::IOUtil::Load(fileName.toStdString()).at(0).GetPointer());
 
   // transform phantom fiducials to tracking space
   mitk::NavigationData::Pointer currentSensorData = this->m_Tracker->GetOutput(0)->Clone();
 
   for (int i = 0; i < m_PhantomConfigurationPointSet->GetSize(); i++)
   {
     mitk::Point3D phantomPoint = m_PhantomConfigurationPointSet->GetPoint(i);
     mitk::Point3D transformedPoint = currentSensorData->TransformPoint(phantomPoint);
     this->m_CalibPointsTool->InsertPoint(i, transformedPoint);
   }
 
   // add point set interactor for image calibration points
   mitk::PointSetDataInteractor::Pointer imageCalibrationPointSetInteractor = mitk::PointSetDataInteractor::New();
   imageCalibrationPointSetInteractor->LoadStateMachine("PointSet.xml");
   imageCalibrationPointSetInteractor->SetEventConfig("PointSetConfig.xml");
   imageCalibrationPointSetInteractor->SetDataNode(m_WorldNode);
   imageCalibrationPointSetInteractor->SetMaxPoints(m_PhantomConfigurationPointSet->GetSize());
   // Call On AddCalibPointPhantomBased() when point was added
   itk::SimpleMemberCommand<QmitkUltrasoundCalibration>::Pointer pointAddedCommand =
     itk::SimpleMemberCommand<QmitkUltrasoundCalibration>::New();
   pointAddedCommand->SetCallbackFunction(this, &QmitkUltrasoundCalibration::OnPhantomCalibPointsChanged);
   m_CalibPointsImage->AddObserver(mitk::PointSetAddEvent(), pointAddedCommand);
   m_CalibPointsImage->AddObserver(mitk::PointSetMoveEvent(), pointAddedCommand);
   // Set size of image points points
   m_WorldNode->ReplaceProperty("point 2D size", mitk::FloatProperty::New(10.0));
 }
 
 void QmitkUltrasoundCalibration::OnPhantomCalibPointsChanged()
 {
   int currentIndex = m_CalibPointsImage->SearchSelectedPoint();
   mitk::Point3D currentImagePoint = m_CalibPointsImage->GetPoint(currentIndex);
   UpdatePhantomAnnotationPointVisualization(currentIndex);
   // create sphere to show radius in which next point has to be placed
    this->GetDataStorage()->Remove(this->GetDataStorage()->GetNamedNode("NextPointIndicator"));
    if (currentIndex < m_CalibPointsTool->GetSize() - 1)
   {
     float distanceToNextPoint =
       m_CalibPointsTool->GetPoint(currentIndex).EuclideanDistanceTo(m_CalibPointsTool->GetPoint(currentIndex + 1));
     vtkSmartPointer<vtkSphereSource> vtkHelperSphere = vtkSmartPointer<vtkSphereSource>::New();
     vtkHelperSphere->SetCenter(currentImagePoint[0], currentImagePoint[1], currentImagePoint[2]);
     vtkHelperSphere->SetRadius(distanceToNextPoint);
     vtkHelperSphere->SetPhiResolution(40);
     vtkHelperSphere->SetThetaResolution(40);
     vtkHelperSphere->Update();
     mitk::Surface::Pointer helperSphere = mitk::Surface::New();
     helperSphere->SetVtkPolyData(vtkHelperSphere->GetOutput());
     mitk::DataNode::Pointer helperSphereNode = mitk::DataNode::New();
     helperSphereNode->SetName("NextPointIndicator");
     helperSphereNode->SetData(helperSphere);
     helperSphereNode->SetColor(0.0, 1.0, 0.0);
     this->GetDataStorage()->Add(helperSphereNode);
   }
   if (m_CalibPointsTool->GetSize() == m_CalibPointsImage->GetSize())
   {
     m_Controls.m_CalibBtnMatchAnnotationToPhantomConfiguration->setEnabled(true);
   }
 }
 
 void QmitkUltrasoundCalibration::UpdatePhantomAnnotationPointVisualization(int index)
 {
   mitk::Point3D currentImagePoint = m_CalibPointsImage->GetPoint(index);
   // create sphere to show current fiducial
   std::stringstream pointName;
   pointName << "Point";
   pointName << index;
   this->GetDataStorage()->Remove(this->GetDataStorage()->GetNamedNode(pointName.str()));
   vtkSmartPointer<vtkSphereSource> vtkPointSphere = vtkSmartPointer<vtkSphereSource>::New();
   vtkPointSphere->SetCenter(currentImagePoint[0], currentImagePoint[1], currentImagePoint[2]);
   vtkPointSphere->SetRadius(5.0);
   vtkPointSphere->SetPhiResolution(40);
   vtkPointSphere->SetThetaResolution(40);
   vtkPointSphere->Update();
   mitk::Surface::Pointer pointSphere = mitk::Surface::New();
   pointSphere->SetVtkPolyData(vtkPointSphere->GetOutput());
   mitk::DataNode::Pointer sphereNode = mitk::DataNode::New();
   sphereNode->SetName(pointName.str());
   sphereNode->SetData(pointSphere);
   sphereNode->SetColor(1.0, 1.0, 0.0);
   this->GetDataStorage()->Add(sphereNode);
 }
 
 void QmitkUltrasoundCalibration::OnMatchAnnotationToPhantomConfiguration()
 {
   // Transform pointset of phantom configuration to currently annotated image points
   vtkSmartPointer<vtkLandmarkTransform> transform = vtkSmartPointer<vtkLandmarkTransform>::New();
   transform->SetModeToRigidBody();
   vtkSmartPointer<vtkPoints> toolLandmarks = this->ConvertPointSetToVtkPolyData(m_CalibPointsTool)->GetPoints();
   transform->SetSourceLandmarks(toolLandmarks);
   transform->SetTargetLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints());
   transform->Update();
   // update image annotation with matched phantom configuration
   vtkSmartPointer<vtkPoints> transformedToolLandmarks = vtkSmartPointer<vtkPoints>::New();
   transform->TransformPoints(toolLandmarks, transformedToolLandmarks);
   for (int i = 0; i < transformedToolLandmarks->GetNumberOfPoints(); i++)
   {
     m_CalibPointsImage->InsertPoint(i, transformedToolLandmarks->GetPoint(i));
     UpdatePhantomAnnotationPointVisualization(i);
   }
   m_Controls.m_RefinePhantomAnnotationsGroupBox->setEnabled(true);
   m_Controls.m_CalibBtnPerformPhantomCalibration->setEnabled(true);
 }
 
 void QmitkUltrasoundCalibration::TranslatePhantomAnnotations(double tx, double ty, double tz)
 {
   vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
   transform->Translate(tx, ty, tz);
   vtkSmartPointer<vtkPoints> currentPoints = this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints();
   vtkSmartPointer<vtkPoints> transformedPoints = vtkSmartPointer<vtkPoints>::New();
   transform->TransformPoints(currentPoints, transformedPoints);
   for (int i = 0; i < transformedPoints->GetNumberOfPoints(); i++)
   {
     m_CalibPointsImage->InsertPoint(i, transformedPoints->GetPoint(i));
     UpdatePhantomAnnotationPointVisualization(i);
   }
 }
 
 void QmitkUltrasoundCalibration::RotatePhantomAnnotations(double angle)
 {
   vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
   transform->RotateZ(angle);
   vtkSmartPointer<vtkPoints> currentPoints = this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints();
   vtkSmartPointer<vtkPoints> transformedPoints = vtkSmartPointer<vtkPoints>::New();
   transform->TransformPoints(currentPoints, transformedPoints);
   for (int i = 0; i < transformedPoints->GetNumberOfPoints(); i++)
   {
     m_CalibPointsImage->InsertPoint(i, transformedPoints->GetPoint(i));
     UpdatePhantomAnnotationPointVisualization(i);
   }
 }
 
 void QmitkUltrasoundCalibration::OnMovePhantomAnnotationsUp()
 {
   this->TranslatePhantomAnnotations(0, -m_Image->GetGeometry()->GetSpacing()[1], 0);
 }
 
 void QmitkUltrasoundCalibration::OnMovePhantomAnnotationsDown()
 {
   this->TranslatePhantomAnnotations(0, m_Image->GetGeometry()->GetSpacing()[1], 0);
 }
 
 void QmitkUltrasoundCalibration::OnMovePhantomAnnotationsLeft()
 {
   this->TranslatePhantomAnnotations(-m_Image->GetGeometry()->GetSpacing()[0], 0, 0);
 }
 
 void QmitkUltrasoundCalibration::OnMovePhantomAnnotationsRight()
 {
   this->TranslatePhantomAnnotations(m_Image->GetGeometry()->GetSpacing()[0], 0, 0);
 }
 
 void QmitkUltrasoundCalibration::OnRotatePhantomAnnotationsRight()
 {
   mitk::BoundingBox::PointType centerOfPointSet = m_CalibPointsImage->GetGeometry()->GetBoundingBox()->GetCenter();
   this->TranslatePhantomAnnotations(-centerOfPointSet[0], -centerOfPointSet[1], -centerOfPointSet[2]);
   this->RotatePhantomAnnotations(0.5);
   this->TranslatePhantomAnnotations(centerOfPointSet[0], centerOfPointSet[1], centerOfPointSet[2]);
 }
 
 void QmitkUltrasoundCalibration::OnRotatePhantomAnnotationsLeft()
 {
   mitk::BoundingBox::PointType centerOfPointSet = m_CalibPointsImage->GetGeometry()->GetBoundingBox()->GetCenter();
   this->TranslatePhantomAnnotations(-centerOfPointSet[0], -centerOfPointSet[1], -centerOfPointSet[2]);
   this->RotatePhantomAnnotations(-0.5);
   this->TranslatePhantomAnnotations(centerOfPointSet[0], centerOfPointSet[1], centerOfPointSet[2]);
 }
 
 void QmitkUltrasoundCalibration::OnPhantomBasedCalibration()
 {
   // perform calibration
   OnCalibration();
   m_Controls.m_CalibBtnSavePhantomCalibration->setEnabled(true);
 }
 
 void QmitkUltrasoundCalibration::OnAddEvalTargetPoint()
 {
   mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition();
 
   this->m_EvalPointsImage->InsertPoint(m_EvalPointsImage->GetSize(), world);
   this->m_EvalPointsTool->InsertPoint(m_EvalPointsTool->GetSize(), this->m_FreezePoint);
 
   QString text = text.number(this->m_EvalPointsTool->GetSize());
   this->m_Controls.m_EvalLblNumTargetPoints->setText(text);
 
   // Update FREs
   // Update Evaluation FRE, but only if it contains more than one point (will crash otherwise)
   if ((m_EvalPointsProjected->GetSize() > 1) && (m_EvalPointsTool->GetSize() > 1))
   {
     m_EvaluationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New();
     m_ProjectionStatistics = mitk::PointSetDifferenceStatisticsCalculator::New();
     mitk::PointSet::Pointer p1 =
       this->m_EvalPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems
     mitk::PointSet::Pointer p2 = this->m_EvalPointsImage->Clone();
     mitk::PointSet::Pointer p3 = this->m_EvalPointsProjected->Clone();
     m_EvaluationStatistics->SetPointSets(p1, p2);
     m_ProjectionStatistics->SetPointSets(p1, p3);
     QString evalText = evalText.number(m_EvaluationStatistics->GetRMS());
     QString projText = projText.number(m_ProjectionStatistics->GetRMS());
     m_Controls.m_EvalLblEvaluationFRE->setText(evalText);
     m_Controls.m_EvalLblProjectionFRE->setText(projText);
   }
   SwitchFreeze();
 }
 
 void QmitkUltrasoundCalibration::OnAddEvalProjectedPoint()
 {
   MITK_WARN << "Projection Evaluation may currently be inaccurate.";
   // TODO: Verify correct Evaluation. Is the Point that is added really current?
   mitk::Point3D projection = this->m_NeedleProjectionFilter->GetProjection()->GetPoint(1);
   m_EvalPointsProjected->InsertPoint(m_EvalPointsProjected->GetSize(), projection);
   QString text = text.number(this->m_EvalPointsProjected->GetSize());
   this->m_Controls.m_EvalLblNumProjectionPoints->setText(text);
 }
 
 void QmitkUltrasoundCalibration::OnSaveEvaluation()
 {
   // Filename without suffix
   QString filename = m_Controls.m_EvalFilePath->text() + "//" + m_Controls.m_EvalFilePrefix->text();
 
   MITK_WARN << "CANNOT SAVE, ABORTING!";
   /* not working any more TODO!
   mitk::PointSetWriter::Pointer psWriter = mitk::PointSetWriter::New();
   psWriter->SetInput(0, m_CalibPointsImage);
   psWriter->SetInput(1, m_CalibPointsTool);
   psWriter->SetInput(2, m_EvalPointsImage);
   psWriter->SetInput(3, m_EvalPointsTool);
   psWriter->SetInput(4, m_EvalPointsProjected);
   psWriter->SetFileName(filename.toStdString() + ".xml");
   psWriter->Write();
   */
 
   // TODO: New writer for transformations must be implemented.
   /*
   mitk::TransformationFileWriter::Pointer tWriter = mitk::TransformationFileWriter::New();
   tWriter->SetInput(0, m_CalibPointsImage);
   tWriter->SetInput(1, m_CalibPointsTool);
   tWriter->SetInput(2, m_EvalPointsImage);
   tWriter->SetInput(3, m_EvalPointsTool);
   tWriter->SetInput(4, m_EvalPointsProjected);
   tWriter->SetOutputFilename(filename.toStdString() + ".txt");
   tWriter->DoWrite(this->m_Transformation);
   */
 }
 
 void QmitkUltrasoundCalibration::OnSaveCalibration()
 {
   m_Controls.m_GotCalibrationLabel->setText("");
   QString filename =
     QFileDialog::getSaveFileName(QApplication::activeWindow(), "Save Calibration", "", "Calibration files *.cal");
 
   QFile file(filename);
   if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
   {
     MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for writing.";
     return;
   }
 
   std::string calibrationSerialization = m_CombinedModality->SerializeCalibration();
 
   QTextStream outStream(&file);
   outStream << QString::fromStdString(calibrationSerialization);
 
   // save additional information
   if (m_Controls.m_saveAdditionalCalibrationLog->isChecked())
   {
     mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New();
     QString filenameScene = filename + "_mitkScene.mitk";
     mitk::NodePredicateNot::Pointer isNotHelperObject =
       mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)));
     mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = this->GetDataStorage()->GetSubset(isNotHelperObject);
     mySceneIO->SaveScene(nodesToBeSaved, this->GetDataStorage(), filenameScene.toStdString().c_str());
   }
 }
 
 void QmitkUltrasoundCalibration::OnReset()
 {
   this->ClearTemporaryMembers();
 
   if (m_Transformation.IsNull())
   {
     m_Transformation = mitk::AffineTransform3D::New();
   }
   m_Transformation->SetIdentity();
 
   if (m_Node.IsNotNull() && (m_Node->GetData() != nullptr) && (m_Node->GetData()->GetGeometry() != nullptr))
   {
     mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast<mitk::SlicedGeometry3D *>(m_Node->GetData()->GetGeometry());
     mitk::PlaneGeometry::Pointer plane = const_cast<mitk::PlaneGeometry *>(sliced3d->GetPlaneGeometry(0));
     plane->SetIndexToWorldTransform(m_Transformation);
   }
 
   QString text1 = text1.number(this->m_EvalPointsTool->GetSize());
   this->m_Controls.m_EvalLblNumTargetPoints->setText(text1);
   QString text2 = text2.number(this->m_EvalPointsProjected->GetSize());
   this->m_Controls.m_EvalLblNumProjectionPoints->setText(text2);
 }
 
 void QmitkUltrasoundCalibration::Update()
 {
   // Update Tracking Data
   std::vector<mitk::NavigationData::Pointer> *datas = new std::vector<mitk::NavigationData::Pointer>();
   datas->push_back(m_Tracker->GetOutput());
   m_Controls.m_CalibTrackingStatus->SetNavigationDatas(datas);
   m_Controls.m_CalibTrackingStatus->Refresh();
   m_Controls.m_EvalTrackingStatus->SetNavigationDatas(datas);
   m_Controls.m_EvalTrackingStatus->Refresh();
 
   m_CombinedModality->Modified();
   m_CombinedModality->Update();
 
   // Update US Image
   mitk::Image::Pointer image = m_CombinedModality->GetOutput();
   // make sure that always the current image is set to the data node
   if (image.IsNotNull() && m_Node->GetData() != image.GetPointer() && image->IsInitialized())
   {
     m_Node->SetData(image);
   }
 
   // Update Needle Projection
   m_NeedleProjectionFilter->Update();
 
   // only update 2d window because it is faster
   this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS);
 }
 
 void QmitkUltrasoundCalibration::SwitchFreeze()
 {
   m_Controls.m_CalibBtnAddPoint->setEnabled(false); // generally deactivate
   // We use the activity state of the timer to determine whether we are currently viewing images
   if (!m_Timer->isActive()) // Activate Imaging
   {
     // if (m_Node) m_Node->ReleaseData();
     if (m_CombinedModality.IsNull())
     {
       m_Timer->stop();
       return;
     }
 
     m_CombinedModality->Update();
     m_Image = m_CombinedModality->GetOutput();
     if (m_Image.IsNotNull() && m_Image->IsInitialized())
     {
       m_Node->SetData(m_Image);
     }
 
     std::vector<mitk::NavigationData::Pointer> datas;
     datas.push_back(m_Tracker->GetOutput());
     m_Controls.m_CalibTrackingStatus->SetNavigationDatas(&datas);
     m_Controls.m_CalibTrackingStatus->ShowStatusLabels();
     m_Controls.m_CalibTrackingStatus->Refresh();
 
     m_Controls.m_EvalTrackingStatus->SetNavigationDatas(&datas);
     m_Controls.m_EvalTrackingStatus->ShowStatusLabels();
     m_Controls.m_EvalTrackingStatus->Refresh();
 
     int interval = 40;
     m_Timer->setInterval(interval);
     m_Timer->start();
 
     m_CombinedModality->SetIsFreezed(false);
   }
   else if (this->m_Tracker->GetOutput(0)->IsDataValid())
   {
     // deactivate Imaging
     m_Timer->stop();
     // Remember last tracking coordinates
     m_FreezePoint = this->m_Tracker->GetOutput(0)->GetPosition();
     m_Controls.m_CalibBtnAddPoint->setEnabled(true); // activate only, if valid point is set
 
     m_CombinedModality->SetIsFreezed(true);
   }
 }
 
 void QmitkUltrasoundCalibration::ShowNeedlePath()
 {
   // Init Filter
   this->m_NeedleProjectionFilter->SelectInput(0);
 
   // Create Node for Pointset
   mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path");
   if (node.IsNull())
   {
     node = mitk::DataNode::New();
     node->SetName("Needle Path");
     node->SetData(m_NeedleProjectionFilter->GetProjection());
     node->SetBoolProperty("show contour", true);
     this->GetDataStorage()->Add(node);
   }
 }
 
 void QmitkUltrasoundCalibration::ClearTemporaryMembers()
 {
   m_CalibPointsTool->Clear();
   m_CalibPointsImage->Clear();
   m_CalibPointsCount = 0;
 
   m_EvalPointsImage->Clear();
   m_EvalPointsTool->Clear();
   m_EvalPointsProjected->Clear();
 
   this->m_Controls.m_CalibPointList->clear();
 
   m_SpacingPoints->Clear();
   m_Controls.m_SpacingPointsList->clear();
   m_SpacingPointsCount = 0;
 }
 
 vtkSmartPointer<vtkPolyData> QmitkUltrasoundCalibration::ConvertPointSetToVtkPolyData(mitk::PointSet::Pointer PointSet)
 {
   vtkSmartPointer<vtkPolyData> returnValue = vtkSmartPointer<vtkPolyData>::New();
   vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
   for (int i = 0; i < PointSet->GetSize(); i++)
   {
     double point[3] = {PointSet->GetPoint(i)[0], PointSet->GetPoint(i)[1], PointSet->GetPoint(i)[2]};
     points->InsertNextPoint(point);
   }
   vtkSmartPointer<vtkPolyData> temp = vtkSmartPointer<vtkPolyData>::New();
   temp->SetPoints(points);
 
   vtkSmartPointer<vtkVertexGlyphFilter> vertexFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New();
   vertexFilter->SetInputData(temp);
   vertexFilter->Update();
 
   returnValue->ShallowCopy(vertexFilter->GetOutput());
 
   return returnValue;
 }
 
 double QmitkUltrasoundCalibration::ComputeFRE(mitk::PointSet::Pointer imageFiducials,
                                               mitk::PointSet::Pointer realWorldFiducials,
                                               vtkSmartPointer<vtkLandmarkTransform> transform)
 {
   if (imageFiducials->GetSize() != realWorldFiducials->GetSize())
     return -1;
   double FRE = 0;
   for (int i = 0; i < imageFiducials->GetSize(); ++i)
   {
     itk::Point<double> current_image_fiducial_point = imageFiducials->GetPoint(i);
     if (transform != nullptr)
     {
       current_image_fiducial_point = transform->TransformPoint(
         imageFiducials->GetPoint(i)[0], imageFiducials->GetPoint(i)[1], imageFiducials->GetPoint(i)[2]);
     }
     double cur_error_squared = current_image_fiducial_point.SquaredEuclideanDistanceTo(realWorldFiducials->GetPoint(i));
     FRE += cur_error_squared;
   }
 
   FRE = sqrt(FRE / (double)imageFiducials->GetSize());
 
   return FRE;
 }
 
 void QmitkUltrasoundCalibration::ApplyTransformToPointSet(mitk::PointSet::Pointer pointSet,
                                                           vtkSmartPointer<vtkAbstractTransform> transform)
 {
   for (int i = 0; i < pointSet->GetSize(); ++i)
   {
     itk::Point<double> current_point_transformed = itk::Point<double>();
     current_point_transformed =
       transform->TransformPoint(pointSet->GetPoint(i)[0], pointSet->GetPoint(i)[1], pointSet->GetPoint(i)[2]);
     pointSet->SetPoint(i, current_point_transformed);
   }
 }
 
 void QmitkUltrasoundCalibration::OnFreezeClicked()
 {
   if (m_CombinedModality.IsNull())
   {
     return;
   }
 
   if (m_CombinedModality->GetIsFreezed())
   {
     // device was already frozen so we need to delete all spacing points because they need to be collected all at once
     // no need to check if all four points are already collected, because if that's the case you can no longer click the
     // Freeze button
     m_SpacingPoints->Clear();
     m_Controls.m_SpacingPointsList->clear();
     m_SpacingPointsCount = 0;
     m_Controls.m_SpacingAddPoint->setEnabled(false);
   }
   else
   {
     m_Controls.m_SpacingAddPoint->setEnabled(true);
   }
   SwitchFreeze();
 }
 
 void QmitkUltrasoundCalibration::OnAddSpacingPoint()
 {
   mitk::Point3D point = this->GetRenderWindowPart()->GetSelectedPosition();
 
   this->m_SpacingPoints->InsertPoint(m_SpacingPointsCount, point);
 
   QString text = text.number(m_SpacingPointsCount + 1);
   text = "Point " + text;
 
   this->m_Controls.m_SpacingPointsList->addItem(text);
 
   m_SpacingPointsCount++;
 
   if (m_SpacingPointsCount == 4) // now we have all 4 points needed
   {
     m_Controls.m_SpacingAddPoint->setEnabled(false);
     m_Controls.m_CalculateSpacing->setEnabled(true);
     m_Controls.m_SpacingBtnFreeze->setEnabled(false);
   }
 }
 
 void QmitkUltrasoundCalibration::OnCalculateSpacing()
 {
   mitk::Point3D horizontalOne = m_SpacingPoints->GetPoint(0);
   mitk::Point3D horizontalTwo = m_SpacingPoints->GetPoint(1);
   mitk::Point3D verticalOne = m_SpacingPoints->GetPoint(2);
   mitk::Point3D verticalTwo = m_SpacingPoints->GetPoint(3);
 
   // Get the distances between the points in the image
   double xDistance = horizontalOne.EuclideanDistanceTo(horizontalTwo);
   double yDistance = verticalOne.EuclideanDistanceTo(verticalTwo);
 
   // Calculate the spacing of the image and fill a vector with it
   double xSpacing = 30 / xDistance;
   double ySpacing = 20 / yDistance;
 
   m_CombinedModality->GetUltrasoundDevice()->SetSpacing(xSpacing, ySpacing);
 
   // Now that the spacing is set clear all stuff and return to Calibration
   m_SpacingPoints->Clear();
   m_Controls.m_SpacingPointsList->clear();
   m_SpacingPointsCount = 0;
   m_CombinedModality->SetIsFreezed(false);
 }
 
 void QmitkUltrasoundCalibration::OnUSDepthChanged(const std::string &key, const std::string &)
 {
   // whenever depth of USImage is changed the spacing should no longer be overwritten
   if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH)
   {
   }
 }
diff --git a/SuperBuild.cmake b/SuperBuild.cmake
index fca770edd6..0f794fd45f 100644
--- a/SuperBuild.cmake
+++ b/SuperBuild.cmake
@@ -1,504 +1,505 @@
 #-----------------------------------------------------------------------------
 # Convenient macro allowing to download a file
 #-----------------------------------------------------------------------------
 
 if(NOT MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL)
   set(MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL http://mitk.org/download/thirdparty)
 endif()
 
 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()
 
 #-----------------------------------------------------------------------------
 # MITK Prerequisites
 #-----------------------------------------------------------------------------
 
 if(UNIX AND NOT APPLE)
 
   include(mitkFunctionCheckPackageHeader)
 
   # Check for libxt-dev
   mitkFunctionCheckPackageHeader(StringDefs.h libxt-dev /usr/include/X11/)
 
   # Check for libtiff4-dev
   mitkFunctionCheckPackageHeader(tiff.h libtiff4-dev)
 
 endif()
 
 # We need a proper patch program. On Linux and MacOS, we assume
 # that "patch" is available. On Windows, we download patch.exe
 # if not patch program is found.
 find_program(PATCH_COMMAND patch)
 if((NOT PATCH_COMMAND OR NOT EXISTS ${PATCH_COMMAND}) AND WIN32)
   downloadFile(${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/patch.exe
                ${CMAKE_CURRENT_BINARY_DIR}/patch.exe)
   find_program(PATCH_COMMAND patch ${CMAKE_CURRENT_BINARY_DIR})
 endif()
 if(NOT PATCH_COMMAND)
   message(FATAL_ERROR "No patch program found.")
 endif()
 
 #-----------------------------------------------------------------------------
 # ExternalProjects
 #-----------------------------------------------------------------------------
 
 get_property(external_projects GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS)
 
 if(MITK_CTEST_SCRIPT_MODE)
   # Write a file containing the list of enabled external project targets.
   # This file can be read by a ctest script to separately build projects.
   set(SUPERBUILD_TARGETS )
   foreach(proj ${external_projects})
     if(MITK_USE_${proj})
       list(APPEND SUPERBUILD_TARGETS ${proj})
     endif()
   endforeach()
   file(WRITE "${CMAKE_BINARY_DIR}/SuperBuildTargets.cmake" "set(SUPERBUILD_TARGETS ${SUPERBUILD_TARGETS})")
 endif()
 
 # A list of "nice" external projects, playing well together with CMake
 set(nice_external_projects ${external_projects})
 list(REMOVE_ITEM nice_external_projects Boost)
 foreach(proj ${nice_external_projects})
   if(MITK_USE_${proj})
     set(EXTERNAL_${proj}_DIR "${${proj}_DIR}" CACHE PATH "Path to ${proj} build directory")
     mark_as_advanced(EXTERNAL_${proj}_DIR)
     if(EXTERNAL_${proj}_DIR)
       set(${proj}_DIR ${EXTERNAL_${proj}_DIR})
     endif()
   endif()
 endforeach()
 
 set(EXTERNAL_BOOST_ROOT "${BOOST_ROOT}" CACHE PATH "Path to Boost directory")
 mark_as_advanced(EXTERNAL_BOOST_ROOT)
 if(EXTERNAL_BOOST_ROOT)
   set(BOOST_ROOT ${EXTERNAL_BOOST_ROOT})
 endif()
 
 # Setup file for setting custom ctest vars
 configure_file(
   CMake/SuperbuildCTestCustom.cmake.in
   ${MITK_BINARY_DIR}/CTestCustom.cmake
   @ONLY
 )
 
 if(BUILD_TESTING)
   set(EXTERNAL_MITK_DATA_DIR "${MITK_DATA_DIR}" CACHE PATH "Path to the MITK data directory")
   mark_as_advanced(EXTERNAL_MITK_DATA_DIR)
   if(EXTERNAL_MITK_DATA_DIR)
     set(MITK_DATA_DIR ${EXTERNAL_MITK_DATA_DIR})
   endif()
 endif()
 
 #-----------------------------------------------------------------------------
 # External project settings
 #-----------------------------------------------------------------------------
 
 include(ExternalProject)
 include(mitkMacroQueryCustomEPVars)
 include(mitkFunctionInstallExternalCMakeProject)
 include(mitkFunctionCleanExternalProject)
 
 option(MITK_AUTOCLEAN_EXTERNAL_PROJECTS "Experimental: Clean external project builds if updated" OFF)
 mark_as_advanced(MITK_AUTOCLEAN_EXTERNAL_PROJECTS)
 
 set(ep_prefix "${CMAKE_BINARY_DIR}/ep")
 set_property(DIRECTORY PROPERTY EP_PREFIX ${ep_prefix})
 
 # Compute -G arg for configuring external projects with the same CMake generator:
 if(CMAKE_EXTRA_GENERATOR)
   set(gen "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
 else()
   set(gen "${CMAKE_GENERATOR}")
 endif()
 
 set(gen_platform ${CMAKE_GENERATOR_PLATFORM})
 
 # Use this value where semi-colons are needed in ep_add args:
 set(sep "^^")
 
 ##
 
 if(MSVC_VERSION)
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /bigobj /MP")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /MP")
 endif()
 
 if(MITK_USE_Boost_LIBRARIES)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_ALL_DYN_LINK")
 endif()
 
 # This is a workaround for passing linker flags
 # actually down to the linker invocation
 set(_cmake_required_flags_orig ${CMAKE_REQUIRED_FLAGS})
 set(CMAKE_REQUIRED_FLAGS "-Wl,-rpath")
 mitkFunctionCheckCompilerFlags(${CMAKE_REQUIRED_FLAGS} _has_rpath_flag)
 set(CMAKE_REQUIRED_FLAGS ${_cmake_required_flags_orig})
 
 set(_install_rpath_linkflag )
 if(_has_rpath_flag)
   if(APPLE)
     set(_install_rpath_linkflag "-Wl,-rpath,@loader_path/../lib")
   else()
     set(_install_rpath_linkflag "-Wl,-rpath='$ORIGIN/../lib'")
   endif()
 endif()
 
 set(_install_rpath)
 if(APPLE)
   set(_install_rpath "@loader_path/../lib")
 elseif(UNIX)
   # this work for libraries as well as executables
   set(_install_rpath "\$ORIGIN/../lib")
 endif()
 
 set(ep_common_args
   -DCMAKE_CXX_EXTENSIONS:STRING=${CMAKE_CXX_EXTENSIONS}
   -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD}
   -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=${CMAKE_CXX_STANDARD_REQUIRED}
   -DCMAKE_MACOSX_RPATH:BOOL=TRUE
   "-DCMAKE_INSTALL_RPATH:STRING=${_install_rpath}"
   -DBUILD_TESTING:BOOL=OFF
   -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
   -DBUILD_SHARED_LIBS:BOOL=ON
   -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
   -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
   -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
   -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
   "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${MITK_CXX14_FLAG}"
   #debug flags
   -DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG}
   -DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG}
   #release flags
   -DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}
   -DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}
   #relwithdebinfo
   -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_CXX_FLAGS_RELWITHDEBINFO}
   -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_C_FLAGS_RELWITHDEBINFO}
   #link flags
   -DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}
   -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}
   -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS}
 )
 
 if(MSVC_VERSION)
   list(APPEND ep_common_args
     -DCMAKE_DEBUG_POSTFIX:STRING=d
   )
 
   set(DCMTK_CMAKE_DEBUG_POSTFIX d)
 endif()
 
 set(ep_common_cache_args
 )
 
 set(ep_common_cache_default_args
   "-DCMAKE_PREFIX_PATH:PATH=<INSTALL_DIR>;${CMAKE_PREFIX_PATH}"
   "-DCMAKE_INCLUDE_PATH:PATH=${CMAKE_INCLUDE_PATH}"
   "-DCMAKE_LIBRARY_PATH:PATH=${CMAKE_LIBRARY_PATH}"
 )
 
 # Pass the CMAKE_OSX variables to external projects
 if(APPLE)
   set(MAC_OSX_ARCHITECTURE_ARGS
         -DCMAKE_OSX_ARCHITECTURES:PATH=${CMAKE_OSX_ARCHITECTURES}
         -DCMAKE_OSX_DEPLOYMENT_TARGET:PATH=${CMAKE_OSX_DEPLOYMENT_TARGET}
         -DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT}
   )
   set(ep_common_args
         ${MAC_OSX_ARCHITECTURE_ARGS}
         ${ep_common_args}
   )
 endif()
 
 set(mitk_superbuild_ep_args)
 set(mitk_depends )
 
 # Include external projects
 include(CMakeExternals/MITKData.cmake)
 foreach(p ${external_projects})
   set(p_hash "")
 
   set(p_file "${CMAKE_SOURCE_DIR}/CMakeExternals/${p}.cmake")
   if(EXISTS ${p_file})
     file(MD5 ${p_file} p_hash)
   else()
     foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS})
       get_filename_component(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIR} ABSOLUTE)
       set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMakeExternals)
       set(p_file "${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/${p}.cmake")
       if(EXISTS ${p_file})
         file(MD5 ${p_file} p_hash)
         break()
       endif()
     endforeach()
   endif()
 
   if(p_hash)
     set(p_hash_file "${ep_prefix}/tmp/${p}-hash.txt")
     if(MITK_AUTOCLEAN_EXTERNAL_PROJECTS)
       if(EXISTS ${p_hash_file})
         file(READ ${p_hash_file} p_prev_hash)
         if(NOT p_hash STREQUAL p_prev_hash)
           mitkCleanExternalProject(${p})
         endif()
       endif()
     endif()
     file(WRITE ${p_hash_file} ${p_hash})
   endif()
 
   include(${p_file} OPTIONAL)
 
   list(APPEND mitk_superbuild_ep_args
        -DMITK_USE_${p}:BOOL=${MITK_USE_${p}}
       )
   get_property(_package GLOBAL PROPERTY MITK_${p}_PACKAGE)
   if(_package)
     list(APPEND mitk_superbuild_ep_args -D${p}_DIR:PATH=${${p}_DIR})
   endif()
 
   list(APPEND mitk_depends ${${p}_DEPENDS})
 endforeach()
 if (SWIG_EXECUTABLE)
   list(APPEND mitk_superbuild_ep_args -DSWIG_EXECUTABLE=${SWIG_EXECUTABLE})
 endif()
 
 #-----------------------------------------------------------------------------
 # Set superbuild boolean args
 #-----------------------------------------------------------------------------
 
 set(mitk_cmake_boolean_args
   BUILD_SHARED_LIBS
   WITH_COVERAGE
   BUILD_TESTING
   MITK_BUILD_ALL_PLUGINS
   MITK_BUILD_ALL_APPS
   MITK_BUILD_EXAMPLES
   MITK_USE_Qt5
   MITK_USE_SYSTEM_Boost
   MITK_USE_BLUEBERRY
   MITK_USE_OpenCL
   MITK_USE_OpenMP
   MITK_ENABLE_PIC_READER
   )
 
 #-----------------------------------------------------------------------------
 # Create the final variable containing superbuild boolean args
 #-----------------------------------------------------------------------------
 
 set(mitk_superbuild_boolean_args)
 foreach(mitk_cmake_arg ${mitk_cmake_boolean_args})
   list(APPEND mitk_superbuild_boolean_args -D${mitk_cmake_arg}:BOOL=${${mitk_cmake_arg}})
 endforeach()
 
 if(MITK_BUILD_ALL_PLUGINS)
   list(APPEND mitk_superbuild_boolean_args -DBLUEBERRY_BUILD_ALL_PLUGINS:BOOL=ON)
 endif()
 
 #-----------------------------------------------------------------------------
 # MITK Utilities
 #-----------------------------------------------------------------------------
 
 set(proj MITK-Utilities)
 ExternalProject_Add(${proj}
   DOWNLOAD_COMMAND ""
   CONFIGURE_COMMAND ""
   BUILD_COMMAND ""
   INSTALL_COMMAND ""
   DEPENDS
     ${mitk_depends}
 )
 #-----------------------------------------------------------------------------
 # Additional MITK CXX/C Flags
 #-----------------------------------------------------------------------------
 
 set(MITK_ADDITIONAL_C_FLAGS "" CACHE STRING "Additional C Flags for MITK")
 set(MITK_ADDITIONAL_C_FLAGS_RELEASE "" CACHE STRING "Additional Release C Flags for MITK")
 set(MITK_ADDITIONAL_C_FLAGS_DEBUG "" CACHE STRING "Additional Debug C Flags for MITK")
 mark_as_advanced(MITK_ADDITIONAL_C_FLAGS MITK_ADDITIONAL_C_FLAGS_DEBUG MITK_ADDITIONAL_C_FLAGS_RELEASE)
 
 set(MITK_ADDITIONAL_CXX_FLAGS "" CACHE STRING "Additional CXX Flags for MITK")
 set(MITK_ADDITIONAL_CXX_FLAGS_RELEASE "" CACHE STRING "Additional Release CXX Flags for MITK")
 set(MITK_ADDITIONAL_CXX_FLAGS_DEBUG "" CACHE STRING "Additional Debug CXX Flags for MITK")
 mark_as_advanced(MITK_ADDITIONAL_CXX_FLAGS MITK_ADDITIONAL_CXX_FLAGS_DEBUG MITK_ADDITIONAL_CXX_FLAGS_RELEASE)
 
 set(MITK_ADDITIONAL_EXE_LINKER_FLAGS "" CACHE STRING "Additional exe linker flags for MITK")
 set(MITK_ADDITIONAL_SHARED_LINKER_FLAGS "" CACHE STRING "Additional shared linker flags for MITK")
 set(MITK_ADDITIONAL_MODULE_LINKER_FLAGS "" CACHE STRING "Additional module linker flags for MITK")
 mark_as_advanced(MITK_ADDITIONAL_EXE_LINKER_FLAGS MITK_ADDITIONAL_SHARED_LINKER_FLAGS MITK_ADDITIONAL_MODULE_LINKER_FLAGS)
 
 #-----------------------------------------------------------------------------
 # MITK Configure
 #-----------------------------------------------------------------------------
 
 if(MITK_INITIAL_CACHE_FILE)
   set(mitk_initial_cache_arg -C "${MITK_INITIAL_CACHE_FILE}")
 endif()
 
 set(mitk_optional_cache_args )
 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()
 
 # Optional python variables
 if(MITK_USE_Python3)
   list(APPEND mitk_optional_cache_args
        -DMITK_USE_Python3:BOOL=${MITK_USE_Python3}
        "-DPython3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE}"
        "-DPython3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIRS}"
        "-DPython3_LIBRARY:FILEPATH=${Python3_LIBRARY}"
        "-DPython3_STDLIB:FILEPATH=${Python3_STDLIB}"
        "-DPython3_SITELIB:FILEPATH=${Python3_SITELIB}"
       )
 endif()
 
 if(OPENSSL_ROOT_DIR)
   list(APPEND mitk_optional_cache_args
     "-DOPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR}"
   )
 endif()
 
 if(CMAKE_FRAMEWORK_PATH)
   list(APPEND mitk_optional_cache_args
     "-DCMAKE_FRAMEWORK_PATH:PATH=${CMAKE_FRAMEWORK_PATH}"
   )
 endif()
 
 if(Eigen_INCLUDE_DIR)
     list(APPEND mitk_optional_cache_args
       -DEigen_INCLUDE_DIR:PATH=${Eigen_INCLUDE_DIR}
     )
 endif()
 
 # Optional pass through of Doxygen
 if(DOXYGEN_EXECUTABLE)
   list(APPEND mitk_optional_cache_args
        -DDOXYGEN_EXECUTABLE:FILEPATH=${DOXYGEN_EXECUTABLE}
   )
 endif()
 
 set(proj MITK-Configure)
 
 ExternalProject_Add(${proj}
   LIST_SEPARATOR ${sep}
   DOWNLOAD_COMMAND ""
   CMAKE_GENERATOR ${gen}
   CMAKE_GENERATOR_PLATFORM ${gen_platform}
   CMAKE_CACHE_ARGS
     # --------------- Build options ----------------
     -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX}
     -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
     "-DCMAKE_PREFIX_PATH:PATH=${ep_prefix};${CMAKE_PREFIX_PATH}"
     "-DCMAKE_LIBRARY_PATH:PATH=${CMAKE_LIBRARY_PATH}"
     "-DCMAKE_INCLUDE_PATH:PATH=${CMAKE_INCLUDE_PATH}"
     # --------------- Compile options ----------------
     -DCMAKE_CXX_EXTENSIONS:STRING=${CMAKE_CXX_EXTENSIONS}
     -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD}
     -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=${CMAKE_CXX_STANDARD_REQUIRED}
     -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
     -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
     "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${MITK_ADDITIONAL_C_FLAGS}"
     "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${MITK_ADDITIONAL_CXX_FLAGS}"
     # debug flags
     "-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} ${MITK_ADDITIONAL_CXX_FLAGS_DEBUG}"
     "-DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG} ${MITK_ADDITIONAL_C_FLAGS_DEBUG}"
     # release flags
     "-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE} ${MITK_ADDITIONAL_CXX_FLAGS_RELEASE}"
     "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE} ${MITK_ADDITIONAL_C_FLAGS_RELEASE}"
     # relwithdebinfo
     -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_CXX_FLAGS_RELWITHDEBINFO}
     -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_C_FLAGS_RELWITHDEBINFO}
     # link flags
     "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} ${MITK_ADDITIONAL_EXE_LINKER_FLAGS}"
     "-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} ${MITK_ADDITIONAL_SHARED_LINKER_FLAGS}"
     "-DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS} ${MITK_ADDITIONAL_MODULE_LINKER_FLAGS}"
     # Output directories
     -DMITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY}
     -DMITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}
     -DMITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY}
     # ------------- Boolean build options --------------
     ${mitk_superbuild_boolean_args}
     ${mitk_optional_cache_args}
     -DMITK_USE_SUPERBUILD:BOOL=OFF
     -DMITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION}
     -DMITK_FAST_TESTING:BOOL=${MITK_FAST_TESTING}
     -DMITK_XVFB_TESTING:BOOL=${MITK_XVFB_TESTING}
+    -DMITK_XVFB_TESTING_COMMAND:BOOL=${MITK_XVFB_TESTING_COMMAND}
     -DCTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS}
     # ----------------- Miscellaneous ---------------
     -DCMAKE_LIBRARY_PATH:PATH=${CMAKE_LIBRARY_PATH}
     -DCMAKE_INCLUDE_PATH:PATH=${CMAKE_INCLUDE_PATH}
     -DMITK_CTEST_SCRIPT_MODE:STRING=${MITK_CTEST_SCRIPT_MODE}
     -DMITK_SUPERBUILD_BINARY_DIR:PATH=${MITK_BINARY_DIR}
     -DMITK_MODULES_TO_BUILD:INTERNAL=${MITK_MODULES_TO_BUILD}
     -DMITK_WHITELIST:STRING=${MITK_WHITELIST}
     -DMITK_WHITELISTS_EXTERNAL_PATH:STRING=${MITK_WHITELISTS_EXTERNAL_PATH}
     -DMITK_WHITELISTS_INTERNAL_PATH:STRING=${MITK_WHITELISTS_INTERNAL_PATH}
     -DMITK_EXTENSION_DIRS:STRING=${MITK_EXTENSION_DIRS}
     -DMITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES}
     -DMITK_ACCESSBYITK_FLOATING_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES}
     -DMITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES}
     -DMITK_ACCESSBYITK_VECTOR_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}
     -DMITK_ACCESSBYITK_DIMENSIONS:STRING=${MITK_ACCESSBYITK_DIMENSIONS}
     -DMITK_CUSTOM_REVISION_DESC:STRING=${MITK_CUSTOM_REVISION_DESC}
     # --------------- External project options ---------------
     -DMITK_DATA_DIR:PATH=${MITK_DATA_DIR}
     -DMITK_EXTERNAL_PROJECT_PREFIX:PATH=${ep_prefix}
     -DCppMicroServices_DIR:PATH=${CppMicroServices_DIR}
     -DDCMTK_CMAKE_DEBUG_POSTFIX:STRING=${DCMTK_CMAKE_DEBUG_POSTFIX}
     -DBOOST_ROOT:PATH=${BOOST_ROOT}
     -DBOOST_LIBRARYDIR:PATH=${BOOST_LIBRARYDIR}
     -DMITK_USE_Boost_LIBRARIES:STRING=${MITK_USE_Boost_LIBRARIES}
     -DQt5_DIR:PATH=${Qt5_DIR}
   CMAKE_ARGS
     ${mitk_initial_cache_arg}
     ${MAC_OSX_ARCHITECTURE_ARGS}
     ${mitk_superbuild_ep_args}
   SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
   BINARY_DIR ${CMAKE_BINARY_DIR}/MITK-build
   BUILD_COMMAND ""
   INSTALL_COMMAND ""
   DEPENDS
     MITK-Utilities
   )
 
 mitkFunctionInstallExternalCMakeProject(${proj})
 
 #-----------------------------------------------------------------------------
 # MITK
 #-----------------------------------------------------------------------------
 
 if(CMAKE_GENERATOR MATCHES ".*Makefiles.*")
   set(mitk_build_cmd "$(MAKE)")
 else()
   set(mitk_build_cmd ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/MITK-build --config ${CMAKE_CFG_INTDIR})
 endif()
 
 if(NOT DEFINED SUPERBUILD_EXCLUDE_MITKBUILD_TARGET OR NOT SUPERBUILD_EXCLUDE_MITKBUILD_TARGET)
   set(MITKBUILD_TARGET_ALL_OPTION "ALL")
 else()
   set(MITKBUILD_TARGET_ALL_OPTION "")
 endif()
 
 add_custom_target(MITK-build ${MITKBUILD_TARGET_ALL_OPTION}
   COMMAND ${mitk_build_cmd}
   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/MITK-build
   DEPENDS MITK-Configure
   )
 
 #-----------------------------------------------------------------------------
 # Custom target allowing to drive the build of the MITK project itself
 #-----------------------------------------------------------------------------
 
 add_custom_target(MITK
   COMMAND ${mitk_build_cmd}
   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/MITK-build
 )