diff --git a/Applications/PluginGenerator/ProjectTemplate/CMakeExternals/MITK.cmake b/Applications/PluginGenerator/ProjectTemplate/CMakeExternals/MITK.cmake index 43155e16cd..60fd693999 100644 --- a/Applications/PluginGenerator/ProjectTemplate/CMakeExternals/MITK.cmake +++ b/Applications/PluginGenerator/ProjectTemplate/CMakeExternals/MITK.cmake @@ -1,211 +1,211 @@ #----------------------------------------------------------------------------- # MITK #----------------------------------------------------------------------------- set(MITK_DEPENDS) set(proj_DEPENDENCIES) set(proj MITK) if(NOT MITK_DIR) #----------------------------------------------------------------------------- # Create CMake options to customize the MITK build #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Use superbuild for MITK" ON) option(MITK_USE_BLUEBERRY "Build the BlueBerry platform in MITK" ON) option(MITK_BUILD_EXAMPLES "Build the MITK examples" OFF) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) option(MITK_BUILD_TESTING "Build the MITK unit tests" OFF) - option(MITK_USE_ACVD "Use Approximated Centroidal Voronoi Diagrams" OFF) + option(MITK_USE_OpenMesh "" OFF) option(MITK_USE_CTK "Use CTK in MITK" ${MITK_USE_BLUEBERRY}) option(MITK_USE_DCMTK "Use DCMTK in MITK" ON) option(MITK_USE_Qt5 "Use Qt 5 library in MITK" ON) option(MITK_USE_DCMQI "Use dcmqi in MITK" OFF) option(MITK_USE_OpenCV "Use Intel's OpenCV library" OFF) option(MITK_USE_Python3 "Enable Python wrapping in MITK" OFF) if(MITK_USE_BLUEBERRY AND 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() if(MITK_USE_CTK AND NOT MITK_USE_Qt5) message("Forcing MITK_USE_Qt5 to ON because of MITK_USE_CTK") set(MITK_USE_Qt5 ON CACHE BOOL "Use Qt 5 library in MITK" FORCE) endif() set(MITK_USE_CableSwig ${MITK_USE_Python3}) set(MITK_USE_GDCM 1) set(MITK_USE_ITK 1) set(MITK_USE_VTK 1) mark_as_advanced(MITK_USE_SUPERBUILD MITK_BUILD_ALL_PLUGINS MITK_BUILD_TESTING ) set(mitk_cmake_boolean_args MITK_USE_SUPERBUILD MITK_USE_BLUEBERRY MITK_BUILD_EXAMPLES MITK_BUILD_ALL_PLUGINS - MITK_USE_ACVD + MITK_USE_OpenMesh MITK_USE_CTK MITK_USE_DCMTK MITK_USE_Qt5 MITK_USE_DCMQI MITK_USE_OpenCV MITK_USE_Python3 ) if(MITK_USE_Qt5) # Look for Qt at the superbuild level, to catch missing Qt libs early find_package(Qt5Widgets REQUIRED) endif() set(additional_mitk_cmakevars ) # Configure the set of default 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") 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 "" 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") foreach(_arg MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS) mark_as_advanced(${_arg}) list(APPEND additional_mitk_cmakevars "-D${_arg}:STRING=${${_arg}}") endforeach() #----------------------------------------------------------------------------- # Create options to inject pre-build dependencies #----------------------------------------------------------------------------- - foreach(proj CTK DCMTK DCMQI GDCM VTK ACVD ITK OpenCV CableSwig) + foreach(proj CTK DCMTK DCMQI GDCM VTK OpenMesh ITK OpenCV CableSwig) if(MITK_USE_${proj}) set(MITK_${proj}_DIR "${${proj}_DIR}" CACHE PATH "Path to ${proj} build directory") mark_as_advanced(MITK_${proj}_DIR) if(MITK_${proj}_DIR) list(APPEND additional_mitk_cmakevars "-D${proj}_DIR:PATH=${MITK_${proj}_DIR}") endif() endif() endforeach() set(MITK_BOOST_ROOT "${BOOST_ROOT}" CACHE PATH "Path to Boost directory") mark_as_advanced(MITK_BOOST_ROOT) if(MITK_BOOST_ROOT) list(APPEND additional_mitk_cmakevars "-DBOOST_ROOT:PATH=${MITK_BOOST_ROOT}") endif() set(MITK_SOURCE_DIR "" CACHE PATH "MITK source code location. If empty, MITK will be cloned from MITK_GIT_REPOSITORY") set(MITK_GIT_REPOSITORY "https://phabricator.mitk.org/source/mitk.git" CACHE STRING "The git repository for cloning MITK") set(MITK_GIT_TAG "origin/master" CACHE STRING "The git tag/hash to be used when cloning from MITK_GIT_REPOSITORY") mark_as_advanced(MITK_SOURCE_DIR MITK_GIT_REPOSITORY MITK_GIT_TAG) #----------------------------------------------------------------------------- # Create the final variable containing superbuild boolean args #----------------------------------------------------------------------------- set(mitk_boolean_args) foreach(mitk_cmake_arg ${mitk_cmake_boolean_args}) list(APPEND mitk_boolean_args -D${mitk_cmake_arg}:BOOL=${${mitk_cmake_arg}}) endforeach() #----------------------------------------------------------------------------- # Additional MITK CMake variables #----------------------------------------------------------------------------- if(MITK_USE_Qt5) list(APPEND additional_mitk_cmakevars "-DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH}") endif() if(MITK_USE_CTK) list(APPEND additional_mitk_cmakevars "-DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE}") endif() if(MITK_INITIAL_CACHE_FILE) list(APPEND additional_mitk_cmakevars "-DMITK_INITIAL_CACHE_FILE:INTERNAL=${MITK_INITIAL_CACHE_FILE}") endif() if(MITK_USE_SUPERBUILD) set(MITK_BINARY_DIR ${proj}-superbuild) else() set(MITK_BINARY_DIR ${proj}-build) endif() set(proj_DEPENDENCIES) set(MITK_DEPENDS ${proj}) # Configure the MITK souce code location if(NOT MITK_SOURCE_DIR) set(mitk_source_location SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj} GIT_REPOSITORY ${MITK_GIT_REPOSITORY} GIT_TAG ${MITK_GIT_TAG} ) else() set(mitk_source_location SOURCE_DIR ${MITK_SOURCE_DIR} ) endif() ExternalProject_Add(${proj} ${mitk_source_location} BINARY_DIR ${MITK_BINARY_DIR} PREFIX ${proj}${ep_suffix} INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${mitk_boolean_args} ${additional_mitk_cmakevars} -DBUILD_SHARED_LIBS:BOOL=ON -DBUILD_TESTING:BOOL=${MITK_BUILD_TESTING} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) if(MITK_USE_SUPERBUILD) set(MITK_DIR "${CMAKE_CURRENT_BINARY_DIR}/${MITK_BINARY_DIR}/MITK-build") else() set(MITK_DIR "${CMAKE_CURRENT_BINARY_DIR}/${MITK_BINARY_DIR}") endif() else() # The project is provided using MITK_DIR, nevertheless since other # projects may depend on MITK, let's add an 'empty' one MacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") # Further, do some sanity checks in the case of a pre-built MITK set(my_itk_dir ${ITK_DIR}) set(my_vtk_dir ${VTK_DIR}) find_package(MITK REQUIRED) if(my_itk_dir AND NOT my_itk_dir STREQUAL ${ITK_DIR}) message(FATAL_ERROR "ITK packages do not match:\n ${MY_PROJECT_NAME}: ${my_itk_dir}\n MITK: ${ITK_DIR}") endif() if(my_vtk_dir AND NOT my_vtk_dir STREQUAL ${VTK_DIR}) message(FATAL_ERROR "VTK packages do not match:\n ${MY_PROJECT_NAME}: ${my_vtk_dir}\n MITK: ${VTK_DIR}") endif() endif() diff --git a/CMake/BuildConfigurations/Default.cmake b/CMake/BuildConfigurations/Default.cmake index 4faffa7f12..ab92d73684 100644 --- a/CMake/BuildConfigurations/Default.cmake +++ b/CMake/BuildConfigurations/Default.cmake @@ -1,23 +1,23 @@ set(MITK_CONFIG_PACKAGES - ACVD + OpenMesh Qt5 BLUEBERRY ) set(MITK_CONFIG_PLUGINS org.mitk.gui.qt.mitkworkbench.intro org.mitk.gui.qt.datamanager org.mitk.gui.qt.stdmultiwidgeteditor org.mitk.gui.qt.dicombrowser org.mitk.gui.qt.imagenavigator org.mitk.gui.qt.measurementtoolbox org.mitk.gui.qt.properties org.mitk.gui.qt.segmentation org.mitk.gui.qt.volumevisualization org.mitk.planarfigure org.mitk.gui.qt.moviemaker org.mitk.gui.qt.pointsetinteraction org.mitk.gui.qt.remeshing org.mitk.gui.qt.viewnavigator org.mitk.gui.qt.imagecropper ) diff --git a/CMake/BuildConfigurations/mitkNavigationModules.cmake b/CMake/BuildConfigurations/mitkNavigationModules.cmake index d6881034ab..5836dc8d04 100644 --- a/CMake/BuildConfigurations/mitkNavigationModules.cmake +++ b/CMake/BuildConfigurations/mitkNavigationModules.cmake @@ -1,35 +1,35 @@ message(STATUS "Configuring MITK Navigation Modules Build") set(MITK_CONFIG_PACKAGES - ACVD + OpenMesh Qt5 BLUEBERRY ) # Enable open cv and open igt link, which is a necessary configuration set(MITK_USE_OpenCV ON CACHE BOOL "MITK Use OpenCV Library" FORCE) set(MITK_USE_OpenIGTLink ON CACHE BOOL "MITK Use OpenIGTLink Library" FORCE) # Enable default plugins and the navigation modules set(MITK_CONFIG_PLUGINS org.mitk.gui.qt.datamanager org.mitk.gui.qt.stdmultiwidgeteditor org.mitk.gui.qt.dicombrowser org.mitk.gui.qt.imagenavigator org.mitk.gui.qt.measurementtoolbox org.mitk.gui.qt.properties org.mitk.gui.qt.segmentation org.mitk.gui.qt.volumevisualization org.mitk.planarfigure org.mitk.gui.qt.moviemaker org.mitk.gui.qt.pointsetinteraction org.mitk.gui.qt.registration org.mitk.gui.qt.remeshing org.mitk.gui.qt.viewnavigator org.mitk.gui.qt.imagecropper org.mitk.gui.qt.igttracking org.mitk.gui.qt.openigtlink org.mitk.gui.qt.ultrasound org.mitk.gui.qt.tofutil ) diff --git a/CMake/PackageDepends/MITK_ACVD_Config.cmake b/CMake/PackageDepends/MITK_ACVD_Config.cmake deleted file mode 100644 index 55d36d47bf..0000000000 --- a/CMake/PackageDepends/MITK_ACVD_Config.cmake +++ /dev/null @@ -1,4 +0,0 @@ -list(APPEND ALL_LIBRARIES ${ACVD_LIBRARIES}) -if(ACVD_INCLUDE_DIRS) - list(APPEND ALL_INCLUDE_DIRECTORIES ${ACVD_INCLUDE_DIRS}) -endif() diff --git a/CMake/PackageDepends/MITK_OpenMesh_Config.cmake b/CMake/PackageDepends/MITK_OpenMesh_Config.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/CMake/PackageDepends/MITK_VTK_Config.cmake b/CMake/PackageDepends/MITK_VTK_Config.cmake index e81aee00b9..f13834dd55 100644 --- a/CMake/PackageDepends/MITK_VTK_Config.cmake +++ b/CMake/PackageDepends/MITK_VTK_Config.cmake @@ -1,12 +1,8 @@ find_package(VTK COMPONENTS ${VTK_REQUIRED_COMPONENTS_BY_MODULE} REQUIRED) -if(VTK_FOUND AND NOT VTK_BUILD_SHARED_LIBS) - message(FATAL_ERROR "MITK only supports a VTK which was built with shared libraries. Turn on BUILD_SHARED_LIBS in your VTK config.") -endif() if(MITK_USE_Qt5) find_package(Qt5Widgets REQUIRED QUIET) endif() list(APPEND ALL_INCLUDE_DIRECTORIES ${VTK_INCLUDE_DIRS}) list(APPEND ALL_LIBRARIES ${VTK_LIBRARIES}) -list(APPEND ALL_COMPILE_DEFINITIONS ${VTK_DEFINITIONS}) diff --git a/CMake/mitkFunctionGetLibrarySearchPaths.cmake b/CMake/mitkFunctionGetLibrarySearchPaths.cmake index 86725d7193..21f2436c0e 100644 --- a/CMake/mitkFunctionGetLibrarySearchPaths.cmake +++ b/CMake/mitkFunctionGetLibrarySearchPaths.cmake @@ -1,213 +1,219 @@ #! Helper function that gets all library search paths. #! #! Usage: #! #! mitkFunctionGetLibrarySearchPaths(search_path intermediate_dir [DEBUG|MINSIZEREL|RELWITHDEBINFO]) #! #! #! The function creates the variable ${search_path}. The variable intermediate_dir contains #! paths that should be added to the search_path but should not be checked for existance, #! because the are not yet created. The option DEBUG, MINSIZEREL or RELWITHDEBINFO can be used to indicate that #! not the paths for release configuration are requested but the debug, min size release or "release with debug info" #! paths. #! function(mitkFunctionGetLibrarySearchPaths search_path intermediate_dir) cmake_parse_arguments(PARSE_ARGV 2 GLS "RELEASE;DEBUG;MINSIZEREL;RELWITHDEBINFO" "" "") set(_dir_candidates "${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}" "${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}/plugins" "${MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY}" "${MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY}/plugins" ) if(MITK_EXTERNAL_PROJECT_PREFIX) list(APPEND _dir_candidates "${MITK_EXTERNAL_PROJECT_PREFIX}/bin" "${MITK_EXTERNAL_PROJECT_PREFIX}/lib" ) endif() # Determine the Qt5 library installation prefix set(_qmake_location ) if(MITK_USE_Qt5 AND TARGET ${Qt5Core_QMAKE_EXECUTABLE}) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) endif() if(_qmake_location) if(NOT _qt_install_libs) if(WIN32) execute_process(COMMAND ${_qmake_location} -query QT_INSTALL_BINS OUTPUT_VARIABLE _qt_install_libs OUTPUT_STRIP_TRAILING_WHITESPACE) else() execute_process(COMMAND ${_qmake_location} -query QT_INSTALL_LIBS OUTPUT_VARIABLE _qt_install_libs OUTPUT_STRIP_TRAILING_WHITESPACE) endif() file(TO_CMAKE_PATH "${_qt_install_libs}" _qt_install_libs) set(_qt_install_libs ${_qt_install_libs} CACHE INTERNAL "Qt library installation prefix" FORCE) endif() if(_qt_install_libs) list(APPEND _dir_candidates ${_qt_install_libs}) endif() elseif(MITK_USE_Qt5) message(WARNING "The qmake executable could not be found.") endif() get_property(_additional_paths GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) if(TARGET OpenSSL::SSL) if(GLS_DEBUG) get_target_property(_openssl_location OpenSSL::SSL IMPORTED_LOCATION_DEBUG) else() get_target_property(_openssl_location OpenSSL::SSL IMPORTED_LOCATION_RELEASE) endif() if(_openssl_location) get_filename_component(_openssl_location ${_openssl_location} DIRECTORY) set(_openssl_location "${_openssl_location}/../../bin") if(EXISTS ${_openssl_location}) get_filename_component(_openssl_location ${_openssl_location} ABSOLUTE) list(APPEND _dir_candidates ${_openssl_location}) endif() endif() endif() if(MITK_USE_HDF5) FIND_PACKAGE(HDF5 COMPONENTS C HL NO_MODULE REQUIRED shared) get_target_property(_location hdf5-shared LOCATION) get_filename_component(_location ${_location} PATH) list(APPEND _additional_paths ${_location}) # This is a work-around. The hdf5-config.cmake file is not robust enough # to be included several times via find_pakcage calls. set(HDF5_LIBRARIES ${HDF5_LIBRARIES} PARENT_SCOPE) endif() if(MITK_USE_Vigra) # we cannot use _find_package(Vigra) here because the vigra-config.cmake file # always includes the target-exports files without using an include guard. This # would lead to errors when another find_package(Vigra) call is processed. The # (bad) assumption here is that for the time being, only the Classification module # is using Vigra. if(UNIX) list(APPEND _additional_paths ${Vigra_DIR}/lib) else() list(APPEND _additional_paths ${Vigra_DIR}/bin) endif() endif() if(_additional_paths) list(APPEND _dir_candidates ${_additional_paths}) endif() # The code below is sub-optimal. It makes assumptions about # the structure of the build directories, pointed to by # the *_DIR variables. Instead, we should rely on package # specific "LIBRARY_DIRS" variables, if they exist. if(WIN32) list(APPEND _dir_candidates "${ITK_DIR}/bin") endif() if(MITK_USE_MatchPoint) if(WIN32) list(APPEND _dir_candidates "${MatchPoint_DIR}/bin") else() list(APPEND _dir_candidates "${MatchPoint_DIR}/lib") endif() endif() # If OpenCV is built within the MITK superbuild set the binary directory # according to the lib path provided by OpenCV. # In the case where an external OpenCV is provided use the binary directory # of this OpenCV directory if(MITK_USE_OpenCV) if(WIN32) if (EXISTS ${OpenCV_LIB_PATH}) list(APPEND _dir_candidates "${OpenCV_LIB_PATH}/../bin") # OpenCV is built in superbuild else() list(APPEND _dir_candidates "${OpenCV_DIR}/bin") # External OpenCV build is used endif() endif() endif() + if(MITK_USE_OpenMesh) + if(WIN32) + list(APPEND _dir_candidates "${MITK_EXTERNAL_PROJECT_PREFIX}") + endif() + endif() + if(MITK_USE_Python3) list(APPEND _dir_candidates "${CTK_DIR}/CMakeExternals/Install/bin") get_filename_component(_python_dir "${Python3_EXECUTABLE}" DIRECTORY) list(APPEND _dir_candidates "${_python_dir}") endif() if(MITK_USE_TOF_PMDO3 OR MITK_USE_TOF_PMDCAMCUBE OR MITK_USE_TOF_PMDCAMBOARD) list(APPEND _dir_candidates "${MITK_PMD_SDK_DIR}/plugins" "${MITK_PMD_SDK_DIR}/bin") endif() if(MITK_USE_CTK) list(APPEND _dir_candidates "${CTK_LIBRARY_DIRS}") foreach(_ctk_library ${CTK_LIBRARIES}) if(${_ctk_library}_LIBRARY_DIRS) list(APPEND _dir_candidates "${${_ctk_library}_LIBRARY_DIRS}") endif() endforeach() endif() if(MITK_USE_BLUEBERRY) if(DEFINED CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY) if(IS_ABSOLUTE "${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") list(APPEND _dir_candidates "${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") else() list(APPEND _dir_candidates "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") endif() endif() endif() if(MITK_LIBRARY_DIRS) list(APPEND _dir_candidates ${MITK_LIBRARY_DIRS}) endif() ################################################################### #get the search paths added by the mitkFunctionAddLibrarySearchPath file(GLOB _additional_path_info_files "${MITK_SUPERBUILD_BINARY_DIR}/MITK-AdditionalLibPaths/*.cmake") foreach(_additional_path_info_file ${_additional_path_info_files}) get_filename_component(_additional_info_name ${_additional_path_info_file} NAME_WE) include(${_additional_path_info_file}) if(GLS_DEBUG) list(APPEND _dir_candidates ${${_additional_info_name}_ADDITIONAL_DEBUG_LIBRARY_SEARCH_PATHS}) elseif(GLS_MINSIZEREL) list(APPEND _dir_candidates ${${_additional_info_name}_ADDITIONAL_MINSIZEREL_LIBRARY_SEARCH_PATHS}) elseif(GLS_RELWITHDEBINFO) list(APPEND _dir_candidates ${${_additional_info_name}_ADDITIONAL_RELWITHDEBINFO_LIBRARY_SEARCH_PATHS}) else() #Release list(APPEND _dir_candidates ${${_additional_info_name}_ADDITIONAL_RELEASE_LIBRARY_SEARCH_PATHS}) endif() endforeach(_additional_path_info_file ${_additional_path_info_files}) ############################################### #sanitize all candidates and compile final list list(REMOVE_DUPLICATES _dir_candidates) set(_search_dirs ) foreach(_dir ${_dir_candidates}) if(EXISTS "${_dir}/${intermediate_dir}") list(APPEND _search_dirs "${_dir}/${intermediate_dir}") else() list(APPEND _search_dirs "${_dir}") endif() endforeach() # Special handling for "internal" search dirs. The intermediate directory # might not have been created yet, so we can't check for its existence. # Hence we just add it for Windows without checking. set(_internal_search_dirs "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/plugins") if(WIN32) foreach(_dir ${_internal_search_dirs}) set(_search_dirs "${_dir}/${intermediate_dir}" ${_search_dirs}) endforeach() else() set(_search_dirs ${_internal_search_dirs} ${_search_dirs}) endif() list(REMOVE_DUPLICATES _search_dirs) set(${search_path} ${_search_dirs} PARENT_SCOPE) endfunction() diff --git a/CMake/mitkFunctionUseModules.cmake b/CMake/mitkFunctionUseModules.cmake index 173e0a5a95..0654f319be 100644 --- a/CMake/mitkFunctionUseModules.cmake +++ b/CMake/mitkFunctionUseModules.cmake @@ -1,163 +1,173 @@ function(_mitk_parse_package_args) set(package_list ${ARGN}) set(PUBLIC_PACKAGE_NAMES ) set(PRIVATE_PACKAGE_NAMES ) set(INTERFACE_PACKAGE_NAMES ) set(_package_visibility PRIVATE) foreach(_package ${package_list}) if(_package STREQUAL "PUBLIC" OR _package STREQUAL "PRIVATE" OR _package STREQUAL "INTERFACE") set(_package_visibility ${_package}) else() list(APPEND packages ${_package}) set(_package_name ) set(_package_components_list ) string(REPLACE "|" ";" _package_list ${_package}) if("${_package_list}" STREQUAL "${_package}") set(_package_name ${_package}) else() list(GET _package_list 0 _package_name) list(GET _package_list 1 _package_components) string(REPLACE "+" ";" _package_components_list "${_package_components}") if(NOT _package_name OR NOT _package_components) message(SEND_ERROR "PACKAGE argument syntax wrong. ${_package} is not of the form PACKAGE[|COMPONENT1[+COMPONENT2]...]") endif() endif() list(APPEND ${_package_visibility}_PACKAGE_NAMES ${_package_name}) list(APPEND ${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS ${_package_components_list}) endif() endforeach() # remove duplicates and set package components in parent scope foreach(_package_visibility PUBLIC PRIVATE INTERFACE) foreach(_package_name ${${_package_visibility}_PACKAGE_NAMES}) if(${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS) list(REMOVE_DUPLICATES ${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS) endif() set(${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS ${${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS} PARENT_SCOPE) endforeach() endforeach() set(PUBLIC_PACKAGE_NAMES ${PUBLIC_PACKAGE_NAMES} PARENT_SCOPE) set(PRIVATE_PACKAGE_NAMES ${PRIVATE_PACKAGE_NAMES} PARENT_SCOPE) set(INTERFACE_PACKAGE_NAMES ${INTERFACE_PACKAGE_NAMES} PARENT_SCOPE) set(PACKAGE_NAMES ${PUBLIC_PACKAGE_NAMES} ${PRIVATE_PACKAGE_NAMES} ${INTERFACE_PACKAGE_NAMES} PARENT_SCOPE) endfunction() function(_include_package_config pkg_config_file) # wrap the inclusion of the MITK__Config.cmake file in a # function to create a scope for its variables; this allows # multiple inclusions of the file in the parent scope include(${pkg_config_file}) set(ALL_INCLUDE_DIRECTORIES ${ALL_INCLUDE_DIRECTORIES} PARENT_SCOPE) set(ALL_LIBRARIES ${ALL_LIBRARIES} PARENT_SCOPE) set(ALL_COMPILE_DEFINITIONS ${ALL_COMPILE_DEFINITIONS} PARENT_SCOPE) set(ALL_COMPILE_OPTIONS ${ALL_COMPILE_OPTIONS} PARENT_SCOPE) endfunction() #! This CMake function sets up the necessary include directories, #! linker dependencies, and compile flags for a given target which #! depends on a set of MITK modules or packages. #! #! A package argument is of the form #! #! [PUBLIC|PRIVATE|INTERFACE] PACKAGE[|COMPONENT1[+COMPONENT2]...] #! #! where PACKAGE is the package name (e.g. VTK) and components are #! the names of required package components or libraries. #! #! If a dependency is not available, an error is thrown. function(mitk_use_modules) set(_macro_params TARGET # The target name (required) ) set(_macro_multiparams MODULES # MITK modules which the given TARGET uses PACKAGES # MITK packages which the given TARGET uses ) set(_macro_options ) cmake_parse_arguments(USE "${_macro_options}" "${_macro_params}" "${_macro_multiparams}" ${ARGN}) # Sanity checks if(NOT USE_TARGET) message(SEND_ERROR "Required TARGET argument missing.") elseif(NOT TARGET ${USE_TARGET}) message(SEND_ERROR "The given TARGET argument ${USE_TARGET} is not a valid target") endif() set(depends ${USE_MODULES}) set(package_depends ${USE_PACKAGES}) if(depends) # Iterate over all module dependencies foreach(dependency ${depends}) if(TARGET ${dependency} AND NOT MODULE_IS_DEPRECATED) get_target_property(_is_interface_lib ${dependency} TYPE) if(NOT _is_interface_lib) get_target_property(_dependency_deprecated_since ${dependency} MITK_MODULE_DEPRECATED_SINCE) if(_dependency_deprecated_since) message(WARNING "Module ${dependency} is deprecated since ${_dependency_deprecated_since}") endif() endif() endif() endforeach() target_link_libraries(${USE_TARGET} PUBLIC ${depends}) endif() # Parse package dependencies if(package_depends) _mitk_parse_package_args(${package_depends}) # Some package config files like MITK_Qt5_Config.cmake rely on a # properly set "MODULE_NAME" variable for the current target. set(MODULE_NAME ${USE_TARGET}) # Read all package information foreach(_package_visibility INTERFACE PUBLIC PRIVATE) foreach(_package ${${_package_visibility}_PACKAGE_NAMES}) set(ALL_INCLUDE_DIRECTORIES) set(ALL_LIBRARIES) set(ALL_COMPILE_DEFINITIONS) set(ALL_COMPILE_OPTIONS) set(${_package}_REQUIRED_COMPONENTS_BY_MODULE ${${_package_visibility}_${_package}_REQUIRED_COMPONENTS}) set(_package_found 0) foreach(dir ${MODULES_PACKAGE_DEPENDS_DIRS}) if((NOT DEFINED MITK_USE_${_package} OR MITK_USE_${_package}) AND EXISTS "${dir}/MITK_${_package}_Config.cmake") _include_package_config("${dir}/MITK_${_package}_Config.cmake") set(_package_found 1) break() endif() endforeach() if(_package_found) if(ALL_INCLUDE_DIRECTORIES) list(REMOVE_DUPLICATES ALL_INCLUDE_DIRECTORIES) target_include_directories(${USE_TARGET} SYSTEM ${_package_visibility} ${ALL_INCLUDE_DIRECTORIES}) endif() if(ALL_LIBRARIES) # Don't remove "duplicats" because ALL_LIBRARIES may be of the form: # "general;bla;debug;blad;general;foo;debug;food" target_link_libraries(${USE_TARGET} ${_package_visibility} ${ALL_LIBRARIES}) endif() if(ALL_COMPILE_DEFINITIONS) list(REMOVE_DUPLICATES ALL_COMPILE_DEFINITIONS) # Compile definitions are always added "PRIVATE" to avoid multiple definitions # on the command line due to transitive and direct dependencies adding the # same definitions. target_compile_definitions(${USE_TARGET} PRIVATE ${ALL_COMPILE_DEFINITIONS}) endif() if(ALL_COMPILE_OPTIONS) list(REMOVE_DUPLICATES ALL_COMPILE_OPTIONS) target_compile_options(${USE_TARGET} ${_package_visibility} ${ALL_COMPILE_OPTIONS}) endif() + if("VTK" STREQUAL _package) + # VTK module autoinit + unset(_vtk_modules) + foreach(_vtk_module ${VTK_REQUIRED_COMPONENTS_BY_MODULE}) + list(APPEND _vtk_modules "VTK::${_vtk_module}") + endforeach() + if(_vtk_modules) + vtk_module_autoinit(TARGETS ${USE_TARGET} MODULES ${_vtk_modules}) + endif() + endif() else() message(SEND_ERROR "Missing package: ${_package}") endif() endforeach() endforeach() endif() endfunction() diff --git a/CMakeExternals/ExternalProjectList.cmake b/CMakeExternals/ExternalProjectList.cmake index e9cd818848..ab452fc867 100644 --- a/CMakeExternals/ExternalProjectList.cmake +++ b/CMakeExternals/ExternalProjectList.cmake @@ -1,26 +1,26 @@ mitkFunctionAddExternalProject(NAME Poco ON COMPONENTS Foundation Net Util XML Zip) mitkFunctionAddExternalProject(NAME DCMTK ON DOC "EXPERIMENTAL, superbuild only: Use DCMTK in MITK") mitkFunctionAddExternalProject(NAME OpenIGTLink OFF) mitkFunctionAddExternalProject(NAME tinyxml ON ADVANCED) mitkFunctionAddExternalProject(NAME GDCM ON ADVANCED) mitkFunctionAddExternalProject(NAME Eigen ON ADVANCED DOC "Use the Eigen library") mitkFunctionAddExternalProject(NAME ANN ON ADVANCED DOC "Use Approximate Nearest Neighbor Library") mitkFunctionAddExternalProject(NAME CppUnit ON ADVANCED DOC "Use CppUnit for unit tests") mitkFunctionAddExternalProject(NAME PCRE OFF ADVANCED NO_PACKAGE) mitkFunctionAddExternalProject(NAME HDF5 ON ADVANCED) mitkFunctionAddExternalProject(NAME SWIG OFF ADVANCED NO_PACKAGE DEPENDS PCRE) mitkFunctionAddExternalProject(NAME OpenCV OFF) mitkFunctionAddExternalProject(NAME Vigra OFF DEPENDS HDF5) mitkFunctionAddExternalProject(NAME ITK ON NO_CACHE DEPENDS HDF5) mitkFunctionAddExternalProject(NAME VTK ON NO_CACHE) mitkFunctionAddExternalProject(NAME Boost ON NO_CACHE) mitkFunctionAddExternalProject(NAME ZLIB OFF ADVANCED) mitkFunctionAddExternalProject(NAME cpprestsdk OFF DEPENDS Boost ZLIB ADVANCED) -mitkFunctionAddExternalProject(NAME ACVD OFF DOC "Use Approximated Centroidal Voronoi Diagrams") +mitkFunctionAddExternalProject(NAME OpenMesh OFF) mitkFunctionAddExternalProject(NAME CTK ON DEPENDS Qt5 DCMTK DOC "Use CTK in MITK") mitkFunctionAddExternalProject(NAME DCMQI ON DEPENDS DCMTK ITK DOC "Use dcmqi in MITK") mitkFunctionAddExternalProject(NAME MatchPoint OFF ADVANCED DEPENDS ITK DOC "Use the MatchPoint translation image registration library") if(MITK_USE_Qt5) mitkFunctionAddExternalProject(NAME Qwt ON ADVANCED DEPENDS Qt5) endif() diff --git a/CMakeExternals/ACVD.cmake b/CMakeExternals/OpenMesh.cmake similarity index 62% rename from CMakeExternals/ACVD.cmake rename to CMakeExternals/OpenMesh.cmake index f011a241ea..4e02342298 100644 --- a/CMakeExternals/ACVD.cmake +++ b/CMakeExternals/OpenMesh.cmake @@ -1,49 +1,50 @@ #----------------------------------------------------------------------------- -# ACVD +# OpenMesh #----------------------------------------------------------------------------- -if(MITK_USE_ACVD) +if(MITK_USE_OpenMesh) # Sanity checks - if(DEFINED ACVD_DIR AND NOT EXISTS ${ACVD_DIR}) - message(FATAL_ERROR "ACVD_DIR variable is defined but corresponds to non-existing directory") + if(DEFINED OpenMesh_DIR AND NOT EXISTS "${OpenMesh_DIR}") + message(FATAL_ERROR "OpenMesh_DIR variable is defined but corresponds to non-existing directory") endif() - set(proj ACVD) - set(proj_DEPENDENCIES VTK) - set(ACVD_DEPENDS ${proj}) + set(proj OpenMesh) + set(proj_DEPENDENCIES ) + set(OpenMesh_DEPENDS ${proj}) - if(NOT DEFINED ACVD_DIR) + if(NOT DEFINED OpenMesh_DIR) set(additional_args ) + if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/ACVD-vtk6_3d5ae388-patched.tar.gz - URL_MD5 a59e658c8309f6a7004705d86d520d12 + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/OpenMesh-8.1.tar.gz + URL_MD5 9e1eb6feeca3882ab95f9fc97681a4da CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} - -DUSE_MULTITHREADING:BOOL=ON - -DBUILD_EXAMPLES:BOOL=OFF - -DVTK_DIR:PATH=${VTK_DIR} CMAKE_CACHE_ARGS ${ep_common_cache_args} + -DBUILD_APPS:BOOL=OFF + -DOPENMESH_BUILD_SHARED:BOOL=ON + -DOPENMESH_DOCS:BOOL=OFF CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) - set(ACVD_DIR ${ep_prefix}) + set(OpenMesh_DIR "${ep_prefix}") mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/VTK-8.1.0.patch b/CMakeExternals/VTK-8.1.0.patch deleted file mode 100644 index 7dc68def65..0000000000 --- a/CMakeExternals/VTK-8.1.0.patch +++ /dev/null @@ -1,93 +0,0 @@ -diff --git a/Rendering/Core/vtkAssembly.cxx b/Rendering/Core/vtkAssembly.cxx -index 79e4d42b65..b17c74e659 100644 ---- a/Rendering/Core/vtkAssembly.cxx -+++ b/Rendering/Core/vtkAssembly.cxx -@@ -116,6 +116,7 @@ int vtkAssembly::RenderTranslucentPolygonalGeometry(vtkViewport *ren) - vtkProp3D* prop3D = static_cast(path->GetLastNode()->GetViewProp()); - if ( prop3D->GetVisibility() ) - { -+ prop3D->SetPropertyKeys(this->GetPropertyKeys()); - prop3D->SetAllocatedRenderTime(fraction, ren); - prop3D->PokeMatrix(path->GetLastNode()->GetMatrix()); - renderedSomething += prop3D->RenderTranslucentPolygonalGeometry(ren); -@@ -143,6 +144,7 @@ int vtkAssembly::HasTranslucentPolygonalGeometry() - vtkProp3D* prop3D = static_cast(path->GetLastNode()->GetViewProp()); - if ( prop3D->GetVisibility() ) - { -+ prop3D->SetPropertyKeys(this->GetPropertyKeys()); - result = prop3D->HasTranslucentPolygonalGeometry(); - } - } -@@ -175,6 +177,7 @@ int vtkAssembly::RenderVolumetricGeometry(vtkViewport *ren) - vtkProp3D* prop3D = static_cast(path->GetLastNode()->GetViewProp()); - if (prop3D->GetVisibility()) - { -+ prop3D->SetPropertyKeys(this->GetPropertyKeys()); - prop3D->SetAllocatedRenderTime(fraction, ren); - prop3D->PokeMatrix(path->GetLastNode()->GetMatrix()); - renderedSomething += prop3D->RenderVolumetricGeometry(ren); -@@ -210,6 +213,7 @@ int vtkAssembly::RenderOpaqueGeometry(vtkViewport *ren) - vtkProp3D* prop3D = static_cast(path->GetLastNode()->GetViewProp()); - if (prop3D->GetVisibility()) - { -+ prop3D->SetPropertyKeys(this->GetPropertyKeys()); - prop3D->PokeMatrix(path->GetLastNode()->GetMatrix()); - prop3D->SetAllocatedRenderTime(fraction, ren); - renderedSomething += prop3D->RenderOpaqueGeometry(ren); -diff --git a/Rendering/Core/vtkPropAssembly.cxx b/Rendering/Core/vtkPropAssembly.cxx -index 5033c3b66e..405b1a75ab 100644 ---- a/Rendering/Core/vtkPropAssembly.cxx -+++ b/Rendering/Core/vtkPropAssembly.cxx -@@ -97,6 +97,7 @@ int vtkPropAssembly::RenderTranslucentPolygonalGeometry(vtkViewport *ren) - prop = path->GetLastNode()->GetViewProp(); - if ( prop->GetVisibility() ) - { -+ prop->SetPropertyKeys(this->GetPropertyKeys()); - prop->SetAllocatedRenderTime(fraction, ren); - prop->PokeMatrix(path->GetLastNode()->GetMatrix()); - renderedSomething += prop->RenderTranslucentPolygonalGeometry(ren); -@@ -125,6 +126,7 @@ int vtkPropAssembly::HasTranslucentPolygonalGeometry() - prop = path->GetLastNode()->GetViewProp(); - if ( prop->GetVisibility() ) - { -+ prop->SetPropertyKeys(this->GetPropertyKeys()); - result=prop->HasTranslucentPolygonalGeometry(); - } - } -@@ -154,6 +156,7 @@ int vtkPropAssembly::RenderVolumetricGeometry(vtkViewport *ren) - prop = path->GetLastNode()->GetViewProp(); - if ( prop->GetVisibility() ) - { -+ prop->SetPropertyKeys(this->GetPropertyKeys()); - prop->SetAllocatedRenderTime(fraction, ren); - prop->PokeMatrix(path->GetLastNode()->GetMatrix()); - renderedSomething += prop->RenderVolumetricGeometry(ren); -@@ -186,6 +189,7 @@ int vtkPropAssembly::RenderOpaqueGeometry(vtkViewport *ren) - prop = path->GetLastNode()->GetViewProp(); - if ( prop->GetVisibility() ) - { -+ prop->SetPropertyKeys(this->GetPropertyKeys()); - prop->SetAllocatedRenderTime(fraction, ren); - prop->PokeMatrix(path->GetLastNode()->GetMatrix()); - renderedSomething += prop->RenderOpaqueGeometry(ren); -@@ -217,6 +221,7 @@ int vtkPropAssembly::RenderOverlay(vtkViewport *ren) - prop = path->GetLastNode()->GetViewProp(); - if ( prop->GetVisibility() ) - { -+ prop->SetPropertyKeys(this->GetPropertyKeys()); - prop->SetAllocatedRenderTime(fraction, ren); - prop->PokeMatrix(path->GetLastNode()->GetMatrix()); - renderedSomething += prop->RenderOverlay(ren); -diff --git a/CMake/VTKGenerateExportHeader.cmake b/CMake/VTKGenerateExportHeader.cmake -index 9a7a76386e..4b5b6855d0 100644 ---- a/CMake/VTKGenerateExportHeader.cmake -+++ b/CMake/VTKGenerateExportHeader.cmake -@@ -174,7 +174,7 @@ macro(_vtk_test_compiler_hidden_visibility) - execute_process(COMMAND ${CMAKE_C_COMPILER} --version - OUTPUT_VARIABLE _gcc_version_info - ERROR_VARIABLE _gcc_version_info) -- string(REGEX MATCH "[3-9]\\.[0-9]\\.[0-9]*" -+ string(REGEX MATCH "([3-9]|10)\\.[0-9]\\.[0-9]*" - _gcc_version "${_gcc_version_info}") - # gcc on mac just reports: "gcc (GCC) 3.3 20030304 ..." without the - # patch level, handle this here: diff --git a/CMakeExternals/VTK.cmake b/CMakeExternals/VTK.cmake index 5000b167c7..36c53a21b2 100644 --- a/CMakeExternals/VTK.cmake +++ b/CMakeExternals/VTK.cmake @@ -1,89 +1,86 @@ #----------------------------------------------------------------------------- # VTK #----------------------------------------------------------------------------- -if(WIN32) - option(VTK_USE_SYSTEM_FREETYPE OFF) -else() - option(VTK_USE_SYSTEM_FREETYPE ON) -endif() - # Sanity checks if(DEFINED VTK_DIR AND NOT EXISTS ${VTK_DIR}) message(FATAL_ERROR "VTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj VTK) set(proj_DEPENDENCIES ) set(VTK_DEPENDS ${proj}) if(MITK_USE_HDF5) list(APPEND proj_DEPENDENCIES HDF5) endif() if(NOT DEFINED VTK_DIR) set(additional_cmake_args ) + if(WIN32) + list(APPEND additional_cmake_args + -DCMAKE_CXX_MP_FLAG:BOOL=ON + ) + else() + list(APPEND additional_cmake_args + -DVTK_MODULE_USE_EXTERNAL_VTK_freetype:BOOL=ON + ) + endif() + # Optionally enable memory leak checks for any objects derived from vtkObject. This # will force unit tests to fail if they have any of these memory leaks. option(MITK_VTK_DEBUG_LEAKS OFF) mark_as_advanced(MITK_VTK_DEBUG_LEAKS) list(APPEND additional_cmake_args -DVTK_DEBUG_LEAKS:BOOL=${MITK_VTK_DEBUG_LEAKS} - -DVTK_WRAP_PYTHON:BOOL=OFF - -DVTK_WINDOWS_PYTHON_DEBUGGABLE:BOOL=OFF ) if(MITK_USE_Qt5) list(APPEND additional_cmake_args - -DVTK_Group_Qt:BOOL=ON + -DVTK_GROUP_ENABLE_Qt:STRING=YES -DQt5_DIR:PATH=${Qt5_DIR} ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() - - set (VTK_PATCH_OPTION - PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_LIST_DIR}/VTK-8.1.0.patch) mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/VTK-8.1.0.tar.gz - URL_MD5 4fa5eadbc8723ba0b8d203f05376d932 - ${VTK_PATCH_OPTION} + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/VTK-9.0.0.tar.gz + URL_MD5 fa61cd36491d89a17edab18522bdda49 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} - -DVTK_WRAP_TCL:BOOL=OFF - -DVTK_WRAP_PYTHON:BOOL=OFF - -DVTK_WRAP_JAVA:BOOL=OFF - -DVTK_USE_SYSTEM_FREETYPE:BOOL=${VTK_USE_SYSTEM_FREETYPE} + -DVTK_ENABLE_WRAPPING:BOOL=OFF -DVTK_LEGACY_REMOVE:BOOL=ON - -DModule_vtkTestingRendering:BOOL=ON + -DVTK_MODULE_ENABLE_VTK_TestingRendering:STRING=YES + -DVTK_MODULE_ENABLE_VTK_RenderingContextOpenGL2:STRING=YES + -DVTK_MODULE_ENABLE_VTK_RenderingVolumeOpenGL2:STRING=YES ${additional_cmake_args} ${${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(VTK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox index c7b64520ce..9d0ec93913 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox @@ -1,216 +1,214 @@ /** \page BuildInstructionsPage Build Instructions \tableofcontents \section BuildInstructions_Introduction Introduction The CMake-based build system of MITK supports a "superbuild" process, meaning that it will download, configure, and build all required third-party libraries (except Qt) automatically. These instructions will show you how to use the MITK superbuild. \note This page explains explicitly how to build MITK itself. If you want to create your own project based on MITK, the process described below is completely automated. Please see \ref HowToNewProject. For more advanced users, the last sections explains how to inject custom build libraries into the superbuild process. \section BuildInstructions_Prerequisites Prerequisites You need: -# Git (there are also numerous third-party graphical clients available). We recommend using Git, but see below for a way how to get the current source code without using it. -# CMake (version \minimumCMakeVersion or higher) -# Qt 5.12 if you plan to develop Qt-based applications -# If you are using macOS you need an XCode installation and the Command Line Tools as it provides the neccessary compilers and SDKs \section BuildInstructions_Qt A note about Qt As we do not provide Qt in the MITK superbuild you need to install Qt manually. The Qt Company provides online installers for all supported platforms. \section BuildInstructions_Get_Source Get a source tree Since MITK is under active development we recommend to use Git to check out the latest stable release from the homepage. If you decide to use the most current nightly release, make sure to get a stable tree: Check the MITK dashboard before checking out. If the build tree is not clean, you can specify an older revision for the checkout or get a stable tar ball from www.mitk.org. To clone MITK's current Git repository do: \code git clone https://phabricator.mitk.org/source/mitk.git MITK \endcode \section BuildInstructions_Build_With_CMake Build MITK with CMake Create a new directory for the superbuild binary tree, change to it and call CMake: In the shell (assuming your current directory is the same as the one where you issued the git clone command): \code mkdir MITK-superbuild cd MITK-superbuild ccmake ../MITK \endcode If you use Windows or prefer to use the CMake GUI, start the CMake GUI and enter the location of the source tree and binary tree, choose a suitable generator and configure the project. CMake will present you a couple of options, these are the most important ones: - - CMAKE_PREFIX_PATH The path to your Qt installation, e.g., C:/Qt/5.12.6/msvc2017_64 or /home/user/Qt/5.12.6/gcc_64 - - MITK_USE_ACVD Build MITK code which depends on ACVD (this - will download and build ACVD) + - CMAKE_PREFIX_PATH The path to your Qt installation, e.g., C:/Qt/5.12.9/msvc2017_64 or /home/user/Qt/5.12.9/gcc_64 - MITK_USE_BLUEBERRY Build the BlueBerry application framework - MITK_USE_Boost_LIBRARIES If you need binary Boost libraries, specify them here. - MITK_USE_OpenCV Build MITK code which depends on OpenCV (this will download and build OpenCV 2.4) - MITK_USE_Python3 Enables Python wrapping in MITK. This will also configure ITK, VTK, and OpenCV (if enabled) to build Python wrappers. - MITK_USE_Qt5 Build MITK code which depends on Qt 5 If you are satisfied with the configuration of your MITK superbuild, generate the project files with CMake by pressing "Generate". Linux and macOS users usually just enter "make" (optionally supplying the number threads to be used for a parallel build): \code make -j6 \endcode Windows users using Visual Studio can open the generated MITK-superbuild.sln solution file in the MITK-superbuild directory and start the build by building the BUILD_ALL project. \section BuildInstructions_Customize Customize your MITK superbuild The MITK superbuild configures MITK as well as all external libraries. The build directories of these libraries, and of MITK itself are located inside the MITK-superbuild directory. For example, the directory layout may look like: \code MITK-superbuild |- ep "external projects" |-bin |-lib |-include |-src |- MITK-build \endcode To change the configuration of the MITK build itself, choose the MITK-build directory as the binary directory in the CMake GUI (not the MITK-superbuild directory). After generating the project files, build the MITK project by either issuing "make" in the MITK-build directory (Linux, macOS), or by opening MITK-build/MITK.sln (Windows). You may also change the configuration of any project configured via the superbuild process. Make sure to also build the changed project and also the projects which depend on it. \section BuildInstructions_Running Running Applications On Linux, just execute the application you want to run. MITK executables are located in MITK-superbuild/MITK-build/bin On Windows, the PATH environment variable must contain the directories containing the third-party libraries. This is automatically done from Visual Studio. For running the applications directly use the generated batch files in the MITK-superbuild/MITK-build/bin. \section BuildInstructions_Documentation Documentation If you have the Doxygen documentation tool installed, you get a new project (Visual Studio) or "make" target named "doc". You can build this to generate the HTML documentation of MITK in the Documentation/Doxygen directory of your MITK-build binary tree or in the MITK_DOXYGEN_OUTPUT_DIR CMake variable (if specified). \section BuildInstructions_Extending Extend MITK on your own (using the application framework BlueBerry) Please see \ref NewPluginPage \section BuildInstructions_As_Toolkit Use MITK in your own project (as a toolkit) To use MITK in your external project, add the CMake command find_package(MITK REQUIRED) to your CMakeLists.txt and make use of the CMake macros mitk_create_module() and mitk_create_executable() provided by MITK. Here is a very basic example CMakeLists.txt including MITK as a project: \code cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(MyProject) find_package(MITK 2018.04.02 REQUIRED) add_executable(MyApp main.cpp) target_link_libraries(MyApp MitkCore) \endcode with the main.ccp being \code #include #include int main() { MITK_INFO << "Hello world!"; return 0; } \endcode \section BuildInstructions_Advanced_Customization Superbuild customization You can inject pre-build third-party libraries into the MITK superbuild by setting certain CMake variables before the first configure step. MITK will then use these third-party libraries instead of downloading and building them by itself. Note that you must take care of configuring those libraries with all options MITK requires. The variables listed below are provided for injecting third-party libraries. Their occurrence in the CMake GUI or in ccmake may depend on specific MITK_USE_* options set to ON. You may also use the variable names below without the EXTERNAL_ prefix, for example when providing their values on a command line call to CMake. - EXTERNAL_BOOST_ROOT Set this variable to your custom Boost installation - EXTERNAL_CTK_DIR Set this variable to your CTK binary tree (the directory containing the CTKConfig.cmake file) - EXTERNAL_CableSwig_DIR Set this variable to your CableSwig binary tree for Python wrapping (the directory containing the CableSwigConfig.cmake file) - EXTERNAL_DCMTK_DIR Set this variable to your DCMTK binary tree (the directory containing the DCMTKConfig.cmake file) - EXTERNAL_GDCM_DIR Set this variable to your GDCM binary tree (the directory containing the GDCMConfig.cmake file) - EXTERNAL_ITK_DIR Set this variable to your ITK binary tree (the directory containing the ITKConfig.cmake file) - EXTERNAL_OpenCV_DIR Set this variable to your OpenCV binary tree (the directory containing the OpenCVConfig.cmake file) - EXTERNAL_VTK_DIR Set this variable to your VTK binary tree (the directory containing the VTKConfig.cmake file) To set CMake options before the first configure step is invoked, supply them on the command line, i.e. \code ccmake -DITK_DIR:PATH=/opt/ITK-release ../MITK \endcode */ diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox index de49eef830..5babea66ab 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox @@ -1,107 +1,107 @@ /** \page thirdpartylibs Third-party libraries The following third-party libraries can be used with MITK by default and can, in part, be automatically downloaded during superbuild. -\par ACVD - -https://www.creatis.insa-lyon.fr/site7/en/acvd - \par ANN https://www.cs.umd.edu/~mount/ANN/ \par Boost https://www.boost.org/ \par C++ REST SDK https://github.com/Microsoft/cpprestsdk/ \par CppUnit https://sourceforge.net/projects/cppunit/ \par CTK https://commontk.org/ \par DCMTK https://dicom.offis.de/dcmtk \par Eigen http://eigen.tuxfamily.org/index.php?title=Main_Page \par GDCM https://gdcm.sourceforge.net/ \par HDF5 https://support.hdfgroup.org/HDF5/ \par ITK https://itk.org/ \par MatchPoint https://www.dkfz.de/en/sidt/projects/MatchPoint/info.html \par OpenCL https://www.khronos.org/opencl/ \par OpenCV https://opencv.org/ \par OpenIGTLink http://openigtlink.org/ +\par OpenMesh + +https://www.openmesh.org/ + \par PCRE https://www.pcre.org/ \par POCO https://pocoproject.org/ \par Python https://www.python.org/ \par Qt https://www.qt.io/ \par Qwt http://qwt.sourceforge.net/ \par SWIG http://www.swig.org/ \par tinyxml http://www.grinninglizard.com/tinyxml/ \par VIGRA https://ukoethe.github.io/vigra/ \par VTK https://vtk.org/ \par zlib https://zlib.net/ For copyright information on any of the above toolkits see the corresponding home page or the corresponding source folder. */ diff --git a/Examples/Plugins/org.mitk.example.gui.imaging/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.imaging/CMakeLists.txt index 9c8b4036f3..4618724877 100644 --- a/Examples/Plugins/org.mitk.example.gui.imaging/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.imaging/CMakeLists.txt @@ -1,7 +1,8 @@ project(org_mitk_example_gui_imaging) mitk_create_plugin( EXPORT_DIRECTIVE EXAMPLES_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkQtWidgetsExt MitkSegmentation + PACKAGE_DEPENDS VTK|IOImage ) diff --git a/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/simpleexample/QmitkSimpleExampleView.cpp b/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/simpleexample/QmitkSimpleExampleView.cpp index 28a8de8327..d4e166ce06 100644 --- a/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/simpleexample/QmitkSimpleExampleView.cpp +++ b/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/simpleexample/QmitkSimpleExampleView.cpp @@ -1,418 +1,418 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "QmitkSimpleExampleView.h" +#include +#include +#include +#include +#include +#include + #include "QmitkRenderWindow.h" #include "QmitkStepperAdapter.h" #include "QmitkFFmpegWriter.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateProperty.h" #include "mitkProperties.h" #include #include #include #include #include -#include -#include -#include -#include -#include -#include - const std::string QmitkSimpleExampleView::VIEW_ID = "org.mitk.views.simpleexample"; QmitkSimpleExampleView::QmitkSimpleExampleView() : m_Controls(nullptr), m_NavigatorsInitialized(false), m_Parent(nullptr) { } QmitkSimpleExampleView::~QmitkSimpleExampleView() { } void QmitkSimpleExampleView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { m_Parent = parent; // create GUI widgets m_Controls = new Ui::QmitkSimpleExampleViewControls; m_Controls->setupUi(parent); this->CreateConnections(); this->RenderWindowPartActivated(this->GetRenderWindowPart()); } } void QmitkSimpleExampleView::SetFocus() { m_Controls->renderWindowComboBox->setFocus(); } void QmitkSimpleExampleView::RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart) { if (renderWindowPart == nullptr) { m_Parent->setEnabled(false); return; } QHashIterator renderIter(renderWindowPart->GetQmitkRenderWindows()); while (renderIter.hasNext()) { renderIter.next(); m_Controls->renderWindowComboBox->addItem(renderIter.key()); } RenderWindowSelected(m_Controls->renderWindowComboBox->currentText()); m_TimeStepper.reset(new QmitkStepperAdapter(m_Controls->sliceNavigatorTime, renderWindowPart->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromSimpleExample")); m_MovieStepper.reset(new QmitkStepperAdapter(m_Controls->movieNavigatorTime, renderWindowPart->GetTimeNavigationController()->GetTime(), "movieNavigatorTimeFromSimpleExample")); m_Parent->setEnabled(true); } void QmitkSimpleExampleView::RenderWindowPartDeactivated(mitk::IRenderWindowPart * /*renderWindowPart*/) { m_Parent->setEnabled(false); m_SliceStepper.reset(); m_TimeStepper.reset(); m_MovieStepper.reset(); m_Controls->renderWindowComboBox->clear(); } void QmitkSimpleExampleView::CreateConnections() { if (m_Controls) { connect(m_Controls->renderWindowComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(RenderWindowSelected(QString))); connect(m_Controls->stereoSelect, SIGNAL(activated(int)), this, SLOT(StereoSelectionChanged(int))); connect(m_Controls->reInitializeNavigatorsButton, SIGNAL(clicked()), this, SLOT(InitNavigators())); connect(m_Controls->genMovieButton, SIGNAL(clicked()), this, SLOT(GenerateMovie())); connect(m_Controls->m_TakeScreenshotBtn, SIGNAL(clicked()), this, SLOT(OnTakeScreenshot())); connect(m_Controls->m_TakeHighResScreenShotBtn, SIGNAL(clicked()), this, SLOT(OnTakeHighResolutionScreenshot())); } } void QmitkSimpleExampleView::InitNavigators() { /* get all nodes that have not set "includeInBoundingBox" to false */ mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New( mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); /* calculate bounding geometry of these nodes */ auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs); /* initialize the views to the bounding geometry */ m_NavigatorsInitialized = mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } /** * Returns path to the ffmpeg lib if configured in preferences. * * This implementation has been reused from MovieMaker view. * * @return The path to ffmpeg lib or empty string if not configured. */ QString QmitkSimpleExampleView::GetFFmpegPath() const { berry::IPreferences::Pointer preferences = berry::Platform::GetPreferencesService()->GetSystemPreferences()->Node("/org.mitk.gui.qt.ext.externalprograms"); return preferences.IsNotNull() ? preferences->Get("ffmpeg", "") : ""; } /** * Reads pixels from specified render window. * * This implementation has been reused from MovieMaker view. * * @param renderWindow * @param x * @param y * @param width * @param height * @return */ static unsigned char *ReadPixels(vtkRenderWindow *renderWindow, int x, int y, int width, int height) { if (renderWindow == nullptr) return nullptr; unsigned char *frame = new unsigned char[width * height * 3]; renderWindow->MakeCurrent(); glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, frame); return frame; } /** * Records a movie from the selected render window with a default frame rate of 30 Hz. * * Parts of this implementation have been reused from MovieMaker view. */ void QmitkSimpleExampleView::GenerateMovie() { QmitkRenderWindow *movieRenderWindow = GetSelectedRenderWindow(); mitk::Stepper::Pointer stepper = movieRenderWindow->GetSliceNavigationController()->GetSlice(); QmitkFFmpegWriter *movieWriter = new QmitkFFmpegWriter(m_Parent); const QString ffmpegPath = GetFFmpegPath(); if (ffmpegPath.isEmpty()) { QMessageBox::information( nullptr, "Movie Maker", "

Set path to FFmpeg1 in preferences (Window -> Preferences... " "(Ctrl+P) -> External Programs) to be able to record your movies to video files.

" "

If you are using Linux, chances are good that FFmpeg is included in the official package " "repositories.

" "

[1] Download FFmpeg from ffmpeg.org

"); return; } movieWriter->SetFFmpegPath(GetFFmpegPath()); - vtkRenderWindow *renderWindow = movieRenderWindow->GetRenderWindow(); + vtkRenderWindow *renderWindow = movieRenderWindow->renderWindow(); if (renderWindow == nullptr) return; const int border = 3; const int x = border; const int y = border; int width = renderWindow->GetSize()[0] - border * 2; int height = renderWindow->GetSize()[1] - border * 2; if (width & 1) --width; if (height & 1) --height; if (width < 16 || height < 16) return; movieWriter->SetSize(width, height); movieWriter->SetFramerate(30); QString saveFileName = QFileDialog::getSaveFileName(nullptr, "Specify a filename", "", "Movie (*.mp4)"); if (saveFileName.isEmpty()) return; if (!saveFileName.endsWith(".mp4")) saveFileName += ".mp4"; movieWriter->SetOutputPath(saveFileName); const unsigned int numberOfFrames = stepper->GetSteps() - stepper->GetPos(); try { movieWriter->Start(); for (unsigned int currentFrame = 0; currentFrame < numberOfFrames; ++currentFrame) { mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); renderWindow->MakeCurrent(); unsigned char *frame = ReadPixels(renderWindow, x, y, width, height); movieWriter->WriteFrame(frame); delete[] frame; stepper->Next(); } movieWriter->Stop(); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } catch (const mitk::Exception &exception) { mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); QMessageBox::critical(nullptr, "Generate Movie", exception.GetDescription()); } } void QmitkSimpleExampleView::StereoSelectionChanged(int id) { /* From vtkRenderWindow.h tells us about stereo rendering: Set/Get what type of stereo rendering to use. CrystalEyes mode uses frame-sequential capabilities available in OpenGL to drive LCD shutter glasses and stereo projectors. RedBlue mode is a simple type of stereo for use with red-blue glasses. Anaglyph mode is a superset of RedBlue mode, but the color output channels can be configured using the AnaglyphColorMask and the color of the original image can be (somewhat maintained using AnaglyphColorSaturation; the default colors for Anaglyph mode is red-cyan. Interlaced stereo mode produces a composite image where horizontal lines alternate between left and right views. StereoLeft and StereoRight modes choose one or the other stereo view. Dresden mode is yet another stereoscopic interleaving. */ mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); vtkRenderWindow *vtkrenderwindow = renderWindowPart->GetQmitkRenderWindow("3d")->GetVtkRenderWindow(); // note: foreground vtkRenderers (at least the department logo renderer) produce errors in stereoscopic visualization. // Therefore, we disable the logo visualization during stereo rendering. switch (id) { case 0: vtkrenderwindow->StereoRenderOff(); break; case 1: vtkrenderwindow->SetStereoTypeToRedBlue(); vtkrenderwindow->StereoRenderOn(); renderWindowPart->EnableDecorations(false, QStringList(mitk::IRenderWindowPart::DECORATION_LOGO)); break; case 2: vtkrenderwindow->SetStereoTypeToDresden(); vtkrenderwindow->StereoRenderOn(); renderWindowPart->EnableDecorations(false, QStringList(mitk::IRenderWindowPart::DECORATION_LOGO)); break; } mitk::BaseRenderer::GetInstance(vtkrenderwindow)->SetMapperID(mitk::BaseRenderer::Standard3D); renderWindowPart->RequestUpdate(); } QmitkRenderWindow *QmitkSimpleExampleView::GetSelectedRenderWindow() const { QString id = m_Controls->renderWindowComboBox->currentText(); if (id.isEmpty()) { return nullptr; } else { return this->GetRenderWindowPart()->GetQmitkRenderWindow(id); } } void QmitkSimpleExampleView::OnTakeHighResolutionScreenshot() { QString filter; QString fileName = QFileDialog::getSaveFileName( nullptr, "Save screenshot to...", QDir::currentPath(), m_PNGExtension + ";;" + m_JPGExtension, &filter); vtkRenderer *renderer = this->GetSelectedRenderWindow()->GetRenderer()->GetVtkRenderer(); if (renderer == nullptr) return; this->TakeScreenshot(renderer, 4, fileName, filter); } void QmitkSimpleExampleView::OnTakeScreenshot() { QString filter; QString fileName = QFileDialog::getSaveFileName( nullptr, "Save screenshot to...", QDir::currentPath(), m_PNGExtension + ";;" + m_JPGExtension, &filter); QmitkRenderWindow *renWin = this->GetSelectedRenderWindow(); if (renWin == nullptr) return; vtkRenderer *renderer = renWin->GetRenderer()->GetVtkRenderer(); if (renderer == nullptr) return; this->TakeScreenshot(renderer, 1, fileName, filter); } void QmitkSimpleExampleView::TakeScreenshot(vtkRenderer *renderer, unsigned int magnificationFactor, QString fileName, QString filter) { if ((renderer == nullptr) || (magnificationFactor < 1) || fileName.isEmpty()) return; bool doubleBuffering(renderer->GetRenderWindow()->GetDoubleBuffer()); renderer->GetRenderWindow()->DoubleBufferOff(); vtkImageWriter *fileWriter = nullptr; QFileInfo fi(fileName); QString suffix = fi.suffix().toLower(); if (suffix.isEmpty() || (suffix != "png" && suffix != "jpg" && suffix != "jpeg")) { if (filter == m_PNGExtension) { suffix = "png"; } else if (filter == m_JPGExtension) { suffix = "jpg"; } fileName += "." + suffix; } if (suffix.compare("jpg", Qt::CaseInsensitive) == 0 || suffix.compare("jpeg", Qt::CaseInsensitive) == 0) { vtkJPEGWriter *w = vtkJPEGWriter::New(); w->SetQuality(100); w->ProgressiveOff(); fileWriter = w; } else // default is png { fileWriter = vtkPNGWriter::New(); } vtkRenderLargeImage *magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(magnificationFactor); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(fileName.toLatin1()); // vtkRenderLargeImage has problems with different layers, therefore we have to // temporarily deactivate all other layers. // we set the background to white, because it is nicer than black... double oldBackground[3]; renderer->GetBackground(oldBackground); double white[] = {1.0, 1.0, 1.0}; renderer->SetBackground(white); mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); renderWindowPart->EnableDecorations(false); fileWriter->Write(); fileWriter->Delete(); renderWindowPart->EnableDecorations(true); renderer->SetBackground(oldBackground); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } void QmitkSimpleExampleView::RenderWindowSelected(const QString &id) { if (!id.isEmpty()) { m_SliceStepper.reset(new QmitkStepperAdapter( m_Controls->sliceNavigator, this->GetRenderWindowPart()->GetQmitkRenderWindow(id)->GetSliceNavigationController()->GetSlice(), "sliceNavigatorFromSimpleExample")); } } diff --git a/Modules/AlgorithmsExt/CMakeLists.txt b/Modules/AlgorithmsExt/CMakeLists.txt index 019fbbee2c..4e593dfe19 100644 --- a/Modules/AlgorithmsExt/CMakeLists.txt +++ b/Modules/AlgorithmsExt/CMakeLists.txt @@ -1,16 +1,16 @@ mitk_create_module( DEPENDS MitkDataTypesExt MitkLegacyGL PACKAGE_DEPENDS PUBLIC ITK|ITKThresholding - PRIVATE ANN ITK|ITKIOImageBase + PRIVATE ANN ITK|ITKIOImageBase VTK|ImagingGeneral ) if(TARGET ${MODULE_TARGET}) if(MITK_USE_OpenMP) target_link_libraries(${MODULE_TARGET} PUBLIC OpenMP::OpenMP_CXX) endif() if(BUILD_TESTING) add_subdirectory(test) endif() endif() diff --git a/Modules/Annotation/CMakeLists.txt b/Modules/Annotation/CMakeLists.txt index 2cf47f8160..fd9f2dee9a 100644 --- a/Modules/Annotation/CMakeLists.txt +++ b/Modules/Annotation/CMakeLists.txt @@ -1,5 +1,6 @@ MITK_CREATE_MODULE( DEPENDS MitkCore + PACKAGE_DEPENDS PUBLIC VTK|RenderingAnnotation PRIVATE VTK|IOImage ) add_subdirectory(test) diff --git a/Modules/AppUtil/CMakeLists.txt b/Modules/AppUtil/CMakeLists.txt index 8af1a86ac5..4685d36486 100644 --- a/Modules/AppUtil/CMakeLists.txt +++ b/Modules/AppUtil/CMakeLists.txt @@ -1,14 +1,14 @@ set(qt5_depends Qt5|Widgets+WebEngine) if(UNIX AND NOT APPLE) set(qt5_depends "${qt5_depends}+X11Extras") endif() mitk_create_module( PACKAGE_DEPENDS PUBLIC CTK|CTKPluginFramework ${qt5_depends} Poco|Util - PRIVATE VTK + PRIVATE VTK|GUISupportQt DEPENDS PUBLIC qtsingleapplication PRIVATE MitkCore ) diff --git a/Modules/AppUtil/src/mitkBaseApplication.cpp b/Modules/AppUtil/src/mitkBaseApplication.cpp index 15c923d3b2..b13e425ccb 100644 --- a/Modules/AppUtil/src/mitkBaseApplication.cpp +++ b/Modules/AppUtil/src/mitkBaseApplication.cpp @@ -1,858 +1,858 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include namespace { void outputQtMessage(QtMsgType type, const QMessageLogContext&, const QString& msg) { auto message = msg.toStdString(); switch (type) { case QtDebugMsg: MITK_DEBUG << message; break; case QtInfoMsg: MITK_INFO << message; break; case QtWarningMsg: MITK_WARN << message; break; case QtCriticalMsg: MITK_ERROR << message; break; case QtFatalMsg: MITK_ERROR << message; abort(); default: MITK_INFO << message; break; } } } namespace mitk { const QString BaseApplication::ARG_APPLICATION = "BlueBerry.application"; const QString BaseApplication::ARG_CLEAN = "BlueBerry.clean"; const QString BaseApplication::ARG_CONSOLELOG = "BlueBerry.consoleLog"; const QString BaseApplication::ARG_DEBUG = "BlueBerry.debug"; const QString BaseApplication::ARG_FORCE_PLUGIN_INSTALL = "BlueBerry.forcePlugins"; const QString BaseApplication::ARG_HOME = "BlueBerry.home"; const QString BaseApplication::ARG_NEWINSTANCE = "BlueBerry.newInstance"; const QString BaseApplication::ARG_NO_LAZY_REGISTRY_CACHE_LOADING = "BlueBerry.noLazyRegistryCacheLoading"; const QString BaseApplication::ARG_NO_REGISTRY_CACHE = "BlueBerry.noRegistryCache"; const QString BaseApplication::ARG_PLUGIN_CACHE = "BlueBerry.plugin_cache_dir"; const QString BaseApplication::ARG_PLUGIN_DIRS = "BlueBerry.plugin_dirs"; const QString BaseApplication::ARG_PRELOAD_LIBRARY = "BlueBerry.preloadLibrary"; const QString BaseApplication::ARG_PRODUCT = "BlueBerry.product"; const QString BaseApplication::ARG_PROVISIONING = "BlueBerry.provisioning"; const QString BaseApplication::ARG_REGISTRY_MULTI_LANGUAGE = "BlueBerry.registryMultiLanguage"; const QString BaseApplication::ARG_SPLASH_IMAGE = "BlueBerry.splashscreen"; const QString BaseApplication::ARG_STORAGE_DIR = "BlueBerry.storageDir"; const QString BaseApplication::ARG_XARGS = "xargs"; const QString BaseApplication::PROP_APPLICATION = "blueberry.application"; const QString BaseApplication::PROP_FORCE_PLUGIN_INSTALL = BaseApplication::ARG_FORCE_PLUGIN_INSTALL; const QString BaseApplication::PROP_NEWINSTANCE = BaseApplication::ARG_NEWINSTANCE; const QString BaseApplication::PROP_NO_LAZY_REGISTRY_CACHE_LOADING = BaseApplication::ARG_NO_LAZY_REGISTRY_CACHE_LOADING; const QString BaseApplication::PROP_NO_REGISTRY_CACHE = BaseApplication::ARG_NO_REGISTRY_CACHE; const QString BaseApplication::PROP_PRODUCT = "blueberry.product"; const QString BaseApplication::PROP_REGISTRY_MULTI_LANGUAGE = BaseApplication::ARG_REGISTRY_MULTI_LANGUAGE; class SplashCloserCallback : public QRunnable { public: SplashCloserCallback(QSplashScreen* splashscreen) : m_Splashscreen(splashscreen) { } void run() override { this->m_Splashscreen->close(); } private: QSplashScreen *m_Splashscreen; // Owned by BaseApplication::Impl }; struct BaseApplication::Impl { ctkProperties m_FWProps; QCoreApplication *m_QApp; int m_Argc; char **m_Argv; #ifdef Q_OS_MAC std::vector m_Argv_macOS; #endif QString m_AppName; QString m_OrgaName; QString m_OrgaDomain; bool m_SingleMode; bool m_SafeMode; QSplashScreen *m_Splashscreen; SplashCloserCallback *m_SplashscreenClosingCallback; QStringList m_PreloadLibs; QString m_ProvFile; Impl(int argc, char **argv) : m_Argc(argc), m_Argv(argv), #ifdef Q_OS_MAC m_Argv_macOS(), #endif m_SingleMode(false), m_SafeMode(true), m_Splashscreen(nullptr), m_SplashscreenClosingCallback(nullptr) { #ifdef Q_OS_MAC /* On macOS the process serial number is passed as an command line argument (-psn_) in certain circumstances. This option causes a Poco exception. We remove it, if present. */ m_Argv_macOS.reserve(argc); const char psn[] = "-psn"; for (decltype(argc) i = 0; i < argc; ++i) { if (0 == strncmp(argv[i], psn, sizeof(psn))) continue; m_Argv_macOS.push_back(argv[i]); } m_Argc = static_cast(m_Argv_macOS.size()); m_Argv = m_Argv_macOS.data(); #endif } ~Impl() { delete m_SplashscreenClosingCallback; delete m_Splashscreen; delete m_QApp; } QVariant getProperty(const QString &property) const { auto iter = m_FWProps.find(property); return m_FWProps.end() != iter ? iter.value() : QVariant(); } void handleBooleanOption(const std::string &name, const std::string &) { auto fwKey = QString::fromStdString(name); // Translate some keys to proper framework properties if (ARG_CONSOLELOG == fwKey) fwKey = ctkPluginFrameworkLauncher::PROP_CONSOLE_LOG; // For all other options we use the command line option name as the // framework property key. m_FWProps[fwKey] = true; } void handlePreloadLibraryOption(const std::string &, const std::string &value) { m_PreloadLibs.push_back(QString::fromStdString(value)); } void handleClean(const std::string &, const std::string &) { m_FWProps[ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN] = ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT; } void initializeCTKPluginFrameworkProperties(Poco::Util::LayeredConfiguration &configuration) { // Add all configuration key/value pairs as framework properties Poco::Util::LayeredConfiguration::Keys keys; Poco::Util::LayeredConfiguration::Keys keyStack; configuration.keys(keyStack); std::vector keyChain; while (!keyStack.empty()) { const auto currSubKey = keyStack.back(); if (!keyChain.empty() && keyChain.back() == currSubKey) { keyChain.pop_back(); keyStack.pop_back(); continue; } Poco::Util::LayeredConfiguration::Keys subKeys; configuration.keys(currSubKey, subKeys); if (subKeys.empty()) { std::string finalKey; keyStack.pop_back(); for (const auto& key : keyChain) finalKey += key + '.'; finalKey += currSubKey; keys.push_back(finalKey); } else { keyChain.push_back(currSubKey); for (const auto& key : subKeys) keyStack.push_back(key); } } for (const auto& key : keys) { if (configuration.hasProperty(key)) { // .ini and command line options overwrite already inserted keys auto qKey = QString::fromStdString(key); m_FWProps[qKey] = QString::fromStdString(configuration.getString(key)); } } } void parseProvisioningFile(const QString &filePath) { // Skip parsing if the file path is empty if (filePath.isEmpty()) return; auto consoleLog = this->getProperty(ctkPluginFrameworkLauncher::PROP_CONSOLE_LOG).toBool(); // Read initial plugins from a provisioning file QFileInfo provFile(filePath); QStringList pluginsToStart; if (provFile.exists()) { MITK_INFO(consoleLog) << "Using provisioning file: " << qPrintable(provFile.absoluteFilePath()); ProvisioningInfo provInfo(provFile.absoluteFilePath()); // It can still happen that the encoding is not compatible with the fromUtf8 function (i.e. when // manipulating the LANG variable). The QStringList in provInfo is empty then. if (provInfo.getPluginDirs().empty()) { MITK_ERROR << "Cannot search for provisioning file, the retrieved directory list is empty.\n" << "This can happen if there are some special non-ASCII characters in the install path."; } else { for(const auto& pluginPath : provInfo.getPluginDirs()) ctkPluginFrameworkLauncher::addSearchPath(pluginPath); auto pluginUrlsToStart = provInfo.getPluginsToStart(); for (const auto& url : pluginUrlsToStart) pluginsToStart.push_back(url.toString()); } } else { MITK_INFO(consoleLog) << "Provisionig file does not exist."; } if (!pluginsToStart.isEmpty()) { m_FWProps[ctkPluginFrameworkLauncher::PROP_PLUGINS] = pluginsToStart; // Use transient start with declared activation policy (this helps when the provisioning file // changes and some plug-ins should not be installed in the application any more). ctkPlugin::StartOptions startOptions(ctkPlugin::START_TRANSIENT | ctkPlugin::START_ACTIVATION_POLICY); m_FWProps[ctkPluginFrameworkLauncher::PROP_PLUGINS_START_OPTIONS] = static_cast(startOptions); } } }; BaseApplication::BaseApplication(int argc, char **argv) : Application(), d(new Impl(argc, argv)) { } BaseApplication::~BaseApplication() { delete d; } void BaseApplication::printHelp(const std::string &, const std::string &) { Poco::Util::HelpFormatter help(this->options()); help.setAutoIndent(); help.setCommand(this->commandName()); help.format(std::cout); exit(EXIT_OK); } void BaseApplication::setApplicationName(const QString &name) { if (nullptr != qApp) qApp->setApplicationName(name); d->m_AppName = name; } QString BaseApplication::getApplicationName() const { return nullptr != qApp ? qApp->applicationName() : d->m_AppName; } void BaseApplication::setOrganizationName(const QString &name) { if (nullptr != qApp) qApp->setOrganizationName(name); d->m_OrgaName = name; } QString BaseApplication::getOrganizationName() const { return nullptr != qApp ? qApp->organizationName() : d->m_OrgaName; } void BaseApplication::setOrganizationDomain(const QString &domain) { if (nullptr != qApp) qApp->setOrganizationDomain(domain); d->m_OrgaDomain = domain; } QString BaseApplication::getOrganizationDomain() const { return nullptr != qApp ? qApp->organizationDomain() : d->m_OrgaDomain; } void BaseApplication::setSingleMode(bool singleMode) { if (nullptr != qApp) return; d->m_SingleMode = singleMode; } bool BaseApplication::getSingleMode() const { return d->m_SingleMode; } void BaseApplication::setSafeMode(bool safeMode) { if (nullptr != qApp && nullptr == d->m_QApp) return; d->m_SafeMode = safeMode; nullptr == d->m_QApp && getSingleMode() ? static_cast(d->m_QApp)->setSafeMode(safeMode) : static_cast(d->m_QApp)->setSafeMode(safeMode); } bool BaseApplication::getSafeMode() const { return d->m_SafeMode; } void BaseApplication::setPreloadLibraries(const QStringList &libraryBaseNames) { d->m_PreloadLibs = libraryBaseNames; } QStringList BaseApplication::getPreloadLibraries() const { return d->m_PreloadLibs; } void BaseApplication::setProvisioningFilePath(const QString &filePath) { d->m_ProvFile = filePath; } QString BaseApplication::getProvisioningFilePath() const { auto provFilePath = d->m_ProvFile; // A null QString means look up a default provisioning file if (provFilePath.isNull() && nullptr != qApp) { QFileInfo appFilePath(QCoreApplication::applicationFilePath()); QDir basePath(QCoreApplication::applicationDirPath()); auto provFileName = appFilePath.baseName() + ".provisioning"; QFileInfo provFile(basePath.absoluteFilePath(provFileName)); #ifdef Q_OS_MAC /* * On macOS, if started from the build directory, the .provisioning file is located at: * * The executable path is: * * In this case we have to cdUp threetimes. * * During packaging the MitkWorkbench.provisioning file is placed at the same * level like the executable. Nothing has to be done. */ if (!provFile.exists()) { basePath.cdUp(); basePath.cdUp(); basePath.cdUp(); provFile = basePath.absoluteFilePath(provFileName); } #endif if (provFile.exists()) { provFilePath = provFile.absoluteFilePath(); } #ifdef CMAKE_INTDIR else { basePath.cdUp(); provFile.setFile(basePath.absoluteFilePath(provFileName)); if (provFile.exists()) provFilePath = provFile.absoluteFilePath(); } #endif } return provFilePath; } void BaseApplication::initializeQt() { if (nullptr != qApp) return; // If parameters have been set before, we have to store them to hand them // through to the application auto appName = this->getApplicationName(); auto orgName = this->getOrganizationName(); auto orgDomain = this->getOrganizationDomain(); // Create a QCoreApplication instance this->getQApplication(); // Provide parameters to QCoreApplication this->setApplicationName(appName); this->setOrganizationName(orgName); this->setOrganizationDomain(orgDomain); qInstallMessageHandler(outputQtMessage); QWebEngineUrlScheme qtHelpScheme("qthelp"); qtHelpScheme.setFlags(QWebEngineUrlScheme::LocalScheme | QWebEngineUrlScheme::LocalAccessAllowed); QWebEngineUrlScheme::registerScheme(qtHelpScheme); } void BaseApplication::initialize(Poco::Util::Application &self) { // 1. Call the super-class method Poco::Util::Application::initialize(self); // 2. Initialize the Qt framework (by creating a QCoreApplication) this->initializeQt(); // 3. Seed the random number generator, once at startup. QTime time = QTime::currentTime(); qsrand((uint)time.msec()); // 4. Load the "default" configuration, which involves parsing // an optional .ini file and parsing any // command line arguments this->loadConfiguration(); // 5. Add configuration data from the command line and the // optional .ini file as CTK plugin // framework properties. d->initializeCTKPluginFrameworkProperties(this->config()); // 6. Initialize splash screen if an image path is provided // in the .ini file this->initializeSplashScreen(qApp); // 7. Set the custom CTK Plugin Framework storage directory QString storageDir = this->getCTKFrameworkStorageDir(); if (!storageDir.isEmpty()) d->m_FWProps[ctkPluginConstants::FRAMEWORK_STORAGE] = storageDir; // 8. Set the library search paths and the pre-load library property this->initializeLibraryPaths(); auto preloadLibs = this->getPreloadLibraries(); if (!preloadLibs.isEmpty()) d->m_FWProps[ctkPluginConstants::FRAMEWORK_PRELOAD_LIBRARIES] = preloadLibs; // 9. Initialize the CppMicroServices library. // The initializeCppMicroServices() method reuses the // FRAMEWORK_STORAGE property, so we call it after the // getCTKFrameworkStorageDir method. this->initializeCppMicroServices(); // 10. Parse the (optional) provisioning file and set the // correct framework properties. d->parseProvisioningFile(this->getProvisioningFilePath()); // 11. Set the CTK Plugin Framework properties ctkPluginFrameworkLauncher::setFrameworkProperties(d->m_FWProps); } void BaseApplication::uninitialize() { auto pfw = this->getFramework(); if (pfw) { pfw->stop(); // Wait for up to 10 seconds for the CTK plugin framework to stop pfw->waitForStop(10000); } Poco::Util::Application::uninitialize(); } int BaseApplication::getArgc() const { return d->m_Argc; } char **BaseApplication::getArgv() const { return d->m_Argv; } QString BaseApplication::getCTKFrameworkStorageDir() const { QString storageDir; if (this->getSingleMode()) { // This function checks if an instance is already running and either sends a message to // it containing the command line arguments or checks if a new instance was forced by // providing the BlueBerry.newInstance command line argument. In the latter case, a path // to a temporary directory for the new application's storage directory is returned. storageDir = handleNewAppInstance(static_cast(d->m_QApp), d->m_Argc, d->m_Argv, ARG_NEWINSTANCE); } if (storageDir.isEmpty()) { // This is a new instance and no other instance is already running. We specify the // storage directory here (this is the same code as in berryInternalPlatform.cpp) // so that we can re-use the location for the persistent data location of the // the CppMicroServices library. // Append a hash value of the absolute path of the executable to the data location. // This allows to start the same application from different build or install trees. storageDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/" + this->getOrganizationName() + "/" + this->getApplicationName() + '_'; storageDir += QString::number(qHash(QCoreApplication::applicationDirPath())) + "/"; } return storageDir; } void BaseApplication::initializeCppMicroServices() { auto storageDir = this->getProperty(ctkPluginConstants::FRAMEWORK_STORAGE).toString(); if (!storageDir.isEmpty()) us::ModuleSettings::SetStoragePath((storageDir + "us" + QDir::separator()).toStdString()); } QCoreApplication *BaseApplication::getQApplication() const { if (nullptr == qApp) { vtkOpenGLRenderWindow::SetGlobalMaximumNumberOfMultiSamples(0); - auto defaultFormat = QVTKOpenGLWidget::defaultFormat(); + auto defaultFormat = QVTKOpenGLNativeWidget::defaultFormat(); defaultFormat.setSamples(0); QSurfaceFormat::setDefaultFormat(defaultFormat); #ifdef Q_OS_OSX QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); #endif QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); d->m_QApp = this->getSingleMode() ? static_cast(new QmitkSingleApplication(d->m_Argc, d->m_Argv, this->getSafeMode())) : static_cast(new QmitkSafeApplication(d->m_Argc, d->m_Argv, this->getSafeMode())); } return qApp; } void BaseApplication::initializeLibraryPaths() { QStringList suffixes; suffixes << "plugins"; #ifdef Q_OS_WINDOWS suffixes << "bin/plugins"; #ifdef CMAKE_INTDIR suffixes << "bin/" CMAKE_INTDIR "/plugins"; #endif #else suffixes << "lib/plugins"; #ifdef CMAKE_INTDIR suffixes << "lib/" CMAKE_INTDIR "/plugins"; #endif #endif #ifdef Q_OS_MAC suffixes << "../../plugins"; #endif // We add a couple of standard library search paths for plug-ins QDir appDir(QCoreApplication::applicationDirPath()); // Walk one directory up and add bin and lib sub-dirs; this might be redundant appDir.cdUp(); for (const auto& suffix : suffixes) ctkPluginFrameworkLauncher::addSearchPath(appDir.absoluteFilePath(suffix)); } int BaseApplication::main(const std::vector &args) { // Start the plugin framework and all installed plug-ins according to their auto-start setting QStringList arguments; for (auto const &arg : args) arguments.push_back(QString::fromStdString(arg)); if (nullptr != d->m_Splashscreen) { // A splash screen is displayed. Create the closing callback. d->m_SplashscreenClosingCallback = new SplashCloserCallback(d->m_Splashscreen); } return ctkPluginFrameworkLauncher::run(d->m_SplashscreenClosingCallback, QVariant::fromValue(arguments)).toInt(); } void BaseApplication::defineOptions(Poco::Util::OptionSet &options) { Poco::Util::Option helpOption("help", "h", "print this help text"); helpOption.callback(Poco::Util::OptionCallback(this, &BaseApplication::printHelp)); options.addOption(helpOption); Poco::Util::Option newInstanceOption(ARG_NEWINSTANCE.toStdString(), "", "forces a new instance of this application"); newInstanceOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(newInstanceOption); Poco::Util::Option cleanOption(ARG_CLEAN.toStdString(), "", "cleans the plugin cache"); cleanOption.callback(Poco::Util::OptionCallback(d, &Impl::handleClean)); options.addOption(cleanOption); Poco::Util::Option productOption(ARG_PRODUCT.toStdString(), "", "the id of the product to be launched"); productOption.argument("").binding(PROP_PRODUCT.toStdString()); options.addOption(productOption); Poco::Util::Option appOption(ARG_APPLICATION.toStdString(), "", "the id of the application extension to be executed"); appOption.argument("").binding(PROP_APPLICATION.toStdString()); options.addOption(appOption); Poco::Util::Option provOption(ARG_PROVISIONING.toStdString(), "", "the location of a provisioning file"); provOption.argument("").binding(ARG_PROVISIONING.toStdString()); options.addOption(provOption); Poco::Util::Option storageDirOption(ARG_STORAGE_DIR.toStdString(), "", "the location for storing persistent application data"); storageDirOption.argument("").binding(ctkPluginConstants::FRAMEWORK_STORAGE.toStdString()); options.addOption(storageDirOption); Poco::Util::Option consoleLogOption(ARG_CONSOLELOG.toStdString(), "", "log messages to the console"); consoleLogOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(consoleLogOption); Poco::Util::Option debugOption(ARG_DEBUG.toStdString(), "", "enable debug mode"); debugOption.argument("", false).binding(ctkPluginFrameworkLauncher::PROP_DEBUG.toStdString()); options.addOption(debugOption); Poco::Util::Option forcePluginOption(ARG_FORCE_PLUGIN_INSTALL.toStdString(), "", "force installing plug-ins with same symbolic name"); forcePluginOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(forcePluginOption); Poco::Util::Option preloadLibsOption(ARG_PRELOAD_LIBRARY.toStdString(), "", "preload a library"); preloadLibsOption.argument("") .repeatable(true) .callback(Poco::Util::OptionCallback(d, &Impl::handlePreloadLibraryOption)); options.addOption(preloadLibsOption); Poco::Util::Option noRegistryCacheOption(ARG_NO_REGISTRY_CACHE.toStdString(), "", "do not use a cache for the registry"); noRegistryCacheOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(noRegistryCacheOption); Poco::Util::Option noLazyRegistryCacheLoadingOption(ARG_NO_LAZY_REGISTRY_CACHE_LOADING.toStdString(), "", "do not use lazy cache loading for the registry"); noLazyRegistryCacheLoadingOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(noLazyRegistryCacheLoadingOption); Poco::Util::Option registryMultiLanguageOption(ARG_REGISTRY_MULTI_LANGUAGE.toStdString(), "", "enable multi-language support for the registry"); registryMultiLanguageOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(registryMultiLanguageOption); Poco::Util::Option splashScreenOption(ARG_SPLASH_IMAGE.toStdString(), "", "optional picture to use as a splash screen"); splashScreenOption.argument("").binding(ARG_SPLASH_IMAGE.toStdString()); options.addOption(splashScreenOption); Poco::Util::Option xargsOption(ARG_XARGS.toStdString(), "", "Extended argument list"); xargsOption.argument("").binding(ARG_XARGS.toStdString()); options.addOption(xargsOption); Poco::Util::Application::defineOptions(options); } QSharedPointer BaseApplication::getFramework() const { return ctkPluginFrameworkLauncher::getPluginFramework(); } ctkPluginContext *BaseApplication::getFrameworkContext() const { auto framework = getFramework(); return framework ? framework->getPluginContext() : nullptr; } void BaseApplication::initializeSplashScreen(QCoreApplication * application) const { auto pixmapFileNameProp = d->getProperty(ARG_SPLASH_IMAGE); if (!pixmapFileNameProp.isNull()) { auto pixmapFileName = pixmapFileNameProp.toString(); QFileInfo checkFile(pixmapFileName); if (checkFile.exists() && checkFile.isFile()) { QPixmap pixmap(checkFile.absoluteFilePath()); d->m_Splashscreen = new QSplashScreen(pixmap, Qt::WindowStaysOnTopHint); d->m_Splashscreen->show(); application->processEvents(); } } } QHash BaseApplication::getFrameworkProperties() const { return d->m_FWProps; } int BaseApplication::run() { this->init(d->m_Argc, d->m_Argv); return Application::run(); } void BaseApplication::setProperty(const QString &property, const QVariant &value) { d->m_FWProps[property] = value; } QVariant BaseApplication::getProperty(const QString &property) const { return d->getProperty(property); } void BaseApplication::installTranslator(QTranslator* translator) { this->getQApplication()->installTranslator(translator); } bool BaseApplication::isRunning() { auto app = dynamic_cast(this->getQApplication()); if (nullptr != app) app->isRunning(); mitkThrow() << "Method not implemented."; } void BaseApplication::sendMessage(const QByteArray msg) { auto app = dynamic_cast(this->getQApplication()); if (nullptr != app) app->sendMessage(msg); mitkThrow() << "Method not implemented."; } } diff --git a/Modules/Classification/CLMiniApps/CMakeLists.txt b/Modules/Classification/CLMiniApps/CMakeLists.txt index 3755b73a83..6e45122c9a 100644 --- a/Modules/Classification/CLMiniApps/CMakeLists.txt +++ b/Modules/Classification/CLMiniApps/CMakeLists.txt @@ -1,117 +1,117 @@ option(BUILD_ClassificationMiniApps "Build commandline tools for classification" OFF) if(BUILD_ClassificationMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( classificationminiapps RandomForestTraining^^MitkCLVigraRandomForest NativeHeadCTSegmentation^^MitkCLVigraRandomForest ManualSegmentationEvaluation^^MitkCLVigraRandomForest CLScreenshot^^MitkCore_MitkQtWidgetsExt_MitkCLUtilities CLDicom2Nrrd^^MitkCore CLResampleImageToReference^^MitkCore CLGlobalImageFeatures^^MitkCLUtilities_MitkQtWidgetsExt CLMRNormalization^^MitkCLUtilities_MitkCLMRUtilities CLStaple^^MitkCLUtilities CLVoxelFeatures^^MitkCLUtilities CLPolyToNrrd^^ CLPlanarFigureToNrrd^^MitkCore_MitkSegmentation_MitkMultilabel CLSimpleVoxelClassification^^MitkDataCollection_MitkCLVigraRandomForest CLVoxelClassification^^MitkDataCollection_MitkCLImportanceWeighting_MitkCLVigraRandomForest CLBrainMask^^MitkCLUtilities XRaxSimulationFromCT^^MitkCLUtilities CLRandomSampling^^MitkCore_MitkCLUtilities CLRemoveEmptyVoxels^^MitkCore CLN4^^MitkCore CLSkullMask^^MitkCore CLPointSetToSegmentation^^ CLMultiForestPrediction^^MitkDataCollection_MitkCLVigraRandomForest CLNrrdToPoly^^MitkCore CL2Dto3DImage^^MitkCore CLWeighting^^MitkCore_MitkCLImportanceWeighting_MitkCLUtilities CLOverlayRoiCenterOfMass^^MitkCore_MitkCLUtilities_MitkQtWidgetsExt CLLungSegmentation^^MitkCore_MitkSegmentation_MitkMultilabel ) foreach(classificationminiapps ${classificationminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${classificationminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore MitkCommandLine ${dependencies_list} - PACKAGE_DEPENDS ITK Qt5|Core Vigra + PACKAGE_DEPENDS ITK Qt5|Core Vigra VTK|IOImage CPP_FILES ${appname}.cpp ) if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() mitk_create_executable(CLMatchPointReg DEPENDS MitkCore MitkCLUtilities MitkMatchPointRegistration MitkCommandLine MitkMatchPointRegistrationUI PACKAGE_DEPENDS ITK Qt5|Core Vigra MatchPoint CPP_FILES CLMatchPointReg.cpp ) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Classification/CLUtilities/CMakeLists.txt b/Modules/Classification/CLUtilities/CMakeLists.txt index ad4d3835f8..3c7f86a35d 100644 --- a/Modules/Classification/CLUtilities/CMakeLists.txt +++ b/Modules/Classification/CLUtilities/CMakeLists.txt @@ -1,14 +1,14 @@ mitk_create_module( DEPENDS MitkCore MitkCLCore MitkCommandLine MitkDICOM - PACKAGE_DEPENDS PUBLIC Eigen PRIVATE tinyxml + PACKAGE_DEPENDS PUBLIC Eigen PRIVATE tinyxml VTK|FiltersStatistics ) if(TARGET ${MODULE_TARGET}) if(MITK_USE_OpenMP) target_link_libraries(${MODULE_TARGET} PUBLIC OpenMP::OpenMP_CXX) endif() if(BUILD_TESTING) add_subdirectory(test) endif() endif() diff --git a/Modules/ContourModel/CMakeLists.txt b/Modules/ContourModel/CMakeLists.txt index b52388f2ec..98b2e63246 100644 --- a/Modules/ContourModel/CMakeLists.txt +++ b/Modules/ContourModel/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE( INCLUDE_DIRS Algorithms DataManagement IO Rendering DEPENDS MitkCore MitkSceneSerializationBase MitkLegacyGL MitkAnnotation MitkMultilabel - PACKAGE_DEPENDS ITK|ITKReview + PACKAGE_DEPENDS PRIVATE ITK|ITKReview VTK|RenderingContext2D+RenderingContextOpenGL2 # AUTOLOAD_WITH MitkCore TODO: Create IO Submodule and autoload that one instead. ) add_subdirectory(Testing) diff --git a/Modules/Core/CMakeLists.txt b/Modules/Core/CMakeLists.txt index 9443972b06..40e19fd8b4 100644 --- a/Modules/Core/CMakeLists.txt +++ b/Modules/Core/CMakeLists.txt @@ -1,65 +1,65 @@ set(TOOL_CPPS "") # temporary suppress warnings in the following files until image accessors are fully integrated. set_source_files_properties( src/DataManagement/mitkImage.cpp COMPILE_FLAGS -DMITK_NO_DEPRECATED_WARNINGS ) set_source_files_properties( src/Controllers/mitkSliceNavigationController.cpp COMPILE_FLAGS -DMITK_NO_DEPRECATED_WARNINGS ) MITK_CREATE_MODULE( INCLUDE_DIRS PUBLIC ${MITK_BINARY_DIR} PRIVATE src/Algorithms src/Controllers src/DataManagement src/Interactions src/IO src/Rendering ${OPENGL_INCLUDE_DIR} DEPENDS PUBLIC mbilog CppMicroServices PACKAGE_DEPENDS PRIVATE tinyxml OpenGL PUBLIC ITK|ITKTransform+ITKImageGrid+ITKImageFeature+ITKIOImageBase+ITKIOHDF5+ITKIOLSM+ITKIOMRC+ITKIOBioRad+ITKIOGE+ITKIOStimulate+ITKIOBruker+ITKIOMINC # We privately use/link all ITK modules in order to support all IO, Transform, etc. # factories from ITK which are registered "automatically" via a factory manager. PRIVATE ITK - PUBLIC VTK|vtkFiltersTexture+vtkFiltersParallel+vtkImagingStencil+vtkImagingMath+vtkInteractionStyle+vtkRenderingOpenGL2+vtkRenderingContextOpenGL2+vtkRenderingVolumeOpenGL2+vtkRenderingFreeType+vtkRenderingLabel+vtkInteractionWidgets+vtkIOGeometry+vtkIOXML + PUBLIC VTK|FiltersTexture+FiltersParallel+ImagingStencil+ImagingMath+InteractionStyle+RenderingOpenGL2+RenderingVolumeOpenGL2+RenderingFreeType+RenderingLabel+InteractionWidgets+IOGeometry+IOXML PUBLIC Boost|boost # Do not automatically create CppMicroServices initialization code. # Because the VTK 6 "auto-init" functionality injects file-local static # initialization code in every cpp file which includes a VTK header, # static initialization order becomes an issue again. For the Mitk # core library, we need to ensure that the VTK static initialization stuff # happens before the CppMicroServices initialization, since the latter # might already use VTK code which needs to access VTK object factories. # Hence, CppMicroServices initialization code is placed manually within # the mitkCoreActivator.cpp file. NO_INIT ) if(NOT TARGET ${MODULE_TARGET}) message(SEND_ERROR "Core target ${MODULE_TARGET} does not exist") endif() function(_itk_create_factory_register_manager) # In MITK_ITK_Config.cmake, we do *not* include ITK_USE_FILE, which # prevents multiple registrations/unregistrations of ITK IO factories # during library loading/unloading (of MITK libraries). However, we need # "one" place where the IO factories are registered at # least once. This could be the application executable, but every executable would # need to take care of that itself. Instead, we allow the auto registration in the # Mitk Core library. set(NO_DIRECTORY_SCOPED_ITK_COMPILE_DEFINITION 1) find_package(ITK) include(${ITK_USE_FILE}) if(NOT ITK_NO_IO_FACTORY_REGISTER_MANAGER) # We manually add the define which will be of target scope. MITK # patches ITK_USE_FILE to remove the directory scoped compile # definition since it would be propagated to other targets in the # same directory scope but these targets might want to *not* # use the ITK factory manager stuff. target_compile_definitions(${MODULE_TARGET} PRIVATE ITK_IO_FACTORY_REGISTER_MANAGER) endif() endfunction() _itk_create_factory_register_manager() if(MSVC_IDE OR MSVC_VERSION) target_link_libraries(${MODULE_TARGET} PRIVATE psapi.lib) endif() if(BUILD_TESTING) add_subdirectory(TestingHelper) add_subdirectory(test) endif() diff --git a/Modules/Core/TestingHelper/CMakeLists.txt b/Modules/Core/TestingHelper/CMakeLists.txt index a94c4819e3..c1d32c6cfd 100644 --- a/Modules/Core/TestingHelper/CMakeLists.txt +++ b/Modules/Core/TestingHelper/CMakeLists.txt @@ -1,7 +1,7 @@ mitk_create_module( DEPENDS PUBLIC MitkCore PACKAGE_DEPENDS PUBLIC CppUnit - PRIVATE VTK|vtkTestingRendering tinyxml OpenGL + PRIVATE VTK|IOImage+TestingRendering tinyxml OpenGL ) diff --git a/Modules/Core/include/mitkPointSet.h b/Modules/Core/include/mitkPointSet.h index 99383bfea8..4a55101604 100755 --- a/Modules/Core/include/mitkPointSet.h +++ b/Modules/Core/include/mitkPointSet.h @@ -1,352 +1,348 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 MITKPointSet_H_HEADER_INCLUDED #define MITKPointSet_H_HEADER_INCLUDED #include "mitkBaseData.h" #include #include namespace mitk { /** - * \brief Data structure which stores a set of points. Superclass of - * mitk::Mesh. + * \brief Data structure which stores a set of points. * * 3D points are grouped within a point set; for time resolved usage, one point * set is created and maintained per time step. A point entry consists of the * point coordinates and point data. * * The point data includes a point ID (unique identifier to address this point * within the point set), the selection state of the point and the type of * the point. * * For further information about different point types see * mitk::PointSpecificationType in mitkVector.h. * * Inserting a point is accompanied by an event, containing an index. The new * point is inserted into the list at the specified position. At the same time * an internal ID is generated and stored for the point. Points at specific time * steps are accessed by specifying the time step number (which defaults to 0). * * The points of itk::PointSet stores the points in a pointContainer * (MapContainer). The points are best accessed by using a ConstIterator (as * defined in MapContainer); avoid access via index. * - * The class internally uses an itk::Mesh for each time step, because - * mitk::Mesh is derived from mitk::PointSet and needs the itk::Mesh structure - * which is also derived from itk::PointSet. Thus several typedefs which seem - * to be in wrong place, are declared here (for example SelectedLinesType). + * The class internally uses an itk::Mesh for each time step. * * \section mitkPointSetDisplayOptions * * The default mappers for this data structure are mitk::PointSetGLMapper2D and * mitk::PointSetVtkMapper3D. See these classes for display options which can * can be set via properties. * * \section Events * * PointSet issues the following events, for which observers can register * (the below events are grouped into a class hierarchy as indicated by * identation level; e.g. PointSetSizeChangeEvent comprises PointSetAddEvent * and PointSetRemoveEvent): * * * PointSetEvent subsumes all PointSet events * PointSetMoveEvent issued when a point of the PointSet is moved * PointSetSizeChangeEvent subsumes add and remove events * PointSetAddEvent issued when a point is added to the PointSet * PointSetRemoveEvent issued when a point is removed from the PointSet * * \ingroup PSIO * \ingroup Data */ class MITKCORE_EXPORT PointSet : public BaseData { public: mitkClassMacro(PointSet, BaseData); itkFactorylessNewMacro(Self); itkCloneMacro(Self); typedef mitk::ScalarType CoordinateType; typedef mitk::ScalarType InterpolationWeightType; static const unsigned int PointDimension = 3; static const unsigned int MaxTopologicalDimension = 3; /** * \brief struct for data of a point */ struct MITKCORE_EXPORT PointDataType { unsigned int id; // to give the point a special ID bool selected; // information about if the point is selected mitk::PointSpecificationType pointSpec; // specifies the type of the point bool operator==(const PointDataType &other) const; }; /** * \brief cellDataType, that stores all indexes of the lines, that are * selected e.g.: points A,B and C.Between A and B there is a line with * index 0. If vector of cellData contains 1 and 2, then the lines between * B and C and C and A is selected. */ typedef std::vector SelectedLinesType; typedef SelectedLinesType::iterator SelectedLinesIter; struct CellDataType { // used to set the whole cell on selected bool selected; // indexes of selected lines. 0 is between pointId 0 and 1 SelectedLinesType selectedLines; // is the polygon already finished and closed bool closed; }; typedef itk::DefaultDynamicMeshTraits MeshTraits; typedef itk::Mesh MeshType; typedef MeshType DataType; typedef Point3D PointType; typedef DataType::PointIdentifier PointIdentifier; typedef DataType::PointsContainer PointsContainer; typedef DataType::PointsContainerIterator PointsIterator; typedef DataType::PointsContainer::ConstIterator PointsConstIterator; typedef DataType::PointDataContainer PointDataContainer; typedef DataType::PointDataContainerIterator PointDataIterator; typedef DataType::PointDataContainerIterator PointDataConstIterator; void Expand(unsigned int timeSteps) override; /** \brief executes the given Operation */ void ExecuteOperation(Operation *operation) override; /** \brief returns the current size of the point-list */ virtual int GetSize(unsigned int t = 0) const; virtual unsigned int GetPointSetSeriesSize() const; /** \brief returns the pointset */ virtual DataType::Pointer GetPointSet(int t = 0) const; PointsIterator Begin(int t = 0); PointsConstIterator Begin(int t = 0) const; PointsIterator End(int t = 0); PointsConstIterator End(int t = 0) const; /** * \brief Get an iterator to the max ID element if existent. Return End() otherwise. */ PointsIterator GetMaxId(int t = 0); /** * \brief Get the point with ID id in world coordinates * * check if the ID exists. If it doesn't exist, then return 0,0,0 */ PointType GetPoint(PointIdentifier id, int t = 0) const; /** * \brief Get the point with ID id in world coordinates * * If a point exists for the ID id, the point is returned in the parameter point * and the method returns true. If the ID does not exist, the method returns false */ bool GetPointIfExists(PointIdentifier id, PointType *point, int t = 0) const; /** * \brief Set the given point in world coordinate system into the itkPointSet. */ void SetPoint(PointIdentifier id, PointType point, int t = 0); /** * \brief Set the given point in world coordinate system with the given PointSpecificationType */ void SetPoint(PointIdentifier id, PointType point, PointSpecificationType spec, int t = 0); /** * \brief Set the given point in world coordinate system into the itkPointSet. */ void InsertPoint(PointIdentifier id, PointType point, int t = 0); /** * \brief Set the given point in world coordinate system with given PointSpecificationType */ void InsertPoint(PointIdentifier id, PointType point, PointSpecificationType spec, int t); /** * \brief Insert the given point in world coordinate system with incremented max id at time step t. */ PointIdentifier InsertPoint(PointType point, int t = 0); /** * \brief Remove point with given id at timestep t, if existent */ bool RemovePointIfExists(PointIdentifier id, int t = 0); /** * \brief Remove max id point at timestep t and return iterator to precedent point */ PointsIterator RemovePointAtEnd(int t = 0); /** * \brief Swap a point at the given position (id) with the upper point (moveUpwards=true) or with the lower point * (moveUpwards=false). * If upper or lower index does not exist false is returned, if swap was successful true. */ bool SwapPointPosition(PointIdentifier id, bool moveUpwards, int t = 0); /** * \brief searches a selected point and returns the id of that point. * If no point is found, then -1 is returned */ virtual int SearchSelectedPoint(int t = 0) const; /** \brief returns true if a point exists at this position */ virtual bool IndexExists(int position, int t = 0) const; /** \brief to get the state selected/unselected of the point on the * position */ virtual bool GetSelectInfo(int position, int t = 0) const; virtual void SetSelectInfo(int position, bool selected, int t = 0); /** \brief to get the type of the point at the position and the moment */ virtual PointSpecificationType GetSpecificationTypeInfo(int position, int t) const; /** \brief returns the number of selected points */ virtual int GetNumberOfSelected(int t = 0) const; /** * \brief searches a point in the list == point +/- distance * * \param point is in world coordinates. * \param distance is in mm. * \param t * returns -1 if no point is found * or the position in the list of the first match */ int SearchPoint(Point3D point, ScalarType distance, int t = 0) const; bool IsEmptyTimeStep(unsigned int t) const override; // virtual methods, that need to be implemented void UpdateOutputInformation() override; void SetRequestedRegionToLargestPossibleRegion() override; bool RequestedRegionIsOutsideOfTheBufferedRegion() override; bool VerifyRequestedRegion() override; void SetRequestedRegion(const itk::DataObject *data) override; // Method for subclasses virtual void OnPointSetChange(){}; protected: mitkCloneMacro(Self); PointSet(); PointSet(const PointSet &other); ~PointSet() override; void PrintSelf(std::ostream &os, itk::Indent indent) const override; ///< print content of the object to os void ClearData() override; void InitializeEmpty() override; /** \brief swaps point coordinates and point data of the points with identifiers id1 and id2 */ bool SwapPointContents(PointIdentifier id1, PointIdentifier id2, int t = 0); typedef std::vector PointSetSeries; PointSetSeries m_PointSetSeries; DataType::PointsContainer::Pointer m_EmptyPointsContainer; /** * @brief flag to indicate the right time to call SetBounds **/ bool m_CalculateBoundingBox; }; /** * @brief Equal A function comparing two pointsets for beeing identical. * @warning This method is deprecated and will not be available in the future. Use the \a bool mitk::Equal(const * mitk::PointSet& p1, const mitk::PointSet& p2) instead. * * @ingroup MITKTestingAPI * * The function compares the Geometry, the size and all points element-wise. * The parameter eps is a tolarence value for all methods which are internally used for comparion. * * @param rightHandSide Compare this against leftHandSide. * @param leftHandSide Compare this against rightHandSide. * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @param checkGeometry if comparing point sets loaded from a file, the geometries might be different and must not be * compared. In all other cases, you should compare the geometries. * @return True, if all subsequent comparisons are true, false otherwise */ DEPRECATED(MITKCORE_EXPORT bool Equal(const mitk::PointSet *leftHandSide, const mitk::PointSet *rightHandSide, mitk::ScalarType eps, bool verbose, bool checkGeometry = true)); /** * @brief Equal A function comparing two pointsets for beeing identical. * * @ingroup MITKTestingAPI * * The function compares the Geometry, the size and all points element-wise. * The parameter eps is a tolarence value for all methods which are internally used for comparion. * * @param rightHandSide Compare this against leftHandSide. * @param leftHandSide Compare this against rightHandSide. * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @param checkGeometry if comparing point sets loaded from a file, the geometries might be different and must not be * compared. In all other cases, you should compare the geometries. * @return True, if all subsequent comparisons are true, false otherwise */ MITKCORE_EXPORT bool Equal(const mitk::PointSet &leftHandSide, const mitk::PointSet &rightHandSide, mitk::ScalarType eps, bool verbose, bool checkGeometry = true); itkEventMacro(PointSetEvent, itk::AnyEvent); itkEventMacro(PointSetMoveEvent, PointSetEvent); itkEventMacro(PointSetSizeChangeEvent, PointSetEvent); itkEventMacro(PointSetAddEvent, PointSetSizeChangeEvent); itkEventMacro(PointSetRemoveEvent, PointSetSizeChangeEvent); itkEventMacro(PointSetExtendTimeRangeEvent, PointSetEvent); } // namespace mitk #endif /* MITKPointSet_H_HEADER_INCLUDED */ diff --git a/Modules/Core/src/IO/mitkIOUtil.cpp b/Modules/Core/src/IO/mitkIOUtil.cpp index b26793be20..13be752926 100644 --- a/Modules/Core/src/IO/mitkIOUtil.cpp +++ b/Modules/Core/src/IO/mitkIOUtil.cpp @@ -1,1027 +1,1027 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkIOUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ITK #include // VTK #include #include #include #include #include static std::string GetLastErrorStr() { #ifdef US_PLATFORM_POSIX return std::string(strerror(errno)); #else // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, nullptr); std::string errMsg((LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return errMsg; #endif } #ifdef US_PLATFORM_WINDOWS #include #include // make the posix flags point to the obsolte bsd types on windows #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #else #include #include #include #endif #include #include static const char validLetters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // A cross-platform version of the mkstemps function static int mkstemps_compat(char *tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary files to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return -1; } /* This is where the Xs start. */ char *XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return -1; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, nullptr); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif for (unsigned int count = 0; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; int fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd >= 0) { errno = savedErrno; return fd; } else if (errno != EEXIST) { return -1; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return -1; } // A cross-platform version of the POSIX mkdtemp function static char *mkdtemps_compat(char *tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary dirs to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary dir. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return nullptr; } /* This is where the Xs start. */ char *XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return nullptr; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, nullptr); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif unsigned int count = 0; for (; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; #ifdef US_PLATFORM_WINDOWS int fd = _mkdir(tmpl); //, _S_IREAD | _S_IWRITE | _S_IEXEC); #else int fd = mkdir(tmpl, S_IRUSR | S_IWUSR | S_IXUSR); #endif if (fd >= 0) { errno = savedErrno; return tmpl; } else if (errno != EEXIST) { return nullptr; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return nullptr; } //#endif //************************************************************** // mitk::IOUtil method definitions namespace mitk { struct IOUtil::Impl { struct FixedReaderOptionsFunctor : public ReaderOptionsFunctorBase { FixedReaderOptionsFunctor(const IFileReader::Options &options) : m_Options(options) {} bool operator()(LoadInfo &loadInfo) const override { IFileReader *reader = loadInfo.m_ReaderSelector.GetSelected().GetReader(); if (reader) { reader->SetOptions(m_Options); } return false; } private: const IFileReader::Options &m_Options; }; struct FixedWriterOptionsFunctor : public WriterOptionsFunctorBase { FixedWriterOptionsFunctor(const IFileReader::Options &options) : m_Options(options) {} bool operator()(SaveInfo &saveInfo) const override { IFileWriter *writer = saveInfo.m_WriterSelector.GetSelected().GetWriter(); if (writer) { writer->SetOptions(m_Options); } return false; } private: const IFileWriter::Options &m_Options; }; static BaseData::Pointer LoadBaseDataFromFile(const std::string &path, const ReaderOptionsFunctorBase* optionsCallback = nullptr); static void SetDefaultDataNodeProperties(mitk::DataNode *node, const std::string &filePath = std::string()); }; BaseData::Pointer IOUtil::Impl::LoadBaseDataFromFile(const std::string &path, const ReaderOptionsFunctorBase *optionsCallback) { std::vector baseDataList = Load(path, optionsCallback); // The Load(path) call above should throw an exception if nothing could be loaded assert(!baseDataList.empty()); return baseDataList.front(); } #ifdef US_PLATFORM_WINDOWS std::string IOUtil::GetProgramPath() { char path[512]; std::size_t index = std::string(path, GetModuleFileName(nullptr, path, 512)).find_last_of('\\'); return std::string(path, index); } #elif defined(US_PLATFORM_APPLE) #include std::string IOUtil::GetProgramPath() { char path[512]; uint32_t size = sizeof(path); if (_NSGetExecutablePath(path, &size) == 0) { std::size_t index = std::string(path).find_last_of('/'); std::string strPath = std::string(path, index); // const char* execPath = strPath.c_str(); // mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(execPath,false); return strPath; } return std::string(); } #else #include #include #include std::string IOUtil::GetProgramPath() { std::stringstream ss; ss << "/proc/" << getpid() << "/exe"; char proc[512] = {0}; ssize_t ch = readlink(ss.str().c_str(), proc, 512); if (ch == -1) return std::string(); std::size_t index = std::string(proc).find_last_of('/'); return std::string(proc, index); } #endif char IOUtil::GetDirectorySeparator() { #ifdef US_PLATFORM_WINDOWS return '\\'; #else return '/'; #endif } std::string IOUtil::GetTempPath() { static std::string result; if (result.empty()) { #ifdef US_PLATFORM_WINDOWS char tempPathTestBuffer[1]; DWORD bufferLength = ::GetTempPath(1, tempPathTestBuffer); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } std::vector tempPath(bufferLength); bufferLength = ::GetTempPath(bufferLength, &tempPath[0]); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } result.assign(tempPath.begin(), tempPath.begin() + static_cast(bufferLength)); #else result = "/tmp/"; #endif } return result; } std::string IOUtil::CreateTemporaryFile(const std::string &templateName, std::string path) { - ofstream tmpOutputStream; + std::ofstream tmpOutputStream; std::string returnValue = CreateTemporaryFile(tmpOutputStream, templateName, path); tmpOutputStream.close(); return returnValue; } std::string IOUtil::CreateTemporaryFile(std::ofstream &f, const std::string &templateName, std::string path) { return CreateTemporaryFile(f, std::ios_base::out | std::ios_base::trunc, templateName, path); } std::string IOUtil::CreateTemporaryFile(std::ofstream &f, std::ios_base::openmode mode, const std::string &templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? -1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? -1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; int fd = mkstemps_compat(&dst_path[0], suffixlen); if (fd != -1) { path.assign(dst_path.begin(), dst_path.end() - 1); f.open(path.c_str(), mode | std::ios_base::out | std::ios_base::trunc); close(fd); } else { mitkThrow() << "Creating temporary file " << &dst_path[0] << " failed: " << GetLastErrorStr(); } return path; } std::string IOUtil::CreateTemporaryDirectory(const std::string &templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += GetDirectorySeparator() + templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? -1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? -1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; if (mkdtemps_compat(&dst_path[0], suffixlen) == nullptr) { mitkThrow() << "Creating temporary directory " << &dst_path[0] << " failed: " << GetLastErrorStr(); } path.assign(dst_path.begin(), dst_path.end() - 1); return path; } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string &path, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback) { std::vector paths; paths.push_back(path); return Load(paths, storage, optionsCallback); } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string &path, const IFileReader::Options &options, DataStorage &storage) { std::vector loadInfos; loadInfos.push_back(LoadInfo(path)); DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } std::vector IOUtil::Load(const std::string &path, const ReaderOptionsFunctorBase *optionsCallback) { std::vector paths; paths.push_back(path); return Load(paths, optionsCallback); } std::vector IOUtil::Load(const std::string &path, const IFileReader::Options &options) { std::vector loadInfos; loadInfos.push_back(LoadInfo(path)); Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(loadInfos, nullptr, nullptr, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return loadInfos.front().m_Output; } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::vector &paths, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback) { DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); std::vector loadInfos; for (auto loadInfo : paths) { loadInfos.push_back(loadInfo); } std::string errMsg = Load(loadInfos, nodeResult, &storage, optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } std::vector IOUtil::Load(const std::vector &paths, const ReaderOptionsFunctorBase *optionsCallback) { std::vector result; std::vector loadInfos; for (auto loadInfo : paths) { loadInfos.push_back(loadInfo); } std::string errMsg = Load(loadInfos, nullptr, nullptr, optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd; ++iter) { result.insert(result.end(), iter->m_Output.begin(), iter->m_Output.end()); } return result; } std::string IOUtil::Load(std::vector &loadInfos, DataStorage::SetOfObjects *nodeResult, DataStorage *ds, const ReaderOptionsFunctorBase *optionsCallback) { if (loadInfos.empty()) { return "No input files given"; } int filesToRead = loadInfos.size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(2 * filesToRead); std::string errMsg; std::map usedReaderItems; std::vector< std::string > read_files; for (auto &loadInfo : loadInfos) { if(std::find(read_files.begin(), read_files.end(), loadInfo.m_Path) != read_files.end()) continue; std::vector readers = loadInfo.m_ReaderSelector.Get(); if (readers.empty()) { if (!itksys::SystemTools::FileExists(loadInfo.m_Path.c_str())) { errMsg += "File '" + loadInfo.m_Path + "' does not exist\n"; } else { errMsg += "No reader available for '" + loadInfo.m_Path + "'\n"; } continue; } bool callOptionsCallback = readers.size() > 1 || !readers.front().GetReader()->GetOptions().empty(); // check if we already used a reader which should be re-used std::vector currMimeTypes = loadInfo.m_ReaderSelector.GetMimeTypes(); std::string selectedMimeType; for (std::vector::const_iterator mimeTypeIter = currMimeTypes.begin(), mimeTypeIterEnd = currMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { std::map::const_iterator oldSelectedItemIter = usedReaderItems.find(mimeTypeIter->GetName()); if (oldSelectedItemIter != usedReaderItems.end()) { // we found an already used item for a mime-type which is contained // in the current reader set, check all current readers if there service // id equals the old reader for (std::vector::const_iterator currReaderItem = readers.begin(), currReaderItemEnd = readers.end(); currReaderItem != currReaderItemEnd; ++currReaderItem) { if (currReaderItem->GetMimeType().GetName() == mimeTypeIter->GetName() && currReaderItem->GetServiceId() == oldSelectedItemIter->second.GetServiceId() && currReaderItem->GetConfidenceLevel() >= oldSelectedItemIter->second.GetConfidenceLevel()) { // okay, we used the same reader already, re-use its options selectedMimeType = mimeTypeIter->GetName(); callOptionsCallback = false; loadInfo.m_ReaderSelector.Select(oldSelectedItemIter->second.GetServiceId()); loadInfo.m_ReaderSelector.GetSelected().GetReader()->SetOptions( oldSelectedItemIter->second.GetReader()->GetOptions()); break; } } if (!selectedMimeType.empty()) break; } } if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(loadInfo); if (!callOptionsCallback && !loadInfo.m_Cancel) { usedReaderItems.erase(selectedMimeType); FileReaderSelector::Item selectedItem = loadInfo.m_ReaderSelector.GetSelected(); usedReaderItems.insert(std::make_pair(selectedItem.GetMimeType().GetName(), selectedItem)); } } if (loadInfo.m_Cancel) { errMsg += "Reading operation(s) cancelled."; break; } IFileReader *reader = loadInfo.m_ReaderSelector.GetSelected().GetReader(); if (reader == nullptr) { errMsg += "Unexpected nullptr reader."; break; } // Do the actual reading try { DataStorage::SetOfObjects::Pointer nodes; if (ds != nullptr) { nodes = reader->Read(*ds); std::vector< std::string > new_files = reader->GetReadFiles(); read_files.insert( read_files.end(), new_files.begin(), new_files.end() ); } else { nodes = DataStorage::SetOfObjects::New(); std::vector baseData = reader->Read(); for (auto iter = baseData.begin(); iter != baseData.end(); ++iter) { if (iter->IsNotNull()) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(*iter); nodes->InsertElement(nodes->Size(), node); } } std::vector< std::string > new_files = reader->GetReadFiles(); read_files.insert( read_files.end(), new_files.begin(), new_files.end() ); } for (DataStorage::SetOfObjects::ConstIterator nodeIter = nodes->Begin(), nodeIterEnd = nodes->End(); nodeIter != nodeIterEnd; ++nodeIter) { const mitk::DataNode::Pointer &node = nodeIter->Value(); mitk::BaseData::Pointer data = node->GetData(); if (data.IsNull()) { continue; } mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(loadInfo.m_Path); data->SetProperty("path", pathProp); loadInfo.m_Output.push_back(data); if (nodeResult) { nodeResult->push_back(nodeIter->Value()); } } if (loadInfo.m_Output.empty() || (nodeResult && nodeResult->Size() == 0)) { errMsg += "Unknown read error occurred reading " + loadInfo.m_Path; } } catch (const std::exception &e) { errMsg += "Exception occured when reading file " + loadInfo.m_Path + ":\n" + e.what() + "\n\n"; } mitk::ProgressBar::GetInstance()->Progress(2); --filesToRead; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2 * filesToRead); return errMsg; } std::vector IOUtil::Load(const us::ModuleResource &usResource, std::ios_base::openmode mode) { us::ModuleResourceStream resStream(usResource, mode); mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); std::vector mimetypes = mimeTypeProvider->GetMimeTypesForFile(usResource.GetResourcePath()); std::vector data; if (mimetypes.empty()) { mitkThrow() << "No mimetype for resource stream: " << usResource.GetResourcePath(); return data; } mitk::FileReaderRegistry fileReaderRegistry; std::vector> refs = fileReaderRegistry.GetReferences(mimetypes[0]); if (refs.empty()) { mitkThrow() << "No reader available for resource stream: " << usResource.GetResourcePath(); return data; } mitk::IFileReader *reader = fileReaderRegistry.GetReader(refs[0]); reader->SetInput(usResource.GetResourcePath(), &resStream); data = reader->Read(); return data; } void IOUtil::Save(const BaseData *data, const std::string &path, bool setPathProperty) { Save(data, path, IFileWriter::Options(), setPathProperty); } void IOUtil::Save(const BaseData *data, const std::string &path, const IFileWriter::Options &options, bool setPathProperty) { Save(data, std::string(), path, options, setPathProperty); } void IOUtil::Save(const BaseData *data, const std::string &mimeType, const std::string &path, bool addExtension, bool setPathProperty) { Save(data, mimeType, path, IFileWriter::Options(), addExtension, setPathProperty); } void IOUtil::Save(const BaseData *data, const std::string &mimeType, const std::string &path, const IFileWriter::Options &options, bool addExtension, bool setPathProperty) { if ((data == nullptr) || (data->IsEmpty())) mitkThrow() << "BaseData cannotbe null or empty for save methods in IOUtil.h."; std::string errMsg; if (options.empty()) { errMsg = Save(data, mimeType, path, nullptr, addExtension, setPathProperty); } else { Impl::FixedWriterOptionsFunctor optionsCallback(options); errMsg = Save(data, mimeType, path, &optionsCallback, addExtension, setPathProperty); } if (!errMsg.empty()) { mitkThrow() << errMsg; } } void IOUtil::Save(std::vector &saveInfos, bool setPathProperty) { std::string errMsg = Save(saveInfos, nullptr, setPathProperty); if (!errMsg.empty()) { mitkThrow() << errMsg; } } std::string IOUtil::Save(const BaseData *data, const std::string &mimeTypeName, const std::string &path, WriterOptionsFunctorBase *optionsCallback, bool addExtension, bool setPathProperty) { if (path.empty()) { return "No output filename given"; } mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName); SaveInfo saveInfo(data, mimeType, path); std::string ext = itksys::SystemTools::GetFilenameExtension(path); if (saveInfo.m_WriterSelector.IsEmpty()) { return std::string("No suitable writer found for the current data of type ") + data->GetNameOfClass() + (mimeType.IsValid() ? (std::string(" and mime-type ") + mimeType.GetName()) : std::string()) + (ext.empty() ? std::string() : (std::string(" with extension ") + ext)); } // Add an extension if not already specified if (ext.empty() && addExtension) { saveInfo.m_MimeType.GetExtensions().empty() ? std::string() : "." + saveInfo.m_MimeType.GetExtensions().front(); } std::vector infos; infos.push_back(saveInfo); return Save(infos, optionsCallback, setPathProperty); } std::string IOUtil::Save(std::vector &saveInfos, WriterOptionsFunctorBase *optionsCallback, bool setPathProperty) { if (saveInfos.empty()) { return "No data for saving available"; } int filesToWrite = saveInfos.size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(2 * filesToWrite); std::string errMsg; std::set usedSaveInfos; for (auto &saveInfo : saveInfos) { const std::string baseDataType = saveInfo.m_BaseData->GetNameOfClass(); std::vector writers = saveInfo.m_WriterSelector.Get(); // Error out if no compatible Writer was found if (writers.empty()) { errMsg += std::string("No writer available for ") + baseDataType + " data.\n"; continue; } bool callOptionsCallback = writers.size() > 1 || !writers[0].GetWriter()->GetOptions().empty(); // check if we already used a writer for this base data type // which should be re-used auto oldSaveInfoIter = usedSaveInfos.find(saveInfo); if (oldSaveInfoIter != usedSaveInfos.end()) { // we previously saved a base data object of the same data with the same mime-type, // check if the same writer is contained in the current writer set and if the // confidence level matches FileWriterSelector::Item oldSelectedItem = oldSaveInfoIter->m_WriterSelector.Get(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); for (std::vector::const_iterator currWriterItem = writers.begin(), currWriterItemEnd = writers.end(); currWriterItem != currWriterItemEnd; ++currWriterItem) { if (currWriterItem->GetServiceId() == oldSelectedItem.GetServiceId() && currWriterItem->GetConfidenceLevel() >= oldSelectedItem.GetConfidenceLevel()) { // okay, we used the same writer already, re-use its options callOptionsCallback = false; saveInfo.m_WriterSelector.Select(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); saveInfo.m_WriterSelector.GetSelected().GetWriter()->SetOptions(oldSelectedItem.GetWriter()->GetOptions()); break; } } } if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(saveInfo); if (!callOptionsCallback && !saveInfo.m_Cancel) { usedSaveInfos.erase(saveInfo); usedSaveInfos.insert(saveInfo); } } if (saveInfo.m_Cancel) { errMsg += "Writing operation(s) cancelled."; break; } IFileWriter *writer = saveInfo.m_WriterSelector.GetSelected().GetWriter(); if (writer == nullptr) { errMsg += "Unexpected nullptr writer."; break; } // Do the actual writing try { writer->SetOutputLocation(saveInfo.m_Path); writer->Write(); } catch (const std::exception &e) { errMsg += std::string("Exception occurred when writing to ") + saveInfo.m_Path + ":\n" + e.what() + "\n"; } if (setPathProperty) saveInfo.m_BaseData->GetPropertyList()->SetStringProperty("path", saveInfo.m_Path.c_str()); mitk::ProgressBar::GetInstance()->Progress(2); --filesToWrite; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2 * filesToWrite); return errMsg; } // This method can be removed after the deprecated LoadDataNode() method was removed void IOUtil::Impl::SetDefaultDataNodeProperties(DataNode *node, const std::string &filePath) { // path 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(node->GetProperty("name")); if (nameProp.IsNull() || nameProp->GetValue() == DataNode::NO_NAME_VALUE()) { // name already defined in BaseData mitk::StringProperty::Pointer baseDataNameProp = dynamic_cast(node->GetData()->GetProperty("name").GetPointer()); if (baseDataNameProp.IsNull() || baseDataNameProp->GetValue() == DataNode::NO_NAME_VALUE()) { // name neither defined in node, nor in BaseData -> name = filename nameProp = mitk::StringProperty::New(itksys::SystemTools::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); } } IOUtil::SaveInfo::SaveInfo(const BaseData *baseData, const MimeType &mimeType, const std::string &path) : m_BaseData(baseData), m_WriterSelector(baseData, mimeType.GetName(), path), m_MimeType(mimeType.IsValid() ? mimeType // use the original mime-type : (m_WriterSelector.IsEmpty() ? mimeType // no writer found, use the original invalid mime-type : m_WriterSelector.GetDefault().GetMimeType() // use the found default mime-type )), m_Path(path), m_Cancel(false) { } bool IOUtil::SaveInfo::operator<(const IOUtil::SaveInfo &other) const { int r = strcmp(m_BaseData->GetNameOfClass(), other.m_BaseData->GetNameOfClass()); if (r == 0) { return m_WriterSelector.GetSelected().GetMimeType() < other.m_WriterSelector.GetSelected().GetMimeType(); } return r < 0; } IOUtil::LoadInfo::LoadInfo(const std::string &path) : m_Path(path), m_ReaderSelector(path), m_Cancel(false) {} } diff --git a/Modules/Core/src/IO/mitkSurfaceStlIO.cpp b/Modules/Core/src/IO/mitkSurfaceStlIO.cpp index e64e9a1634..21aeb441e0 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 #include #include #include #include #include #include namespace mitk { - std::string SurfaceStlIO::OPTION_MERGE_POINTS() - { - static std::string s = "Merge points"; - return s; - } + // 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_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> SurfaceStlIO::DoRead() { LocaleSwitch localeSwitch("C"); Options options = this->GetReaderOptions(); mitk::Surface::Pointer output = mitk::Surface::New(); vtkSmartPointer stlReader = vtkSmartPointer::New(); stlReader->SetFileName(this->GetLocalFileName().c_str()); - bool mergePoints = true; + // bool mergePoints = true; bool tagSolids = false; bool cleanData = true; try { - mergePoints = us::any_cast(options[OPTION_MERGE_POINTS()]); + // mergePoints = us::any_cast(options[OPTION_MERGE_POINTS()]); tagSolids = us::any_cast(options[OPTION_TAG_SOLIDS()]); cleanData = us::any_cast(options[OPTION_CLEAN()]); } catch (const us::BadAnyCastException &e) { MITK_WARN << "Unexpected error: " << e.what(); } - stlReader->SetMerging(mergePoints); + // stlReader->SetMerging(mergePoints); stlReader->SetScalarTags(tagSolids); vtkSmartPointer normalsGenerator = vtkSmartPointer::New(); normalsGenerator->SetInputConnection(stlReader->GetOutputPort()); vtkSmartPointer algo = normalsGenerator; if (cleanData) { vtkSmartPointer cleanPolyDataFilter = vtkSmartPointer::New(); cleanPolyDataFilter->SetInputConnection(normalsGenerator->GetOutputPort()); cleanPolyDataFilter->PieceInvariantOff(); cleanPolyDataFilter->ConvertLinesToPointsOff(); cleanPolyDataFilter->ConvertPolysToLinesOff(); cleanPolyDataFilter->ConvertStripsToPolysOff(); - if (mergePoints) - { + // if (mergePoints) + // { cleanPolyDataFilter->PointMergingOn(); - } + // } algo = cleanPolyDataFilter; } algo->Update(); if (algo->GetOutput() != nullptr) { vtkSmartPointer surfaceWithNormals = algo->GetOutput(); output->SetVtkPolyData(surfaceWithNormals); } std::vector result; result.push_back(output.GetPointer()); return result; } void SurfaceStlIO::Write() { LocaleSwitch localeSwitch("C"); ValidateOutputLocation(); const auto *input = dynamic_cast(this->GetInput()); const unsigned int timesteps = input->GetTimeGeometry()->CountTimeSteps(); for (unsigned int t = 0; t < timesteps; ++t) { std::string fileName; vtkSmartPointer polyData = this->GetPolyData(t, fileName); vtkSmartPointer triangleFilter = vtkSmartPointer::New(); triangleFilter->SetInputData(polyData); vtkSmartPointer writer = vtkSmartPointer::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 ffe36e1e60..2e95e8ab2e 100644 --- a/Modules/Core/src/IO/mitkSurfaceStlIO.h +++ b/Modules/Core/src/IO/mitkSurfaceStlIO.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 _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; // -------------- AbstractFileWriter ------------- void Write() override; protected: std::vector> DoRead() override; private: SurfaceStlIO *IOClone() const override; - static std::string OPTION_MERGE_POINTS(); + // vtkSTLReader crashes with this option + // 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/Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp b/Modules/Core/src/Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp index 7f8b7029e7..4db486904d 100644 --- a/Modules/Core/src/Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp +++ b/Modules/Core/src/Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp @@ -1,580 +1,582 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkPlaneGeometryDataVtkMapper3D.h" #include "mitkImageVtkMapper2D.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" #include "mitkSmartPointerProperty.h" #include "mitkSurface.h" #include "mitkVtkRepresentationProperty.h" #include "mitkWeakPointerProperty.h" #include "vtkMitkLevelWindowFilter.h" #include "vtkNeverTranslucentTexture.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { PlaneGeometryDataVtkMapper3D::PlaneGeometryDataVtkMapper3D() : m_NormalsActorAdded(false), m_DataStorage(nullptr) { m_EdgeTuber = vtkTubeFilter::New(); m_EdgeMapper = vtkPolyDataMapper::New(); m_SurfaceCreator = PlaneGeometryDataToSurfaceFilter::New(); m_SurfaceCreatorBoundingBox = BoundingBox::New(); m_SurfaceCreatorPointsContainer = BoundingBox::PointsContainer::New(); m_Edges = vtkFeatureEdges::New(); m_Edges->BoundaryEdgesOn(); m_Edges->FeatureEdgesOff(); m_Edges->NonManifoldEdgesOff(); m_Edges->ManifoldEdgesOff(); m_EdgeTransformer = vtkTransformPolyDataFilter::New(); m_NormalsTransformer = vtkTransformPolyDataFilter::New(); m_EdgeActor = vtkActor::New(); m_BackgroundMapper = vtkPolyDataMapper::New(); m_BackgroundActor = vtkActor::New(); m_Prop3DAssembly = vtkAssembly::New(); m_ImageAssembly = vtkAssembly::New(); m_SurfaceCreatorBoundingBox->SetPoints(m_SurfaceCreatorPointsContainer); m_Cleaner = vtkCleanPolyData::New(); m_Cleaner->PieceInvariantOn(); m_Cleaner->ConvertLinesToPointsOn(); m_Cleaner->ConvertPolysToLinesOn(); m_Cleaner->ConvertStripsToPolysOn(); m_Cleaner->PointMergingOn(); // Make sure that the FeatureEdge algorithm is initialized with a "valid" // (though empty) input vtkPolyData *emptyPolyData = vtkPolyData::New(); m_Cleaner->SetInputData(emptyPolyData); emptyPolyData->Delete(); m_Edges->SetInputConnection(m_Cleaner->GetOutputPort()); m_EdgeTransformer->SetInputConnection(m_Edges->GetOutputPort()); m_EdgeTuber->SetInputConnection(m_EdgeTransformer->GetOutputPort()); m_EdgeTuber->SetVaryRadiusToVaryRadiusOff(); m_EdgeTuber->SetNumberOfSides(12); m_EdgeTuber->CappingOn(); m_EdgeMapper->SetInputConnection(m_EdgeTuber->GetOutputPort()); m_EdgeMapper->ScalarVisibilityOff(); m_BackgroundMapper->SetInputData(emptyPolyData); m_BackgroundMapper->Update(); m_EdgeActor->SetMapper(m_EdgeMapper); m_BackgroundActor->GetProperty()->SetAmbient(0.5); m_BackgroundActor->GetProperty()->SetColor(0.0, 0.0, 0.0); m_BackgroundActor->GetProperty()->SetOpacity(0.0); m_BackgroundActor->SetMapper(m_BackgroundMapper); vtkProperty *backfaceProperty = m_BackgroundActor->MakeProperty(); backfaceProperty->SetColor(0.0, 0.0, 0.0); m_BackgroundActor->SetBackfaceProperty(backfaceProperty); backfaceProperty->Delete(); m_FrontHedgeHog = vtkHedgeHog::New(); m_BackHedgeHog = vtkHedgeHog::New(); m_FrontNormalsMapper = vtkPolyDataMapper::New(); m_FrontNormalsMapper->SetInputConnection(m_FrontHedgeHog->GetOutputPort()); m_BackNormalsMapper = vtkPolyDataMapper::New(); m_Prop3DAssembly->AddPart(m_EdgeActor); m_Prop3DAssembly->AddPart(m_ImageAssembly); m_FrontNormalsActor = vtkActor::New(); m_FrontNormalsActor->SetMapper(m_FrontNormalsMapper); m_BackNormalsActor = vtkActor::New(); m_BackNormalsActor->SetMapper(m_BackNormalsMapper); m_ImageMapperDeletedCommand = MemberCommandType::New(); m_ImageMapperDeletedCommand->SetCallbackFunction(this, &PlaneGeometryDataVtkMapper3D::ImageMapperDeletedCallback); } PlaneGeometryDataVtkMapper3D::~PlaneGeometryDataVtkMapper3D() { m_ImageAssembly->Delete(); m_Prop3DAssembly->Delete(); m_EdgeTuber->Delete(); m_EdgeMapper->Delete(); m_EdgeTransformer->Delete(); m_Cleaner->Delete(); m_Edges->Delete(); m_NormalsTransformer->Delete(); m_EdgeActor->Delete(); m_BackgroundMapper->Delete(); m_BackgroundActor->Delete(); m_FrontNormalsMapper->Delete(); m_FrontNormalsActor->Delete(); m_FrontHedgeHog->Delete(); m_BackNormalsMapper->Delete(); m_BackNormalsActor->Delete(); m_BackHedgeHog->Delete(); for (auto it = m_ImageActors.begin(); it != m_ImageActors.end(); ++it) it->second.m_Actor->ReleaseGraphicsResources(nullptr); // Delete entries in m_ImageActors list one by one m_ImageActors.clear(); m_DataStorage = nullptr; } vtkProp *PlaneGeometryDataVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) { if ((this->GetDataNode() != nullptr) && (m_ImageAssembly != nullptr)) { // Do not transform the entire Prop3D assembly, but only the image part // here. The colored frame is transformed elsewhere (via m_EdgeTransformer), // since only vertices should be transformed there, not the poly data // itself, to avoid distortion for anisotropic datasets. m_ImageAssembly->SetUserTransform(this->GetDataNode()->GetVtkTransform()); } return m_Prop3DAssembly; } void PlaneGeometryDataVtkMapper3D::UpdateVtkTransform(mitk::BaseRenderer * /*renderer*/) { m_ImageAssembly->SetUserTransform(this->GetDataNode()->GetVtkTransform(this->GetTimestep())); } const PlaneGeometryData *PlaneGeometryDataVtkMapper3D::GetInput() { return static_cast(GetDataNode()->GetData()); } void PlaneGeometryDataVtkMapper3D::SetDataStorageForTexture(mitk::DataStorage *storage) { if (storage != nullptr && m_DataStorage != storage) { m_DataStorage = storage; this->Modified(); } } void PlaneGeometryDataVtkMapper3D::ImageMapperDeletedCallback(itk::Object *caller, const itk::EventObject & /*event*/) { auto *imageMapper = dynamic_cast(caller); if ((imageMapper != nullptr)) { if (m_ImageActors.count(imageMapper) > 0) { m_ImageActors[imageMapper].m_Sender = nullptr; // sender is already destroying itself m_ImageActors.erase(imageMapper); } } } void PlaneGeometryDataVtkMapper3D::GenerateDataForRenderer(BaseRenderer *renderer) { // Remove all actors from the assembly, and re-initialize it with the // edge actor m_ImageAssembly->GetParts()->RemoveAllItems(); bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if (!visible) { // visibility has explicitly to be set in the single actors // due to problems when using cell picking: // even if the assembly is invisible, the renderer contains // references to the assemblies parts. During picking the // visibility of each part is checked, and not only for the // whole assembly. m_ImageAssembly->VisibilityOff(); m_EdgeActor->VisibilityOff(); return; } // visibility has explicitly to be set in the single actors // due to problems when using cell picking: // even if the assembly is invisible, the renderer contains // references to the assemblies parts. During picking the // visibility of each part is checked, and not only for the // whole assembly. m_ImageAssembly->VisibilityOn(); bool drawEdges = true; this->GetDataNode()->GetBoolProperty("draw edges", drawEdges, renderer); m_EdgeActor->SetVisibility(drawEdges); PlaneGeometryData::ConstPointer input = this->GetInput(); if (input.IsNotNull() && (input->GetPlaneGeometry() != nullptr)) { SmartPointerProperty::Pointer surfacecreatorprop; surfacecreatorprop = dynamic_cast(GetDataNode()->GetProperty("surfacegeometry", renderer)); if ((surfacecreatorprop.IsNull()) || (surfacecreatorprop->GetSmartPointer().IsNull()) || ((m_SurfaceCreator = dynamic_cast(surfacecreatorprop->GetSmartPointer().GetPointer())) .IsNull())) { m_SurfaceCreator->PlaceByGeometryOn(); surfacecreatorprop = SmartPointerProperty::New(m_SurfaceCreator); GetDataNode()->SetProperty("surfacegeometry", surfacecreatorprop); } m_SurfaceCreator->SetInput(input); int res; if (GetDataNode()->GetIntProperty("xresolution", res, renderer)) { m_SurfaceCreator->SetXResolution(res); } if (GetDataNode()->GetIntProperty("yresolution", res, renderer)) { m_SurfaceCreator->SetYResolution(res); } double tubeRadius = 1.0; // Radius of tubular edge surrounding plane // Clip the PlaneGeometry with the reference geometry bounds (if available) if (input->GetPlaneGeometry()->HasReferenceGeometry()) { const BaseGeometry *referenceGeometry = input->GetPlaneGeometry()->GetReferenceGeometry(); BoundingBox::PointType boundingBoxMin, boundingBoxMax; boundingBoxMin = referenceGeometry->GetBoundingBox()->GetMinimum(); boundingBoxMax = referenceGeometry->GetBoundingBox()->GetMaximum(); if (referenceGeometry->GetImageGeometry()) { for (unsigned int i = 0; i < 3; ++i) { boundingBoxMin[i] -= 0.5; boundingBoxMax[i] -= 0.5; } } m_SurfaceCreatorPointsContainer->CreateElementAt(0) = boundingBoxMin; m_SurfaceCreatorPointsContainer->CreateElementAt(1) = boundingBoxMax; m_SurfaceCreatorBoundingBox->ComputeBoundingBox(); m_SurfaceCreator->SetBoundingBox(m_SurfaceCreatorBoundingBox); tubeRadius = referenceGeometry->GetDiagonalLength() / 450.0; } // If no reference geometry is available, clip with the current global // bounds else if (!m_DataStorage.IsExpired()) { m_SurfaceCreator->SetBoundingBox(m_DataStorage.Lock()->ComputeVisibleBoundingBox(nullptr, "includeInBoundingBox")); tubeRadius = sqrt(m_SurfaceCreator->GetBoundingBox()->GetDiagonalLength2()) / 450.0; } // Calculate the surface of the PlaneGeometry m_SurfaceCreator->Update(); Surface *surface = m_SurfaceCreator->GetOutput(); // Check if there's something to display, otherwise return if ((surface->GetVtkPolyData() == nullptr) || (surface->GetVtkPolyData()->GetNumberOfCells() == 0)) { m_ImageAssembly->VisibilityOff(); return; } // add a graphical representation of the surface normals if requested DataNode *node = this->GetDataNode(); bool displayNormals = false; bool colorTwoSides = false; bool invertNormals = false; node->GetBoolProperty("draw normals 3D", displayNormals, renderer); node->GetBoolProperty("color two sides", colorTwoSides, renderer); node->GetBoolProperty("invert normals", invertNormals, renderer); // if we want to draw the display normals or render two sides we have to get the colors if (displayNormals || colorTwoSides) { // get colors float frontColor[3] = {0.0, 0.0, 1.0}; node->GetColor(frontColor, renderer, "front color"); float backColor[3] = {1.0, 0.0, 0.0}; node->GetColor(backColor, renderer, "back color"); if (displayNormals) { m_NormalsTransformer->SetInputData(surface->GetVtkPolyData()); m_NormalsTransformer->SetTransform(node->GetVtkTransform(this->GetTimestep())); m_FrontHedgeHog->SetInputConnection(m_NormalsTransformer->GetOutputPort()); m_FrontHedgeHog->SetVectorModeToUseNormal(); m_FrontHedgeHog->SetScaleFactor(invertNormals ? 1.0 : -1.0); m_FrontHedgeHog->Update(); m_FrontNormalsActor->GetProperty()->SetColor(frontColor[0], frontColor[1], frontColor[2]); m_BackHedgeHog->SetInputConnection(m_NormalsTransformer->GetOutputPort()); m_BackHedgeHog->SetVectorModeToUseNormal(); m_BackHedgeHog->SetScaleFactor(invertNormals ? -1.0 : 1.0); m_BackHedgeHog->Update(); m_BackNormalsActor->GetProperty()->SetColor(backColor[0], backColor[1], backColor[2]); // if there is no actor added yet, add one if (!m_NormalsActorAdded) { m_Prop3DAssembly->AddPart(m_FrontNormalsActor); m_Prop3DAssembly->AddPart(m_BackNormalsActor); m_NormalsActorAdded = true; } } // if we don't want to display normals AND there is an actor added remove the actor else if (m_NormalsActorAdded) { m_Prop3DAssembly->RemovePart(m_FrontNormalsActor); m_Prop3DAssembly->RemovePart(m_BackNormalsActor); m_NormalsActorAdded = false; } if (colorTwoSides) { if (!invertNormals) { m_BackgroundActor->GetProperty()->SetColor(backColor[0], backColor[1], backColor[2]); m_BackgroundActor->GetBackfaceProperty()->SetColor(frontColor[0], frontColor[1], frontColor[2]); } else { m_BackgroundActor->GetProperty()->SetColor(frontColor[0], frontColor[1], frontColor[2]); m_BackgroundActor->GetBackfaceProperty()->SetColor(backColor[0], backColor[1], backColor[2]); } } } // Add black background for all images (which may be transparent) m_BackgroundMapper->SetInputData(surface->GetVtkPolyData()); // m_ImageAssembly->AddPart(m_BackgroundActor); LayerSortedActorList layerSortedActors; // Traverse the data tree to find nodes resliced by ImageMapperGL2D // use a predicate to get all data nodes which are "images" or inherit from mitk::Image mitk::TNodePredicateDataType::Pointer predicateAllImages = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer all = m_DataStorage.Lock()->GetSubset(predicateAllImages); // process all found images for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode *node = it->Value(); if (node != nullptr) this->ProcessNode(node, renderer, surface, layerSortedActors); } // Add all image actors to the assembly, sorted according to // layer property LayerSortedActorList::iterator actorIt; for (actorIt = layerSortedActors.begin(); actorIt != layerSortedActors.end(); ++actorIt) { m_ImageAssembly->AddPart(actorIt->second); } // Configurate the tube-shaped frame: size according to the surface // bounds, color as specified in the plane's properties vtkPolyData *surfacePolyData = surface->GetVtkPolyData(); m_Cleaner->SetInputData(surfacePolyData); m_EdgeTransformer->SetTransform(this->GetDataNode()->GetVtkTransform(this->GetTimestep())); // Adjust the radius according to extent m_EdgeTuber->SetRadius(tubeRadius); // Get the plane's color and set the tube properties accordingly ColorProperty::Pointer colorProperty; colorProperty = dynamic_cast(this->GetDataNode()->GetProperty("color")); if (colorProperty.IsNotNull()) { const Color &color = colorProperty->GetColor(); m_EdgeActor->GetProperty()->SetColor(color.GetRed(), color.GetGreen(), color.GetBlue()); } else { m_EdgeActor->GetProperty()->SetColor(1.0, 1.0, 1.0); } m_ImageAssembly->SetUserTransform(this->GetDataNode()->GetVtkTransform(this->GetTimestep())); } VtkRepresentationProperty *representationProperty; this->GetDataNode()->GetProperty(representationProperty, "material.representation", renderer); if (representationProperty != nullptr) m_BackgroundActor->GetProperty()->SetRepresentation(representationProperty->GetVtkRepresentation()); } void PlaneGeometryDataVtkMapper3D::ProcessNode(DataNode *node, BaseRenderer *renderer, Surface *surface, LayerSortedActorList &layerSortedActors) { if (node != nullptr) { // we need to get the information from the 2D mapper to render the texture on the 3D plane auto *imageMapper = dynamic_cast(node->GetMapper(1)); // GetMapper(1) provides the 2D mapper for the data node // if there is a 2D mapper, which is not the standard image mapper... if (!imageMapper && node->GetMapper(1)) { //... check if it is the composite mapper std::string cname(node->GetMapper(1)->GetNameOfClass()); if (!cname.compare("CompositeMapper")) // string.compare returns 0 if the two strings are equal. { // get the standard image mapper. // This is a special case in MITK and does only work for the CompositeMapper. imageMapper = dynamic_cast(node->GetMapper(3)); } } if ((node->IsVisible(renderer)) && imageMapper) { WeakPointerProperty::Pointer rendererProp = dynamic_cast(GetDataNode()->GetPropertyList()->GetProperty("renderer")); if (rendererProp.IsNotNull()) { BaseRenderer::Pointer planeRenderer = dynamic_cast(rendererProp->GetWeakPointer().GetPointer()); // Retrieve and update image to be mapped const ImageVtkMapper2D::LocalStorage *localStorage = imageMapper->GetConstLocalStorage(planeRenderer); if (planeRenderer.IsNotNull()) { // perform update of imagemapper if needed (maybe the respective 2D renderwindow is not rendered/update // before) imageMapper->Update(planeRenderer); // If it has not been initialized already in a previous pass, // generate an actor and a texture object to // render the image associated with the ImageVtkMapper2D. vtkActor *imageActor; vtkDataSetMapper *dataSetMapper = nullptr; vtkTexture *texture; if (m_ImageActors.count(imageMapper) == 0) { dataSetMapper = vtkDataSetMapper::New(); texture = vtkNeverTranslucentTexture::New(); texture->RepeatOff(); imageActor = vtkActor::New(); imageActor->SetMapper(dataSetMapper); imageActor->SetTexture(texture); imageActor->GetProperty()->SetOpacity( 0.999); // HACK! otherwise VTK wouldn't recognize this as translucent // surface (if LUT values map to alpha < 255 // improvement: apply "opacity" property onle HERE and also in 2D image mapper. DO NOT change LUT to // achieve // translucent images (see method ChangeOpacity in image mapper 2D) // Make imageActor the sole owner of the mapper and texture // objects dataSetMapper->UnRegister(nullptr); texture->UnRegister(nullptr); // Store the actor so that it may be accessed in following // passes. m_ImageActors[imageMapper].Initialize(imageActor, imageMapper, m_ImageMapperDeletedCommand); } else { // Else, retrieve the actor and associated objects from the // previous pass. imageActor = m_ImageActors[imageMapper].m_Actor; dataSetMapper = (vtkDataSetMapper *)imageActor->GetMapper(); texture = imageActor->GetTexture(); } // Set poly data new each time its object changes (e.g. when // switching between planar and curved geometries) if ((dataSetMapper != nullptr) && (dataSetMapper->GetInput() != surface->GetVtkPolyData())) { dataSetMapper->SetInputData(surface->GetVtkPolyData()); } dataSetMapper->Update(); // Check if the m_ReslicedImage is nullptr. // This is the case when no image geometry is met by // the reslicer. In that case, the texture has to be // empty (black) and we don't have to do anything. // See fixed bug #13275 if (localStorage->m_ReslicedImage != nullptr) { texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort()); // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter) texture->SetColorModeToDirectScalars(); // re-use properties from the 2D image mapper - imageActor->SetProperty(localStorage->m_ImageActor->GetProperty()); - imageActor->GetProperty()->SetAmbient(0.5); + auto property = vtkSmartPointer::New(); + localStorage->m_ImageActor->GetProperty()->DeepCopy(property); + property->LightingOff(); + imageActor->SetProperty(property); // Set texture interpolation on/off bool textureInterpolation = node->IsOn("texture interpolation", renderer); texture->SetInterpolate(textureInterpolation); // Store this actor to be added to the actor assembly, sort // by layer int layer = 1; node->GetIntProperty("layer", layer); layerSortedActors.insert(std::pair(layer, imageActor)); } } } } } } void PlaneGeometryDataVtkMapper3D::ActorInfo::Initialize(vtkActor *actor, itk::Object *sender, itk::Command *command) { m_Actor = actor; m_Sender = sender; // Get informed when ImageMapper object is deleted, so that // the data structures built here can be deleted as well m_ObserverID = sender->AddObserver(itk::DeleteEvent(), command); } PlaneGeometryDataVtkMapper3D::ActorInfo::ActorInfo() : m_Actor(nullptr), m_Sender(nullptr), m_ObserverID(0) {} PlaneGeometryDataVtkMapper3D::ActorInfo::~ActorInfo() { if (m_Sender != nullptr) { m_Sender->RemoveObserver(m_ObserverID); } if (m_Actor != nullptr) { m_Actor->ReleaseGraphicsResources(nullptr); m_Actor->Delete(); } } } // namespace mitk diff --git a/Modules/Core/src/Rendering/mitkSurfaceVtkMapper3D.cpp b/Modules/Core/src/Rendering/mitkSurfaceVtkMapper3D.cpp index 8d45e37923..33016c95e0 100644 --- a/Modules/Core/src/Rendering/mitkSurfaceVtkMapper3D.cpp +++ b/Modules/Core/src/Rendering/mitkSurfaceVtkMapper3D.cpp @@ -1,519 +1,520 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkSurfaceVtkMapper3D.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include #include #include #include #include #include +#include const mitk::Surface *mitk::SurfaceVtkMapper3D::GetInput() { return static_cast(GetDataNode()->GetData()); } mitk::SurfaceVtkMapper3D::SurfaceVtkMapper3D() { m_GenerateNormals = false; } mitk::SurfaceVtkMapper3D::~SurfaceVtkMapper3D() { } void mitk::SurfaceVtkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if (!visible) { ls->m_Actor->VisibilityOff(); return; } // // set the input-object at time t for the mapper // mitk::Surface::ConstPointer input = this->GetInput(); vtkSmartPointer polydata = input->GetVtkPolyData(this->GetTimestep()); if (polydata == nullptr) { ls->m_Actor->VisibilityOff(); return; } if (m_GenerateNormals) { ls->m_VtkPolyDataNormals->SetInputData(polydata); ls->m_VtkPolyDataMapper->SetInputConnection(ls->m_VtkPolyDataNormals->GetOutputPort()); } else { bool depthsorting = false; GetDataNode()->GetBoolProperty("Depth Sorting", depthsorting); if (depthsorting) { ls->m_DepthSort->SetInputData(polydata); ls->m_DepthSort->SetCamera(renderer->GetVtkRenderer()->GetActiveCamera()); ls->m_DepthSort->SetDirectionToBackToFront(); ls->m_DepthSort->Update(); ls->m_VtkPolyDataMapper->SetInputConnection(ls->m_DepthSort->GetOutputPort()); } else { ls->m_VtkPolyDataMapper->SetInputData(polydata); } } // // apply properties read from the PropertyList // ApplyAllProperties(renderer, ls->m_Actor); if (visible) ls->m_Actor->VisibilityOn(); } void mitk::SurfaceVtkMapper3D::ResetMapper(BaseRenderer *renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); ls->m_Actor->VisibilityOff(); } void mitk::SurfaceVtkMapper3D::ApplyMitkPropertiesToVtkProperty(mitk::DataNode *node, vtkProperty *property, mitk::BaseRenderer *renderer) { // Backface culling { mitk::BoolProperty::Pointer p; node->GetProperty(p, "Backface Culling", renderer); bool useCulling = false; if (p.IsNotNull()) useCulling = p->GetValue(); property->SetBackfaceCulling(useCulling); } // Colors { double ambient[3] = {0.5, 0.5, 0.0}; double diffuse[3] = {0.5, 0.5, 0.0}; double specular[3] = {1.0, 1.0, 1.0}; float coeff_ambient = 0.5f; float coeff_diffuse = 0.5f; float coeff_specular = 0.5f; float power_specular = 10.0f; // Color { mitk::ColorProperty::Pointer p; node->GetProperty(p, "color", renderer); if (p.IsNotNull()) { mitk::Color c = p->GetColor(); ambient[0] = c.GetRed(); ambient[1] = c.GetGreen(); ambient[2] = c.GetBlue(); diffuse[0] = c.GetRed(); diffuse[1] = c.GetGreen(); diffuse[2] = c.GetBlue(); // Setting specular color to the same, make physically no real sense, however vtk rendering slows down, if these // colors are different. specular[0] = c.GetRed(); specular[1] = c.GetGreen(); specular[2] = c.GetBlue(); } } // Ambient { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.ambientColor", renderer); if (p.IsNotNull()) { mitk::Color c = p->GetColor(); ambient[0] = c.GetRed(); ambient[1] = c.GetGreen(); ambient[2] = c.GetBlue(); } } // Diffuse { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.diffuseColor", renderer); if (p.IsNotNull()) { mitk::Color c = p->GetColor(); diffuse[0] = c.GetRed(); diffuse[1] = c.GetGreen(); diffuse[2] = c.GetBlue(); } } // Specular { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.specularColor", renderer); if (p.IsNotNull()) { mitk::Color c = p->GetColor(); specular[0] = c.GetRed(); specular[1] = c.GetGreen(); specular[2] = c.GetBlue(); } } // Ambient coeff { node->GetFloatProperty("material.ambientCoefficient", coeff_ambient, renderer); } // Diffuse coeff { node->GetFloatProperty("material.diffuseCoefficient", coeff_diffuse, renderer); } // Specular coeff { node->GetFloatProperty("material.specularCoefficient", coeff_specular, renderer); } // Specular power { node->GetFloatProperty("material.specularPower", power_specular, renderer); } property->SetAmbient(coeff_ambient); property->SetDiffuse(coeff_diffuse); property->SetSpecular(coeff_specular); property->SetSpecularPower(power_specular); property->SetAmbientColor(ambient); property->SetDiffuseColor(diffuse); property->SetSpecularColor(specular); } // Render mode { // Opacity { float opacity = 1.0f; if (node->GetOpacity(opacity, renderer)) property->SetOpacity(opacity); } // Wireframe line width { float lineWidth = 1; node->GetFloatProperty("material.wireframeLineWidth", lineWidth, renderer); property->SetLineWidth(lineWidth); } // Point size { float pointSize = 1.0f; node->GetFloatProperty("material.pointSize", pointSize, renderer); property->SetPointSize(pointSize); } // Representation { mitk::VtkRepresentationProperty::Pointer p; node->GetProperty(p, "material.representation", renderer); if (p.IsNotNull()) property->SetRepresentation(p->GetVtkRepresentation()); } // Interpolation { mitk::VtkInterpolationProperty::Pointer p; node->GetProperty(p, "material.interpolation", renderer); if (p.IsNotNull()) property->SetInterpolation(p->GetVtkInterpolation()); } } } void mitk::SurfaceVtkMapper3D::ApplyAllProperties(mitk::BaseRenderer *renderer, vtkActor * /*actor*/) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); Superclass::ApplyColorAndOpacityProperties(renderer, ls->m_Actor); // VTK Properties ApplyMitkPropertiesToVtkProperty(this->GetDataNode(), ls->m_Actor->GetProperty(), renderer); mitk::TransferFunctionProperty::Pointer transferFuncProp; this->GetDataNode()->GetProperty(transferFuncProp, "Surface.TransferFunction", renderer); if (transferFuncProp.IsNotNull()) { ls->m_VtkPolyDataMapper->SetLookupTable(transferFuncProp->GetValue()->GetColorTransferFunction()); } mitk::LookupTableProperty::Pointer lookupTableProp; this->GetDataNode()->GetProperty(lookupTableProp, "LookupTable", renderer); if (lookupTableProp.IsNotNull()) { ls->m_VtkPolyDataMapper->SetLookupTable(lookupTableProp->GetLookupTable()->GetVtkLookupTable()); } mitk::LevelWindow levelWindow; if (this->GetDataNode()->GetLevelWindow(levelWindow, renderer, "levelWindow")) { ls->m_VtkPolyDataMapper->SetScalarRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); } else if (this->GetDataNode()->GetLevelWindow(levelWindow, renderer)) { ls->m_VtkPolyDataMapper->SetScalarRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); } bool scalarVisibility = false; this->GetDataNode()->GetBoolProperty("scalar visibility", scalarVisibility); ls->m_VtkPolyDataMapper->SetScalarVisibility((scalarVisibility ? 1 : 0)); if (scalarVisibility) { mitk::VtkScalarModeProperty *scalarMode; if (this->GetDataNode()->GetProperty(scalarMode, "scalar mode", renderer)) ls->m_VtkPolyDataMapper->SetScalarMode(scalarMode->GetVtkScalarMode()); else ls->m_VtkPolyDataMapper->SetScalarModeToDefault(); bool colorMode = false; this->GetDataNode()->GetBoolProperty("color mode", colorMode); ls->m_VtkPolyDataMapper->SetColorMode((colorMode ? 1 : 0)); double scalarsMin = 0; this->GetDataNode()->GetDoubleProperty("ScalarsRangeMinimum", scalarsMin, renderer); double scalarsMax = 1.0; this->GetDataNode()->GetDoubleProperty("ScalarsRangeMaximum", scalarsMax, renderer); ls->m_VtkPolyDataMapper->SetScalarRange(scalarsMin, scalarsMax); } mitk::SmartPointerProperty::Pointer imagetextureProp = dynamic_cast(GetDataNode()->GetProperty("Surface.Texture", renderer)); if (imagetextureProp.IsNotNull()) { mitk::Image *miktTexture = dynamic_cast(imagetextureProp->GetSmartPointer().GetPointer()); vtkSmartPointer vtkTxture = vtkSmartPointer::New(); // Either select the first slice of a volume if (miktTexture->GetDimension(2) > 1) { MITK_WARN << "3D Textures are not supported by VTK and MITK. The first slice of the volume will be used instead!"; mitk::ImageSliceSelector::Pointer sliceselector = mitk::ImageSliceSelector::New(); sliceselector->SetSliceNr(0); sliceselector->SetChannelNr(0); sliceselector->SetTimeNr(0); sliceselector->SetInput(miktTexture); sliceselector->Update(); vtkTxture->SetInputData(sliceselector->GetOutput()->GetVtkImageData()); } else // or just use the 2D image { vtkTxture->SetInputData(miktTexture->GetVtkImageData()); } // pass the texture to the actor ls->m_Actor->SetTexture(vtkTxture); if (ls->m_VtkPolyDataMapper->GetInput()->GetPointData()->GetTCoords() == nullptr) { MITK_ERROR << "Surface.Texture property was set, but there are no texture coordinates. Please provide texture " "coordinates for the vtkPolyData via vtkPolyData->GetPointData()->SetTCoords()."; } // if no texture is set, this will also remove a previously used texture // and reset the actor to it's default behaviour } else { ls->m_Actor->SetTexture(nullptr); } // deprecated settings bool deprecatedUseCellData = false; this->GetDataNode()->GetBoolProperty("deprecated useCellDataForColouring", deprecatedUseCellData); bool deprecatedUsePointData = false; this->GetDataNode()->GetBoolProperty("deprecated usePointDataForColouring", deprecatedUsePointData); if (deprecatedUseCellData) { ls->m_VtkPolyDataMapper->SetColorModeToDefault(); ls->m_VtkPolyDataMapper->SetScalarRange(0, 255); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_VtkPolyDataMapper->SetScalarModeToUseCellData(); ls->m_Actor->GetProperty()->SetSpecular(1); ls->m_Actor->GetProperty()->SetSpecularPower(50); ls->m_Actor->GetProperty()->SetInterpolationToPhong(); } else if (deprecatedUsePointData) { float scalarsMin = 0; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum")) != nullptr) scalarsMin = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum"))->GetValue(); float scalarsMax = 0.1; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum")) != nullptr) scalarsMax = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum"))->GetValue(); ls->m_VtkPolyDataMapper->SetScalarRange(scalarsMin, scalarsMax); ls->m_VtkPolyDataMapper->SetColorModeToMapScalars(); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_Actor->GetProperty()->SetSpecular(1); ls->m_Actor->GetProperty()->SetSpecularPower(50); ls->m_Actor->GetProperty()->SetInterpolationToPhong(); } int deprecatedScalarMode = VTK_COLOR_MODE_DEFAULT; if (this->GetDataNode()->GetIntProperty("deprecated scalar mode", deprecatedScalarMode, renderer)) { ls->m_VtkPolyDataMapper->SetScalarMode(deprecatedScalarMode); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_Actor->GetProperty()->SetSpecular(1); ls->m_Actor->GetProperty()->SetSpecularPower(50); } // Check whether one or more ClippingProperty objects have been defined for // this node. Check both renderer specific and global property lists, since // properties in both should be considered. const PropertyList::PropertyMap *rendererProperties = this->GetDataNode()->GetPropertyList(renderer)->GetMap(); const PropertyList::PropertyMap *globalProperties = this->GetDataNode()->GetPropertyList(nullptr)->GetMap(); // Add clipping planes (if any) ls->m_ClippingPlaneCollection->RemoveAllItems(); PropertyList::PropertyMap::const_iterator it; for (it = rendererProperties->begin(); it != rendererProperties->end(); ++it) { this->CheckForClippingProperty(renderer, (*it).second.GetPointer()); } for (it = globalProperties->begin(); it != globalProperties->end(); ++it) { this->CheckForClippingProperty(renderer, (*it).second.GetPointer()); } if (ls->m_ClippingPlaneCollection->GetNumberOfItems() > 0) { ls->m_VtkPolyDataMapper->SetClippingPlanes(ls->m_ClippingPlaneCollection); } else { ls->m_VtkPolyDataMapper->RemoveAllClippingPlanes(); } } vtkProp *mitk::SurfaceVtkMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); return ls->m_Actor; } void mitk::SurfaceVtkMapper3D::CheckForClippingProperty(mitk::BaseRenderer *renderer, mitk::BaseProperty *property) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); auto *clippingProperty = dynamic_cast(property); if ((clippingProperty != nullptr) && (clippingProperty->GetClippingEnabled())) { const Point3D &origin = clippingProperty->GetOrigin(); const Vector3D &normal = clippingProperty->GetNormal(); vtkSmartPointer clippingPlane = vtkSmartPointer::New(); clippingPlane->SetOrigin(origin[0], origin[1], origin[2]); clippingPlane->SetNormal(normal[0], normal[1], normal[2]); ls->m_ClippingPlaneCollection->AddItem(clippingPlane); } } void mitk::SurfaceVtkMapper3D::SetDefaultPropertiesForVtkProperty(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { // Shading { node->AddProperty("material.wireframeLineWidth", mitk::FloatProperty::New(1.0f), renderer, overwrite); node->AddProperty("material.pointSize", mitk::FloatProperty::New(1.0f), renderer, overwrite); node->AddProperty("material.ambientCoefficient", mitk::FloatProperty::New(0.05f), renderer, overwrite); node->AddProperty("material.diffuseCoefficient", mitk::FloatProperty::New(0.9f), renderer, overwrite); node->AddProperty("material.specularCoefficient", mitk::FloatProperty::New(1.0f), renderer, overwrite); node->AddProperty("material.specularPower", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("material.representation", mitk::VtkRepresentationProperty::New(), renderer, overwrite); node->AddProperty("material.interpolation", mitk::VtkInterpolationProperty::New(), renderer, overwrite); } } void mitk::SurfaceVtkMapper3D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { node->AddProperty("color", mitk::ColorProperty::New(1.0f, 1.0f, 1.0f), renderer, overwrite); node->AddProperty("opacity", mitk::FloatProperty::New(1.0), renderer, overwrite); mitk::SurfaceVtkMapper3D::SetDefaultPropertiesForVtkProperty(node, renderer, overwrite); // Shading node->AddProperty("scalar visibility", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("color mode", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("scalar mode", mitk::VtkScalarModeProperty::New(), renderer, overwrite); mitk::Surface::Pointer surface = dynamic_cast(node->GetData()); if (surface.IsNotNull()) { if ((surface->GetVtkPolyData() != nullptr) && (surface->GetVtkPolyData()->GetPointData() != nullptr) && (surface->GetVtkPolyData()->GetPointData()->GetScalars() != nullptr)) { node->AddProperty("scalar visibility", mitk::BoolProperty::New(true), renderer, overwrite); node->AddProperty("color mode", mitk::BoolProperty::New(true), renderer, overwrite); } } // Backface culling node->AddProperty("Backface Culling", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("Depth Sorting", mitk::BoolProperty::New(false), renderer, overwrite); mitk::CoreServicePointer propDescService(mitk::CoreServices::GetPropertyDescriptions()); propDescService->AddDescription( "Depth Sorting", "Enables correct rendering for transparent objects by ordering polygons according to the distance " "to the camera. It is not recommended to enable this property for large surfaces (rendering might " "be slow)."); Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Modules/Core/src/Rendering/vtkMitkLevelWindowFilter.cpp b/Modules/Core/src/Rendering/vtkMitkLevelWindowFilter.cpp index e439ac8968..5bbc93108e 100644 --- a/Modules/Core/src/Rendering/vtkMitkLevelWindowFilter.cpp +++ b/Modules/Core/src/Rendering/vtkMitkLevelWindowFilter.cpp @@ -1,585 +1,580 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "vtkMitkLevelWindowFilter.h" #include "vtkObjectFactory.h" #include #include #include #include #include #include #include #include // used for acos etc. #include // used for PI #include #include static const double PI = itk::Math::pi; vtkStandardNewMacro(vtkMitkLevelWindowFilter); vtkMitkLevelWindowFilter::vtkMitkLevelWindowFilter() : m_LookupTable(nullptr), m_OpacityFunction(nullptr), m_MinOpacity(0.0), m_MaxOpacity(255.0) { // MITK_INFO << "mitk level/window filter uses " << GetNumberOfThreads() << " thread(s)"; } vtkMitkLevelWindowFilter::~vtkMitkLevelWindowFilter() { } vtkMTimeType vtkMitkLevelWindowFilter::GetMTime() { vtkMTimeType mTime = this->vtkObject::GetMTime(); vtkMTimeType time; if (this->m_LookupTable != nullptr) { time = this->m_LookupTable->GetMTime(); mTime = (time > mTime ? time : mTime); } return mTime; } void vtkMitkLevelWindowFilter::SetLookupTable(vtkScalarsToColors *lookupTable) { if (m_LookupTable != lookupTable) { m_LookupTable = lookupTable; this->Modified(); } } vtkScalarsToColors *vtkMitkLevelWindowFilter::GetLookupTable() { return m_LookupTable; } void vtkMitkLevelWindowFilter::SetOpacityPiecewiseFunction(vtkPiecewiseFunction *opacityFunction) { if (m_OpacityFunction != opacityFunction) { m_OpacityFunction = opacityFunction; this->Modified(); } } // This code was copied from the iil. The template works only for float and double. // Internal method which should never be used anywhere else and should not be in th header. // Convert color pixels from (R,G,B) to (H,S,I). // Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002. template void RGBtoHSI(T *RGB, T *HSI) { T R = RGB[0], G = RGB[1], B = RGB[2], nR = (R < 0 ? 0 : (R > 255 ? 255 : R)) / 255, nG = (G < 0 ? 0 : (G > 255 ? 255 : G)) / 255, nB = (B < 0 ? 0 : (B > 255 ? 255 : B)) / 255, m = nR < nG ? (nR < nB ? nR : nB) : (nG < nB ? nG : nB), theta = (T)(std::acos(0.5f * ((nR - nG) + (nR - nB)) / std::sqrt(std::pow(nR - nG, 2) + (nR - nB) * (nG - nB))) * 180 / PI), sum = nR + nG + nB; T H = 0, S = 0, I = 0; if (theta > 0) H = (nB <= nG) ? theta : 360 - theta; if (sum > 0) S = 1 - 3 / sum * m; I = sum / 3; HSI[0] = (T)H; HSI[1] = (T)S; HSI[2] = (T)I; } // This code was copied from the iil. The template works only for float and double. // Internal method which should never be used anywhere else and should not be in th header. // Convert color pixels from (H,S,I) to (R,G,B). template void HSItoRGB(T *HSI, T *RGB) { T H = (T)HSI[0], S = (T)HSI[1], I = (T)HSI[2], a = I * (1 - S), R = 0, G = 0, B = 0; if (H < 120) { B = a; R = (T)(I * (1 + S * std::cos(H * PI / 180) / std::cos((60 - H) * PI / 180))); G = 3 * I - (R + B); } else if (H < 240) { H -= 120; R = a; G = (T)(I * (1 + S * std::cos(H * PI / 180) / std::cos((60 - H) * PI / 180))); B = 3 * I - (R + G); } else { H -= 240; G = a; B = (T)(I * (1 + S * std::cos(H * PI / 180) / std::cos((60 - H) * PI / 180))); R = 3 * I - (G + B); } R *= 255; G *= 255; B *= 255; RGB[0] = (T)(R < 0 ? 0 : (R > 255 ? 255 : R)); RGB[1] = (T)(G < 0 ? 0 : (G > 255 ? 255 : G)); RGB[2] = (T)(B < 0 ? 0 : (B > 255 ? 255 : B)); } // Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkApplyLookupTableOnRGBA(vtkMitkLevelWindowFilter *self, vtkImageData *inData, vtkImageData *outData, int outExt[6], double *clippingBounds, T *) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); vtkLookupTable *lookupTable; const int maxC = inData->GetNumberOfScalarComponents(); double tableRange[2]; lookupTable = dynamic_cast(self->GetLookupTable()); lookupTable->GetTableRange(tableRange); // parameters for RGB level window const double scale = (tableRange[1] - tableRange[0] > 0 ? 255.0 / (tableRange[1] - tableRange[0]) : 0.0); const double bias = tableRange[0] * scale; // parameters for opaque level window const double scaleOpac = (self->GetMaxOpacity() - self->GetMinOpacity() > 0 ? 255.0 / (self->GetMaxOpacity() - self->GetMinOpacity()) : 0.0); const double biasOpac = self->GetMinOpacity() * scaleOpac; int y = outExt[2]; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { T *inputSI = inputIt.BeginSpan(); T *outputSI = outputIt.BeginSpan(); T *outputSIEnd = outputIt.EndSpan(); if (y >= clippingBounds[2] && y < clippingBounds[3]) { int x = outExt[0]; while (outputSI != outputSIEnd) { if (x >= clippingBounds[0] && x < clippingBounds[1]) { double rgb[3], alpha, hsi[3]; // level/window mechanism for intensity in HSI space rgb[0] = static_cast(*inputSI); inputSI++; rgb[1] = static_cast(*inputSI); inputSI++; rgb[2] = static_cast(*inputSI); inputSI++; RGBtoHSI(rgb, hsi); hsi[2] = hsi[2] * 255.0 * scale - bias; hsi[2] = (hsi[2] > 255.0 ? 255 : (hsi[2] < 0.0 ? 0 : hsi[2])); hsi[2] /= 255.0; HSItoRGB(hsi, rgb); *outputSI = static_cast(rgb[0]); outputSI++; *outputSI = static_cast(rgb[1]); outputSI++; *outputSI = static_cast(rgb[2]); outputSI++; unsigned char finalAlpha = 255; // RGBA case if (maxC >= 4) { // level/window mechanism for opacity alpha = static_cast(*inputSI); inputSI++; alpha = alpha * scaleOpac - biasOpac; if (alpha > 255.0) { alpha = 255.0; } else if (alpha < 0.0) { alpha = 0.0; } finalAlpha = static_cast(alpha); for (int c = 4; c < maxC; c++) inputSI++; } *outputSI = static_cast(finalAlpha); outputSI++; } else { inputSI += maxC; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; } x++; } } else { while (outputSI != outputSIEnd) { *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; } } inputIt.NextSpan(); outputIt.NextSpan(); y++; } } // Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkApplyLookupTableOnScalarsFast( vtkMitkLevelWindowFilter *self, vtkImageData *inData, vtkImageData *outData, int outExt[6], T *) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); double tableRange[2]; // access vtkLookupTable auto *lookupTable = dynamic_cast(self->GetLookupTable()); lookupTable->GetTableRange(tableRange); // access elements of the vtkLookupTable - const int *realLookupTable = reinterpret_cast(lookupTable->GetTable()->GetPointer(0)); - int maxIndex = lookupTable->GetNumberOfColors() - 1; + auto *realLookupTable = lookupTable->GetPointer(0); + size_t maxIndex = lookupTable->GetNumberOfColors() - 1; const float scale = (tableRange[1] - tableRange[0] > 0 ? (maxIndex + 1) / (tableRange[1] - tableRange[0]) : 0.0); // ensuring that starting point is zero float bias = -tableRange[0] * scale; // due to later conversion to int for rounding bias += 0.5f; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { unsigned char *outputSI = outputIt.BeginSpan(); unsigned char *outputSIEnd = outputIt.EndSpan(); T *inputSI = inputIt.BeginSpan(); while (outputSI != outputSIEnd) { // map to an index - auto idx = static_cast(*inputSI * scale + bias); + auto idx = std::min(static_cast(std::max(0, static_cast(*inputSI * scale + bias))), maxIndex) * 4; - if (idx < 0) - idx = 0; - else if (idx > maxIndex) - idx = maxIndex; - - *reinterpret_cast(outputSI) = realLookupTable[idx]; + memcpy(outputSI, &realLookupTable[idx], 4); inputSI++; outputSI += 4; } inputIt.NextSpan(); outputIt.NextSpan(); } } // Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkApplyLookupTableOnScalars(vtkMitkLevelWindowFilter *self, vtkImageData *inData, vtkImageData *outData, int outExt[6], double *clippingBounds, T *) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); vtkScalarsToColors *lookupTable = self->GetLookupTable(); int y = outExt[2]; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { unsigned char *outputSI = outputIt.BeginSpan(); - unsigned char *outputSIEnd = outputIt.EndSpan(); + const unsigned char * const outputSIEnd = outputIt.EndSpan(); // do we iterate over the inner vertical clipping bounds if (y >= clippingBounds[2] && y < clippingBounds[3]) { T *inputSI = inputIt.BeginSpan(); int x = outExt[0]; while (outputSI != outputSIEnd) { // is this pixel within horizontal clipping bounds if (x >= clippingBounds[0] && x < clippingBounds[1]) { // fetching original value auto grayValue = static_cast(*inputSI); - // applying lookuptable - copy the 4 (RGBA) chars as a single int - *reinterpret_cast(outputSI) = *reinterpret_cast(lookupTable->MapValue(grayValue)); + // applying lookuptable + memcpy(outputSI, lookupTable->MapValue(grayValue), 4); } else { // outer horizontal clipping bounds - write a transparent RGBA pixel as a single int - *reinterpret_cast(outputSI) = 0; + memset(outputSI, 0, 4); } inputSI++; outputSI += 4; x++; } } else { // outer vertical clipping bounds - write a transparent RGBA line as ints while (outputSI != outputSIEnd) { *reinterpret_cast(outputSI) = 0; outputSI += 4; } } inputIt.NextSpan(); outputIt.NextSpan(); y++; } } // Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkApplyLookupTableOnScalarsCTF(vtkMitkLevelWindowFilter *self, vtkImageData *inData, vtkImageData *outData, int outExt[6], double *clippingBounds, T *) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); auto *lookupTable = dynamic_cast(self->GetLookupTable()); vtkPiecewiseFunction *opacityFunction = self->GetOpacityPiecewiseFunction(); int y = outExt[2]; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { unsigned char *outputSI = outputIt.BeginSpan(); unsigned char *outputSIEnd = outputIt.EndSpan(); // do we iterate over the inner vertical clipping bounds if (y >= clippingBounds[2] && y < clippingBounds[3]) { T *inputSI = inputIt.BeginSpan(); int x = outExt[0]; while (outputSI != outputSIEnd) { // is this pixel within horizontal clipping bounds if (x >= clippingBounds[0] && x < clippingBounds[1]) { // fetching original value auto grayValue = static_cast(*inputSI); // applying directly colortransferfunction // because vtkColorTransferFunction::MapValue is not threadsafe double rgba[4]; lookupTable->GetColor(grayValue, rgba); // RGB mapping rgba[3] = 1.0; if (opacityFunction) rgba[3] = opacityFunction->GetValue(grayValue); // Alpha mapping for (int i = 0; i < 4; ++i) { outputSI[i] = static_cast(255.0 * rgba[i] + 0.5); } } else { // outer horizontal clipping bounds - write a transparent RGBA pixel as a single int *reinterpret_cast(outputSI) = 0; } inputSI++; outputSI += 4; x++; } } else { // outer vertical clipping bounds - write a transparent RGBA line as ints while (outputSI != outputSIEnd) { *reinterpret_cast(outputSI) = 0; outputSI += 4; } } inputIt.NextSpan(); outputIt.NextSpan(); y++; } } int vtkMitkLevelWindowFilter::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkInformation *outInfo = outputVector->GetInformationObject(0); // do nothing except copy scalar type info this->CopyInputArrayAttributesToOutput(request, inputVector, outputVector); vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, 4); return 1; } // Method to run the filter in different threads. void vtkMitkLevelWindowFilter::ThreadedExecute(vtkImageData *inData, vtkImageData *outData, int extent[6], int /*id*/) { if (inData->GetNumberOfScalarComponents() > 2) { switch (inData->GetScalarType()) { vtkTemplateMacro( vtkApplyLookupTableOnRGBA(this, inData, outData, extent, m_ClippingBounds, static_cast(nullptr))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } else { bool dontClip = extent[2] >= m_ClippingBounds[2] && extent[3] <= m_ClippingBounds[3] && extent[0] >= m_ClippingBounds[0] && extent[1] <= m_ClippingBounds[1]; if (this->GetLookupTable()) this->GetLookupTable()->Build(); auto *vlt = dynamic_cast(this->GetLookupTable()); auto *ctf = dynamic_cast(this->GetLookupTable()); bool linearLookupTable = vlt && vlt->GetScale() == VTK_SCALE_LINEAR; bool useFast = dontClip && linearLookupTable; if (ctf) { switch (inData->GetScalarType()) { vtkTemplateMacro(vtkApplyLookupTableOnScalarsCTF( this, inData, outData, extent, m_ClippingBounds, static_cast(nullptr))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } else if (useFast) { switch (inData->GetScalarType()) { vtkTemplateMacro( vtkApplyLookupTableOnScalarsFast(this, inData, outData, extent, static_cast(nullptr))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } else { switch (inData->GetScalarType()) { vtkTemplateMacro(vtkApplyLookupTableOnScalars( this, inData, outData, extent, m_ClippingBounds, static_cast(nullptr))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } } } // void vtkMitkLevelWindowFilter::ExecuteInformation( // vtkImageData *vtkNotUsed(inData), vtkImageData *vtkNotUsed(outData)) //{ //} void vtkMitkLevelWindowFilter::SetMinOpacity(double minOpacity) { m_MinOpacity = minOpacity; } inline double vtkMitkLevelWindowFilter::GetMinOpacity() const { return m_MinOpacity; } void vtkMitkLevelWindowFilter::SetMaxOpacity(double maxOpacity) { m_MaxOpacity = maxOpacity; } inline double vtkMitkLevelWindowFilter::GetMaxOpacity() const { return m_MaxOpacity; } void vtkMitkLevelWindowFilter::SetClippingBounds(double *bounds) // TODO does double[4] work?? { for (unsigned int i = 0; i < 4; ++i) m_ClippingBounds[i] = bounds[i]; } diff --git a/Modules/Core/test/CMakeLists.txt b/Modules/Core/test/CMakeLists.txt index 7b3e5e46e9..e33bc212b2 100644 --- a/Modules/Core/test/CMakeLists.txt +++ b/Modules/Core/test/CMakeLists.txt @@ -1,192 +1,192 @@ # The core tests need relaxed compiler flags... # TODO fix core tests to compile without these additional no-error flags if(MSVC_VERSION) # disable deprecated warnings (they would lead to errors) mitkFunctionCheckCAndCXXCompilerFlags("/wd4996" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) else() mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-declarations" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) endif() MITK_CREATE_MODULE_TESTS() if(TARGET ${TESTDRIVER}) - mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES ITK|ITKThresholding+ITKTestKernel VTK|vtkTestingRendering tinyxml) + mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES ITK|ITKThresholding+ITKTestKernel VTK|TestingRendering tinyxml) mitkAddCustomModuleTest(mitkVolumeCalculatorTest_Png2D-bw mitkVolumeCalculatorTest ${MITK_DATA_DIR}/Png2D-bw.png ${MITK_DATA_DIR}/Pic2DplusT.nrrd ) mitkAddCustomModuleTest(mitkEventConfigTest_CreateObjectInDifferentWays mitkEventConfigTest ${MITK_SOURCE_DIR}/Modules/Core/test/resource/Interactions/StatemachineConfigTest.xml ) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.nrrd ) mitkAddCustomModuleTest(mitkPointSetReaderTest mitkPointSetReaderTest ${MITK_DATA_DIR}/PointSetReaderTestData.mps ) mitkAddCustomModuleTest(mitkImageTest_4DImageData mitkImageTest ${MITK_DATA_DIR}/US4DCyl.nrrd ) mitkAddCustomModuleTest(mitkImageTest_2D+tImageData mitkImageTest ${MITK_DATA_DIR}/Pic2DplusT.nrrd ) mitkAddCustomModuleTest(mitkImageTest_3DImageData mitkImageTest ${MITK_DATA_DIR}/Pic3D.nrrd ) mitkAddCustomModuleTest(mitkImageEqualTest mitkImageEqualTest) mitkAddCustomModuleTest(mitkImageTest_brainImage mitkImageTest ${MITK_DATA_DIR}/brain.mhd ) mitkAddCustomModuleTest(mitkLevelWindowManagerTest mitkLevelWindowManagerTest ${MITK_DATA_DIR}/Pic3D.nrrd ) mitkAddCustomModuleTest(mitkMultiComponentImageDataComparisonFilterTest mitkMultiComponentImageDataComparisonFilterTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg ) mitkAddCustomModuleTest(mitkImageToItkTest mitkImageToItkTest ${MITK_DATA_DIR}/Pic3D.nrrd ) mitkAddCustomModuleTest(mitkImageSliceSelectorTest mitkImageSliceSelectorTest ${MITK_DATA_DIR}/Pic2DplusT.nrrd ) mitkAddCustomModuleTest(mitkRotatedSlice4DTest mitkRotatedSlice4DTest ${MITK_DATA_DIR}/UltrasoundImages/4D_TEE_Data_MV.dcm ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2DTest ${MITK_DATA_DIR}/RenderingTestData/rgbaImage.png #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/rgbaImage640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3d640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2DColorTest #test for color property (=blue) Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dColorBlue640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2DLevelWindowTest #test for levelwindow property (=blood) #Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dLevelWindowBlood640x480REF.png #corresponding reference #screenshot ) #mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dOpacity640x480 mitkImageVtkMapper2DOpacityTest #test for opacity (=0.5) Pic3D coronal slice # ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage # -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dOpacity640x480REF.png corresponding reference screenshot #) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DSwivelTest #test for a randomly chosen Pic3D swivelled slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dSwivel640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkPointSetVtkMapper2D_openMeAlone640x480 mitkPointSetVtkMapper2DTest ${MITK_DATA_DIR}/RenderingTestData/openMeAlone.mps #input point set to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/openMeAlone640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkPointSetVtkMapper2D_Pic3DPointSetForPic3D640x480 mitkPointSetVtkMapper2DImageTest ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/RenderingTestData/PointSetForPic3D.mps #input point set and image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Pic3DPointSetForPic3D640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkPointSetVtkMapper2D_openMeAloneGlyphType640x480 mitkPointSetVtkMapper2DGlyphTypeTest ${MITK_DATA_DIR}/RenderingTestData/openMeAlone.mps #input point set to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/openMeAloneGlyphType640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkPointSetVtkMapper2D_openMeAloneTransformed640x480 mitkPointSetVtkMapper2DTransformedPointsTest ${MITK_DATA_DIR}/RenderingTestData/openMeAlone.mps #input point set to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/openMeAloneTransformedPoints640x480REF.png #corresponding reference screenshot ) # Currently not working on windows because of a rendering timing issue # see bug 18083 for details if(NOT WIN32) mitkAddCustomModuleTest(mitkSurfaceDepthSortingTransparency_StanfordBunnySTL640x480 mitkSurfaceDepthSortingTest ${MITK_DATA_DIR}/RenderingTestData/Stanford_bunny.stl -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Stanford_bunnySTLDepthSorting640x480REF.png) endif() # BUG 18695 - tests deactivated, because win 32 bit continuous renders images slightly different. TODO! #Test reslice interpolation #note: nearest mode is already tested by swivel test #mitkAddCustomModuleTest(ResliceInterpolationIsLinear mitkImageVtkMapper2DResliceInterpolationPropertyTest # 1 #linear # ${MITK_DATA_DIR}/Pic3D.nrrd # -V # ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dRefLinear.png #corresponding reference screenshot LINEAR #) #mitkAddCustomModuleTest(ResliceInterpolationIsCubic mitkImageVtkMapper2DResliceInterpolationPropertyTest # 3 #cubic # ${MITK_DATA_DIR}/Pic3D.nrrd # -V # ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dRefCubic.png #corresponding reference screenshot CUBIC #) #End test reslice interpolation # Testing of the rendering of binary images #mitkAddCustomModuleTest(mitkImageVtkMapper2D_binaryTestImage640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice # ${MITK_DATA_DIR}/RenderingTestData/binaryImage.nrrd #input image to load in data storage # -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/binaryImage640x480REF.png #corresponding reference screenshot #) #mitkAddCustomModuleTest(mitkImageVtkMapper2D_binaryTestImageWithRef640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice # ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/RenderingTestData/binaryImage.nrrd #input image to load in data storage # -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/binaryImageWithRef640x480REF.png #corresponding reference screenshot #) # End of binary image tests mitkAddCustomModuleTest(mitkSurfaceVtkMapper3DTest_TextureProperty mitkSurfaceVtkMapper3DTest ${MITK_DATA_DIR}/RenderingTestData/earth.jpg -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/texturedSphere640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2DTransferFunctionTest_Png2D-bw mitkImageVtkMapper2DTransferFunctionTest ${MITK_DATA_DIR}/Png2D-bw.png -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Png2D-bw-TransferFunctionRGBImage640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2DOpacityTransferFunctionTest_Png2D-bw mitkImageVtkMapper2DOpacityTransferFunctionTest ${MITK_DATA_DIR}/Png2D-bw.png -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Png2D-bw-OpacityTransferFunctionRGBImage640x480REF.png #corresponding reference screenshot ) ############################## DISABLED TESTS mitkAddCustomModuleTest(mitkImageVtkMapper2DLookupTableTest_Png2D-bw mitkImageVtkMapper2DLookupTableTest ${MITK_DATA_DIR}/Png2D-bw.png -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Png2D-bw-LookupTableRGBImage640x480REF.png #corresponding reference screenshot ) #mitkAddCustomModuleTest(mitkImageTest_color2DImage mitkImageTest # ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg #) #mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest # ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz #) mitkAddCustomModuleTest(mitkPlaneGeometryDataMapper2DTest mitkPlaneGeometryDataMapper2DTest ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/PlaneGeometryMapper640x480REF.png #corresponding reference screenshot ) SET_PROPERTY(TEST mitkRotatedSlice4DTest mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DTransferFunctionTest_Png2D-bw # mitkImageVtkMapper2D_pic3dOpacity640x480 mitkSurfaceVtkMapper2DTest mitkSurfaceVtkMapper3DTest_TextureProperty mitkPointSetVtkMapper2D_Pic3DPointSetForPic3D640x480 mitkPointSetVtkMapper2D_openMeAlone640x480 mitkPointSetVtkMapper2D_openMeAloneGlyphType640x480 mitkPointSetVtkMapper2D_openMeAloneTransformed640x480 mitkPlaneGeometryDataMapper2DTest PROPERTY RUN_SERIAL TRUE) endif() # TARGET ${TESTDRIVER} diff --git a/Modules/Core/test/mitkImageVtkMapper2DColorTest.cpp b/Modules/Core/test/mitkImageVtkMapper2DColorTest.cpp index e45b0afdcb..dc33b72adf 100644 --- a/Modules/Core/test/mitkImageVtkMapper2DColorTest.cpp +++ b/Modules/Core/test/mitkImageVtkMapper2DColorTest.cpp @@ -1,57 +1,57 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkRenderingTestHelper.h" #include "mitkTestingMacros.h" // VTK #include int mitkImageVtkMapper2DColorTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); // Set the opacity for all images - renderingHelper.SetImageProperty("color", mitk::ColorProperty::New(0.0f, 0.0f, 255.0f)); + renderingHelper.SetImageProperty("color", mitk::ColorProperty::New(0.0f, 0.0f, 1.0f)); // for now this test renders in sagittal view direction renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION(renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?"); //#################### // Use this to generate a reference screenshot or save the file. //(Only in your local version of the test!) if (false) { renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); } //#################### MITK_TEST_END(); } diff --git a/Modules/DataTypesExt/files.cmake b/Modules/DataTypesExt/files.cmake index f8569f2e63..0508c5b9f1 100644 --- a/Modules/DataTypesExt/files.cmake +++ b/Modules/DataTypesExt/files.cmake @@ -1,46 +1,45 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkAffineBaseDataInteractor3D.cpp mitkAffineImageCropperInteractor.cpp mitkApplyDiffImageOperation.cpp mitkBoundingObject.cpp mitkBoundingObjectGroup.cpp mitkCellOperation.cpp mitkClippingPlaneInteractor3D.cpp mitkColorSequence.cpp mitkColorSequenceCycleH.cpp mitkColorSequenceRainbow.cpp mitkCompressedImageContainer.cpp mitkCone.cpp mitkCuboid.cpp mitkCylinder.cpp mitkDataStorageSelection.cpp mitkEllipsoid.cpp mitkGridRepresentationProperty.cpp mitkGridVolumeMapperProperty.cpp mitkLabeledImageLookupTable.cpp mitkLabeledImageVolumeCalculator.cpp mitkLineOperation.cpp mitkLookupTableSource.cpp - mitkMesh.cpp mitkMultiStepper.cpp mitkPlane.cpp mitkSurfaceDeformationDataInteractor3D.cpp mitkUnstructuredGrid.cpp mitkUnstructuredGridSource.cpp mitkVideoSource.cpp mitkColorConversions.cpp ) set(RESOURCE_FILES Interactions/AffineInteraction3D.xml Interactions/AffineMouseConfig.xml Interactions/AffineKeyConfig.xml Interactions/ClippingPlaneInteraction3D.xml Interactions/ClippingPlaneTranslationConfig.xml Interactions/ClippingPlaneRotationConfig.xml Interactions/ClippingPlaneDeformationConfig.xml Interactions/CropperDeformationConfig.xml ) diff --git a/Modules/DataTypesExt/include/mitkMesh.h b/Modules/DataTypesExt/include/mitkMesh.h deleted file mode 100644 index 215e71e648..0000000000 --- a/Modules/DataTypesExt/include/mitkMesh.h +++ /dev/null @@ -1,126 +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 MITKMESH_H_HEADER_INCLUDED -#define MITKMESH_H_HEADER_INCLUDED - -#include "MitkDataTypesExtExports.h" -#include "mitkPointSet.h" - -#include -#include -#include -#include -#include - -#include -#include - -namespace mitk -{ - /** - * \brief DataStructure which stores a set of points (incl. pointdata) where - * each point can be associated to an element of a cell. - * - * A mesh contains several cells that can be of different celltypes - * (Line, Triangle, Polygone...). A cell is always closed. If a linestrip is - * to be created, then declare several cells, each containing one line. - * - * The operations take care of the coherence. If a line is added to an - * existing LineCell, then a TriangleCell is built with the old and the new - * parameter (and so on). Deletion is done the opposite way. - * - * Example for inserting a line into a TriangleCell: - * existing PIds ind the cell: 1, 2, 4; - * inserting (2, 3) so that new PIds in Cell: 1, 2, 3, 4 - * - * The cell is now of type QuadrilateralCell - * - * \ingroup Data - */ - class MITKDATATYPESEXT_EXPORT Mesh : public PointSet - { - public: - mitkClassMacro(Mesh, PointSet); - - itkFactorylessNewMacro(Self); - - itkCloneMacro(Self); - - typedef Superclass::DataType::CellType CellType; - typedef CellType::CellAutoPointer CellAutoPointer; - typedef Superclass::MeshTraits::CellTraits CellTraits; - typedef CellTraits::PointIdConstIterator PointIdConstIterator; - typedef CellTraits::PointIdIterator PointIdIterator; - typedef DataType::CellDataContainer CellDataContainer; - typedef DataType::CellDataContainerIterator CellDataIterator; - typedef Superclass::DataType::CellsContainer::Iterator CellIterator; - typedef Superclass::DataType::CellsContainer::ConstIterator ConstCellIterator; - typedef itk::PolygonCell PolygonType; - typedef MeshType::CellType::MultiVisitor MeshMultiVisitor; - - /** \brief returns the current number of cells in the mesh */ - virtual unsigned long GetNumberOfCells(int t = 0); - - /** \brief returns the mesh */ - virtual const DataType *GetMesh(int t = 0) const; - - /** \brief returns the mesh */ - virtual DataType *GetMesh(int t = 0); - - void SetMesh(DataType *mesh, int t = 0); - - /** \brief checks if the given point is in a cell and returns that cellId. - * Basicaly it searches lines and points that are hit. - */ - virtual bool EvaluatePosition(Point3D point, unsigned long &cellId, float precision, int t = 0); - - /** \brief searches for the next new cellId and returns that id */ - unsigned long GetNewCellId(int t = 0); - - /** \brief returns the first cell that includes the given pointId */ - virtual int SearchFirstCell(unsigned long pointId, int t = 0); - - /** \brief searches for a line, that is hit by the given point. - * Then returns the lineId and the cellId - */ - virtual bool SearchLine(Point3D point, float distance, unsigned long &lineId, unsigned long &cellId, int t = 0); - - /** \brief searches a line according to the cellId and lineId and returns - * the PointIds, that assign the line; if successful, then return - * param = true; - */ - virtual bool GetPointIds(unsigned long cellId, unsigned long lineId, int &idA, int &idB, int t = 0); - - /** \brief searches a selected cell and returns the id of that cell. If no - * cell is found, then -1 is returned - */ - virtual int SearchSelectedCell(int t = 0); - - /** \brief creates a BoundingBox and computes it with the given points of - * the cell. - * - * Returns the BoundingBox != IsNull() if successful. - */ - virtual DataType::BoundingBoxPointer GetBoundingBoxFromCell(unsigned long cellId, int t = 0); - - /** \brief executes the given Operation */ - void ExecuteOperation(Operation *operation) override; - - protected: - Mesh(); - ~Mesh() override; - }; - -} // namespace mitk - -#endif /* MITKMESH_H_HEADER_INCLUDED */ diff --git a/Modules/DataTypesExt/include/mitkMeshUtil.h b/Modules/DataTypesExt/include/mitkMeshUtil.h deleted file mode 100644 index a40c69cb20..0000000000 --- a/Modules/DataTypesExt/include/mitkMeshUtil.h +++ /dev/null @@ -1,1677 +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 MITKMESHUTIL_H_INCLUDED -#define MITKMESHUTIL_H_INCLUDED - -#if (_MSC_VER == 1200) -#error MeshUtils currently not supported for MS Visual C++ 6.0. Sorry. -#endif - -//#include -#include -#include -#include -#include -#include -//#include -#include -//#include -//#include -//#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -template -class NullScalarAccessor -{ -public: - static inline double GetPointScalar(typename MeshType::PointDataContainer * /*pointData*/, - typename MeshType::PointIdentifier /*idx*/, - MeshType * /*mesh*/ = nullptr, - unsigned int /*type*/ = 0) - { - return (double)0.0; - }; - - static inline double GetCellScalar(typename MeshType::CellDataContainer * /*cellData*/, - typename MeshType::CellIdentifier /*idx*/, - MeshType * /*mesh*/ = nullptr, - unsigned int /*type*/ = 0) - { - return (double)0.0; - }; -}; - -template -class MeshScalarAccessor -{ -public: - static inline double GetPointScalar(typename MeshType::PointDataContainer *pointData, - typename MeshType::PointIdentifier idx, - MeshType * /*mesh*/ = nullptr, - unsigned int /*type*/ = 0) - { - return (double)pointData->GetElement(idx); - }; - - static inline double GetCellScalar(typename MeshType::CellDataContainer *cellData, - typename MeshType::CellIdentifier idx, - MeshType * /*mesh*/ = nullptr, - unsigned int /*type*/ = 0) - { - return (double)cellData->GetElement(idx); - }; -}; - -template -class MeanCurvatureAccessor : public NullScalarAccessor -{ -public: - static inline double GetPointScalar(typename MeshType::PointDataContainer * /*point*/, - typename MeshType::PointIdentifier idx, - MeshType *mesh, - unsigned int /*type*/ = 0) - { - typename MeshType::PixelType dis = 0; - mesh->GetPointData(idx, &dis); - return (double)dis; - }; -}; - -template -class SimplexMeshAccessor : public NullScalarAccessor -{ -public: - static inline double GetPointScalar(typename MeshType::PointDataContainer * /*point*/, - typename MeshType::PointIdentifier idx, - MeshType *mesh, - unsigned int type = 0) - { - typename MeshType::GeometryMapPointer geometryData = mesh->GetGeometryData(); - - if (type == 0) - { - double val = mesh->GetMeanCurvature(idx); - mesh->SetPointData(idx, val); - return val; - } - else if (type == 1) - { - double val = geometryData->GetElement(idx)->meanTension; - mesh->SetPointData(idx, val); - return val; - } - else if (type == 2) - { - double val = geometryData->GetElement(idx)->externalForce.GetNorm(); - mesh->SetPointData(idx, val); - return val; - } - else if (type == 3) - return geometryData->GetElement(idx)->internalForce.GetNorm(); - else if (type == 4) - return geometryData->GetElement(idx)->externalForce.GetNorm() * mesh->GetDistance(idx); - else if (type == 5) - { - typename MeshType::PixelType dis = 0; - mesh->GetPointData(idx, &dis); - return (double)dis; - } - else if (type == 6) - { - return (double)((geometryData->GetElement(idx))->allowSplitting); - } - else - return (double)0; - }; -}; - -/*! -\brief The class provides mehtods for ITK - VTK mesh conversion -* -* \todo document the inner class -* \todo maybe inner class should be moved out -*/ - -template > -class MeshUtil -{ - /*! - \brief A visitor to create VTK cells by means of a class - defining the InsertImplementation interface - - The InsertImplementation interface defines the methods - \code - void InsertLine(vtkIdType *pts); - void InsertTriangle(vtkIdType *pts); - void InsertPolygon(vtkIdType npts, vtkIdType *pts); - void InsertQuad(vtkIdType *pts); - void InsertTetra(vtkIdType *pts); - void InsertHexahedron(vtkIdType *pts); - \endcode - - This class calls the appropriate insert-method of the - InsertImplementation according to the cell type of - the visited cell \em and its actual contents: e.g., - for a polygon cell with just two points, a line will - be created by calling InsertLine. - \sa ExactSwitchByCellType - \sa SingleCellArrayInsertImplementation - \sa DistributeInsertImplementation - */ - template - class SwitchByCellType : public InsertImplementation - { - // typedef the itk cells we are interested in - typedef typename itk::CellInterface - CellInterfaceType; - typedef itk::LineCell floatLineCell; - typedef itk::TriangleCell floatTriangleCell; - typedef itk::PolygonCell floatPolygonCell; - typedef itk::QuadrilateralCell floatQuadrilateralCell; - typedef itk::TetrahedronCell floatTetrahedronCell; - typedef itk::HexahedronCell floatHexahedronCell; - typedef typename CellInterfaceType::PointIdConstIterator PointIdIterator; - - public: - /*! - Visit a line and create the VTK_LINE cell - */ - void Visit(unsigned long cellId, floatLineCell *t) - { - vtkIdType pts[2]; - int i = 0; - unsigned long num = t->GetNumberOfVertices(); - vtkIdType vtkCellId = -1; - if (num == 2) - { // useless because itk::LineCell always returns 2 - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertLine((vtkIdType *)pts); - } - - if (this->m_UseCellScalarAccessor && vtkCellId >= 0) - { - this->m_CellScalars->InsertTuple1(vtkCellId, ScalarAccessor::GetCellScalar(this->m_CellData, cellId)); - } - } - - /*! - Visit a polygon and create the VTK_POLYGON cell - */ - void Visit(unsigned long cellId, floatPolygonCell *t) - { - vtkIdType pts[4096]; - int i = 0; - unsigned long num = t->GetNumberOfVertices(); - vtkIdType vtkCellId = -1; - if (num > 4096) - { - MITK_ERROR << "Problem in mitkMeshUtil: Polygon with more than maximum number of vertices encountered." - << std::endl; - } - else if (num > 3) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertPolygon(num, (vtkIdType *)pts); - } - else if (num == 3) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertTriangle((vtkIdType *)pts); - } - else if (num == 2) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertLine((vtkIdType *)pts); - } - - if (this->m_UseCellScalarAccessor && vtkCellId >= 0) - { - this->m_CellScalars->InsertTuple1(vtkCellId, ScalarAccessor::GetCellScalar(this->m_CellData, cellId)); - } - } - - /*! - Visit a triangle and create the VTK_TRIANGLE cell - */ - void Visit(unsigned long cellId, floatTriangleCell *t) - { - vtkIdType pts[3]; - int i = 0; - unsigned long num = t->GetNumberOfVertices(); - vtkIdType vtkCellId = -1; - if (num == 3) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertTriangle((vtkIdType *)pts); - } - else if (num == 2) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertLine((vtkIdType *)pts); - } - - if (this->m_UseCellScalarAccessor && vtkCellId >= 0) - { - this->m_CellScalars->InsertTuple1(vtkCellId, ScalarAccessor::GetCellScalar(this->m_CellData, cellId)); - } - } - - /*! - Visit a quad and create the VTK_QUAD cell - */ - void Visit(unsigned long cellId, floatQuadrilateralCell *t) - { - vtkIdType pts[4]; - int i = 0; - unsigned long num = t->GetNumberOfVertices(); - vtkIdType vtkCellId = -1; - if (num == 4) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - { - if (i == 2) - pts[3] = *it; - else if (i == 3) - pts[2] = *it; - else - pts[i] = *it; - i++; - // pts[i++] = *it; - } - vtkCellId = this->InsertQuad((vtkIdType *)pts); - } - else if (num == 3) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertTriangle((vtkIdType *)pts); - } - else if (num == 2) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertLine((vtkIdType *)pts); - } - - if (this->m_UseCellScalarAccessor && vtkCellId >= 0) - { - this->m_CellScalars->InsertTuple1(vtkCellId, ScalarAccessor::GetCellScalar(this->m_CellData, cellId)); - } - } - - /*! - Visit a tetrahedra and create the VTK_TETRA cell - */ - void Visit(unsigned long cellId, floatTetrahedronCell *t) - { - vtkIdType pts[4]; - int i = 0; - unsigned long num = t->GetNumberOfVertices(); - vtkIdType vtkCellId = -1; - if (num == 4) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertTetra((vtkIdType *)pts); - } - else if (num == 3) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertTriangle((vtkIdType *)pts); - } - else if (num == 2) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertLine((vtkIdType *)pts); - } - - if (this->m_UseCellScalarAccessor && vtkCellId >= 0) - { - this->m_CellScalars->InsertTuple1(vtkCellId, ScalarAccessor::GetCellScalar(this->m_CellData, cellId)); - } - } - - /*! - Visit a hexahedron and create the VTK_HEXAHEDRON cell - */ - void Visit(unsigned long cellId, floatHexahedronCell *t) - { - vtkIdType pts[8]; - int i = 0; - unsigned long num = t->GetNumberOfVertices(); - vtkIdType vtkCellId = -1; - if (num == 8) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - { - if (i == 2) - pts[i++] = *(it + 1); - else if (i == 3) - pts[i++] = *(it - 1); - else if (i == 6) - pts[i++] = *(it + 1); - else if (i == 7) - pts[i++] = *(it - 1); - else - pts[i++] = *it; - } - vtkCellId = this->InsertHexahedron((vtkIdType *)pts); - } - else if (num == 4) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertQuad((vtkIdType *)pts); - } - else if (num == 3) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertTriangle((vtkIdType *)pts); - } - else if (num == 2) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - vtkCellId = this->InsertLine((vtkIdType *)pts); - } - - if (this->m_UseCellScalarAccessor && vtkCellId >= 0) - { - this->m_CellScalars->InsertTuple1(vtkCellId, ScalarAccessor::GetCellScalar(this->m_CellData, cellId)); - } - } - }; - - /*! - \brief A visitor similar to SwitchByCellType, but with - exact matching of cell types - - Works as described in SwitchByCellType, but does exact - matching of cell types, e.g., for a polygon cell with just - two points, \em no insert-method will be called, because - a polygon must have at least three points. - \sa SwitchByCellType - \sa SingleCellArrayInsertImplementation - \sa DistributeInsertImplementation - */ - template - class ExactSwitchByCellType : public InsertImplementation - { - // typedef the itk cells we are interested in - typedef typename itk::CellInterface - CellInterfaceType; - typedef itk::LineCell floatLineCell; - typedef itk::TriangleCell floatTriangleCell; - typedef itk::PolygonCell floatPolygonCell; - typedef itk::QuadrilateralCell floatQuadrilateralCell; - typedef itk::TetrahedronCell floatTetrahedronCell; - typedef itk::HexahedronCell floatHexahedronCell; - typedef typename CellInterfaceType::PointIdConstIterator PointIdIterator; - - public: - /*! - Visit a line and create the VTK_LINE cell - */ - void Visit(unsigned long, floatLineCell *t) - { - unsigned long num = t->GetNumberOfVertices(); - vtkIdType pts[2]; - int i = 0; - - if (num == 2) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - this->InsertLine(pts); - } - } - - /*! - Visit a polygon and create the VTK_POLYGON cell - */ - void Visit(unsigned long, floatPolygonCell *t) - { - vtkIdType pts[4096]; - unsigned long num = t->GetNumberOfVertices(); - if (num > 4096) - { - MITK_ERROR << "Problem in mitkMeshUtil: Polygon with more than maximum number of vertices encountered." - << std::endl; - } - int i = 0; - - if (num > 3) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - this->InsertPolygon(num, pts); - } - } - - /*! - Visit a triangle and create the VTK_TRIANGLE cell - */ - void Visit(unsigned long, floatTriangleCell *t) - { - unsigned long num = t->GetNumberOfVertices(); - vtkIdType pts[3]; - int i = 0; - - if (num == 3) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - this->InsertTriangle(pts); - } - } - - /*! - Visit a quadrilateral and create the VTK_QUAD cell - */ - void Visit(unsigned long, floatQuadrilateralCell *t) - { - unsigned long num = t->GetNumberOfVertices(); - vtkIdType pts[4]; - int i = 0; - - if (num == 4) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - - vtkIdType tmpId = pts[2]; - pts[2] = pts[3]; - pts[3] = tmpId; - this->InsertQuad(pts); - } - } - - /*! - Visit a tetrahedron and create the VTK_TETRA cell - */ - void Visit(unsigned long, floatTetrahedronCell *t) - { - unsigned long num = t->GetNumberOfVertices(); - - vtkIdType pts[4]; - int i = 0; - - if (num == 4) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - this->InsertTetra(pts); - } - } - - /*! - Visit a hexahedron and create the VTK_HEXAHEDRON cell - */ - void Visit(unsigned long, floatHexahedronCell *t) - { - unsigned long num = t->GetNumberOfVertices(); - vtkIdType pts[8]; - int i = 0; - - if (num == 8) - { - for (PointIdIterator it = t->PointIdsBegin(); it != t->PointIdsEnd(); it++) - pts[i++] = *it; - - vtkIdType tmp[8]; - for (unsigned int i = 0; i < 8; i++) - tmp[i] = pts[i]; - pts[2] = tmp[3]; - pts[3] = tmp[2]; - pts[6] = tmp[7]; - pts[7] = tmp[6]; - this->InsertHexahedron(pts); - } - } - }; - - /*! - \brief Implementation of the InsertImplementation interface of - SwitchByCellType to define a visitor that create cells - according to their types and put them in a single - vtkCellArray (for vtkUnstructuredGrid construction) - */ - class SingleCellArrayInsertImplementation - { - vtkCellArray *m_Cells; - int *m_TypeArray; - // vtkIdType cellId; - - protected: - bool m_UseCellScalarAccessor; - vtkFloatArray *m_CellScalars; - typename MeshType::CellDataContainer::Pointer m_CellData; - - public: - SingleCellArrayInsertImplementation() : m_UseCellScalarAccessor(false) {} - /*! Set the vtkCellArray that will be constructed - */ - void SetCellArray(vtkCellArray *cells) { m_Cells = cells; } - /*! - Set the type array for storing the vtk cell types - */ - void SetTypeArray(int *i) { m_TypeArray = i; } - void SetUseCellScalarAccessor(bool flag) { m_UseCellScalarAccessor = flag; } - void SetCellScalars(vtkFloatArray *scalars) { m_CellScalars = scalars; } - vtkFloatArray *GetCellScalars() { return m_CellScalars; } - void SetMeshCellData(typename MeshType::CellDataContainer *data) { m_CellData = data; } - vtkIdType InsertLine(vtkIdType *pts) - { - vtkIdType cellId = m_Cells->InsertNextCell(2, pts); - m_TypeArray[cellId] = VTK_LINE; - return cellId; - } - - vtkIdType InsertTriangle(vtkIdType *pts) - { - vtkIdType cellId = m_Cells->InsertNextCell(3, pts); - m_TypeArray[cellId] = VTK_TRIANGLE; - return cellId; - } - - vtkIdType InsertPolygon(vtkIdType npts, vtkIdType *pts) - { - vtkIdType cellId = m_Cells->InsertNextCell(npts, pts); - m_TypeArray[cellId] = VTK_POLYGON; - return cellId; - } - - vtkIdType InsertQuad(vtkIdType *pts) - { - vtkIdType cellId = m_Cells->InsertNextCell(4, pts); - m_TypeArray[cellId] = VTK_QUAD; - return cellId; - } - - vtkIdType InsertTetra(vtkIdType *pts) - { - vtkIdType cellId = m_Cells->InsertNextCell(4, pts); - m_TypeArray[cellId] = VTK_TETRA; - return cellId; - } - - vtkIdType InsertHexahedron(vtkIdType *pts) - { - vtkIdType cellId = m_Cells->InsertNextCell(8, pts); - m_TypeArray[cellId] = VTK_HEXAHEDRON; - return cellId; - } - }; - - /*! - \brief Implementation of the InsertImplementation interface of - SwitchByCellType to define a visitor that distributes cells - according to their types (for vtkPolyData construction) - */ - class DistributeInsertImplementation - { - vtkCellArray *m_LineCells; - vtkCellArray *m_TriangleCells; - vtkCellArray *m_PolygonCells; - vtkCellArray *m_QuadCells; - - protected: - bool m_UseCellScalarAccessor; - vtkFloatArray *m_CellScalars; - typename MeshType::CellDataContainer::Pointer m_CellData; - - public: - DistributeInsertImplementation() : m_UseCellScalarAccessor(false) {} - /*! Set the vtkCellArray that will be constructed - */ - void SetCellArrays(vtkCellArray *lines, vtkCellArray *triangles, vtkCellArray *polygons, vtkCellArray *quads) - { - m_LineCells = lines; - m_TriangleCells = triangles; - m_PolygonCells = polygons; - m_QuadCells = quads; - } - - vtkIdType InsertLine(vtkIdType *pts) { return m_LineCells->InsertNextCell(2, pts); } - vtkIdType InsertTriangle(vtkIdType *pts) { return m_TriangleCells->InsertNextCell(3, pts); } - vtkIdType InsertPolygon(vtkIdType npts, vtkIdType *pts) { return m_PolygonCells->InsertNextCell(npts, pts); } - vtkIdType InsertQuad(vtkIdType *pts) { return m_QuadCells->InsertNextCell(4, pts); } - vtkIdType InsertTetra(vtkIdType * /*pts*/) { return -1; } // ignored - vtkIdType InsertHexahedron(vtkIdType * /*pts*/) { return -1; } // ignored - }; - - // typedef typename MeshType::CellType CellType; - // typedef typename itk::LineCell< CellType > LineType; - // typedef typename itk::PolygonCell< CellType > PolygonType; - // typedef typename itk::TriangleCell< CellType > TriangleType; - - typedef SwitchByCellType SingleCellArrayUserVisitorType; - typedef SwitchByCellType DistributeUserVisitorType; - typedef ExactSwitchByCellType ExactUserVisitorType; - -public: - typedef itk::MatrixOffsetTransformBase ITKTransformType; - typedef itk::MatrixOffsetTransformBase MITKTransformType; - - /*! - Convert a MITK transformation to an ITK transformation - Necessary because ITK uses double and MITK uses float values - */ - static void ConvertTransformToItk(const MITKTransformType *mitkTransform, ITKTransformType *itkTransform) - { - typename MITKTransformType::MatrixType mitkM = mitkTransform->GetMatrix(); - typename ITKTransformType::MatrixType itkM; - - typename MITKTransformType::OffsetType mitkO = mitkTransform->GetOffset(); - typename ITKTransformType::OffsetType itkO; - - for (short i = 0; i < 3; ++i) - { - for (short j = 0; j < 3; ++j) - { - itkM[i][j] = (double)mitkM[i][j]; - } - itkO[i] = (double)mitkO[i]; - } - - itkTransform->SetMatrix(itkM); - itkTransform->SetOffset(itkO); - } - - /*! - create an itkMesh object from a vtkPolyData - */ - static typename MeshType::Pointer MeshFromPolyData(vtkPolyData *poly, - mitk::BaseGeometry *geometryFrame = nullptr, - mitk::BaseGeometry *polyDataGeometryFrame = nullptr) - { - // Create a new mesh - typename MeshType::Pointer output = MeshType::New(); - output->SetCellsAllocationMethod(MeshType::CellsAllocatedDynamicallyCellByCell); - - typedef typename MeshType::CellDataContainer MeshCellDataContainerType; - - output->SetCellData(MeshCellDataContainerType::New()); - - // Get the points from vtk - vtkPoints *vtkpoints = poly->GetPoints(); - const unsigned int numPoints = poly->GetNumberOfPoints(); - - // Create a compatible point container for the mesh - // the mesh is created with a null points container - // MeshType::PointsContainer::Pointer points = - // MeshType::PointsContainer::New(); - // // Resize the point container to be able to fit the vtk points - // points->Reserve(numPoints); - // // Set the point container on the mesh - // output->SetPoints(points); - double vtkpoint[3]; - typename MeshType::PointType itkPhysicalPoint; - if (geometryFrame == nullptr) - { - if (polyDataGeometryFrame == nullptr) - { - for (unsigned int i = 0; i < numPoints; ++i) - { - vtkpoints->GetPoint(i, vtkpoint); - // MITK_INFO << "next point: " << test[0]<< "," << test[1] << "," << test[2] << std::endl; - // typename MeshType::PixelType* apoint = (typename MeshType::PixelType*) vtkpoints->GetPoint(i); - mitk::vtk2itk(vtkpoint, itkPhysicalPoint); - output->SetPoint(i, itkPhysicalPoint); - } - } - else - { - for (unsigned int i = 0; i < numPoints; ++i) - { - vtkpoints->GetPoint(i, vtkpoint); - // MITK_INFO << "next point: " << test[0]<< "," << test[1] << "," << test[2] << std::endl; - // typename MeshType::PixelType* apoint = (typename MeshType::PixelType*) vtkpoints->GetPoint(i); - mitk::Point3D mitkWorldPoint; - mitk::vtk2itk(vtkpoint, mitkWorldPoint); - polyDataGeometryFrame->IndexToWorld(mitkWorldPoint, mitkWorldPoint); - mitk::vtk2itk(mitkWorldPoint, itkPhysicalPoint); - output->SetPoint(i, itkPhysicalPoint); - } - } - } - else - { - mitk::Point3D mitkWorldPoint; - if (polyDataGeometryFrame == nullptr) - { - for (unsigned int i = 0; i < numPoints; ++i) - { - vtkpoints->GetPoint(i, vtkpoint); - // MITK_INFO << "next point: " << test[0]<< "," << test[1] << "," << test[2] << std::endl; - // typename MeshType::PixelType* apoint = (typename MeshType::PixelType*) vtkpoints->GetPoint(i); - mitk::vtk2itk(vtkpoint, mitkWorldPoint); - geometryFrame->WorldToItkPhysicalPoint(mitkWorldPoint, itkPhysicalPoint); - output->SetPoint(i, itkPhysicalPoint); - } - } - else - { - for (unsigned int i = 0; i < numPoints; ++i) - { - vtkpoints->GetPoint(i, vtkpoint); - // MITK_INFO << "next point: " << test[0]<< "," << test[1] << "," << test[2] << std::endl; - // typename MeshType::PixelType* apoint = (typename MeshType::PixelType*) vtkpoints->GetPoint(i); - mitk::vtk2itk(vtkpoint, mitkWorldPoint); - polyDataGeometryFrame->IndexToWorld(mitkWorldPoint, mitkWorldPoint); - geometryFrame->WorldToItkPhysicalPoint(mitkWorldPoint, itkPhysicalPoint); - output->SetPoint(i, itkPhysicalPoint); - } - } - } - - vtkCellArray *vtkcells = poly->GetPolys(); - // vtkCellArray* vtkcells = poly->GetStrips(); - // MeshType::CellsContainerPointer cells = MeshType::CellsContainer::New(); - // output->SetCells(cells); - // extract the cell id's from the vtkUnstructuredGrid - int numcells = vtkcells->GetNumberOfCells(); - int *vtkCellTypes = new int[numcells]; - int cellId = 0; - // poly ids start after verts and lines! - int cellIdOfs = poly->GetNumberOfVerts() + poly->GetNumberOfLines(); - for (; cellId < numcells; cellId++) - { - vtkCellTypes[cellId] = poly->GetCellType(cellId + cellIdOfs); - } - - // cells->Reserve(numcells); - vtkIdType npts; - vtkIdType *pts; - cellId = 0; - - typedef typename MeshType::MeshTraits OMeshTraits; - typedef typename OMeshTraits::PixelType OPixelType; - typedef typename MeshType::CellTraits CellTraits; - typedef typename itk::CellInterface CellInterfaceType; - typedef typename itk::TriangleCell TriCellType; - typedef typename TriCellType::CellAutoPointer TriCellPointer; - - TriCellPointer newCell; - output->GetCells()->Reserve(poly->GetNumberOfPolys() + poly->GetNumberOfStrips()); - output->GetCellData()->Reserve(poly->GetNumberOfPolys() + poly->GetNumberOfStrips()); - - for (vtkcells->InitTraversal(); vtkcells->GetNextCell(npts, pts); cellId++) - { - switch (vtkCellTypes[cellId]) - { - case VTK_TRIANGLE: - { - if (npts != 3) - continue; // skip non-triangles; - itk::IdentifierType pointIds[3]; - pointIds[0] = (unsigned long)pts[0]; - pointIds[1] = (unsigned long)pts[1]; - pointIds[2] = (unsigned long)pts[2]; - - newCell.TakeOwnership(new TriCellType); - newCell->SetPointIds(pointIds); //(unsigned long*)pts); - output->SetCell(cellId, newCell); - output->SetCellData(cellId, (typename MeshType::PixelType)3); - break; - } - - case VTK_QUAD: - { - if (npts != 4) - continue; // skip non-quadrilateral - itk::IdentifierType pointIds[3]; - - pointIds[0] = (unsigned long)pts[0]; - pointIds[1] = (unsigned long)pts[1]; - pointIds[2] = (unsigned long)pts[2]; - newCell.TakeOwnership(new TriCellType); - newCell->SetPointIds(pointIds); - output->SetCell(cellId, newCell); - output->SetCellData(cellId, (typename MeshType::PixelType)3); - cellId++; - - pointIds[0] = (unsigned long)pts[2]; - pointIds[1] = (unsigned long)pts[3]; - pointIds[2] = (unsigned long)pts[0]; - newCell.TakeOwnership(new TriCellType); - newCell->SetPointIds(pointIds); - output->SetCell(cellId, newCell); - output->SetCellData(cellId, (typename MeshType::PixelType)3); - break; - } - - case VTK_EMPTY_CELL: - { - if (npts != 3) - { - MITK_ERROR << "Only empty triangle cell supported by now..." << std::endl; // skip non-triangle empty cells; - continue; - } - itk::IdentifierType pointIds[3]; - pointIds[0] = (unsigned long)pts[0]; - pointIds[1] = (unsigned long)pts[1]; - pointIds[2] = (unsigned long)pts[2]; - - newCell.TakeOwnership(new TriCellType); - newCell->SetPointIds(pointIds); - output->SetCell(cellId, newCell); - output->SetCellData(cellId, (typename MeshType::PixelType)3); - break; - } - - // case VTK_VERTEX: // If need to implement use - // case VTK_POLY_VERTEX: // the poly->GetVerts() and - // case VTK_LINE: // poly->GetLines() routines - // case VTK_POLY_LINE: // outside of the switch..case. - case VTK_POLYGON: - case VTK_PIXEL: - { - if (npts != 4) - continue; // skip non-quadrilateral - itk::IdentifierType pointIds[3]; - for (unsigned int idx = 0; idx <= 1; idx++) - { - pointIds[0] = (unsigned long)pts[idx]; - pointIds[1] = (unsigned long)pts[idx + 1]; - pointIds[2] = (unsigned long)pts[idx + 2]; - newCell.TakeOwnership(new TriCellType); - newCell->SetPointIds(pointIds); - output->SetCell(cellId + idx, newCell); - output->SetCellData(cellId + idx, (typename MeshType::PixelType)3); - } - cellId++; - break; - } - - case VTK_TETRA: - case VTK_VOXEL: - case VTK_HEXAHEDRON: - case VTK_WEDGE: - case VTK_PYRAMID: - case VTK_PARAMETRIC_CURVE: - case VTK_PARAMETRIC_SURFACE: - default: - MITK_WARN << "Warning, unhandled cell type " << vtkCellTypes[cellId] << std::endl; - } - } - - if (poly->GetNumberOfStrips() != 0) - { - vtkcells = poly->GetStrips(); - numcells = vtkcells->GetNumberOfCells(); - vtkCellTypes = new int[numcells]; - int stripId = 0; - // strip ids start after verts, lines and polys! - int stripIdOfs = poly->GetNumberOfVerts() + poly->GetNumberOfLines() + poly->GetNumberOfPolys(); - for (; stripId < numcells; stripId++) - { - vtkCellTypes[stripId] = poly->GetCellType(stripId + stripIdOfs); - } - stripId = 0; - - vtkcells->InitTraversal(); - while (vtkcells->GetNextCell(npts, pts)) - { - if (vtkCellTypes[stripId] != VTK_TRIANGLE_STRIP) - { - MITK_ERROR << "Only triangle strips supported!" << std::endl; - continue; - } - stripId++; - - unsigned int numberOfTrianglesInStrip = npts - 2; - itk::IdentifierType pointIds[3]; - pointIds[0] = (unsigned long)pts[0]; - pointIds[1] = (unsigned long)pts[1]; - pointIds[2] = (unsigned long)pts[2]; - - for (unsigned int t = 0; t < numberOfTrianglesInStrip; t++) - { - newCell.TakeOwnership(new TriCellType); - newCell->SetPointIds(pointIds); - output->SetCell(cellId, newCell); - output->SetCellData(cellId, (typename MeshType::PixelType)3); - cellId++; - pointIds[0] = pointIds[1]; - pointIds[1] = pointIds[2]; - pointIds[2] = pts[t + 3]; - } - } - } - // output->Print(std::cout); - output->BuildCellLinks(); - delete[] vtkCellTypes; - return output; - } - - /*! - create an itkMesh object from an mitk::Surface - */ - static typename MeshType::Pointer MeshFromSurface(mitk::Surface *surface, mitk::BaseGeometry *geometryFrame = nullptr) - { - if (surface == nullptr) - return nullptr; - return MeshFromPolyData(surface->GetVtkPolyData(), geometryFrame, surface->GetGeometry()); - } - - /*! - create an vtkUnstructuredGrid object from an itkMesh - */ - static vtkUnstructuredGrid *MeshToUnstructuredGrid(MeshType *mesh, - bool usePointScalarAccessor = false, - bool useCellScalarAccessor = false, - unsigned int pointDataType = 0, - mitk::BaseGeometry *geometryFrame = nullptr) - { - /*! - default SingleCellArray line cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation, - SingleCellArrayUserVisitorType> - SingleCellArrayLineVisitor; - - /*! - default SingleCellArray polygon cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation, - SingleCellArrayUserVisitorType> - SingleCellArrayPolygonVisitor; - - /*! - default SingleCellArray triangle cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation< - typename MeshType::CellPixelType, - typename MeshType::CellTraits, - itk::TriangleCell>, - SingleCellArrayUserVisitorType> - SingleCellArrayTriangleVisitor; - - /*! - default SingleCellArray quad cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation< - typename MeshType::CellPixelType, - typename MeshType::CellTraits, - itk::QuadrilateralCell>, - SingleCellArrayUserVisitorType> - SingleCellArrayQuadrilateralVisitor; - - /*! - default SingleCellArray tetra cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation< - typename MeshType::CellPixelType, - typename MeshType::CellTraits, - itk::TetrahedronCell>, - SingleCellArrayUserVisitorType> - SingleCellArrayTetrahedronVisitor; - - /*! - default SingleCellArray hex cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation< - typename MeshType::CellPixelType, - typename MeshType::CellTraits, - itk::HexahedronCell>, - SingleCellArrayUserVisitorType> - SingleCellArrayHexahedronVisitor; - - // Get the number of points in the mesh - int numPoints = mesh->GetNumberOfPoints(); - if (numPoints == 0) - { - // mesh->Print(std::cerr); - MITK_FATAL << "no points in Grid " << std::endl; - exit(-1); - } - // Create a vtkUnstructuredGrid - vtkUnstructuredGrid *vgrid = vtkUnstructuredGrid::New(); - // Create the vtkPoints object and set the number of points - vtkPoints *vpoints = vtkPoints::New(VTK_DOUBLE); - - vtkFloatArray *pointScalars = vtkFloatArray::New(); - vtkFloatArray *cellScalars = vtkFloatArray::New(); - pointScalars->SetNumberOfComponents(1); - cellScalars->SetNumberOfComponents(1); - - typename MeshType::PointsContainer::Pointer points = mesh->GetPoints(); - typename MeshType::PointsContainer::Iterator i; - - // iterate over all the points in the itk mesh to find - // the maximal index - unsigned int maxIndex = 0; - for (i = points->Begin(); i != points->End(); ++i) - { - if (maxIndex < i->Index()) - maxIndex = i->Index(); - } - - // initialize vtk-classes for points and scalars - vpoints->SetNumberOfPoints(maxIndex + 1); - pointScalars->SetNumberOfTuples(maxIndex + 1); - cellScalars->SetNumberOfTuples(mesh->GetNumberOfCells()); - - double vtkpoint[3]; - typename MeshType::PointType itkPhysicalPoint; - if (geometryFrame == nullptr) - { - for (i = points->Begin(); i != points->End(); ++i) - { - // Get the point index from the point container iterator - int idx = i->Index(); - - itkPhysicalPoint = i->Value(); - mitk::itk2vtk(itkPhysicalPoint, vtkpoint); - // Set the vtk point at the index with the the coord array from itk - vpoints->SetPoint(idx, vtkpoint); - - if (usePointScalarAccessor) - { - pointScalars->InsertTuple1( - idx, ScalarAccessor::GetPointScalar(mesh->GetPointData(), i->Index(), mesh, pointDataType)); - } - } - } - else - { - mitk::Point3D mitkWorldPoint; - for (i = points->Begin(); i != points->End(); ++i) - { - // Get the point index from the point container iterator - int idx = i->Index(); - - itkPhysicalPoint = i->Value(); - geometryFrame->ItkPhysicalPointToWorld(itkPhysicalPoint, mitkWorldPoint); - mitk::itk2vtk(mitkWorldPoint, vtkpoint); - // Set the vtk point at the index with the the coord array from itk - vpoints->SetPoint(idx, vtkpoint); - - if (usePointScalarAccessor) - { - pointScalars->InsertTuple1( - idx, ScalarAccessor::GetPointScalar(mesh->GetPointData(), i->Index(), mesh, pointDataType)); - } - } - } - // Set the points on the vtk grid - vgrid->SetPoints(vpoints); - if (usePointScalarAccessor) - vgrid->GetPointData()->SetScalars(pointScalars); - - // Now create the cells using the MultiVisitor - // 1. Create a MultiVisitor - typename MeshType::CellType::MultiVisitor::Pointer mv = MeshType::CellType::MultiVisitor::New(); - // 2. Create visitors - typename SingleCellArrayLineVisitor::Pointer lv = SingleCellArrayLineVisitor::New(); - typename SingleCellArrayPolygonVisitor::Pointer pv = SingleCellArrayPolygonVisitor::New(); - typename SingleCellArrayTriangleVisitor::Pointer tv = SingleCellArrayTriangleVisitor::New(); - typename SingleCellArrayQuadrilateralVisitor::Pointer qv = SingleCellArrayQuadrilateralVisitor::New(); - typename SingleCellArrayTetrahedronVisitor::Pointer tetv = SingleCellArrayTetrahedronVisitor::New(); - typename SingleCellArrayHexahedronVisitor::Pointer hv = SingleCellArrayHexahedronVisitor::New(); - // 3. Set up the visitors - // int vtkCellCount = 0; // running counter for current cell being inserted into vtk - int numCells = mesh->GetNumberOfCells(); - int *types = new int[numCells]; // type array for vtk - // create vtk cells and estimate the size - vtkCellArray *cells = vtkCellArray::New(); - cells->Allocate(numCells); - // Set the TypeArray CellCount and CellArray for the visitors - lv->SetTypeArray(types); - lv->SetCellArray(cells); - pv->SetTypeArray(types); - pv->SetCellArray(cells); - tv->SetTypeArray(types); - // tv->SetCellCounter(&vtkCellCount); - tv->SetCellArray(cells); - qv->SetTypeArray(types); - // qv->SetCellCounter(&vtkCellCount); - qv->SetCellArray(cells); - tetv->SetTypeArray(types); - tetv->SetCellArray(cells); - hv->SetTypeArray(types); - hv->SetCellArray(cells); - - if (useCellScalarAccessor) - { - lv->SetUseCellScalarAccessor(true); - lv->SetCellScalars(cellScalars); - lv->SetMeshCellData(mesh->GetCellData()); - - pv->SetUseCellScalarAccessor(true); - pv->SetCellScalars(cellScalars); - pv->SetMeshCellData(mesh->GetCellData()); - - tv->SetUseCellScalarAccessor(true); - tv->SetCellScalars(cellScalars); - tv->SetMeshCellData(mesh->GetCellData()); - - qv->SetUseCellScalarAccessor(true); - qv->SetCellScalars(cellScalars); - qv->SetMeshCellData(mesh->GetCellData()); - - tetv->SetUseCellScalarAccessor(true); - tetv->SetCellScalars(cellScalars); - tetv->SetMeshCellData(mesh->GetCellData()); - - hv->SetUseCellScalarAccessor(true); - hv->SetCellScalars(cellScalars); - hv->SetMeshCellData(mesh->GetCellData()); - } - - // add the visitors to the multivisitor - mv->AddVisitor(lv); - mv->AddVisitor(pv); - mv->AddVisitor(tv); - mv->AddVisitor(qv); - mv->AddVisitor(tetv); - mv->AddVisitor(hv); - // Now ask the mesh to accept the multivisitor which - // will Call Visit for each cell in the mesh that matches the - // cell types of the visitors added to the MultiVisitor - mesh->Accept(mv); - // Now set the cells on the vtk grid with the type array and cell array - - vgrid->SetCells(types, cells); - vgrid->GetCellData()->SetScalars(cellScalars); - - // Clean up vtk objects (no vtkSmartPointer ... ) - cells->Delete(); - vpoints->Delete(); - delete[] types; - - pointScalars->Delete(); - cellScalars->Delete(); - // MITK_INFO << "meshToUnstructuredGrid end" << std::endl; - return vgrid; - } - - /*! - create a vtkPolyData object from an itkMesh - */ - static vtkPolyData *MeshToPolyData(MeshType *mesh, - bool onlyTriangles = false, - bool useScalarAccessor = false, - unsigned int pointDataType = 0, - mitk::BaseGeometry *geometryFrame = nullptr, - vtkPolyData *polydata = nullptr) - { - /*! - default Distribute line cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation, - DistributeUserVisitorType> - DistributeLineVisitor; - - /*! - default Distribute polygon cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation, - DistributeUserVisitorType> - DistributePolygonVisitor; - - /*! - default Distribute triangle cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation< - typename MeshType::CellPixelType, - typename MeshType::CellTraits, - itk::TriangleCell>, - DistributeUserVisitorType> - DistributeTriangleVisitor; - - /*! - default Distribute quad cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation< - typename MeshType::CellPixelType, - typename MeshType::CellTraits, - itk::QuadrilateralCell>, - DistributeUserVisitorType> - DistributeQuadrilateralVisitor; - - /*! - default Distribute triangle cell visitior definition - */ - typedef typename itk::CellInterfaceVisitorImplementation< - typename MeshType::CellPixelType, - typename MeshType::CellTraits, - itk::TriangleCell>, - ExactUserVisitorType> - ExactTriangleVisitor; - - // Get the number of points in the mesh - int numPoints = mesh->GetNumberOfPoints(); - if (numPoints == 0) - { - // mesh->Print(std::cerr); - MITK_ERROR << "no points in Grid " << std::endl; - } - // Create a vtkPolyData - if (polydata == nullptr) - polydata = vtkPolyData::New(); - else - polydata->Initialize(); - - // Create the vtkPoints object and set the number of points - vtkPoints *vpoints = vtkPoints::New(VTK_DOUBLE); - - vtkFloatArray *scalars = vtkFloatArray::New(); - scalars->SetNumberOfComponents(1); - - typename MeshType::PointsContainer::Pointer points = mesh->GetPoints(); - typename MeshType::PointsContainer::Iterator i; - - // iterate over all the points in the itk mesh to find - // the maximal index - unsigned int maxIndex = 0; - for (i = points->Begin(); i != points->End(); ++i) - { - if (maxIndex < i->Index()) - maxIndex = i->Index(); - } - - // initialize vtk-classes for points and scalars - vpoints->SetNumberOfPoints(maxIndex + 1); - scalars->SetNumberOfTuples(maxIndex + 1); - - // iterate over all the points in the itk mesh filling in - // the vtkPoints object as we go - - double vtkpoint[3]; - typename MeshType::PointType itkPhysicalPoint; - if (geometryFrame == nullptr) - { - for (i = points->Begin(); i != points->End(); ++i) - { - // Get the point index from the point container iterator - int idx = i->Index(); - - itkPhysicalPoint = i->Value(); - mitk::itk2vtk(itkPhysicalPoint, vtkpoint); - // Set the vtk point at the index with the the coord array from itk - // itk returns a const pointer, but vtk is not const correct, so - // we have to use a const cast to get rid of the const - // vpoints->SetPoint(idx, const_cast(i->Value().GetDataPointer())); - vpoints->SetPoint(idx, vtkpoint); - - if (useScalarAccessor) - { - scalars->InsertTuple1(idx, - ScalarAccessor::GetPointScalar(mesh->GetPointData(), i->Index(), mesh, pointDataType)); - } - } - } - else - { - mitk::Point3D mitkWorldPoint; - for (i = points->Begin(); i != points->End(); ++i) - { - // Get the point index from the point container iterator - int idx = i->Index(); - - itkPhysicalPoint = i->Value(); - geometryFrame->ItkPhysicalPointToWorld(itkPhysicalPoint, mitkWorldPoint); - mitk::itk2vtk(mitkWorldPoint, vtkpoint); - // Set the vtk point at the index with the the coord array from itk - // itk returns a const pointer, but vtk is not const correct, so - // we have to use a const cast to get rid of the const - // vpoints->SetPoint(idx, const_cast(i->Value().GetDataPointer())); - vpoints->SetPoint(idx, vtkpoint); - - if (useScalarAccessor) - { - scalars->InsertTuple1(idx, - ScalarAccessor::GetPointScalar(mesh->GetPointData(), i->Index(), mesh, pointDataType)); - } - } - } - - // Set the points on the vtk grid - polydata->SetPoints(vpoints); - if (useScalarAccessor) - polydata->GetPointData()->SetScalars(scalars); - polydata->GetPointData()->CopyAllOn(); - - // Now create the cells using the MulitVisitor - // 1. Create a MultiVisitor - typedef typename MeshType::CellType::MultiVisitor MeshMV; - typename MeshMV::Pointer mv = MeshMV::New(); - - int numCells = mesh->GetNumberOfCells(); - - if (onlyTriangles) - { - // create vtk cells and allocate - vtkCellArray *trianglecells = vtkCellArray::New(); - trianglecells->Allocate(numCells); - - // 2. Create a triangle visitor and add it to the multivisitor - typename ExactTriangleVisitor::Pointer tv = ExactTriangleVisitor::New(); - tv->SetCellArrays(nullptr, trianglecells, nullptr, nullptr); - mv->AddVisitor(tv); - // 3. Now ask the mesh to accept the multivisitor which - // will Call Visit for each cell in the mesh that matches the - // cell types of the visitors added to the MultiVisitor - mesh->Accept(mv); - - // 4. Set the result into our vtkPolyData - if (trianglecells->GetNumberOfCells() > 0) - polydata->SetStrips(trianglecells); - - // 5. Clean up vtk objects (no vtkSmartPointer ... ) - trianglecells->Delete(); - } - else - { - // create vtk cells and allocate - vtkCellArray *linecells = vtkCellArray::New(); - vtkCellArray *trianglecells = vtkCellArray::New(); - vtkCellArray *polygoncells = vtkCellArray::New(); - linecells->Allocate(numCells); - trianglecells->Allocate(numCells); - polygoncells->Allocate(numCells); - - // 2. Create visitors - typename DistributeLineVisitor::Pointer lv = DistributeLineVisitor::New(); - typename DistributePolygonVisitor::Pointer pv = DistributePolygonVisitor::New(); - typename DistributeTriangleVisitor::Pointer tv = DistributeTriangleVisitor::New(); - typename DistributeQuadrilateralVisitor::Pointer qv = DistributeQuadrilateralVisitor::New(); - - lv->SetCellArrays(linecells, trianglecells, polygoncells, polygoncells); - pv->SetCellArrays(linecells, trianglecells, polygoncells, polygoncells); - tv->SetCellArrays(linecells, trianglecells, polygoncells, polygoncells); - qv->SetCellArrays(linecells, trianglecells, polygoncells, polygoncells); - - // add the visitors to the multivisitor - mv->AddVisitor(tv); - mv->AddVisitor(lv); - mv->AddVisitor(pv); - mv->AddVisitor(qv); - // 3. Now ask the mesh to accept the multivisitor which - // will Call Visit for each cell in the mesh that matches the - // cell types of the visitors added to the MultiVisitor - mesh->Accept(mv); - - // 4. Set the result into our vtkPolyData - if (linecells->GetNumberOfCells() > 0) - polydata->SetLines(linecells); - if (trianglecells->GetNumberOfCells() > 0) - polydata->SetStrips(trianglecells); - if (polygoncells->GetNumberOfCells() > 0) - polydata->SetPolys(polygoncells); - - // 5. Clean up vtk objects (no vtkSmartPointer ... ) - linecells->Delete(); - trianglecells->Delete(); - polygoncells->Delete(); - } - vpoints->Delete(); - scalars->Delete(); - - // MITK_INFO << "meshToPolyData end" << std::endl; - return polydata; - } - - static typename MeshType::Pointer CreateRegularSphereMesh(typename MeshType::PointType center, - typename MeshType::PointType::VectorType scale, - int resolution) - { - typedef itk::RegularSphereMeshSource SphereSourceType; - typename SphereSourceType::Pointer mySphereSource = SphereSourceType::New(); - - mySphereSource->SetCenter(center); - mySphereSource->SetScale(scale); - mySphereSource->SetResolution(resolution); - mySphereSource->Update(); - - typename MeshType::Pointer resultMesh = mySphereSource->GetOutput(); - resultMesh->Register(); // necessary ???? - return resultMesh; - } - - static typename MeshType::Pointer CreateSphereMesh(typename MeshType::PointType center, - typename MeshType::PointType scale, - int *resolution) - { - typedef typename itk::SphereMeshSource SphereSource; - - typename SphereSource::Pointer mySphereSource = SphereSource::New(); - - mySphereSource->SetCenter(center); - mySphereSource->SetScale(scale); - mySphereSource->SetResolutionX(resolution[0]); - mySphereSource->SetResolutionY(resolution[1]); - mySphereSource->SetSquareness1(1); - mySphereSource->SetSquareness2(1); - mySphereSource->Update(); - mySphereSource->GetOutput(); - - typename MeshType::Pointer resultMesh = mySphereSource->GetOutput(); - resultMesh->Register(); - - return resultMesh; - } - - // static typename MeshType::Pointer TranslateMesh(typename MeshType::PointType vec, MeshType* input) - // { - // - // typename MeshType::Pointer output = MeshType::New(); - // { - // output->SetPoints(input->GetPoints()); - // output->SetPointData(input->GetPointData()); - // output->SetCells(input->GetCells()); - // output->SetLastCellId( input->GetLastCellId() ); - // typename MeshType::GeometryMapIterator pointDataIterator = input->GetGeometryData()->Begin(); - // typename MeshType::GeometryMapIterator pointDataEnd = input->GetGeometryData()->End(); - // - // typename MeshType::PointType inputPoint,outputPoint; - // - // while (pointDataIterator != pointDataEnd) - // { - // unsigned long pointId = pointDataIterator->Index(); - // itk::SimplexMeshGeometry* newGeometry = new itk::SimplexMeshGeometry(); - // itk::SimplexMeshGeometry* refGeometry = pointDataIterator->Value(); - // - // input->GetPoint(pointId, &inputPoint ); - // outputPoint[0] = inputPoint[0] + vec[0]; - // outputPoint[1] = inputPoint[1] + vec[1]; - // outputPoint[2] = inputPoint[2] + vec[2]; - // output->SetPoint( pointId, outputPoint ); - // - // - // newGeometry->pos = outputPoint; - // newGeometry->neighborIndices = refGeometry->neighborIndices; - // newGeometry->meanCurvature = refGeometry->meanCurvature; - // newGeometry->neighbors = refGeometry->neighbors; - // newGeometry->oldPos = refGeometry->oldPos; - // newGeometry->eps = refGeometry->eps; - // newGeometry->referenceMetrics = refGeometry->referenceMetrics; - // newGeometry->neighborSet = refGeometry->neighborSet; - // newGeometry->distance = refGeometry->distance; - // newGeometry->externalForce = refGeometry->externalForce; - // newGeometry->internalForce = refGeometry->internalForce; - // output->SetGeometryData(pointId, newGeometry); - // pointDataIterator++; - // } - // } - //// output->SetGeometryData( inputMesh->GetGeometryData() ); - // return output; - // } - - static typename MeshType::Pointer CreateRegularSphereMesh2(typename MeshType::PointType center, - typename MeshType::PointType scale, - int resolution) - { - typedef typename itk::AutomaticTopologyMeshSource MeshSourceType; - typename MeshSourceType::Pointer mySphereSource = MeshSourceType::New(); - - typename MeshType::PointType pnt0, pnt1, pnt2, pnt3, pnt4, pnt5, pnt6, pnt7, pnt8, pnt9, pnt10, pnt11; - double c1 = 0.5 * (1.0 + sqrt(5.0)); - double c2 = 1.0; - double len = sqrt(c1 * c1 + c2 * c2); - c1 /= len; - c2 /= len; - - pnt0[0] = center[0] - c1 * scale[0]; - pnt0[1] = center[1]; - pnt0[2] = center[2] + c2 * scale[2]; - pnt1[0] = center[0]; - pnt1[1] = center[1] + c2 * scale[1]; - pnt1[2] = center[2] - c1 * scale[2]; - pnt2[0] = center[0]; - pnt2[1] = center[1] + c2 * scale[1]; - pnt2[2] = center[2] + c1 * scale[2]; - pnt3[0] = center[0] + c1 * scale[0]; - pnt3[1] = center[1]; - pnt3[2] = center[2] - c2 * scale[2]; - pnt4[0] = center[0] - c2 * scale[0]; - pnt4[1] = center[1] - c1 * scale[1]; - pnt4[2] = center[2]; - pnt5[0] = center[0] - c2 * scale[0]; - pnt5[1] = center[1] + c1 * scale[1]; - pnt5[2] = center[2]; - pnt6[0] = center[0]; - pnt6[1] = center[1] - c2 * scale[1]; - pnt6[2] = center[2] + c1 * scale[2]; - pnt7[0] = center[0] + c2 * scale[0]; - pnt7[1] = center[1] + c1 * scale[1]; - pnt7[2] = center[2]; - pnt8[0] = center[0]; - pnt8[1] = center[1] - c2 * scale[1]; - pnt8[2] = center[2] - c1 * scale[2]; - pnt9[0] = center[0] + c1 * scale[0]; - pnt9[1] = center[1]; - pnt9[2] = center[2] + c2 * scale[2]; - pnt10[0] = center[0] + c2 * scale[0]; - pnt10[1] = center[1] - c1 * scale[1]; - pnt10[2] = center[2]; - pnt11[0] = center[0] - c1 * scale[0]; - pnt11[1] = center[1]; - pnt11[2] = center[2] - c2 * scale[2]; - - addTriangle(mySphereSource, scale, pnt9, pnt2, pnt6, resolution); - addTriangle(mySphereSource, scale, pnt1, pnt11, pnt5, resolution); - addTriangle(mySphereSource, scale, pnt11, pnt1, pnt8, resolution); - addTriangle(mySphereSource, scale, pnt0, pnt11, pnt4, resolution); - addTriangle(mySphereSource, scale, pnt3, pnt1, pnt7, resolution); - addTriangle(mySphereSource, scale, pnt3, pnt8, pnt1, resolution); - addTriangle(mySphereSource, scale, pnt9, pnt3, pnt7, resolution); - addTriangle(mySphereSource, scale, pnt0, pnt6, pnt2, resolution); - addTriangle(mySphereSource, scale, pnt4, pnt10, pnt6, resolution); - addTriangle(mySphereSource, scale, pnt1, pnt5, pnt7, resolution); - addTriangle(mySphereSource, scale, pnt7, pnt5, pnt2, resolution); - addTriangle(mySphereSource, scale, pnt8, pnt3, pnt10, resolution); - addTriangle(mySphereSource, scale, pnt4, pnt11, pnt8, resolution); - addTriangle(mySphereSource, scale, pnt9, pnt7, pnt2, resolution); - addTriangle(mySphereSource, scale, pnt10, pnt9, pnt6, resolution); - addTriangle(mySphereSource, scale, pnt0, pnt5, pnt11, resolution); - addTriangle(mySphereSource, scale, pnt0, pnt2, pnt5, resolution); - addTriangle(mySphereSource, scale, pnt8, pnt10, pnt4, resolution); - addTriangle(mySphereSource, scale, pnt3, pnt9, pnt10, resolution); - addTriangle(mySphereSource, scale, pnt6, pnt0, pnt4, resolution); - - return mySphereSource->GetOutput(); - } - -private: - static void addTriangle(typename itk::AutomaticTopologyMeshSource::Pointer meshSource, - typename MeshType::PointType scale, - typename MeshType::PointType pnt0, - typename MeshType::PointType pnt1, - typename MeshType::PointType pnt2, - int resolution) - { - if (resolution == 0) - { - // add triangle - meshSource->AddTriangle(meshSource->AddPoint(pnt0), meshSource->AddPoint(pnt1), meshSource->AddPoint(pnt2)); - } - else - { - vnl_vector_fixed v1, v2, res, pv; - v1 = (pnt1 - pnt0).Get_vnl_vector(); - v2 = (pnt2 - pnt0).Get_vnl_vector(); - res = vnl_cross_3d(v1, v2); - pv = pnt0.GetVectorFromOrigin().Get_vnl_vector(); - // double d = res[0]*pv[0] + res[1]*pv[1] + res[2]*pv[2]; - - // subdivision - typename MeshType::PointType pnt01, pnt12, pnt20; - for (int d = 0; d < 3; d++) - { - pnt01[d] = (pnt0[d] + pnt1[d]) / 2.0; - pnt12[d] = (pnt1[d] + pnt2[d]) / 2.0; - pnt20[d] = (pnt2[d] + pnt0[d]) / 2.0; - } - // map new points to sphere - double lenPnt01 = 0; - for (int d = 0; d < 3; d++) - lenPnt01 += pnt01[d] * pnt01[d]; - lenPnt01 = sqrt(lenPnt01); - double lenPnt12 = 0; - for (int d = 0; d < 3; d++) - lenPnt12 += pnt12[d] * pnt12[d]; - lenPnt12 = sqrt(lenPnt12); - double lenPnt20 = 0; - for (int d = 0; d < 3; d++) - lenPnt20 += pnt20[d] * pnt20[d]; - lenPnt20 = sqrt(lenPnt20); - for (int d = 0; d < 3; d++) - { - pnt01[d] *= scale[d] / lenPnt01; - pnt12[d] *= scale[d] / lenPnt12; - pnt20[d] *= scale[d] / lenPnt20; - } - addTriangle(meshSource, scale, pnt0, pnt01, pnt20, resolution - 1); - addTriangle(meshSource, scale, pnt01, pnt1, pnt12, resolution - 1); - addTriangle(meshSource, scale, pnt20, pnt12, pnt2, resolution - 1); - addTriangle(meshSource, scale, pnt01, pnt12, pnt20, resolution - 1); - } - } -}; - -#endif // MITKMESHUTIL_H_INCLUDED diff --git a/Modules/DataTypesExt/src/mitkMesh.cpp b/Modules/DataTypesExt/src/mitkMesh.cpp deleted file mode 100644 index b88524fc13..0000000000 --- a/Modules/DataTypesExt/src/mitkMesh.cpp +++ /dev/null @@ -1,805 +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 "mitkMesh.h" -#include "mitkInteractionConst.h" -#include "mitkLine.h" -#include "mitkLineOperation.h" -#include "mitkLineOperation.h" -#include "mitkNumericTypes.h" -#include "mitkOperation.h" -#include "mitkOperationActor.h" -#include "mitkPointOperation.h" -#include "mitkRenderingManager.h" -#include "mitkStatusBar.h" - -mitk::Mesh::Mesh() -{ -} - -mitk::Mesh::~Mesh() -{ -} - -const mitk::Mesh::DataType *mitk::Mesh::GetMesh(int t) const -{ - return m_PointSetSeries[t]; -} - -mitk::Mesh::DataType *mitk::Mesh::GetMesh(int t) -{ - return m_PointSetSeries[t]; -} - -void mitk::Mesh::SetMesh(DataType *mesh, int t) -{ - this->Expand(t + 1); - m_PointSetSeries[t] = mesh; -} - -unsigned long mitk::Mesh::GetNumberOfCells(int t) -{ - return m_PointSetSeries[t]->GetNumberOfCells(); -} - -// search a line that is close enough according to the given position -bool mitk::Mesh::SearchLine(Point3D point, float distance, unsigned long &lineId, unsigned long &cellId, int t) -{ - // returns true if a line is found - ScalarType bestDist = distance; - - // iterate through all cells. - ConstCellIterator cellIt = m_PointSetSeries[t]->GetCells()->Begin(); - ConstCellIterator cellEnd = m_PointSetSeries[t]->GetCells()->End(); - while (cellIt != cellEnd) - { - if (cellIt.Value()->GetNumberOfPoints() > 1) - { - // then iterate through all indexes of points in it->Value() - PointIdIterator inAIt = cellIt.Value()->PointIdsBegin(); // first point - PointIdIterator inBIt = cellIt.Value()->PointIdsBegin(); // second point - PointIdIterator inEnd = cellIt.Value()->PointIdsEnd(); - - ++inAIt; // so it points to the point before inBIt - - int currentLineId = 0; - while (inAIt != inEnd) - { - mitk::PointSet::PointType pointA, pointB; - if (m_PointSetSeries[t]->GetPoint((*inAIt), &pointA) && m_PointSetSeries[t]->GetPoint((*inBIt), &pointB)) - { - auto line = new Line(); - line->SetPoints(pointA, pointB); - double thisDistance = line->Distance(point); - if (thisDistance < bestDist) - { - cellId = cellIt->Index(); - lineId = currentLineId; - bestDist = thisDistance; - } - } - ++inAIt; - ++inBIt; - ++currentLineId; - } - - // If the cell is closed, then check the line from the last index to - // the first index if inAIt points to inEnd, then inBIt points to the - // last index. - CellDataType cellData; - bool dataOk = m_PointSetSeries[t]->GetCellData(cellIt->Index(), &cellData); - if (dataOk) - { - if (cellData.closed) - { - // get the points - PointIdIterator inAIt = cellIt.Value()->PointIdsBegin(); // first point - // inBIt points to last. - mitk::PointSet::PointType pointA, pointB; - if (m_PointSetSeries[t]->GetPoint((*inAIt), &pointA) && m_PointSetSeries[t]->GetPoint((*inBIt), &pointB)) - { - auto line = new Line(); - line->SetPoints(pointA, pointB); - double thisDistance = line->Distance(point); - if (thisDistance < bestDist) - { - cellId = cellIt->Index(); - lineId = currentLineId; - bestDist = thisDistance; - } - } - } - } - } - ++cellIt; - } - return (bestDist < distance); -} - -int mitk::Mesh::SearchFirstCell(unsigned long pointId, int t) -{ - // iterate through all cells and find the cell the given pointId is inside - ConstCellIterator it = m_PointSetSeries[t]->GetCells()->Begin(); - ConstCellIterator end = m_PointSetSeries[t]->GetCells()->End(); - while (it != end) - { - PointIdIterator position = std::find(it->Value()->PointIdsBegin(), it->Value()->PointIdsEnd(), pointId); - - if (position != it->Value()->PointIdsEnd()) - { - return it->Index(); - } - ++it; - } - return -1; -} - -// Due to not implemented itk::CellInterface::EvaluatePosition and errors in -// using vtkCell::EvaluatePosition (changing iterator!) we must implement -// it in mitk::Mesh -// make it easy and look for hit points and hit lines: needs to be done anyway! -bool mitk::Mesh::EvaluatePosition(mitk::Point3D point, unsigned long &cellId, float precision, int t) -{ - int pointId = this->SearchPoint(point, precision, t); - if (pointId > -1) - { - // search the cell the point lies inside - cellId = this->SearchFirstCell(pointId, t); - return true; - } - unsigned long lineId = 0; - if (this->SearchLine(point, precision, lineId, cellId, t)) - { - return true; - } - - return false; -} - -unsigned long mitk::Mesh::GetNewCellId(int t) -{ - long nextCellId = -1; - ConstCellIterator it = m_PointSetSeries[t]->GetCells()->Begin(); - ConstCellIterator end = m_PointSetSeries[t]->GetCells()->End(); - - while (it != end) - { - nextCellId = it.Index(); - ++it; - } - ++nextCellId; - return nextCellId; -} - -int mitk::Mesh::SearchSelectedCell(int t) -{ - CellDataIterator cellDataIt, cellDataEnd; - cellDataEnd = m_PointSetSeries[t]->GetCellData()->End(); - for (cellDataIt = m_PointSetSeries[t]->GetCellData()->Begin(); cellDataIt != cellDataEnd; cellDataIt++) - { - // then declare an operation which unselects this line; UndoOperation as well! - if (cellDataIt->Value().selected) - { - return cellDataIt->Index(); - } - } - return -1; -} - -// get the cell; then iterate through the Ids times lineId. Then IdA ist the -// one, IdB ist ne next.don't forget the last closing line if the cell is -// closed -bool mitk::Mesh::GetPointIds(unsigned long cellId, unsigned long lineId, int &idA, int &idB, int t) -{ - CellAutoPointer cellAutoPointer; - bool ok = m_PointSetSeries[t]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellType *cell = cellAutoPointer.GetPointer(); - - // Get the cellData to also check the closing line - CellDataType cellData; - m_PointSetSeries[t]->GetCellData(cellId, &cellData); - bool closed = cellData.closed; - - PointIdIterator pointIdIt = cell->PointIdsBegin(); - PointIdIterator pointIdEnd = cell->PointIdsEnd(); - unsigned int counter = 0; - bool found = false; - while (pointIdIt != pointIdEnd) - { - if (counter == lineId) - { - idA = (*pointIdIt); - ++pointIdIt; - found = true; - break; - } - ++counter; - ++pointIdIt; - } - if (found) - { - // if in the middle - if (pointIdIt != pointIdEnd) - { - idB = (*pointIdIt); - } - // if found but on the end, then it is the closing connection, so the - // last and the first point - else if (closed) - { - pointIdIt = cell->PointIdsBegin(); - idB = (*pointIdIt); - } - } - else - ok = false; - } - return ok; -} - -void mitk::Mesh::ExecuteOperation(Operation *operation) -{ - // adding only the operations, that aren't implemented by the pointset. - switch (operation->GetOperationType()) - { - case OpNOTHING: - break; - - case OpNEWCELL: - { - auto *lineOp = dynamic_cast(operation); - - // if no lineoperation, then call superclass pointSet - if (lineOp == nullptr) - { - Superclass::ExecuteOperation(operation); - } - - bool ok; - int cellId = lineOp->GetCellId(); - CellAutoPointer cellAutoPointer; - ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - - // if it doesn't already exist - if (!ok) - { - cellAutoPointer.TakeOwnership(new PolygonType); - m_PointSetSeries[0]->SetCell(cellId, cellAutoPointer); - CellDataType cellData; - cellData.selected = true; - cellData.selectedLines.clear(); - cellData.closed = false; - m_PointSetSeries[0]->SetCellData(cellId, cellData); - } - } - break; - - case OpDELETECELL: - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) // if no lineoperation, then call superclass pointSet - { - Superclass::ExecuteOperation(operation); - } - m_PointSetSeries[0]->GetCells()->DeleteIndex((unsigned)lineOp->GetCellId()); - m_PointSetSeries[0]->GetCellData()->DeleteIndex((unsigned)lineOp->GetCellId()); - } - break; - - case OpCLOSECELL: - // sets the bolean flag closed from a specified cell to true. - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) // if no lineoperation, then call superclass pointSet - { - // then search the selected cell!//TODO - Superclass::ExecuteOperation(operation); - } - bool ok; - int cellId = lineOp->GetCellId(); - if (cellId < 0) // cellId isn't set - { - cellId = this->SearchSelectedCell(0); - if (cellId < 0) // still not found - return; - } - CellAutoPointer cellAutoPointer; - - // get directly the celldata!TODO - ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellDataType cellData; - m_PointSetSeries[0]->GetCellData(cellId, &cellData); - cellData.closed = true; - m_PointSetSeries[0]->SetCellData(cellId, cellData); - } - } - break; - - case OpOPENCELL: - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) // if no lineoperation, then call superclass pointSet - { - Superclass::ExecuteOperation(operation); - } - bool ok; - int cellId = lineOp->GetCellId(); - CellAutoPointer cellAutoPointer; - ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellDataType cellData; - m_PointSetSeries[0]->GetCellData(cellId, &cellData); - cellData.closed = false; - ; - m_PointSetSeries[0]->SetCellData(cellId, cellData); - } - } - break; - - case OpADDLINE: - // inserts the ID of the selected point into the indexes of lines in the - // selected cell afterwars the added line is selected - { - auto *lineOp = dynamic_cast(operation); - - int cellId = -1; - int pId = -1; - - if (lineOp == nullptr) - { - cellId = this->SearchSelectedCell(0); - if (cellId == -1) - return; - - pId = this->SearchSelectedPoint(0); - if (pId == -1) - return; - } - else - { - cellId = lineOp->GetCellId(); - if (cellId == -1) - return; - pId = lineOp->GetPIdA(); - if (pId == -1) - return; - } - - bool ok; - CellAutoPointer cellAutoPointer; - ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellType *cell = cellAutoPointer.GetPointer(); - if (cell->GetType() == CellType::POLYGON_CELL) - { - auto *polygon = static_cast(cell); - // add the pointId to the Cell. filling the empty cell with - // one id doesn't mean to add a line, it means, that the - // initilal PointId is set. The next addition of a pointId adds - // a line - polygon->AddPointId(pId); - - // select the line, if we really added a line, so now have more than - // 1 pointID in the cell - CellDataType cellData; - ok = m_PointSetSeries[0]->GetCellData(cellId, &cellData); - if (ok) - { - // A line between point 0 and 1 has the Id 0. A line between - // 1 and 2 has a Id = 1. So we add getnumberofpoints-2. - if (polygon->GetNumberOfPoints() > 1) - cellData.selectedLines.push_back(polygon->GetNumberOfPoints() - 2); - } - m_PointSetSeries[0]->SetCellData(cellId, cellData); - m_PointSetSeries[0]->SetCell(cellId, cellAutoPointer); - } - } - } - break; - - case OpDELETELINE: - { - // deleted the last line through removing the index PIdA - // (if set to -1, use the last point) in the given cellId - auto *lineOp = dynamic_cast(operation); - int cellId = -1; - int pId = -1; - - if (lineOp == nullptr) - { - cellId = this->SearchSelectedCell(0); - if (cellId == -1) - return; - pId = this->SearchSelectedPoint(0); - } - else - { - cellId = lineOp->GetCellId(); - if (cellId == -1) - return; - pId = lineOp->GetPIdA(); - } - - bool ok; - CellAutoPointer cellAutoPointer; - ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellType *cell = cellAutoPointer.GetPointer(); - if (cell->GetType() == CellType::POLYGON_CELL) - { - auto *oldPolygon = static_cast(cell); - - auto newPolygonCell = new PolygonType; - CellAutoPointer newCell; - newCell.TakeOwnership(newPolygonCell); - - PointIdConstIterator it, oldend; - oldend = oldPolygon->PointIdsEnd(); - if (pId >= 0) - { - for (it = oldPolygon->PointIdsBegin(); it != oldend; ++it) - { - if ((*it) != (MeshType::PointIdentifier)pId) - { - newPolygonCell->AddPointId(*it); - } - } - } - else - { - --oldend; - for (it = oldPolygon->PointIdsBegin(); it != oldend; ++it) - newPolygonCell->AddPointId(*it); - } - oldPolygon->SetPointIds(0, newPolygonCell->GetNumberOfPoints(), newPolygonCell->PointIdsBegin()); - } - } - } - break; - - case OpREMOVELINE: - // Remove the given Index in the given cell through copying everything - // into a new cell accept the one that has to be deleted. - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) // if no lineoperation, then call superclass pointSet - { - Superclass::ExecuteOperation(operation); - } - - bool ok; - CellAutoPointer cellAutoPointer; - int cellId = lineOp->GetCellId(); - ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (!ok) - return; - - CellType *cell = cellAutoPointer.GetPointer(); - CellAutoPointer newCellAutoPointer; - newCellAutoPointer.TakeOwnership(new PolygonType); - auto *newPolygon = static_cast(cell); - - PointIdIterator it = cell->PointIdsBegin(); - PointIdIterator end = cell->PointIdsEnd(); - int pointId = lineOp->GetPIdA(); - if (pointId < 0) // if not initialized!! - return; - - while (it != end) - { - if ((*it) == (unsigned int)pointId) - { - break; - } - else - { - newPolygon->AddPointId(*it); - } - ++it; - } - while (it != end) - { - newPolygon->AddPointId(*it); - it++; - } - m_PointSetSeries[0]->SetCell(cellId, newCellAutoPointer); - } - break; - - case OpINSERTLINE: - // //insert line between two other points. - ////before A--B after A--C--B - // //the points A, B and C have to be in the pointset. - // //needed: CellId, Id of C , Id A and Id B - ////the cell has to exist! - //{ - // mitk::LineOperation *lineOp = dynamic_cast(operation); - // if (lineOp == nullptr)//if no lineoperation, then call superclass pointSet - // { - // Superclass::ExecuteOperation(operation); - // } - // int cellId = lineOp->GetCellId(); - // int pIdC = lineOp->GetPIdC(); - // int pIdA = lineOp->GetPIdA(); - // int pIdB = lineOp->GetPIdB(); - - // //the points of the given PointIds have to exist in the PointSet - // bool ok; - // ok = m_PointSetSeries[0]->GetPoints()->IndexExists(pIdA); - // if (!ok) - // return; - // ok = m_PointSetSeries[0]->GetPoints()->IndexExists(pIdB); - // if (!ok) - // return; - // ok = m_PointSetSeries[0]->GetPoints()->IndexExists(pIdC); - // if (!ok) - // return; - - // // so the points do exist. So now check, if there is already a cell - // // with the given Id - // DataType::CellAutoPointer cell; - // ok = m_PointSetSeries[0]->GetCell(cellId, cell); - // if (!ok) - // return; - - // //pIdA and pIdB should exist in the cell - // - // PointIdIterator pit = cell->PointIdsBegin(); - // PointIdIterator end = cell->PointIdsEnd(); - // - // //now arrange the new Ids in the cell like desired; pIdC between - // // pIdA and pIdB - // unsigned int nuPoints = cell->GetNumberOfPoints(); - - // std::vector newPoints; - // pit = cell->PointIdsBegin(); - // end = cell->PointIdsEnd(); - // int i = 0; - // while( pit != end ) - // { - // if ((*pit) = pIdA) - // { - // //now we have found the place to add pIdC after - // newPoints[i] = (*pit); - // i++; - // newPoints[i] = pIdC; - // } - // else - // newPoints[i] = (*pit); - // pit++; - // } - - // //now we have the Ids, that existed before combined with the new ones - // //so delete the old cell - // //doesn't seem to be necessary! - // //cell->ClearPoints(); - // pit = cell->PointIdsBegin(); - // cell->SetPointIds(pit); - //} - break; - - case OpMOVELINE: //(moves two points) - { - auto *lineOp = dynamic_cast(operation); - - if (lineOp == nullptr) - { - mitk::StatusBar::GetInstance()->DisplayText( - "Message from mitkMesh: Recieved wrong type of operation! See mitkMeshInteractor.cpp", 10000); - return; - } - - // create two operations out of the one operation and call superclass - // through the transmitted pointIds get the koordinates of the points. - // then add the transmitted vestor to them - // create two operations and send them to superclass - Point3D pointA, pointB; - pointA.Fill(0.0); - pointB.Fill(0.0); - m_PointSetSeries[0]->GetPoint(lineOp->GetPIdA(), &pointA); - m_PointSetSeries[0]->GetPoint(lineOp->GetPIdB(), &pointB); - - pointA[0] += lineOp->GetVector()[0]; - pointA[1] += lineOp->GetVector()[1]; - pointA[2] += lineOp->GetVector()[2]; - pointB[0] += lineOp->GetVector()[0]; - pointB[1] += lineOp->GetVector()[1]; - pointB[2] += lineOp->GetVector()[2]; - - auto operationA = new mitk::PointOperation(OpMOVE, pointA, lineOp->GetPIdA()); - auto operationB = new mitk::PointOperation(OpMOVE, pointB, lineOp->GetPIdB()); - - Superclass::ExecuteOperation(operationA); - Superclass::ExecuteOperation(operationB); - } - break; - - case OpSELECTLINE: //(select the given line) - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) // if no lineoperation, then call superclass pointSet - { - Superclass::ExecuteOperation(operation); - } - int cellId = lineOp->GetCellId(); - CellAutoPointer cellAutoPointer; - bool ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellDataType cellData; - m_PointSetSeries[0]->GetCellData(cellId, &cellData); - SelectedLinesType *selectedLines = &(cellData.selectedLines); - auto position = std::find(selectedLines->begin(), selectedLines->end(), (unsigned int)lineOp->GetId()); - - if (position == selectedLines->end()) // if not alsready selected - { - cellData.selectedLines.push_back(lineOp->GetId()); - } - m_PointSetSeries[0]->SetCellData(lineOp->GetCellId(), cellData); - } - } - break; - - case OpDESELECTLINE: //(deselect the given line) - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) - { - Superclass::ExecuteOperation(operation); - } - int cellId = lineOp->GetCellId(); - CellAutoPointer cellAutoPointer; - bool ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellDataType cellData; - m_PointSetSeries[0]->GetCellData(cellId, &cellData); - SelectedLinesType *selectedLines = &(cellData.selectedLines); - auto position = std::find(selectedLines->begin(), selectedLines->end(), (unsigned int)lineOp->GetId()); - - if (position != selectedLines->end()) // if found - { - selectedLines->erase(position); - } - m_PointSetSeries[0]->SetCellData(cellId, cellData); - } - } - break; - - case OpSELECTCELL: //(select the given cell) - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) // if no lineoperation, then call superclass pointSet - { - Superclass::ExecuteOperation(operation); - } - - int cellId = lineOp->GetCellId(); - CellAutoPointer cellAutoPointer; - - // directly get the data!//TODO - bool ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellDataType cellData; - m_PointSetSeries[0]->GetCellData(cellId, &cellData); - cellData.selected = true; - m_PointSetSeries[0]->SetCellData(cellId, cellData); - } - } - break; - - case OpDESELECTCELL: //(deselect the given cell) - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) // if no lineoperation, then call superclass pointSet - { - Superclass::ExecuteOperation(operation); - } - int cellId = lineOp->GetCellId(); - CellAutoPointer cellAutoPointer; - bool ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (ok) - { - CellDataType cellData; - m_PointSetSeries[0]->GetCellData(cellId, &cellData); - cellData.selected = false; - m_PointSetSeries[0]->SetCellData(cellId, cellData); - } - } - break; - - case OpMOVECELL: - // moves all Points of one cell according to the given vector - { - auto *lineOp = dynamic_cast(operation); - if (lineOp == nullptr) // if no celloperation, then call superclass pointSet - { - Superclass::ExecuteOperation(operation); - } - - int cellId = lineOp->GetCellId(); - Vector3D vector = lineOp->GetVector(); - - // get the cell - CellAutoPointer cellAutoPointer; - bool ok = m_PointSetSeries[0]->GetCell(cellId, cellAutoPointer); - if (!ok) - return; - - CellDataType cellData; - m_PointSetSeries[0]->GetCellData(cellId, &cellData); - // iterate through the pointIds of the CellData and move those points in - // the pointset - PointIdIterator it = cellAutoPointer->PointIdsBegin(); - PointIdIterator end = cellAutoPointer->PointIdsEnd(); - while (it != end) - { - unsigned int position = (*it); - PointType point; - point.Fill(0); - m_PointSetSeries[0]->GetPoint(position, &point); - point = point + vector; - m_PointSetSeries[0]->SetPoint(position, point); - ++it; - } - } - break; - - default: - // if the operation couldn't be handled here, then send it to superclass - Superclass::ExecuteOperation(operation); - return; - } - // to tell the mappers, that the data is modifierd and has to be updated - this->Modified(); - - mitk::OperationEndEvent endevent(operation); - ((const itk::Object *)this)->InvokeEvent(endevent); - - // As discussed lately, don't mess with rendering from inside data structures - //*todo has to be done here, cause of update-pipeline not working yet - // mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - -mitk::Mesh::DataType::BoundingBoxPointer mitk::Mesh::GetBoundingBoxFromCell(unsigned long cellId, int t) -{ - // itk::CellInterface has also a GetBoundingBox, but it - // returns CoordRepType [PointDimension *2] - DataType::BoundingBoxPointer bBoxPointer = nullptr; - CellAutoPointer cellAutoPointer; - if (m_PointSetSeries[t]->GetCell(cellId, cellAutoPointer)) - { - DataType::PointsContainerPointer pointsContainer = DataType::PointsContainer::New(); - PointIdIterator bbIt = cellAutoPointer.GetPointer()->PointIdsBegin(); - PointIdIterator bbEnd = cellAutoPointer.GetPointer()->PointIdsEnd(); - while (bbIt != bbEnd) - { - mitk::PointSet::PointType point; - bool pointOk = m_PointSetSeries[t]->GetPoint((*bbIt), &point); - if (pointOk) - pointsContainer->SetElement((*bbIt), point); - ++bbIt; - } - bBoxPointer = DataType::BoundingBoxType::New(); - bBoxPointer->SetPoints(pointsContainer); - bBoxPointer->ComputeBoundingBox(); - } - return bBoxPointer; -} diff --git a/Modules/DataTypesExt/test/files.cmake b/Modules/DataTypesExt/test/files.cmake index 048ece655e..356091d282 100644 --- a/Modules/DataTypesExt/test/files.cmake +++ b/Modules/DataTypesExt/test/files.cmake @@ -1,18 +1,17 @@ set(MODULE_TESTS mitkColorSequenceRainbowTest.cpp - mitkMeshTest.cpp mitkMultiStepperTest.cpp mitkUnstructuredGridTest.cpp ) set(MODULE_IMAGE_TESTS mitkCompressedImageContainerTest.cpp #only runs on images ) set(MODULE_TESTIMAGE US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png ) diff --git a/Modules/DataTypesExt/test/mitkMeshTest.cpp b/Modules/DataTypesExt/test/mitkMeshTest.cpp deleted file mode 100644 index aa6dd719a9..0000000000 --- a/Modules/DataTypesExt/test/mitkMeshTest.cpp +++ /dev/null @@ -1,74 +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 -#include -#include -#include -#include - -int mitkMeshTest(int /*argc*/, char * /*argv*/ []) -{ - // Create mesh - mitk::Mesh::Pointer mesh; - mesh = mitk::Mesh::New(); - - // try to get the itkmesh - std::cout << "Create a mesh and try to get the itkMesh"; - mitk::Mesh::DataType::Pointer itkdata = nullptr; - itkdata = mesh->GetMesh(); - if (itkdata.IsNull()) - { - std::cout << "[FAILED]" << std::endl; - return EXIT_FAILURE; - } - - // fresh mesh has to be empty! - std::cout << "Is the mesh empty?"; - if (mesh->GetSize() != 0) - { - std::cout << "[FAILED]" << std::endl; - return EXIT_FAILURE; - } - - // create an operation and add a point. - int position = 0; - mitk::Point3D point; - point.Fill(1); - auto doOp = new mitk::PointOperation(mitk::OpINSERT, point, position); - mesh->ExecuteOperation(doOp); - - // now check new condition! - if ((mesh->GetSize() != 1) || (!mesh->IndexExists(position))) - { - std::cout << "[FAILED]" << std::endl; - return EXIT_FAILURE; - } - delete doOp; - - // get the point and check if it is still the same - std::cout << "Create an operation and add a point. Then try to get that point."; - mitk::Point3D tempPoint; - tempPoint.Fill(0); - tempPoint = mesh->GetPoint(position); - if (tempPoint != point) - { - std::cout << "[FAILED]" << std::endl; - return EXIT_FAILURE; - } - - // well done!!! Passed! - std::cout << "[PASSED]" << std::endl; - - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; -} diff --git a/Modules/IOExt/CMakeLists.txt b/Modules/IOExt/CMakeLists.txt index ccfb990d3c..61b51b291e 100644 --- a/Modules/IOExt/CMakeLists.txt +++ b/Modules/IOExt/CMakeLists.txt @@ -1,4 +1,4 @@ MITK_CREATE_MODULE(DEPENDS MitkDataTypesExt MitkMapperExt MitkSceneSerialization MitkLegacyIO - PACKAGE_DEPENDS PRIVATE ITK|ITKIOImageBase VTK|vtkIOPLY+vtkIOExport+vtkIOParallelXML + PACKAGE_DEPENDS PRIVATE ITK|ITKIOImageBase VTK|IOPLY+IOExport+IOParallelXML AUTOLOAD_WITH MitkCore ) diff --git a/Modules/IOExt/Internal/mitkIOExtObjectFactory.cpp b/Modules/IOExt/Internal/mitkIOExtObjectFactory.cpp index d268917ff6..86ca564d52 100644 --- a/Modules/IOExt/Internal/mitkIOExtObjectFactory.cpp +++ b/Modules/IOExt/Internal/mitkIOExtObjectFactory.cpp @@ -1,180 +1,167 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkIOExtObjectFactory.h" #include "mitkCoreObjectFactory.h" #include "mitkParRecFileIOFactory.h" //#include "mitkObjFileIOFactory.h" #include "mitkStlVolumeTimeSeriesIOFactory.h" #include "mitkVtkVolumeTimeSeriesIOFactory.h" #include "mitkUnstructuredGridVtkWriter.h" #include "mitkUnstructuredGridVtkWriterFactory.h" #include "mitkVolumeMapperVtkSmart3D.h" -#include "mitkMesh.h" -#include "mitkMeshMapper2D.h" -#include "mitkMeshVtkMapper3D.h" #include "mitkUnstructuredGridMapper2D.h" #include "mitkUnstructuredGridVtkMapper3D.h" #include "mitkVtkGLMapperWrapper.h" #include #include #include mitk::IOExtObjectFactory::IOExtObjectFactory() : CoreObjectFactoryBase(), m_ParRecFileIOFactory(ParRecFileIOFactory::New().GetPointer()) //, m_ObjFileIOFactory(ObjFileIOFactory::New().GetPointer()) , m_StlVolumeTimeSeriesIOFactory(StlVolumeTimeSeriesIOFactory::New().GetPointer()), m_VtkVolumeTimeSeriesIOFactory(VtkVolumeTimeSeriesIOFactory::New().GetPointer()), m_UnstructuredGridVtkWriterFactory(UnstructuredGridVtkWriterFactory::New().GetPointer()) { static bool alreadyDone = false; if (!alreadyDone) { MITK_DEBUG << "IOExtObjectFactory c'tor" << std::endl; itk::ObjectFactoryBase::RegisterFactory(m_ParRecFileIOFactory); itk::ObjectFactoryBase::RegisterFactory(m_StlVolumeTimeSeriesIOFactory); itk::ObjectFactoryBase::RegisterFactory(m_VtkVolumeTimeSeriesIOFactory); itk::ObjectFactoryBase::RegisterFactory(m_UnstructuredGridVtkWriterFactory); m_FileWriters.push_back(mitk::UnstructuredGridVtkWriter::New().GetPointer()); m_FileWriters.push_back(mitk::UnstructuredGridVtkWriter::New().GetPointer()); m_FileWriters.push_back(mitk::UnstructuredGridVtkWriter::New().GetPointer()); CreateFileExtensionsMap(); alreadyDone = true; } } mitk::IOExtObjectFactory::~IOExtObjectFactory() { itk::ObjectFactoryBase::UnRegisterFactory(m_ParRecFileIOFactory); itk::ObjectFactoryBase::UnRegisterFactory(m_StlVolumeTimeSeriesIOFactory); itk::ObjectFactoryBase::UnRegisterFactory(m_VtkVolumeTimeSeriesIOFactory); itk::ObjectFactoryBase::UnRegisterFactory(m_UnstructuredGridVtkWriterFactory); } mitk::Mapper::Pointer mitk::IOExtObjectFactory::CreateMapper(mitk::DataNode *node, MapperSlotId id) { mitk::Mapper::Pointer newMapper = nullptr; mitk::BaseData *data = node->GetData(); if (id == mitk::BaseRenderer::Standard2D) { - if ((dynamic_cast(data) != nullptr)) - { - newMapper = mitk::MeshMapper2D::New(); - newMapper->SetDataNode(node); - } - else if ((dynamic_cast(data) != nullptr)) + if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::VtkGLMapperWrapper::New(mitk::UnstructuredGridMapper2D::New().GetPointer()); newMapper->SetDataNode(node); } } else if (id == mitk::BaseRenderer::Standard3D) { if ((dynamic_cast(data) != nullptr) && std::string("Image").compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::VolumeMapperVtkSmart3D::New(); newMapper->SetDataNode(node); } - else if ((dynamic_cast(data) != nullptr)) - { - newMapper = mitk::MeshVtkMapper3D::New(); - newMapper->SetDataNode(node); - } else if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::UnstructuredGridVtkMapper3D::New(); newMapper->SetDataNode(node); } } return newMapper; } void mitk::IOExtObjectFactory::SetDefaultProperties(mitk::DataNode *node) { if (node == nullptr) return; mitk::DataNode::Pointer nodePointer = node; mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image.IsNotNull() && image->IsInitialized()) { mitk::VolumeMapperVtkSmart3D::SetDefaultProperties(node); } if (dynamic_cast(node->GetData())) { mitk::UnstructuredGridVtkMapper3D::SetDefaultProperties(node); } } std::string mitk::IOExtObjectFactory::GetFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_FileExtensionsMap, fileExtension); return fileExtension.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::IOExtObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } mitk::CoreObjectFactoryBase::MultimapType mitk::IOExtObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } void mitk::IOExtObjectFactory::CreateFileExtensionsMap() { m_FileExtensionsMap.insert(std::pair("*.vtu", "VTK Unstructured Grid")); m_FileExtensionsMap.insert(std::pair("*.vtk", "VTK Unstructured Grid")); m_FileExtensionsMap.insert(std::pair("*.pvtu", "VTK Unstructured Grid")); m_SaveFileExtensionsMap.insert(std::pair("*.pvtu", "VTK Parallel XML Unstructured Grid")); m_SaveFileExtensionsMap.insert(std::pair("*.vtu", "VTK XML Unstructured Grid")); m_SaveFileExtensionsMap.insert(std::pair("*.vtk", "VTK Legacy Unstructured Grid")); } std::string mitk::IOExtObjectFactory::GetSaveFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension); return fileExtension.c_str(); } struct RegisterIOExtObjectFactory { RegisterIOExtObjectFactory() : m_Factory(mitk::IOExtObjectFactory::New()) { mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory(m_Factory); } ~RegisterIOExtObjectFactory() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory(m_Factory); } mitk::IOExtObjectFactory::Pointer m_Factory; }; static RegisterIOExtObjectFactory registerIOExtObjectFactory; diff --git a/Modules/ImageStatistics/CMakeLists.txt b/Modules/ImageStatistics/CMakeLists.txt index 73a49bc11d..532b38bdf4 100644 --- a/Modules/ImageStatistics/CMakeLists.txt +++ b/Modules/ImageStatistics/CMakeLists.txt @@ -1,10 +1,10 @@ MITK_CREATE_MODULE( DEPENDS MitkImageExtraction MitkPlanarFigure MitkMultilabel PACKAGE_DEPENDS PUBLIC ITK|ITKIOXML - PRIVATE ITK|ITKVTK+ITKConvolution + PRIVATE ITK|ITKVTK+ITKConvolution VTK|IOImage ) if(BUILD_TESTING) add_subdirectory(Testing) endif() diff --git a/Modules/MapperExt/CMakeLists.txt b/Modules/MapperExt/CMakeLists.txt index e3b7025b99..ca202f89be 100644 --- a/Modules/MapperExt/CMakeLists.txt +++ b/Modules/MapperExt/CMakeLists.txt @@ -1,13 +1,14 @@ mitk_create_module( DEPENDS MitkDataTypesExt MitkLegacyGL + PACKAGE_DEPENDS PRIVATE VTK|CommonComputationalGeometry+CommonSystem+RenderingVolumeOpenGL2 ) if(TARGET ${MODULE_TARGET}) if(MITK_USE_OpenMP) target_link_libraries(${MODULE_TARGET} PUBLIC OpenMP::OpenMP_CXX) endif() if(BUILD_TESTING) add_subdirectory(test) endif() endif() diff --git a/Modules/MapperExt/files.cmake b/Modules/MapperExt/files.cmake index 3ec5ef80f6..01778f6a7a 100644 --- a/Modules/MapperExt/files.cmake +++ b/Modules/MapperExt/files.cmake @@ -1,20 +1,18 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkEnhancedPointSetVtkMapper3D.cpp mitkGPUVolumeMapper3D.cpp - mitkMeshMapper2D.cpp - mitkMeshVtkMapper3D.cpp mitkSplineVtkMapper3D.cpp mitkUnstructuredGridMapper2D.cpp mitkUnstructuredGridVtkMapper3D.cpp mitkVectorImageMapper2D.cpp mitkVolumeMapperVtkSmart3D.cpp vtkMaskedGlyph2D.cpp vtkMaskedGlyph3D.cpp vtkMitkGPUVolumeRayCastMapper.cpp vtkUnstructuredGridMapper.cpp vtkPointSetSlicer.cxx ) diff --git a/Modules/MapperExt/include/mitkMeshMapper2D.h b/Modules/MapperExt/include/mitkMeshMapper2D.h deleted file mode 100644 index 30926d3089..0000000000 --- a/Modules/MapperExt/include/mitkMeshMapper2D.h +++ /dev/null @@ -1,53 +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 MITKMESHMAPPER2D_H_HEADER_INCLUDED -#define MITKMESHMAPPER2D_H_HEADER_INCLUDED - -#include "MitkMapperExtExports.h" -#include "mitkCommon.h" -#include "mitkGLMapper.h" - -namespace mitk -{ - class BaseRenderer; - class Mesh; - - /** - * \brief OpenGL-based mapper to display a mesh in a 2D window - * - * \todo implement for AbstractTransformGeometry. - * \ingroup Mapper - */ - class MITKMAPPEREXT_EXPORT MeshMapper2D : public GLMapper - { - public: - mitkClassMacro(MeshMapper2D, GLMapper); - - itkFactorylessNewMacro(Self); - - itkCloneMacro(Self); - - /** @brief Get the Mesh to map */ - const mitk::Mesh *GetInput(void); - - void Paint(mitk::BaseRenderer *renderer) override; - - protected: - MeshMapper2D(); - - ~MeshMapper2D() override; - }; - -} // namespace mitk - -#endif /* MITKMESHMapper2D_H_HEADER_INCLUDED */ diff --git a/Modules/MapperExt/include/mitkMeshVtkMapper3D.h b/Modules/MapperExt/include/mitkMeshVtkMapper3D.h deleted file mode 100644 index 59391e03f4..0000000000 --- a/Modules/MapperExt/include/mitkMeshVtkMapper3D.h +++ /dev/null @@ -1,87 +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 MITKMESHVTKMAPPER3D_H_HEADER_INCLUDED -#define MITKMESHVTKMAPPER3D_H_HEADER_INCLUDED - -#include "MitkMapperExtExports.h" -#include "mitkBaseRenderer.h" -#include "mitkCommon.h" -#include "mitkMesh.h" -#include "mitkVtkMapper.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class vtkActor; -class vtkAssembly; -class vtkFollower; -class vtkPolyDataMapper; -class vtkPropAssembly; - -namespace mitk -{ - /** - * \brief Vtk-based mapper for PointList - * \ingroup Mapper - */ - class MITKMAPPEREXT_EXPORT MeshVtkMapper3D : public VtkMapper - { - public: - mitkClassMacro(MeshVtkMapper3D, VtkMapper); - - itkFactorylessNewMacro(Self); - - itkCloneMacro(Self); - - virtual const mitk::Mesh *GetInput(); - - vtkProp *GetVtkProp(mitk::BaseRenderer *renderer) override; - void UpdateVtkTransform(mitk::BaseRenderer *renderer) override; - - LocalStorageHandler m_LSH; - - protected: - MeshVtkMapper3D(); - - ~MeshVtkMapper3D() override; - - void GenerateDataForRenderer(mitk::BaseRenderer *renderer) override; - - void ResetMapper(BaseRenderer *renderer) override; - - vtkPropAssembly *m_PropAssembly; - - vtkActor *m_SpheresActor; - vtkActor *m_ContourActor; - vtkPolyDataMapper *m_ContourMapper; - vtkPolyDataMapper *m_SpheresMapper; - - vtkPolyDataMapper *m_TextVtkPolyDataMapper; - - vtkAppendPolyData *m_Spheres; - vtkPolyData *m_Contour; - }; - -} // namespace mitk - -#endif /* MITKMESHVTKMAPPER3D_H_HEADER_INCLUDED*/ diff --git a/Modules/MapperExt/include/mitkVolumeMapperVtkSmart3D.h b/Modules/MapperExt/include/mitkVolumeMapperVtkSmart3D.h index 9745bc07c2..34731725da 100644 --- a/Modules/MapperExt/include/mitkVolumeMapperVtkSmart3D.h +++ b/Modules/MapperExt/include/mitkVolumeMapperVtkSmart3D.h @@ -1,81 +1,75 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKVTKSMARTVOLUMEMAPPER_H_HEADER_INCLUDED #define MITKVTKSMARTVOLUMEMAPPER_H_HEADER_INCLUDED // MITK #include "MitkMapperExtExports.h" #include "mitkBaseRenderer.h" #include "mitkCommon.h" #include "mitkImage.h" #include "mitkVtkMapper.h" // VTK #include #include #include #include #include #include #include -class vtkRenderingOpenGL2ObjectFactory; -class vtkRenderingVolumeOpenGL2ObjectFactory; - namespace mitk { //##Documentation //## @brief Vtk-based mapper for VolumeData //## //## @ingroup Mapper class MITKMAPPEREXT_EXPORT VolumeMapperVtkSmart3D : public VtkMapper { public: mitkClassMacro(VolumeMapperVtkSmart3D, VtkMapper); itkFactorylessNewMacro(Self); itkCloneMacro(Self); vtkProp *GetVtkProp(mitk::BaseRenderer *renderer) override; void ApplyProperties(vtkActor *actor, mitk::BaseRenderer *renderer) override; static void SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer = nullptr, bool overwrite = false); protected: VolumeMapperVtkSmart3D(); ~VolumeMapperVtkSmart3D() override; void GenerateDataForRenderer(mitk::BaseRenderer *renderer) override; void createMapper(vtkImageData*); void createVolume(); void createVolumeProperty(); vtkImageData* GetInputImage(); vtkSmartPointer m_Volume; vtkSmartPointer m_ImageChangeInformation; vtkSmartPointer m_SmartVolumeMapper; vtkSmartPointer m_VolumeProperty; - vtkSmartPointer m_RenderingOpenGL2ObjectFactory; - vtkSmartPointer m_RenderingVolumeOpenGL2ObjectFactory; - void UpdateTransferFunctions(mitk::BaseRenderer *renderer); void UpdateRenderMode(mitk::BaseRenderer *renderer); }; } // namespace mitk #endif /* MITKVTKSMARTVOLUMEMAPPER_H_HEADER_INCLUDED */ diff --git a/Modules/MapperExt/src/mitkMeshMapper2D.cpp b/Modules/MapperExt/src/mitkMeshMapper2D.cpp deleted file mode 100644 index c67bb42de6..0000000000 --- a/Modules/MapperExt/src/mitkMeshMapper2D.cpp +++ /dev/null @@ -1,472 +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 "mitkMeshMapper2D.h" -#include "mitkBaseRenderer.h" -#include "mitkColorProperty.h" -#include "mitkGL.h" -#include "mitkLine.h" -#include "mitkMesh.h" -#include "mitkPlaneGeometry.h" -#include "mitkProperties.h" - -#include - -#include - -const float selectedColor[] = {1.0f, 0.0f, 0.6f}; // for selected! - -mitk::MeshMapper2D::MeshMapper2D() -{ -} - -mitk::MeshMapper2D::~MeshMapper2D() -{ -} - -const mitk::Mesh *mitk::MeshMapper2D::GetInput(void) -{ - return static_cast(GetDataNode()->GetData()); -} - -// Return whether a point is "smaller" than the second -static bool point3DSmaller(const mitk::Point3D &elem1, const mitk::Point3D &elem2) -{ - if (elem1[0] != elem2[0]) - return elem1[0] < elem2[0]; - if (elem1[1] != elem2[1]) - return elem1[1] < elem2[1]; - return elem1[2] < elem2[2]; -} - -void mitk::MeshMapper2D::Paint(mitk::BaseRenderer *renderer) -{ - bool visible = true; - - GetDataNode()->GetVisibility(visible, renderer, "visible"); - - if (!visible) - return; - - // @FIXME: Logik fuer update - bool updateNeccesary = true; - - if (updateNeccesary) - { - // aus GenerateData - mitk::Mesh::Pointer input = const_cast(this->GetInput()); - - // Get the TimeGeometry of the input object - const TimeGeometry *inputTimeGeometry = input->GetTimeGeometry(); - if ((inputTimeGeometry == nullptr) || (inputTimeGeometry->CountTimeSteps() == 0)) - { - return; - } - - // - // get the world time - // - ScalarType time = renderer->GetTime(); - - // - // convert the world time in time steps of the input object - // - int timeStep = 0; - if (time > itk::NumericTraits::NonpositiveMin()) - timeStep = inputTimeGeometry->TimePointToTimeStep(time); - if (inputTimeGeometry->IsValidTimeStep(timeStep) == false) - { - return; - } - - mitk::Mesh::MeshType::Pointer itkMesh = input->GetMesh(timeStep); - - if (itkMesh.GetPointer() == nullptr) - { - return; - } - - const PlaneGeometry *worldplanegeometry = (renderer->GetCurrentWorldPlaneGeometry()); - - // apply color and opacity read from the PropertyList - ApplyColorAndOpacityProperties(renderer); - - vtkLinearTransform *transform = GetDataNode()->GetVtkTransform(); - - // List of the Points - Mesh::DataType::PointsContainerConstIterator it, end; - it = itkMesh->GetPoints()->Begin(); - end = itkMesh->GetPoints()->End(); - - // iterator on the additional data of each point - Mesh::PointDataIterator dataIt; //, dataEnd; - dataIt = itkMesh->GetPointData()->Begin(); - - // for switching back to old color after using selected color - float unselectedColor[4]; - glGetFloatv(GL_CURRENT_COLOR, unselectedColor); - - while (it != end) - { - mitk::Point3D p, projected_p; - float vtkp[3]; - - itk2vtk(it->Value(), vtkp); - transform->TransformPoint(vtkp, vtkp); - vtk2itk(vtkp, p); - - renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p); - Vector3D diff = p - projected_p; - if (diff.GetSquaredNorm() < 4.0) - { - Point2D pt2d, tmp; - renderer->WorldToDisplay(p, pt2d); - - Vector2D horz, vert; - horz[0] = 5; - horz[1] = 0; - vert[0] = 0; - vert[1] = 5; - - // check if the point is to be marked as selected - if (dataIt->Value().selected) - { - horz[0] = 8; - vert[1] = 8; - glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red - - switch (dataIt->Value().pointSpec) - { - case PTSTART: - // a quad - glBegin(GL_LINE_LOOP); - tmp = pt2d - horz + vert; - glVertex2dv(&tmp[0]); - tmp = pt2d + horz + vert; - glVertex2dv(&tmp[0]); - tmp = pt2d + horz - vert; - glVertex2dv(&tmp[0]); - tmp = pt2d - horz - vert; - glVertex2dv(&tmp[0]); - glEnd(); - break; - case PTUNDEFINED: - // a diamond around the point - glBegin(GL_LINE_LOOP); - tmp = pt2d - horz; - glVertex2dv(&tmp[0]); - tmp = pt2d + vert; - glVertex2dv(&tmp[0]); - tmp = pt2d + horz; - glVertex2dv(&tmp[0]); - tmp = pt2d - vert; - glVertex2dv(&tmp[0]); - glEnd(); - break; - default: - break; - } // switch - - // the actual point - glBegin(GL_POINTS); - tmp = pt2d; - glVertex2dv(&tmp[0]); - glEnd(); - } - else // if not selected - { - glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]); - switch (dataIt->Value().pointSpec) - { - case PTSTART: - // a quad - glBegin(GL_LINE_LOOP); - tmp = pt2d - horz + vert; - glVertex2dv(&tmp[0]); - tmp = pt2d + horz + vert; - glVertex2dv(&tmp[0]); - tmp = pt2d + horz - vert; - glVertex2dv(&tmp[0]); - tmp = pt2d - horz - vert; - glVertex2dv(&tmp[0]); - glEnd(); - break; - case PTUNDEFINED: - // drawing crosses - glBegin(GL_LINES); - tmp = pt2d - horz; - glVertex2dv(&tmp[0]); - tmp = pt2d + horz; - glVertex2dv(&tmp[0]); - tmp = pt2d - vert; - glVertex2dv(&tmp[0]); - tmp = pt2d + vert; - glVertex2dv(&tmp[0]); - glEnd(); - break; - default: - { - break; - } - } // switch - } // else - } - ++it; - ++dataIt; - } - - // now connect the lines inbetween - mitk::Mesh::PointType thisPoint; - thisPoint.Fill(0); - Point2D *firstOfCell = nullptr; - Point2D *lastPoint = nullptr; - unsigned int lastPointId = 0; - bool lineSelected = false; - - Point3D firstOfCell3D; - Point3D lastPoint3D; - bool first; - mitk::Line line; - std::vector intersectionPoints; - double t; - - // iterate through all cells and then iterate through all indexes of points in that cell - Mesh::CellIterator cellIt, cellEnd; - Mesh::CellDataIterator cellDataIt; //, cellDataEnd; - Mesh::PointIdIterator cellIdIt, cellIdEnd; - - cellIt = itkMesh->GetCells()->Begin(); - cellEnd = itkMesh->GetCells()->End(); - cellDataIt = itkMesh->GetCellData()->Begin(); - - while (cellIt != cellEnd) - { - unsigned int numOfPointsInCell = cellIt->Value()->GetNumberOfPoints(); - if (numOfPointsInCell > 1) - { - // iterate through all id's in the cell - cellIdIt = cellIt->Value()->PointIdsBegin(); - cellIdEnd = cellIt->Value()->PointIdsEnd(); - - firstOfCell3D = input->GetPoint(*cellIdIt, timeStep); - - intersectionPoints.clear(); - intersectionPoints.reserve(numOfPointsInCell); - - first = true; - - while (cellIdIt != cellIdEnd) - { - lastPoint3D = thisPoint; - - thisPoint = input->GetPoint(*cellIdIt, timeStep); - - // search in data (vector<> selectedLines) if the index of the point is set. if so, then the line is selected. - lineSelected = false; - Mesh::SelectedLinesType selectedLines = cellDataIt->Value().selectedLines; - - // a line between 1(lastPoint) and 2(pt2d) has the Id 1, so look for the Id of lastPoint - // since we only start, if we have more than one point in the cell, lastPointId is initiated with 0 - auto position = std::find(selectedLines.begin(), selectedLines.end(), lastPointId); - if (position != selectedLines.end()) - { - lineSelected = true; - } - - mitk::Point3D p, projected_p; - float vtkp[3]; - itk2vtk(thisPoint, vtkp); - transform->TransformPoint(vtkp, vtkp); - vtk2itk(vtkp, p); - renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p); - Vector3D diff = p - projected_p; - if (diff.GetSquaredNorm() < 4.0) - { - Point2D pt2d, tmp; - renderer->WorldToDisplay(p, pt2d); - - if (lastPoint == nullptr) - { - // set the first point in the cell. This point in needed to close the polygon - firstOfCell = new Point2D; - *firstOfCell = pt2d; - lastPoint = new Point2D; - *lastPoint = pt2d; - lastPointId = *cellIdIt; - } - else - { - if (lineSelected) - { - glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red - // a line from lastPoint to thisPoint - glBegin(GL_LINES); - glVertex2dv(&(*lastPoint)[0]); - glVertex2dv(&pt2d[0]); - glEnd(); - } - else // if not selected - { - glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]); - // drawing crosses - glBegin(GL_LINES); - glVertex2dv(&(*lastPoint)[0]); - glVertex2dv(&pt2d[0]); - glEnd(); - } - // to draw the line to the next in iteration step - *lastPoint = pt2d; - // and to search for the selection state of the line - lastPointId = *cellIdIt; - } // if..else - } // if <4.0 - - // fill off-plane polygon part 1 - if ((!first) && (worldplanegeometry != nullptr)) - { - line.SetPoints(lastPoint3D, thisPoint); - if (worldplanegeometry->IntersectionPointParam(line, t) && ((t >= 0) && (t <= 1))) - { - intersectionPoints.push_back(line.GetPoint(t)); - } - } - ++cellIdIt; - first = false; - } // while cellIdIter - - // closed polygon? - if (cellDataIt->Value().closed) - { - // close the polygon if needed - if (firstOfCell != nullptr) - { - lineSelected = false; - Mesh::SelectedLinesType selectedLines = cellDataIt->Value().selectedLines; - auto position = std::find(selectedLines.begin(), selectedLines.end(), lastPointId); - if (position != selectedLines.end()) // found the index - { - glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red - // a line from lastPoint to firstPoint - glBegin(GL_LINES); - glVertex2dv(&(*lastPoint)[0]); - glVertex2dv(&(*firstOfCell)[0]); - glEnd(); - } - else - { - glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]); - glBegin(GL_LINES); - glVertex2dv(&(*lastPoint)[0]); - glVertex2dv(&(*firstOfCell)[0]); - glEnd(); - } - } - } // if closed - - // Axis-aligned bounding box(AABB) around the cell if selected and set in Property - bool showBoundingBox; - if (dynamic_cast(this->GetDataNode()->GetProperty("showBoundingBox")) == nullptr) - showBoundingBox = false; - else - showBoundingBox = - dynamic_cast(this->GetDataNode()->GetProperty("showBoundingBox"))->GetValue(); - - if (showBoundingBox) - { - if (cellDataIt->Value().selected) - { - mitk::Mesh::DataType::BoundingBoxPointer aABB = input->GetBoundingBoxFromCell(cellIt->Index()); - if (aABB.IsNotNull()) - { - mitk::Mesh::PointType min, max; - min = aABB->GetMinimum(); - max = aABB->GetMaximum(); - - // project to the displayed geometry - Point2D min2D, max2D; - Point3D p, projected_p; - float vtkp[3]; - itk2vtk(min, vtkp); - transform->TransformPoint(vtkp, vtkp); - vtk2itk(vtkp, p); - renderer->WorldToDisplay(p, min2D); - - itk2vtk(max, vtkp); - transform->TransformPoint(vtkp, vtkp); - vtk2itk(vtkp, p); - renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p); - Vector3D diff = p - projected_p; - if (diff.GetSquaredNorm() < 4.0) - { - renderer->WorldToDisplay(p, max2D); - - // draw the BoundingBox - glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red - // a line from lastPoint to firstPoint - glBegin(GL_LINE_LOOP); - glVertex2f(min2D[0], min2D[1]); - glVertex2f(min2D[0], max2D[1]); - glVertex2f(max2D[0], max2D[1]); - glVertex2f(max2D[0], min2D[1]); - glEnd(); - } // draw bounding-box - } // bounding-box exists - } // cell selected - } // show bounding-box - - // fill off-plane polygon part 2 - if (worldplanegeometry != nullptr) - { - // consider line from last to first - line.SetPoints(thisPoint, firstOfCell3D); - if (worldplanegeometry->IntersectionPointParam(line, t) && ((t >= 0) && (t <= 1))) - { - intersectionPoints.push_back(line.GetPoint(t)); - } - std::sort(intersectionPoints.begin(), intersectionPoints.end(), point3DSmaller); - std::vector::iterator it, end; - end = intersectionPoints.end(); - if ((intersectionPoints.size() % 2) != 0) - { - --end; // ensure even number of intersection-points - } - Point2D pt2d; - for (it = intersectionPoints.begin(); it != end; ++it) - { - glBegin(GL_LINES); - renderer->WorldToDisplay(*it, pt2d); - glVertex2dv(pt2d.GetDataPointer()); - ++it; - renderer->WorldToDisplay(*it, pt2d); - glVertex2dv(pt2d.GetDataPointer()); - glEnd(); - } - if (it != intersectionPoints.end()) - { - glBegin(GL_LINES); - renderer->WorldToDisplay(*it, pt2d); - glVertex2dv(pt2d.GetDataPointer()); - glVertex2dv(pt2d.GetDataPointer()); - glEnd(); - } - } // fill off-plane polygon part 2 - } // if numOfPointsInCell>1 - delete firstOfCell; - delete lastPoint; - lastPoint = nullptr; - firstOfCell = nullptr; - lastPointId = 0; - ++cellIt; - ++cellDataIt; - } - } -} diff --git a/Modules/MapperExt/src/mitkMeshVtkMapper3D.cpp b/Modules/MapperExt/src/mitkMeshVtkMapper3D.cpp deleted file mode 100644 index 1fca78d220..0000000000 --- a/Modules/MapperExt/src/mitkMeshVtkMapper3D.cpp +++ /dev/null @@ -1,226 +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 "mitkMeshVtkMapper3D.h" -#include "mitkDataNode.h" -#include "mitkProperties.h" -#include "mitkVtkPropRenderer.h" - -#ifndef VCL_VC60 -#include "mitkMeshUtil.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -const mitk::Mesh *mitk::MeshVtkMapper3D::GetInput() -{ - return static_cast(GetDataNode()->GetData()); -} - -vtkProp *mitk::MeshVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) -{ - return m_PropAssembly; -} - -void mitk::MeshVtkMapper3D::UpdateVtkTransform(mitk::BaseRenderer * /*renderer*/) -{ - vtkLinearTransform *vtktransform = this->GetDataNode()->GetVtkTransform(this->GetTimestep()); - - m_SpheresActor->SetUserTransform(vtktransform); - m_ContourActor->SetUserTransform(vtktransform); -} - -mitk::MeshVtkMapper3D::MeshVtkMapper3D() : m_PropAssembly(nullptr) -{ - m_Spheres = vtkAppendPolyData::New(); - m_Contour = vtkPolyData::New(); - - m_SpheresActor = vtkActor::New(); - m_SpheresMapper = vtkPolyDataMapper::New(); - m_SpheresActor->SetMapper(m_SpheresMapper); - - m_ContourActor = vtkActor::New(); - m_ContourMapper = vtkPolyDataMapper::New(); - m_ContourActor->SetMapper(m_ContourMapper); - m_ContourActor->GetProperty()->SetAmbient(1.0); - - m_PropAssembly = vtkPropAssembly::New(); - - // a vtkPropAssembly is not a sub-class of vtkProp3D, so - // we cannot use m_Prop3D. -} - -mitk::MeshVtkMapper3D::~MeshVtkMapper3D() -{ - m_ContourActor->Delete(); - m_SpheresActor->Delete(); - m_ContourMapper->Delete(); - m_SpheresMapper->Delete(); - m_PropAssembly->Delete(); - m_Spheres->Delete(); - m_Contour->Delete(); -} - -void mitk::MeshVtkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) -{ - BaseLocalStorage *ls = m_LSH.GetLocalStorage(renderer); - bool needGenerateData = ls->IsGenerateDataRequired(renderer, this, GetDataNode()); - - if (needGenerateData) - { - ls->UpdateGenerateDataTime(); - - m_PropAssembly->VisibilityOn(); - - if (m_PropAssembly->GetParts()->IsItemPresent(m_SpheresActor)) - m_PropAssembly->RemovePart(m_SpheresActor); - if (m_PropAssembly->GetParts()->IsItemPresent(m_ContourActor)) - m_PropAssembly->RemovePart(m_ContourActor); - - m_Spheres->RemoveAllInputs(); - m_Contour->Initialize(); - - mitk::Mesh::Pointer input = const_cast(this->GetInput()); - input->Update(); - - mitk::Mesh::DataType::Pointer itkMesh = input->GetMesh(this->GetTimestep()); - - if (itkMesh.GetPointer() == nullptr) - { - m_PropAssembly->VisibilityOff(); - return; - } - - mitk::Mesh::PointsContainer::Iterator i; - - int j; - - float floatRgba[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - double doubleRgba[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - mitk::Color tmpColor; - - // check for color prop and use it for rendering if it exists - m_DataNode->GetColor(floatRgba, nullptr); - - if (dynamic_cast(this->GetDataNode()->GetProperty("unselectedcolor")) != nullptr) - { - tmpColor = dynamic_cast(this->GetDataNode()->GetProperty("unselectedcolor"))->GetValue(); - floatRgba[0] = tmpColor[0]; - floatRgba[1] = tmpColor[1]; - floatRgba[2] = tmpColor[2]; - floatRgba[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value - doubleRgba[0] = floatRgba[0]; - doubleRgba[1] = floatRgba[1]; - doubleRgba[2] = floatRgba[2]; - doubleRgba[3] = floatRgba[3]; - } - - if (itkMesh->GetNumberOfPoints() > 0) - { - // build m_Spheres->GetOutput() vtkPolyData - float pointSize = 2.0; - mitk::FloatProperty::Pointer pointSizeProp = - dynamic_cast(this->GetDataNode()->GetProperty("pointsize")); - if (pointSizeProp.IsNotNull()) - pointSize = pointSizeProp->GetValue(); - - for (j = 0, i = itkMesh->GetPoints()->Begin(); i != itkMesh->GetPoints()->End(); i++, j++) - { - vtkSmartPointer sphere = vtkSmartPointer::New(); - - sphere->SetRadius(pointSize); - sphere->SetCenter(i.Value()[0], i.Value()[1], i.Value()[2]); - - m_Spheres->AddInputConnection(sphere->GetOutputPort()); - sphere->Delete(); - } - - // setup mapper, actor and add to assembly - m_SpheresMapper->SetInputConnection(m_Spheres->GetOutputPort()); - m_SpheresActor->GetProperty()->SetColor(doubleRgba); - m_PropAssembly->AddPart(m_SpheresActor); - } - - if (itkMesh->GetNumberOfCells() > 0) - { -// build m_Contour vtkPolyData -#ifdef VCL_VC60 - itkExceptionMacro(<< "MeshVtkMapper3D currently not working for MS Visual C++ 6.0, because MeshUtils are " - "currently not supported."); -#else - m_Contour = - MeshUtil::MeshToPolyData(itkMesh.GetPointer(), false, false, 0, nullptr, m_Contour); -#endif - - if (m_Contour->GetNumberOfCells() > 0) - { - // setup mapper, actor and add to assembly - m_ContourMapper->SetInputData(m_Contour); - bool wireframe = true; - GetDataNode()->GetVisibility(wireframe, nullptr, "wireframe"); - if (wireframe) - m_ContourActor->GetProperty()->SetRepresentationToWireframe(); - else - m_ContourActor->GetProperty()->SetRepresentationToSurface(); - m_ContourActor->GetProperty()->SetColor(doubleRgba); - m_PropAssembly->AddPart(m_ContourActor); - } - } - } - - bool visible = true; - GetDataNode()->GetVisibility(visible, renderer, "visible"); - - if (!visible) - { - m_SpheresActor->VisibilityOff(); - m_ContourActor->VisibilityOff(); - return; - } - - bool makeContour = false; - this->GetDataNode()->GetBoolProperty("show contour", makeContour); - - if (makeContour) - { - m_ContourActor->VisibilityOn(); - } - else - { - m_ContourActor->VisibilityOff(); - } - - bool showPoints = true; - this->GetDataNode()->GetBoolProperty("show points", showPoints); - if (showPoints) - { - m_SpheresActor->VisibilityOn(); - } - else - { - m_SpheresActor->VisibilityOff(); - } -} - -void mitk::MeshVtkMapper3D::ResetMapper(BaseRenderer * /*renderer*/) -{ - m_PropAssembly->VisibilityOff(); -} diff --git a/Modules/MapperExt/src/mitkUnstructuredGridMapper2D.cpp b/Modules/MapperExt/src/mitkUnstructuredGridMapper2D.cpp index a4e89fbf06..a4db90ea37 100644 --- a/Modules/MapperExt/src/mitkUnstructuredGridMapper2D.cpp +++ b/Modules/MapperExt/src/mitkUnstructuredGridMapper2D.cpp @@ -1,555 +1,555 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkUnstructuredGridMapper2D.h" #include #include "mitkAbstractTransformGeometry.h" #include "mitkBaseRenderer.h" #include "mitkColorProperty.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include "mitkTransferFunction.h" #include "mitkTransferFunctionProperty.h" #include "mitkUnstructuredGrid.h" #include "mitkVtkMapper3D.h" #include "mitkVtkScalarModeProperty.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vtkPointSetSlicer.h" void mitk::UnstructuredGridMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { BaseLocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool needGenerateData = ls->IsGenerateDataRequired(renderer, this, GetDataNode()); if (needGenerateData) { ls->UpdateGenerateDataTime(); mitk::DataNode::ConstPointer node = this->GetDataNode(); if (node.IsNull()) return; if (!node->GetProperty(m_ScalarMode, "scalar mode")) { m_ScalarMode = mitk::VtkScalarModeProperty::New(0); } if (!node->GetProperty(m_ScalarVisibility, "scalar visibility")) { m_ScalarVisibility = mitk::BoolProperty::New(true); } if (!node->GetProperty(m_Outline, "outline polygons")) { m_Outline = mitk::BoolProperty::New(false); } if (!node->GetProperty(m_Color, "color")) { m_Color = mitk::ColorProperty::New(1.0f, 1.0f, 1.0f); } if (!node->GetProperty(m_LineWidth, "line width")) { m_LineWidth = mitk::IntProperty::New(1); } } mitk::BaseData::Pointer input = GetDataNode()->GetData(); assert(input); input->Update(); if (m_VtkPointSet) m_VtkPointSet->UnRegister(nullptr); m_VtkPointSet = this->GetVtkPointSet(renderer, this->GetTimestep()); assert(m_VtkPointSet); m_VtkPointSet->Register(nullptr); if (m_ScalarVisibility->GetValue()) { mitk::DataNode::ConstPointer node = this->GetDataNode(); mitk::TransferFunctionProperty::Pointer transferFuncProp; node->GetProperty(transferFuncProp, "TransferFunction", renderer); if (transferFuncProp.IsNotNull()) { mitk::TransferFunction::Pointer tf = transferFuncProp->GetValue(); if (m_ScalarsToColors) m_ScalarsToColors->UnRegister(nullptr); m_ScalarsToColors = static_cast(tf->GetColorTransferFunction()); m_ScalarsToColors->Register(nullptr); if (m_ScalarsToOpacity) m_ScalarsToOpacity->UnRegister(nullptr); m_ScalarsToOpacity = tf->GetScalarOpacityFunction(); m_ScalarsToOpacity->Register(nullptr); } else { if (m_ScalarsToColors) m_ScalarsToColors->UnRegister(nullptr); m_ScalarsToColors = this->GetVtkLUT(renderer); assert(m_ScalarsToColors); m_ScalarsToColors->Register(nullptr); float opacity; node->GetOpacity(opacity, renderer); if (m_ScalarsToOpacity) m_ScalarsToOpacity->UnRegister(nullptr); m_ScalarsToOpacity = vtkPiecewiseFunction::New(); double range[2]; m_VtkPointSet->GetScalarRange(range); m_ScalarsToOpacity->AddSegment(range[0], opacity, range[1], opacity); } } } void mitk::UnstructuredGridMapper2D::Paint(mitk::BaseRenderer *renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if (!visible) return; vtkLinearTransform *vtktransform = GetDataNode()->GetVtkTransform(); vtkLinearTransform *inversetransform = vtktransform->GetLinearInverse(); PlaneGeometry::ConstPointer worldGeometry = renderer->GetCurrentWorldPlaneGeometry(); PlaneGeometry::ConstPointer worldPlaneGeometry = dynamic_cast(worldGeometry.GetPointer()); Point3D point; Vector3D normal; if (worldPlaneGeometry.IsNotNull()) { // set up vtkPlane according to worldGeometry point = worldPlaneGeometry->GetOrigin(); normal = worldPlaneGeometry->GetNormal(); normal.Normalize(); m_Plane->SetTransform((vtkAbstractTransform *)nullptr); } else { //@FIXME: does not work correctly. Does m_Plane->SetTransform really transforms a "plane plane" into a "curved //plane"? return; AbstractTransformGeometry::ConstPointer worldAbstractGeometry = dynamic_cast(renderer->GetCurrentWorldPlaneGeometry()); if (worldAbstractGeometry.IsNotNull()) { // set up vtkPlane according to worldGeometry point = worldAbstractGeometry->GetParametricBoundingBox()->GetMinimum(); FillVector3D(normal, 0, 0, 1); m_Plane->SetTransform(worldAbstractGeometry->GetVtkAbstractTransform()->GetInverse()); } else return; } double vp[3], vnormal[3]; vnl2vtk(point.GetVnlVector(), vp); vnl2vtk(normal.GetVnlVector(), vnormal); // normally, we would need to transform the surface and cut the transformed surface with the cutter. // This might be quite slow. Thus, the idea is, to perform an inverse transform of the plane instead. //@todo It probably does not work for scaling operations yet:scaling operations have to be // dealed with after the cut is performed by scaling the contour. inversetransform->TransformPoint(vp, vp); inversetransform->TransformNormalAtPoint(vp, vnormal, vnormal); m_Plane->SetOrigin(vp); m_Plane->SetNormal(vnormal); // set data into cutter m_Slicer->SetInputData(m_VtkPointSet); // m_Cutter->GenerateCutScalarsOff(); // m_Cutter->SetSortByToSortByCell(); // calculate the cut m_Slicer->Update(); // apply color and opacity read from the PropertyList ApplyColorAndOpacityProperties(renderer); // traverse the cut contour vtkPolyData *contour = m_Slicer->GetOutput(); vtkPoints *vpoints = contour->GetPoints(); vtkCellArray *vlines = contour->GetLines(); vtkCellArray *vpolys = contour->GetPolys(); vtkPointData *vpointdata = contour->GetPointData(); vtkDataArray *vscalars = vpointdata->GetScalars(); vtkCellData *vcelldata = contour->GetCellData(); vtkDataArray *vcellscalars = vcelldata->GetScalars(); const int numberOfLines = contour->GetNumberOfLines(); const int numberOfPolys = contour->GetNumberOfPolys(); const bool useCellData = m_ScalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_DEFAULT || m_ScalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_USE_CELL_DATA; const bool usePointData = m_ScalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_USE_POINT_DATA; Point3D p; Point2D p2d; vlines->InitTraversal(); vpolys->InitTraversal(); mitk::Color outlineColor = m_Color->GetColor(); glLineWidth((float)m_LineWidth->GetValue()); for (int i = 0; i < numberOfLines; ++i) { - vtkIdType *cell(nullptr); + const vtkIdType *cell(nullptr); vtkIdType cellSize(0); vlines->GetNextCell(cellSize, cell); float rgba[4] = {outlineColor[0], outlineColor[1], outlineColor[2], 1.0f}; if (m_ScalarVisibility->GetValue() && vcellscalars) { if (useCellData) { // color each cell according to cell data double scalar = vcellscalars->GetComponent(i, 0); double rgb[3] = {1.0f, 1.0f, 1.0f}; m_ScalarsToColors->GetColor(scalar, rgb); rgba[0] = (float)rgb[0]; rgba[1] = (float)rgb[1]; rgba[2] = (float)rgb[2]; rgba[3] = (float)m_ScalarsToOpacity->GetValue(scalar); } else if (usePointData) { double scalar = vscalars->GetComponent(i, 0); double rgb[3] = {1.0f, 1.0f, 1.0f}; m_ScalarsToColors->GetColor(scalar, rgb); rgba[0] = (float)rgb[0]; rgba[1] = (float)rgb[1]; rgba[2] = (float)rgb[2]; rgba[3] = (float)m_ScalarsToOpacity->GetValue(scalar); } } glColor4fv(rgba); glBegin(GL_LINE_LOOP); for (int j = 0; j < cellSize; ++j) { vpoints->GetPoint(cell[j], vp); // take transformation via vtktransform into account vtktransform->TransformPoint(vp, vp); vtk2itk(vp, p); // convert 3D point (in mm) to display coordinates (units ) renderer->WorldToDisplay(p, p2d); // convert display coordinates ( (0,0) is top-left ) in GL coordinates ( (0,0) is bottom-left ) // p2d[1]=toGL-p2d[1]; // add the current vertex to the line glVertex2f(p2d[0], p2d[1]); } glEnd(); } bool polyOutline = m_Outline->GetValue(); bool scalarVisibility = m_ScalarVisibility->GetValue(); // cache the transformed points // a fixed size array is way faster than 'new' // slices through 3d cells usually do not generated // polygons with more than 6 vertices const int maxPolySize = 10; auto *cachedPoints = new Point2D[maxPolySize * numberOfPolys]; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only draw polygons if there are cell scalars // or the outline property is set to true if (scalarVisibility && vcellscalars) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); for (int i = 0; i < numberOfPolys; ++i) { - vtkIdType *cell(nullptr); + const vtkIdType *cell(nullptr); vtkIdType cellSize(0); vpolys->GetNextCell(cellSize, cell); float rgba[4] = {1.0f, 1.0f, 1.0f, 0}; if (scalarVisibility && vcellscalars) { if (useCellData) { // color each cell according to cell data double scalar = vcellscalars->GetComponent(i + numberOfLines, 0); double rgb[3] = {1.0f, 1.0f, 1.0f}; m_ScalarsToColors->GetColor(scalar, rgb); rgba[0] = (float)rgb[0]; rgba[1] = (float)rgb[1]; rgba[2] = (float)rgb[2]; rgba[3] = (float)m_ScalarsToOpacity->GetValue(scalar); } else if (usePointData) { double scalar = vscalars->GetComponent(i, 0); double rgb[3] = {1.0f, 1.0f, 1.0f}; m_ScalarsToColors->GetColor(scalar, rgb); rgba[0] = (float)rgb[0]; rgba[1] = (float)rgb[1]; rgba[2] = (float)rgb[2]; rgba[3] = (float)m_ScalarsToOpacity->GetValue(scalar); } } glColor4fv(rgba); glBegin(GL_POLYGON); for (int j = 0; j < cellSize; ++j) { vpoints->GetPoint(cell[j], vp); // take transformation via vtktransform into account vtktransform->TransformPoint(vp, vp); vtk2itk(vp, p); // convert 3D point (in mm) to display coordinates (units ) renderer->WorldToDisplay(p, p2d); // convert display coordinates ( (0,0) is top-left ) in GL coordinates ( (0,0) is bottom-left ) // p2d[1]=toGL-p2d[1]; cachedPoints[i * 10 + j][0] = p2d[0]; cachedPoints[i * 10 + j][1] = p2d[1]; // add the current vertex to the line glVertex2f(p2d[0], p2d[1]); } glEnd(); } if (polyOutline) { vpolys->InitTraversal(); glColor4f(outlineColor[0], outlineColor[1], outlineColor[2], 1.0f); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); for (int i = 0; i < numberOfPolys; ++i) { - vtkIdType *cell(nullptr); + const vtkIdType *cell(nullptr); vtkIdType cellSize(0); vpolys->GetNextCell(cellSize, cell); glBegin(GL_POLYGON); // glPolygonOffset(1.0, 1.0); for (int j = 0; j < cellSize; ++j) { // add the current vertex to the line glVertex2f(cachedPoints[i * 10 + j][0], cachedPoints[i * 10 + j][1]); } glEnd(); } } } glDisable(GL_BLEND); delete[] cachedPoints; } vtkAbstractMapper3D *mitk::UnstructuredGridMapper2D::GetVtkAbstractMapper3D(mitk::BaseRenderer *renderer) { // MITK_INFO << "GETVTKABSTRACTMAPPER3D\n"; mitk::DataNode::ConstPointer node = this->GetDataNode(); if (node.IsNull()) return nullptr; mitk::VtkMapper::Pointer mitkMapper = dynamic_cast(node->GetMapper(2)); if (mitkMapper.IsNull()) { return nullptr; } mitkMapper->Update(renderer); auto *assembly = dynamic_cast(mitkMapper->GetVtkProp(renderer)); if (assembly) { vtkProp3DCollection *collection = assembly->GetParts(); collection->InitTraversal(); vtkProp3D *prop3d = nullptr; do { prop3d = collection->GetNextProp3D(); auto *actor = dynamic_cast(prop3d); if (actor) { return dynamic_cast(actor->GetMapper()); } auto *volume = dynamic_cast(prop3d); if (volume) { return dynamic_cast(volume->GetMapper()); } } while (prop3d != collection->GetLastProp3D()); } else { auto *actor = dynamic_cast(mitkMapper->GetVtkProp(renderer)); if (actor) { return dynamic_cast(actor->GetMapper()); } auto *volume = dynamic_cast(mitkMapper->GetVtkProp(renderer)); if (volume) { return dynamic_cast(volume->GetMapper()); } } return nullptr; } vtkPointSet *mitk::UnstructuredGridMapper2D::GetVtkPointSet(mitk::BaseRenderer *renderer, int time) { // MITK_INFO << "GETVTKPOINTSET\n"; vtkAbstractMapper3D *abstractMapper = GetVtkAbstractMapper3D(renderer); if (abstractMapper == nullptr) { // try to get data from the node mitk::DataNode::ConstPointer node = this->GetDataNode(); if (node.IsNull()) return nullptr; mitk::BaseData::Pointer data = node->GetData(); mitk::UnstructuredGrid::Pointer grid = dynamic_cast(data.GetPointer()); if (!grid.IsNull()) return static_cast(grid->GetVtkUnstructuredGrid(time)); return nullptr; } else { auto *mapper = dynamic_cast(abstractMapper); if (mapper) { return dynamic_cast(mapper->GetInput()); } auto *volMapper = dynamic_cast(abstractMapper); if (volMapper) { return dynamic_cast(volMapper->GetDataSetInput()); } } return nullptr; } vtkScalarsToColors *mitk::UnstructuredGridMapper2D::GetVtkLUT(mitk::BaseRenderer *renderer) { // MITK_INFO << "GETVTKLUT\n"; auto *mapper = dynamic_cast(GetVtkAbstractMapper3D(renderer)); if (mapper) return mapper->GetLookupTable(); else { mitk::DataNode::ConstPointer node = this->GetDataNode(); if (node.IsNull()) return nullptr; mitk::VtkMapper::Pointer mitkMapper = dynamic_cast(node->GetMapper(2)); if (mitkMapper.IsNull()) { // MITK_INFO << "mitkMapper is null\n"; return nullptr; } mitkMapper->Update(renderer); auto *volume = dynamic_cast(mitkMapper->GetVtkProp(renderer)); if (volume) { // MITK_INFO << "found volume prop\n"; return static_cast(volume->GetProperty()->GetRGBTransferFunction()); } auto *assembly = dynamic_cast(mitkMapper->GetVtkProp(renderer)); if (assembly) { // MITK_INFO << "found assembly prop\n"; mitk::TransferFunctionProperty::Pointer transferFuncProp; node->GetProperty(transferFuncProp, "TransferFunction", nullptr); if (transferFuncProp.IsNotNull()) { MITK_INFO << "return colortransferfunction\n"; return static_cast(transferFuncProp->GetValue()->GetColorTransferFunction()); } } return nullptr; } } bool mitk::UnstructuredGridMapper2D::IsConvertibleToVtkPointSet(mitk::BaseRenderer *renderer) { return (GetVtkPointSet(renderer, this->GetTimestep()) != nullptr); } mitk::UnstructuredGridMapper2D::UnstructuredGridMapper2D() { m_Plane = vtkPlane::New(); m_Slicer = vtkPointSetSlicer::New(); m_Slicer->SetSlicePlane(m_Plane); m_ScalarsToColors = nullptr; m_ScalarsToOpacity = nullptr; m_VtkPointSet = nullptr; // m_LUT = vtkLookupTable::New(); // m_LUT->SetTableRange( 0, 255 ); // m_LUT->SetNumberOfColors( 255 ); // m_LUT->SetRampToLinear (); // m_LUT->Build(); } mitk::UnstructuredGridMapper2D::~UnstructuredGridMapper2D() { m_Slicer->Delete(); m_Plane->Delete(); if (m_ScalarsToOpacity != nullptr) m_ScalarsToOpacity->UnRegister(nullptr); if (m_ScalarsToColors != nullptr) m_ScalarsToColors->UnRegister(nullptr); if (m_VtkPointSet != nullptr) m_VtkPointSet->UnRegister(nullptr); } diff --git a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp index 502d8a43e4..ee9a32ef57 100644 --- a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp +++ b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp @@ -1,244 +1,237 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkVolumeMapperVtkSmart3D.h" #include "mitkTransferFunctionProperty.h" #include "mitkTransferFunctionInitializer.h" #include "mitkLevelWindowProperty.h" #include -#include -#include #include #include +#include void mitk::VolumeMapperVtkSmart3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { bool value; this->GetDataNode()->GetBoolProperty("volumerendering", value, renderer); if (!value) { m_Volume->VisibilityOff(); return; } else { m_Volume->VisibilityOn(); } UpdateTransferFunctions(renderer); UpdateRenderMode(renderer); this->Modified(); } vtkProp* mitk::VolumeMapperVtkSmart3D::GetVtkProp(mitk::BaseRenderer *) { if (!m_Volume->GetMapper()) { createMapper(GetInputImage()); createVolume(); createVolumeProperty(); } return m_Volume; } void mitk::VolumeMapperVtkSmart3D::ApplyProperties(vtkActor *, mitk::BaseRenderer *) { } void mitk::VolumeMapperVtkSmart3D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { // GPU_INFO << "SetDefaultProperties"; node->AddProperty("volumerendering", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.usemip", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.cpu.ambient", mitk::FloatProperty::New(0.10f), renderer, overwrite); node->AddProperty("volumerendering.cpu.diffuse", mitk::FloatProperty::New(0.50f), renderer, overwrite); node->AddProperty("volumerendering.cpu.specular", mitk::FloatProperty::New(0.40f), renderer, overwrite); node->AddProperty("volumerendering.cpu.specular.power", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("volumerendering.usegpu", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.useray", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.gpu.ambient", mitk::FloatProperty::New(0.25f), renderer, overwrite); node->AddProperty("volumerendering.gpu.diffuse", mitk::FloatProperty::New(0.50f), renderer, overwrite); node->AddProperty("volumerendering.gpu.specular", mitk::FloatProperty::New(0.40f), renderer, overwrite); node->AddProperty("volumerendering.gpu.specular.power", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("binary", mitk::BoolProperty::New(false), renderer, overwrite); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image.IsNotNull() && image->IsInitialized()) { if ((overwrite) || (node->GetProperty("TransferFunction", renderer) == nullptr)) { // add a default transfer function mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(tf); tfInit->SetTransferFunctionMode(0); node->SetProperty("TransferFunction", mitk::TransferFunctionProperty::New(tf.GetPointer())); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } vtkImageData* mitk::VolumeMapperVtkSmart3D::GetInputImage() { auto input = dynamic_cast(this->GetDataNode()->GetData()); return input->GetVtkImageData(this->GetTimestep()); } void mitk::VolumeMapperVtkSmart3D::createMapper(vtkImageData* imageData) { Vector3D spacing; FillVector3D(spacing, 1.0, 1.0, 1.0); m_ImageChangeInformation->SetInputData(imageData); m_ImageChangeInformation->SetOutputSpacing(spacing.GetDataPointer()); m_SmartVolumeMapper->SetBlendModeToComposite(); m_SmartVolumeMapper->SetInputConnection(m_ImageChangeInformation->GetOutputPort()); } void mitk::VolumeMapperVtkSmart3D::createVolume() { m_Volume->VisibilityOff(); m_Volume->SetMapper(m_SmartVolumeMapper); m_Volume->SetProperty(m_VolumeProperty); } void mitk::VolumeMapperVtkSmart3D::createVolumeProperty() { m_VolumeProperty->ShadeOn(); m_VolumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION); } void mitk::VolumeMapperVtkSmart3D::UpdateTransferFunctions(mitk::BaseRenderer *renderer) { vtkSmartPointer opacityTransferFunction; vtkSmartPointer gradientTransferFunction; vtkSmartPointer colorTransferFunction; bool isBinary = false; this->GetDataNode()->GetBoolProperty("binary", isBinary, renderer); if (isBinary) { colorTransferFunction = vtkSmartPointer::New(); float rgb[3]; if (!GetDataNode()->GetColor(rgb, renderer)) rgb[0] = rgb[1] = rgb[2] = 1; colorTransferFunction->AddRGBPoint(0, rgb[0], rgb[1], rgb[2]); colorTransferFunction->Modified(); opacityTransferFunction = vtkSmartPointer::New(); gradientTransferFunction = vtkSmartPointer::New(); } else { auto *transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction", renderer)); if (transferFunctionProp) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } else { opacityTransferFunction = vtkSmartPointer::New(); gradientTransferFunction = vtkSmartPointer::New(); colorTransferFunction = vtkSmartPointer::New(); } } m_VolumeProperty->SetColor(colorTransferFunction); m_VolumeProperty->SetScalarOpacity(opacityTransferFunction); m_VolumeProperty->SetGradientOpacity(gradientTransferFunction); } void mitk::VolumeMapperVtkSmart3D::UpdateRenderMode(mitk::BaseRenderer *renderer) { bool usegpu = false; bool useray = false; bool usemip = false; this->GetDataNode()->GetBoolProperty("volumerendering.usegpu", usegpu); this->GetDataNode()->GetBoolProperty("volumerendering.useray", useray); this->GetDataNode()->GetBoolProperty("volumerendering.usemip", usemip); if (usegpu) m_SmartVolumeMapper->SetRequestedRenderModeToGPU(); else if (useray) m_SmartVolumeMapper->SetRequestedRenderModeToRayCast(); else m_SmartVolumeMapper->SetRequestedRenderModeToDefault(); int blendMode; if (this->GetDataNode()->GetIntProperty("volumerendering.blendmode", blendMode)) m_SmartVolumeMapper->SetBlendMode(blendMode); else if (usemip) m_SmartVolumeMapper->SetBlendMode(vtkSmartVolumeMapper::MAXIMUM_INTENSITY_BLEND); // shading parameter if (m_SmartVolumeMapper->GetRequestedRenderMode() == vtkSmartVolumeMapper::GPURenderMode) { float value = 0; if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.ambient", value, renderer)) m_VolumeProperty->SetAmbient(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.diffuse", value, renderer)) m_VolumeProperty->SetDiffuse(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.specular", value, renderer)) m_VolumeProperty->SetSpecular(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.specular.power", value, renderer)) m_VolumeProperty->SetSpecularPower(value); } else { float value = 0; if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.ambient", value, renderer)) m_VolumeProperty->SetAmbient(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.diffuse", value, renderer)) m_VolumeProperty->SetDiffuse(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.specular", value, renderer)) m_VolumeProperty->SetSpecular(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.specular.power", value, renderer)) m_VolumeProperty->SetSpecularPower(value); } } mitk::VolumeMapperVtkSmart3D::VolumeMapperVtkSmart3D() { - m_RenderingOpenGL2ObjectFactory = vtkSmartPointer::New(); - m_RenderingVolumeOpenGL2ObjectFactory = vtkSmartPointer::New(); - - vtkObjectFactory::RegisterFactory(m_RenderingOpenGL2ObjectFactory); - vtkObjectFactory::RegisterFactory(m_RenderingVolumeOpenGL2ObjectFactory); - m_SmartVolumeMapper = vtkSmartPointer::New(); m_SmartVolumeMapper->SetBlendModeToComposite(); m_ImageChangeInformation = vtkSmartPointer::New(); m_VolumeProperty = vtkSmartPointer::New(); m_Volume = vtkSmartPointer::New(); } mitk::VolumeMapperVtkSmart3D::~VolumeMapperVtkSmart3D() { } diff --git a/Modules/MapperExt/src/vtkPointSetSlicer.cxx b/Modules/MapperExt/src/vtkPointSetSlicer.cxx index 19246c9152..f240df59bb 100644 --- a/Modules/MapperExt/src/vtkPointSetSlicer.cxx +++ b/Modules/MapperExt/src/vtkPointSetSlicer.cxx @@ -1,634 +1,629 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "vtkPointSetSlicer.h" #include "vtkCellArray.h" +#include "vtkCellArrayIterator.h" #include "vtkCellData.h" #include "vtkCutter.h" #include "vtkDataSet.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkGenericCell.h" #include "vtkMergePoints.h" #include "vtkObjectFactory.h" #include "vtkPlane.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkUnstructuredGrid.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkStreamingDemandDrivenPipeline.h" vtkStandardNewMacro(vtkPointSetSlicer); // Construct with user-specified implicit function; initial value of 0.0; and // generating cut scalars turned off. vtkPointSetSlicer::vtkPointSetSlicer(vtkPlane *cf) { this->SlicePlane = cf; this->GenerateCutScalars = 0; this->Locator = nullptr; this->Cutter = vtkCutter::New(); this->Cutter->GenerateValues(1, 0, 1); } vtkPointSetSlicer::~vtkPointSetSlicer() { this->SetSlicePlane(nullptr); if (this->Locator) { this->Locator->UnRegister(this); this->Locator = nullptr; } this->Cutter->Delete(); } void vtkPointSetSlicer::SetSlicePlane(vtkPlane *plane) { if (this->SlicePlane == plane) { return; } if (this->SlicePlane) { this->SlicePlane->UnRegister(this); this->SlicePlane = nullptr; } if (plane) { plane->Register(this); this->Cutter->SetCutFunction(plane); } this->SlicePlane = plane; this->Modified(); } // Overload standard modified time function. If cut functions is modified, // or contour values modified, then this object is modified as well. vtkMTimeType vtkPointSetSlicer::GetMTime() { vtkMTimeType mTime = this->Superclass::GetMTime(); vtkMTimeType time; if (this->SlicePlane != nullptr) { time = this->SlicePlane->GetMTime(); mTime = (time > mTime ? time : mTime); } if (this->Locator != nullptr) { time = this->Locator->GetMTime(); mTime = (time > mTime ? time : mTime); } return mTime; } int vtkPointSetSlicer::RequestData(vtkInformation * /*request*/, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { // get the info objects vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the input and ouptut vtkDataSet *input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkDebugMacro(<< "Executing cutter"); if (!this->SlicePlane) { vtkErrorMacro("No slice plane specified"); return 0; } if (input->GetNumberOfPoints() < 1) { return 1; } if (input->GetDataObjectType() == VTK_STRUCTURED_POINTS || input->GetDataObjectType() == VTK_IMAGE_DATA) { if (input->GetCell(0) && input->GetCell(0)->GetCellDimension() >= 3) { // this->StructuredPointsCutter(input, output, request, inputVector, outputVector); return 1; } } if (input->GetDataObjectType() == VTK_STRUCTURED_GRID) { if (input->GetCell(0)) { int dim = input->GetCell(0)->GetCellDimension(); // only do 3D structured grids (to be extended in the future) if (dim >= 3) { // this->StructuredGridCutter(input, output); return 1; } } } if (input->GetDataObjectType() == VTK_RECTILINEAR_GRID) { // this->RectilinearGridCutter(input, output); return 1; } if (input->GetDataObjectType() == VTK_UNSTRUCTURED_GRID) { vtkDebugMacro(<< "Executing Unstructured Grid Cutter"); this->UnstructuredGridCutter(input, output); } else { vtkDebugMacro(<< "Executing DataSet Cutter"); // this->DataSetCutter(input, output); } return 1; } int vtkPointSetSlicer::RequestUpdateExtent(vtkInformation *, vtkInformationVector **inputVector, vtkInformationVector *) { vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1); return 1; } int vtkPointSetSlicer::FillInputPortInformation(int, vtkInformation *info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); return 1; } void vtkPointSetSlicer::UnstructuredGridCutter(vtkDataSet *input, vtkPolyData *output) { - vtkIdType cellId, i; + vtkIdType i; vtkDoubleArray *cellScalars; vtkCellArray *newVerts, *newLines, *newPolys; vtkPoints *newPoints; vtkDoubleArray *cutScalars; double s; vtkIdType estimatedSize, numCells = input->GetNumberOfCells(); vtkIdType numPts = input->GetNumberOfPoints(); - vtkIdType cellArrayIt = 0; - int numCellPts; + vtkIdType numCellPts; + const vtkIdType* cellPts = nullptr; vtkPointData *inPD, *outPD; vtkCellData *inCD = input->GetCellData(), *outCD = output->GetCellData(); vtkIdList *cellIds; int abortExecute = 0; double range[2]; // Create objects to hold output of contour operation // estimatedSize = (vtkIdType)pow((double)numCells, .75); estimatedSize = estimatedSize / 1024 * 1024; // multiple of 1024 if (estimatedSize < 1024) { estimatedSize = 1024; } newPoints = vtkPoints::New(); newPoints->Allocate(estimatedSize, estimatedSize / 2); newVerts = vtkCellArray::New(); newVerts->Allocate(estimatedSize, estimatedSize / 2); newLines = vtkCellArray::New(); newLines->Allocate(estimatedSize, estimatedSize / 2); newPolys = vtkCellArray::New(); newPolys->Allocate(estimatedSize, estimatedSize / 2); cutScalars = vtkDoubleArray::New(); cutScalars->SetNumberOfTuples(numPts); // Interpolate data along edge. If generating cut scalars, do necessary setup if (this->GenerateCutScalars) { inPD = vtkPointData::New(); inPD->ShallowCopy(input->GetPointData()); // copies original attributes inPD->SetScalars(cutScalars); } else { inPD = input->GetPointData(); } outPD = output->GetPointData(); outPD->InterpolateAllocate(inPD, estimatedSize, estimatedSize / 2); outCD->CopyAllocate(inCD, estimatedSize, estimatedSize / 2); // locator used to merge potentially duplicate points if (this->Locator == nullptr) { this->CreateDefaultLocator(); } this->Locator->InitPointInsertion(newPoints, input->GetBounds()); // Loop over all points evaluating scalar function at each point // for (i = 0; i < numPts; i++) { s = this->SlicePlane->FunctionValue(input->GetPoint(i)); cutScalars->SetComponent(i, 0, s); } // Compute some information for progress methods // vtkIdType numCuts = numCells; vtkIdType progressInterval = numCuts / 20 + 1; int cut = 0; vtkUnstructuredGrid *grid = (vtkUnstructuredGrid *)input; - vtkIdType *cellArrayPtr = grid->GetCells()->GetPointer(); + auto cellArrayIt = vtk::TakeSmartPointer(grid->GetCells()->NewIterator()); double *scalarArrayPtr = cutScalars->GetPointer(0); double tempScalar; cellScalars = cutScalars->NewInstance(); cellScalars->SetNumberOfComponents(cutScalars->GetNumberOfComponents()); cellScalars->Allocate(VTK_CELL_SIZE * cutScalars->GetNumberOfComponents()); // Three passes over the cells to process lower dimensional cells first. // For poly data output cells need to be added in the order: // verts, lines and then polys, or cell data gets mixed up. // A better solution is to have an unstructured grid output. // I create a table that maps cell type to cell dimensionality, // because I need a fast way to get cell dimensionality. // This assumes GetCell is slow and GetCellType is fast. // I do not like hard coding a list of cell types here, // but I do not want to add GetCellDimension(vtkIdType cellId) // to the vtkDataSet API. Since I anticipate that the output // will change to vtkUnstructuredGrid. This temporary solution // is acceptable. // int cellType; unsigned char cellTypeDimensions[VTK_NUMBER_OF_CELL_TYPES]; vtkCutter::GetCellTypeDimensions(cellTypeDimensions); int dimensionality; // We skip 0d cells (points), because they cannot be cut (generate no data). for (dimensionality = 1; dimensionality <= 3; ++dimensionality) { // Loop over all cells; get scalar values for all cell points // and process each cell. // - cellArrayIt = 0; - for (cellId = 0; cellId < numCells && !abortExecute; cellId++) + for(cellArrayIt->GoToFirstCell(); !cellArrayIt->IsDoneWithTraversal() && !abortExecute; cellArrayIt->GoToNextCell()) { - numCellPts = cellArrayPtr[cellArrayIt]; + cellArrayIt->GetCurrentCell(numCellPts, cellPts); // I assume that "GetCellType" is fast. - cellType = input->GetCellType(cellId); + cellType = input->GetCellType(cellArrayIt->GetCurrentCellId()); if (cellType >= VTK_NUMBER_OF_CELL_TYPES) { // Protect against new cell types added. vtkErrorMacro("Unknown cell type " << cellType); - cellArrayIt += 1 + numCellPts; continue; } if (cellTypeDimensions[cellType] != dimensionality) { - cellArrayIt += 1 + numCellPts; continue; } - cellArrayIt++; // find min and max values in scalar data - range[0] = scalarArrayPtr[cellArrayPtr[cellArrayIt]]; - range[1] = scalarArrayPtr[cellArrayPtr[cellArrayIt]]; - cellArrayIt++; + range[0] = scalarArrayPtr[cellPts[0]]; + range[1] = scalarArrayPtr[cellPts[0]]; for (i = 1; i < numCellPts; i++) { - tempScalar = scalarArrayPtr[cellArrayPtr[cellArrayIt]]; - cellArrayIt++; + tempScalar = scalarArrayPtr[cellPts[i]]; if (tempScalar <= range[0]) { range[0] = tempScalar; } // if tempScalar <= min range value if (tempScalar >= range[1]) { range[1] = tempScalar; } // if tempScalar >= max range value } // for all points in this cell int needCell = 0; if (0.0 >= range[0] && 0.0 <= range[1]) { needCell = 1; } if (needCell) { - vtkCell *cell = input->GetCell(cellId); + vtkCell *cell = input->GetCell(cellArrayIt->GetCurrentCellId()); cellIds = cell->GetPointIds(); cutScalars->GetTuples(cellIds, cellScalars); // Loop over all contour values. if (dimensionality == 3 && !(++cut % progressInterval)) { vtkDebugMacro(<< "Cutting #" << cut); this->UpdateProgress(static_cast(cut) / numCuts); abortExecute = this->GetAbortExecute(); } this->ContourUnstructuredGridCell( - cell, cellScalars, this->Locator, newVerts, newLines, newPolys, inPD, outPD, inCD, cellId, outCD); + cell, cellScalars, this->Locator, newVerts, newLines, newPolys, inPD, outPD, inCD, cellArrayIt->GetCurrentCellId(), outCD); } // if need cell } // for all cells } // for all dimensions (1,2,3). // Update ourselves. Because we don't know upfront how many verts, lines, // polys we've created, take care to reclaim memory. // cellScalars->Delete(); cutScalars->Delete(); if (this->GenerateCutScalars) { inPD->Delete(); } output->SetPoints(newPoints); newPoints->Delete(); if (newVerts->GetNumberOfCells()) { output->SetVerts(newVerts); } newVerts->Delete(); if (newLines->GetNumberOfCells()) { output->SetLines(newLines); } newLines->Delete(); if (newPolys->GetNumberOfCells()) { output->SetPolys(newPolys); } newPolys->Delete(); this->Locator->Initialize(); // release any extra memory output->Squeeze(); } void vtkPointSetSlicer::ContourUnstructuredGridCell(vtkCell *cell, vtkDataArray *cellScalars, vtkPointLocator *locator, vtkCellArray *verts, vtkCellArray *lines, vtkCellArray *polys, vtkPointData *inPd, vtkPointData *outPd, vtkCellData *inCd, vtkIdType cellId, vtkCellData *outCd) { if (cell->GetCellType() == VTK_HEXAHEDRON) { static int CASE_MASK[8] = {1, 2, 4, 8, 16, 32, 64, 128}; POLY_CASES *polyCase; EDGE_LIST *edge; int i, j, index, *vert; volatile int pnum; int v1, v2, newCellId; double t, x1[3], x2[3], x[3], deltaScalar; vtkIdType offset = verts->GetNumberOfCells() + lines->GetNumberOfCells(); // Build the case table for (i = 0, index = 0; i < 8; i++) { if (cellScalars->GetComponent(i, 0) >= 0) { index |= CASE_MASK[i]; } } polyCase = polyCases + index; edge = polyCase->edges; // get the point number of the polygon pnum = 0; for (i = 0; i < 8; i++) if (edge[i] > -1) pnum++; else break; vtkIdType *pts = new vtkIdType[pnum]; for (i = 0; i < pnum; i++) // insert polygon { vert = edges[edge[i]]; // calculate a preferred interpolation direction deltaScalar = (cellScalars->GetComponent(vert[1], 0) - cellScalars->GetComponent(vert[0], 0)); if (deltaScalar > 0) { v1 = vert[0]; v2 = vert[1]; } else { v1 = vert[1]; v2 = vert[0]; deltaScalar = -deltaScalar; } // linear interpolation t = (deltaScalar == 0.0 ? 0.0 : (-cellScalars->GetComponent(v1, 0)) / deltaScalar); cell->GetPoints()->GetPoint(v1, x1); cell->GetPoints()->GetPoint(v2, x2); for (j = 0; j < 3; j++) { x[j] = x1[j] + t * (x2[j] - x1[j]); } if (locator->InsertUniquePoint(x, pts[i])) { if (outPd) { vtkIdType p1 = cell->GetPointIds()->GetId(v1); vtkIdType p2 = cell->GetPointIds()->GetId(v2); outPd->InterpolateEdge(inPd, pts[i], p1, p2, t); } } } // check for degenerate polygon std::vector pset; for (i = 0; i < pnum; i++) { if (std::find(pset.begin(), pset.end(), pts[i]) == pset.end()) pset.push_back(pts[i]); } if (pset.size() > 2) { i = 0; for (std::vector::iterator iter = pset.begin(); iter != pset.end(); iter++) { pts[i] = *iter; i++; } newCellId = offset + polys->InsertNextCell(pset.size(), pts); outCd->CopyData(inCd, cellId, newCellId); } delete[] pts; } else { cell->Contour(0, cellScalars, locator, verts, lines, polys, inPd, outPd, inCd, cellId, outCd); } } // Specify a spatial locator for merging points. By default, // an instance of vtkMergePoints is used. void vtkPointSetSlicer::SetLocator(vtkPointLocator *locator) { if (this->Locator == locator) { return; } if (this->Locator) { this->Locator->UnRegister(this); this->Locator = nullptr; } if (locator) { locator->Register(this); } this->Locator = locator; this->Modified(); } void vtkPointSetSlicer::CreateDefaultLocator() { if (this->Locator == nullptr) { this->Locator = vtkMergePoints::New(); this->Locator->Register(this); this->Locator->Delete(); } } void vtkPointSetSlicer::PrintSelf(std::ostream &os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Slice Plane: " << this->SlicePlane << "\n"; if (this->Locator) { os << indent << "Locator: " << this->Locator << "\n"; } else { os << indent << "Locator: (none)\n"; } os << indent << "Generate Cut Scalars: " << (this->GenerateCutScalars ? "On\n" : "Off\n"); } int vtkPointSetSlicer::edges[12][2] = { {0, 1}, {1, 2}, {3, 2}, {0, 3}, {4, 5}, {5, 6}, {7, 6}, {4, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; vtkPointSetSlicer::POLY_CASES vtkPointSetSlicer::polyCases[256] = { {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{0, 3, 8, -1, -1, -1, -1, -1}}, {{1, 0, 9, -1, -1, -1, -1, -1}}, {{1, 3, 8, 9, -1, -1, -1, -1}}, {{2, 1, 10, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{2, 0, 9, 10, -1, -1, -1, -1}}, {{2, 10, 9, 8, 3, -1, -1, -1}}, {{3, 2, 11, -1, -1, -1, -1, -1}}, {{0, 2, 11, 8, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{1, 9, 8, 11, 2, -1, -1, -1}}, {{3, 1, 10, 11, -1, -1, -1, -1}}, {{0, 8, 11, 10, 1, -1, -1, -1}}, {{3, 11, 10, 9, 0, -1, -1, -1}}, {{8, 9, 10, 11, -1, -1, -1, -1}}, {{4, 7, 8, -1, -1, -1, -1, -1}}, {{3, 7, 4, 0, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{9, 1, 3, 7, 4, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{11, 2, 0, 4, 7, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{1, 2, 11, 7, 4, 9, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{4, 7, 11, 10, 9, -1, -1, -1}}, {{5, 4, 9, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{0, 4, 5, 1, -1, -1, -1, -1}}, {{8, 3, 1, 5, 4, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{10, 2, 0, 4, 5, -1, -1, -1}}, {{2, 3, 8, 4, 5, 10, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{5, 4, 8, 11, 10, -1, -1, -1}}, {{5, 7, 8, 9, -1, -1, -1, -1}}, {{9, 5, 7, 3, 0, -1, -1, -1}}, {{8, 7, 5, 1, 0, -1, -1, -1}}, {{1, 3, 7, 5, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{2, 10, 5, 7, 3, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{2, 11, 7, 5, 1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{5, 7, 11, 10, -1, -1, -1, -1}}, {{6, 5, 10, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{1, 5, 6, 2, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{9, 0, 2, 6, 5, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{11, 3, 1, 5, 6, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{3, 0, 9, 5, 6, 11, -1, -1}}, {{6, 5, 9, 8, 11, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{6, 4, 9, 10, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{10, 6, 4, 0, 1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{9, 4, 6, 2, 1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{2, 0, 4, 6, -1, -1, -1, -1}}, {{3, 8, 4, 6, 2, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{3, 11, 6, 4, 0, -1, -1, -1}}, {{6, 4, 8, 11, -1, -1, -1, -1}}, {{6, 10, 9, 8, 7, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{6, 7, 8, 0, 1, 10, -1, -1}}, {{6, 10, 1, 3, 7, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{7, 8, 0, 2, 6, -1, -1, -1}}, {{2, 6, 7, 3, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{6, 7, 11, -1, -1, -1, -1, -1}}, {{7, 6, 11, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{2, 6, 7, 3, -1, -1, -1, -1}}, {{8, 0, 2, 6, 7, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{10, 1, 3, 7, 6, -1, -1, -1}}, {{0, 1, 10, 6, 7, 8, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{7, 6, 10, 9, 8, -1, -1, -1}}, {{4, 6, 11, 8, -1, -1, -1, -1}}, {{11, 6, 4, 0, 3, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{8, 4, 6, 2, 3, -1, -1, -1}}, {{0, 2, 6, 4, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{1, 9, 4, 6, 2, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{1, 10, 6, 4, 0, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{4, 6, 10, 9, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{5, 9, 8, 11, 6, -1, -1, -1}}, {{5, 6, 11, 3, 0, 9, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{6, 11, 3, 1, 5, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{5, 9, 0, 2, 6, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{1, 5, 6, 2, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{5, 6, 10, -1, -1, -1, -1, -1}}, {{7, 5, 10, 11, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{11, 7, 5, 1, 2, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{10, 5, 7, 3, 2, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{3, 1, 5, 7, -1, -1, -1, -1}}, {{0, 8, 7, 5, 1, -1, -1, -1}}, {{0, 9, 5, 7, 3, -1, -1, -1}}, {{7, 5, 9, 8, -1, -1, -1, -1}}, {{4, 8, 11, 10, 5, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{4, 5, 10, 2, 3, 8, -1, -1}}, {{5, 10, 2, 0, 4, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{4, 8, 3, 1, 5, -1, -1, -1}}, {{0, 4, 5, 1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{4, 5, 9, -1, -1, -1, -1, -1}}, {{7, 11, 10, 9, 4, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{7, 4, 9, 1, 2, 11, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{7, 11, 2, 0, 4, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{4, 9, 1, 3, 7, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{3, 7, 4, 0, -1, -1, -1, -1}}, {{7, 4, 8, -1, -1, -1, -1, -1}}, {{10, 11, 8, 9, -1, -1, -1, -1}}, {{0, 3, 11, 10, 9, -1, -1, -1}}, {{1, 0, 8, 11, 10, -1, -1, -1}}, {{1, 3, 11, 10, -1, -1, -1, -1}}, {{2, 1, 9, 8, 11, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{2, 0, 8, 11, -1, -1, -1, -1}}, {{2, 3, 11, -1, -1, -1, -1, -1}}, {{3, 2, 10, 9, 8, -1, -1, -1}}, {{0, 2, 10, 9, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}, {{1, 2, 10, -1, -1, -1, -1, -1}}, {{3, 1, 9, 8, -1, -1, -1, -1}}, {{0, 1, 9, -1, -1, -1, -1, -1}}, {{3, 0, 8, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, -1, -1}}}; diff --git a/Modules/MatchPointRegistration/CMakeLists.txt b/Modules/MatchPointRegistration/CMakeLists.txt index acbcd26ff3..71204d9f1a 100644 --- a/Modules/MatchPointRegistration/CMakeLists.txt +++ b/Modules/MatchPointRegistration/CMakeLists.txt @@ -1,28 +1,29 @@ MITK_CREATE_MODULE( INCLUDE_DIRS PUBLIC algorithms PRIVATE src/Helper src/Rendering DEPENDS MitkCore MitkSceneSerializationBase PACKAGE_DEPENDS PUBLIC MatchPoint + PRIVATE VTK|ImagingGeneral+ImagingHybrid ) if(TARGET ${MODULE_TARGET}) set(ALG_PROFILE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/algorithms) include(${MatchPoint_SOURCE_DIR}/CMake/mapFunctionCreateAlgorithmProfile.cmake) file(GLOB ALG_PROFILE_FILES LIST_DIRECTORIES false RELATIVE ${ALG_PROFILE_DIR} "${ALG_PROFILE_DIR}/*.profile") foreach(profile_file ${ALG_PROFILE_FILES}) get_filename_component(profile_name ${profile_file} NAME_WE) MESSAGE(STATUS "... generate MDRA profile ${profile_name} (from ${profile_file})...") CREATE_ALGORITHM_PROFILE(${profile_name} ${ALG_PROFILE_DIR}/${profile_file}) endforeach(profile_file) ADD_SUBDIRECTORY(autoload/IO) ADD_SUBDIRECTORY(deployment) if(BUILD_TESTING) ADD_SUBDIRECTORY(Testing) endif(BUILD_TESTING) ADD_SUBDIRECTORY(cmdapps) endif() diff --git a/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterBase.h b/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterBase.h index 80fc069e09..dce6a5d2ce 100644 --- a/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterBase.h +++ b/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterBase.h @@ -1,194 +1,194 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERBASE_H #define MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERBASE_H #include "mitkImageToImageFilter.h" #include //Includes for smart pointer usage #include "mitkCommon.h" #include "itkLightObject.h" // Includes for AddEnmemberMatrix #include "mitkPAPropertyCalculator.h" #include namespace mitk { namespace pa { /** * \brief The spectral unmixing filter base is designed as superclass for several spectral unmixing filter eg. Eigen- or Vigrabased ones. * One can add wavelengths and chromophores and get a unmixed output images out of one MITK input image using algorithms from the subclasses. * * Input: * The unmixing input has to be a 3D MITK image where the XY-plane is a image and the Z-direction represents recordings for different * wavelengths. Herein a XY-plane for a specific Z-direction will be called "image". Every image has to be assigned to a certain wavelength. * The "AddWavelength" uses "push_back" to write float values into a vector. The first wavelength will correspond to the first image!!! * If there a more input images 'I' then added wavelengths 'w' the filter base interprets the next x images as repetition sequence of the same * wavelengths. If I % w !=0 the surplus image(s) will be dropped. * Addtionaly one has to add chromophores from the property calculator class enum "ChromophoreType" with the "AddChromophore" method. * This method as well uses "push_back" but the chosen (arbitary) order will be the order of the outputs. * * Output: * The output will be one MITK image per chosen chromophore. Where the XY-plane is a image and the Z-direction represents recordings for different * sequences. Furthermore it is possible to creat an output image that contains the information about the relative error between unmixing result * and the input image. * * Subclasses: * - mitkPASpectralUnmixingFilterVigra * - mitkPALinearSpectralUnmixingFilter (uses Eigen algorithms) * - mitkPASpectralUnmixingFilterSimplex * * Possible exceptions: * - "PIXELTYPE ERROR! FLOAT 32 REQUIRED": The MITK input image has to consist out of floats. * - "ERROR! REMOVE WAVELENGTHS!": One needs at least the same amount of images (z-dimension) then added wavelengths. * - "ADD MORE WAVELENGTHS!": One needs at least the same amount of wavelengths then added chromophores. * - "WAVELENGTH XXX nm NOT SUPPORTED!": The wavelength is not part of the proptery calculater data base. The data base can be found @ * [...]/mitk/Modules/PhotoacousticsLib/Resources/spectralLIB.dat * - "ADD OUTPUTS HAS TO BE LARGER THEN ZERO!" * - "NO WAVELENGHTS/CHROMOPHORES SELECZED! * - "INDEX ERROR! NUMBER OF OUTPUTS DOESN'T FIT TO OTHER SETTIGNS!" */ class MITKPHOTOACOUSTICSLIB_EXPORT SpectralUnmixingFilterBase : public mitk::ImageToImageFilter { public: mitkClassMacro(SpectralUnmixingFilterBase, mitk::ImageToImageFilter); /** * \brief AddChromophore takes mitk::pa::PropertyCalculator::ChromophoreType and writes them at the end of the m_Chromophore vector. * The call of the method sets the order of the GetOutput method! * * @param chromophore has to be element of porperty calculater enum chromophore type * @return for wavelength smaller then 300nm and larger then 1000nm the return will be 0, because not at the data base (2018/06/19) */ void AddChromophore(mitk::pa::PropertyCalculator::ChromophoreType chromophore); /** * \brief AddWavelength takes integers and writes them at the end of the m_Wavelength vector. The first call of the method then * corresponds to the first input image and so on. * @param wavelength database supports integers between 300 and 1000 nm */ void AddWavelength(int wavelength); /* * \brief Verbose gives more information to the console. Default value is false. * @param verbose is the boolian to activate the MITK_INFO logged to the console */ virtual void Verbose(bool verbose); /** * \brief AddOutputs takes an integer and sets indexed outputs * @param outputs integer correponds to the number of output images * @throws if outputs == 0 */ virtual void AddOutputs(unsigned int outputs); /* * \brief RelativeError returns a image which compare the L2 norm of the input vector with the unmixing result * @param relativeError is the boolian to activate this tool */ virtual void RelativeError(bool relativeError); /** * \brief AddRelativeErrorSettings takes integers and writes them at the end of the m_RelativeErrorSettings vector. * @param value has to be a integer */ virtual void AddRelativeErrorSettings(int value); - ofstream myfile; // just for testing purposes; has to be removeed + std::ofstream myfile; // just for testing purposes; has to be removeed protected: /** * \brief Constructor creats proptery calculater smart pointer new() */ SpectralUnmixingFilterBase(); ~SpectralUnmixingFilterBase() override; /** * \brief The subclasses will override the mehtod to calculate the spectral unmixing result vector. * @param endmemberMatrix Matrix with number of chromophores colums and number of wavelengths rows so matrix element (i,j) contains * the absorbtion of chromophore j @ wavelength i taken from the database by PropertyElement method. * @param inputVector Vector containing values of one pixel of XY-plane image with number of wavelength rows (z-dimension of a sequenece) * so the pixelvalue of the first wavelength is stored in inputVector[0] and so on. * @throws if algorithm implementiation fails (implemented for the algorithms with critical requirements) */ virtual Eigen::VectorXf SpectralUnmixingAlgorithm(Eigen::Matrix endmemberMatrix, Eigen::VectorXf inputVector) = 0; bool m_Verbose = false; bool m_RelativeError = false; std::vector m_Chromophore; std::vector m_Wavelength; std::vector m_RelativeErrorSettings; private: /* * \brief Initialized output images with the same XY-plane size like the input image and total size in z-direction equals number of sequences. * The pixel type is set to float. * @param totalNumberOfSequences = (unsigned int) (numberOfInputImages / numberOfWavelength) >= 1 */ virtual void InitializeOutputs(unsigned int totalNumberOfSequences); /* * \brief Checks if there are a suitable amount of wavelengths and if the input image consists of floats. * @param input pointer on the MITK input image * @throws if there are more wavelength then images * @throws if there are more chromophores then wavelengths * @throws if the pixel type is not float 32 * @throws if no chromophores or wavelengths selected as input * @throws if the number of indexed outputs does'nt fit to the expected number */ virtual void CheckPreConditions(mitk::Image::Pointer input); /* * \brief Inherit from the "ImageToImageFilter" Superclass. Herain it calls InitializeOutputs, CalculateEndmemberMatrix and * CheckPreConditions methods and enables pixelwise access to do spectral unmixing with the "SpectralUnmixingAlgorithm" * method. In the end the method writes the results into the new MITK output images. */ void GenerateData() override; /* * \brief Creats a Matrix with number of chromophores colums and number of wavelengths rows so matrix element (i,j) contains * the absorbtion of chromophore j @ wavelength i. The absorbtion values are taken from the "PropertyElement" method. * @param m_Chromophore is a vector of "PropertyCalculator::ChromophoreType" containing all selected chromophores for the unmixing * @param m_Wavelength is a vector of integers containing all wavelengths of one sequence */ virtual Eigen::Matrix CalculateEndmemberMatrix( std::vector m_Chromophore, std::vector m_Wavelength); /* * \brief "PropertyElement" is the tool to access the absorbtion values out of the database using mitk::pa::PropertyCalculator::GetAbsorptionForWavelengt * and checks if the requested wavelength is part of the database (not zero values). The "ONEENDMEMBER" is a pseudo absorber with static absorbtion 1 * at every wavelength and is therefor not part of the database. If this one is the selected chromophore the return value is 1 for every wavelength. * @param wavelength has to be integer between 300 and 1000 nm * @param chromophore has to be a mitk::pa::PropertyCalculator::ChromophoreType * @throws if mitk::pa::PropertyCalculator::GetAbsorptionForWavelengt returns 0, because this means that the delivered wavelength is not in the database. */ virtual float PropertyElement(mitk::pa::PropertyCalculator::ChromophoreType, int wavelength); /* * \brief calculates the relative error between the input image and the unmixing result in the L2 norm * @param endmemberMatrix is a Eigen matrix containing the endmember information * @param inputVector is a Eigen vector containing the multispectral information of one pixel * @param resultVector is a Eigen vector containing the spectral unmmixing result */ float CalculateRelativeError(Eigen::Matrix endmemberMatrix, Eigen::VectorXf inputVector, Eigen::VectorXf resultVector); PropertyCalculator::Pointer m_PropertyCalculatorEigen; }; } } #endif // MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERBASE_ diff --git a/Modules/PlanarFigure/CMakeLists.txt b/Modules/PlanarFigure/CMakeLists.txt index af4c93bb9c..ca2b93bce7 100644 --- a/Modules/PlanarFigure/CMakeLists.txt +++ b/Modules/PlanarFigure/CMakeLists.txt @@ -1,10 +1,11 @@ MITK_CREATE_MODULE( INCLUDE_DIRS PRIVATE src/Algorithms src/DataManagement src/Interactions src/Rendering DEPENDS MitkLegacyGL MitkAnnotation + PACKAGE_DEPENDS PRIVATE VTK|RenderingContextOpenGL2 ) add_subdirectory(autoload/IO) if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/Modules/PlanarFigure/test/CMakeLists.txt b/Modules/PlanarFigure/test/CMakeLists.txt index d6f5cf2a16..c58498e56b 100644 --- a/Modules/PlanarFigure/test/CMakeLists.txt +++ b/Modules/PlanarFigure/test/CMakeLists.txt @@ -1,153 +1,153 @@ MITK_CREATE_MODULE_TESTS() if(TARGET ${TESTDRIVER}) - mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES VTK|vtkTestingRendering) + mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES VTK|TestingRendering) set(testcaseBasename mitkViewportRenderingTest) # set verbose to 1 to get a list of all defined test cases during CMake configuration set(verbose 0) # viewportTest(): # # 1. Sets up a scene with a DICOM image, several planar figures, an STL file # 2. Modifies the viewport of the VTK renderer to only a part of the render window # 3. Compares the rendering result against an expected version # # Parameters determine the size and position of the viewport and the render window # The expected result is mitkViewportRenderingTest_${testPostfix}.png # function(viewportTest testPostfix # postfix to uniquely identify the test case rwWidth rwHeight # "rw" = render window vpLeft vpBottom vpWidth vpHeight # "vp" = viewport # list of images/files for visualization ) set(data ${ARGN}) # use all ADDITIONAL parameters after vpHeight as filenames # transform the input parameters in required test parameters math(EXPR vpRight "${vpLeft} + ${vpWidth}") math(EXPR vpTop "${vpBottom} + ${vpHeight}") #message(STATUS "Testing viewport of ${vpWidth}x${vpHeight} at ${vpLeft},${vpBottom} in render window of size ${rwWidth}x${rwHeight} ('${testPostfix}')") # add the actual test mitkAddCustomModuleTest( mitkViewportRenderingTest_${testPostfix} mitkViewportRenderingTest ${rwWidth} ${rwHeight} ${vpLeft} ${vpBottom} ${vpRight} ${vpTop} ${data} -V ${MITK_DATA_DIR}/RenderingTestData/viewport/mitkViewportRenderingTest_${testPostfix}.png #corresponding reference screenshot ) set_property(TEST mitkViewportRenderingTest_${testPostfix} PROPERTY RUN_SERIAL TRUE) endfunction() function(getFirstCharacter string charVar) string(SUBSTRING ${string} 0 1 c) set(${charVar} ${c} PARENT_SCOPE) endfunction() # The following lines loop over several variations of aspect ratios for # - render window # - a viewport within this render window # - an input image (defines the input world geometry) # --------------------------------------------------------------------- # # Render window # - Square # - Landscape # - Portrait # # Viewport # - Square # - Landscape # - Portrait # # World / Image # - Square # - Landscape # - Portrait # foreach(renderWindowAspect Square Landscape Portrait) foreach(viewportAspect Square Landscape Portrait) foreach(worldAspect Square Landscape Portrait) getFirstCharacter(${renderWindowAspect} renderWindowAspectSymbol) getFirstCharacter(${viewportAspect} viewportAspectSymbol) getFirstCharacter(${worldAspect} worldAspectSymbol) # construct test case name from various aspect ratios set(testCaseShortname "r${renderWindowAspectSymbol}v${viewportAspectSymbol}w${worldAspectSymbol}") # construct test image name from aspect ratio set(testImage ${MITK_DATA_DIR}/RenderingTestData/viewport/input_${worldAspect}/SCSFREN.dcm) # nice DICOM name encoding and gray value test image set(testObjects ${MITK_DATA_DIR}/RenderingTestData/PlanarFigures/Line1.pf ${MITK_DATA_DIR}/RenderingTestData/PlanarFigures/Path1.pf ${MITK_DATA_DIR}/RenderingTestData/PlanarFigures/FourPointAngle1.pf ${MITK_DATA_DIR}/RenderingTestData/PlanarFigures/Rectangle1.pf ${MITK_DATA_DIR}/binary.stl ) # render window size if (renderWindowAspect STREQUAL Landscape) set(renderWindowWidth 600) else() set(renderWindowWidth 500) endif() if (renderWindowAspect STREQUAL Portrait) set(renderWindowHeight 600) else() set(renderWindowHeight 500) endif() # viewport size if (viewportAspect STREQUAL Landscape) set(viewportWidth 450) else() set(viewportWidth 300) endif() if (viewportAspect STREQUAL Portrait) set(viewportHeight 450) else() set(viewportHeight 300) endif() # world size if (worldAspect STREQUAL Portrait) set(worldWidth 300) set(worldHeight 420) elseif (worldAspect STREQUAL Landscape) set(worldWidth 420) set(worldHeight 300) else() set(worldWidth 512) set(worldHeight 512) endif() # Summary set(viewportX 30) set(viewportY 45) if (verbose) message(STATUS "(${testCaseShortname}) " "Render window ${renderWindowAspect} (${renderWindowWidth}x${renderWindowHeight}), " "Viewport ${viewportAspect} (${viewportWidth}x${viewportHeight}+${viewportX}+${viewportY}), " "World ${worldAspect} (${worldWidth}x${worldHeight})" ) endif() viewPortTest(${testCaseShortname} ${renderWindowWidth} ${renderWindowHeight} ${viewportX} ${viewportY} ${viewportWidth} ${viewportHeight} ${testImage} ${testObjects}) endforeach() endforeach() endforeach() endif() # endif TARGET ${TESTDRIVER} diff --git a/Modules/QtWidgets/CMakeLists.txt b/Modules/QtWidgets/CMakeLists.txt index 1938494ee8..f383232898 100644 --- a/Modules/QtWidgets/CMakeLists.txt +++ b/Modules/QtWidgets/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE( INCLUDE_DIRS PRIVATE resource # for xpm includes DEPENDS MitkPlanarFigure MitkAnnotation PACKAGE_DEPENDS - PUBLIC ITK|ITKIOImageBase VTK|vtkGUISupportQt+vtkRenderingQt Qt5|Widgets+OpenGL+Core + PUBLIC ITK|ITKIOImageBase VTK|GUISupportQt+RenderingQt Qt5|Widgets+OpenGL+Core ) add_subdirectory(test) diff --git a/Modules/QtWidgets/include/QmitkRenderWindow.h b/Modules/QtWidgets/include/QmitkRenderWindow.h index ff133d2e6e..308235e392 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindow.h +++ b/Modules/QtWidgets/include/QmitkRenderWindow.h @@ -1,151 +1,154 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 QMITKRENDERWINDOW_H #define QMITKRENDERWINDOW_H #include "mitkRenderWindowBase.h" #include "QmitkRenderWindowMenu.h" #include #include -#include +#include #include "mitkBaseRenderer.h" #include "mitkInteractionEventConst.h" class QDragEnterEvent; class QDropEvent; class QInputEvent; +class QMouseEvent; /** * \ingroup QmitkModule * \brief MITK implementation of the QVTKWidget */ -class MITKQTWIDGETS_EXPORT QmitkRenderWindow : public QVTKOpenGLWidget, public mitk::RenderWindowBase +class MITKQTWIDGETS_EXPORT QmitkRenderWindow : public QVTKOpenGLNativeWidget, public mitk::RenderWindowBase { Q_OBJECT public: QmitkRenderWindow( QWidget *parent = nullptr, const QString &name = "unnamed renderwindow", mitk::VtkPropRenderer *renderer = nullptr); ~QmitkRenderWindow() override; /** * \brief Whether Qt events should be passed to parent (default: true) * * With introduction of the QVTKWidget the behaviour regarding Qt events changed. * QVTKWidget "accepts" Qt events like mouse clicks (i.e. set an "accepted" flag). * When this flag is set, Qt fininshed handling of this event -- otherwise it is * reached through to the widget's parent. * * This reaching through to the parent was implicitly required by QmitkMaterialWidget / QmitkMaterialShowCase. * * The default behaviour of QmitkRenderWindow is now to clear the "accepted" flag * of Qt events after they were handled by QVTKWidget. This way parents can also * handle events. * * If you don't want this behaviour, call SetResendQtEvents(true) on your render window. */ virtual void SetResendQtEvents(bool resend); // Set Layout Index to define the Layout Type void SetLayoutIndex(QmitkRenderWindowMenu::LayoutIndex layoutIndex); // Get Layout Index to define the Layout Type QmitkRenderWindowMenu::LayoutIndex GetLayoutIndex(); // MenuWidget need to update the Layout Design List when Layout had changed void LayoutDesignListChanged(QmitkRenderWindowMenu::LayoutDesign layoutDesign); // Activate or Deactivate MenuWidget. void ActivateMenuWidget(bool state); bool GetActivateMenuWidgetFlag() { return m_MenuWidgetActivated; } // Get it from the QVTKWidget parent - vtkRenderWindow *GetVtkRenderWindow() override { return GetRenderWindow(); } + vtkRenderWindow *GetVtkRenderWindow() override { return this->renderWindow(); } vtkRenderWindowInteractor *GetVtkRenderWindowInteractor() override { return nullptr; } protected: // catch-all event handler bool event(QEvent *e) override; // overloaded move handler void moveEvent(QMoveEvent *event) override; // overloaded show handler void showEvent(QShowEvent *event) override; // overloaded enter handler void enterEvent(QEvent *) override; // overloaded leave handler void leaveEvent(QEvent *) override; // Overloaded resize handler, see decs in QVTKOpenGLWidget. // Basically, we have to ensure the VTK rendering is updated for each change in window size. void resizeGL(int w, int h) override; /// \brief Simply says we accept the event type. void dragEnterEvent(QDragEnterEvent *event) override; /// \brief If the dropped type is application/x-mitk-datanodes we process the request by converting to mitk::DataNode /// pointers and emitting the NodesDropped signal. void dropEvent(QDropEvent *event) override; void AdjustRenderWindowMenuVisibility(const QPoint &pos); Q_SIGNALS: void LayoutDesignChanged(QmitkRenderWindowMenu::LayoutDesign); void ResetView(); void CrosshairRotationModeChanged(int); void CrosshairVisibilityChanged(bool); void moved(); /// \brief Emits a signal to say that this window has had the following nodes dropped on it. void NodesDropped(QmitkRenderWindow *thisWindow, std::vector nodes); + void mouseEvent(QMouseEvent *); + private Q_SLOTS: void DeferredHideMenu(); private: // Helper Functions to Convert Qt-Events to Mitk-Events mitk::Point2D GetMousePosition(QMouseEvent *me) const; mitk::Point2D GetMousePosition(QWheelEvent *we) const; mitk::InteractionEvent::MouseButtons GetEventButton(QMouseEvent *me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QMouseEvent *me) const; mitk::InteractionEvent::ModifierKeys GetModifiers(QInputEvent *me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QWheelEvent *we) const; std::string GetKeyLetter(QKeyEvent *ke) const; int GetDelta(QWheelEvent *we) const; bool m_ResendQtEvents; QmitkRenderWindowMenu *m_MenuWidget; bool m_MenuWidgetActivated; QmitkRenderWindowMenu::LayoutIndex m_LayoutIndex; vtkSmartPointer m_InternalRenderWindow; }; #endif // QMITKRENDERWINDOW_H diff --git a/Modules/QtWidgets/src/QmitkRenderWindow.cpp b/Modules/QtWidgets/src/QmitkRenderWindow.cpp index e378c102a4..6405ef419c 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindow.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindow.cpp @@ -1,458 +1,458 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "QmitkRenderWindow.h" #include "mitkInteractionKeyEvent.h" #include "mitkInternalEvent.h" #include "mitkMouseDoubleClickEvent.h" #include "mitkMouseMoveEvent.h" #include "mitkMousePressEvent.h" #include "mitkMouseReleaseEvent.h" #include "mitkMouseWheelEvent.h" #include #include #include #include #include #include #include #include #include #include #include "QmitkMimeTypes.h" #include "QmitkRenderWindowMenu.h" QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, const QString &name, mitk::VtkPropRenderer *) - : QVTKOpenGLWidget(parent) + : QVTKOpenGLNativeWidget(parent) , m_ResendQtEvents(true) , m_MenuWidget(nullptr) , m_MenuWidgetActivated(false) , m_LayoutIndex(QmitkRenderWindowMenu::LayoutIndex::AXIAL) { m_InternalRenderWindow = vtkSmartPointer::New(); m_InternalRenderWindow->SetMultiSamples(0); m_InternalRenderWindow->SetAlphaBitPlanes(0); - SetRenderWindow(m_InternalRenderWindow); + setRenderWindow(m_InternalRenderWindow); Initialize(name.toStdString().c_str()); setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setSizePolicy(sizePolicy); } QmitkRenderWindow::~QmitkRenderWindow() { Destroy(); // Destroy mitkRenderWindowBase } void QmitkRenderWindow::SetResendQtEvents(bool resend) { m_ResendQtEvents = resend; } void QmitkRenderWindow::SetLayoutIndex(QmitkRenderWindowMenu::LayoutIndex layoutIndex) { m_LayoutIndex = layoutIndex; if (nullptr != m_MenuWidget) { m_MenuWidget->SetLayoutIndex(layoutIndex); } } QmitkRenderWindowMenu::LayoutIndex QmitkRenderWindow::GetLayoutIndex() { if (nullptr != m_MenuWidget) { return m_MenuWidget->GetLayoutIndex(); } else { return QmitkRenderWindowMenu::LayoutIndex::AXIAL; } } void QmitkRenderWindow::LayoutDesignListChanged(QmitkRenderWindowMenu::LayoutDesign layoutDesign) { if (nullptr != m_MenuWidget) { m_MenuWidget->UpdateLayoutDesignList(layoutDesign); } } void QmitkRenderWindow::ActivateMenuWidget(bool state) { if (nullptr == m_MenuWidget) { m_MenuWidget = new QmitkRenderWindowMenu(this, nullptr, m_Renderer); m_MenuWidget->SetLayoutIndex(m_LayoutIndex); } m_MenuWidgetActivated = state; if (m_MenuWidgetActivated) { connect(m_MenuWidget, &QmitkRenderWindowMenu::LayoutDesignChanged, this, &QmitkRenderWindow::LayoutDesignChanged); connect(m_MenuWidget, &QmitkRenderWindowMenu::ResetView, this, &QmitkRenderWindow::ResetView); connect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairVisibilityChanged, this, &QmitkRenderWindow::CrosshairVisibilityChanged); connect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairRotationModeChanged, this, &QmitkRenderWindow::CrosshairRotationModeChanged); } else { disconnect(m_MenuWidget, &QmitkRenderWindowMenu::LayoutDesignChanged, this, &QmitkRenderWindow::LayoutDesignChanged); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::ResetView, this, &QmitkRenderWindow::ResetView); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairVisibilityChanged, this, &QmitkRenderWindow::CrosshairVisibilityChanged); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairRotationModeChanged, this, &QmitkRenderWindow::CrosshairRotationModeChanged); m_MenuWidget->hide(); } } void QmitkRenderWindow::moveEvent(QMoveEvent *event) { - QVTKOpenGLWidget::moveEvent(event); + QVTKOpenGLNativeWidget::moveEvent(event); // after a move the overlays need to be positioned emit moved(); } void QmitkRenderWindow::showEvent(QShowEvent *event) { - QVTKOpenGLWidget::showEvent(event); + QVTKOpenGLNativeWidget::showEvent(event); // this singleshot is necessary to have the overlays positioned correctly after initial show // simple call of moved() is no use here!! QTimer::singleShot(0, this, SIGNAL(moved())); } bool QmitkRenderWindow::event(QEvent* e) { mitk::InteractionEvent::Pointer mitkEvent = nullptr; switch (e->type()) { case QEvent::MouseMove: { auto me = static_cast(e); this->AdjustRenderWindowMenuVisibility(me->pos()); mitkEvent = mitk::MouseMoveEvent::New(m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me)); break; } case QEvent::MouseButtonPress: { auto me = static_cast(e); mitkEvent = mitk::MousePressEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me)); break; } case QEvent::MouseButtonRelease: { auto me = static_cast(e); mitkEvent = mitk::MouseReleaseEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me)); break; } case QEvent::MouseButtonDblClick: { auto me = static_cast(e); mitkEvent = mitk::MouseDoubleClickEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me)); break; } case QEvent::Wheel: { auto we = static_cast(e); mitkEvent = mitk::MouseWheelEvent::New( m_Renderer, GetMousePosition(we), GetButtonState(we), GetModifiers(we), GetDelta(we)); break; } case QEvent::KeyPress: { auto ke = static_cast(e); mitkEvent = mitk::InteractionKeyEvent::New(m_Renderer, GetKeyLetter(ke), GetModifiers(ke)); break; } default: { break; } } if (mitkEvent != nullptr) { if (this->HandleEvent(mitkEvent.GetPointer())) { return m_ResendQtEvents ? false : true; } } - return QVTKOpenGLWidget::event(e); + return QVTKOpenGLNativeWidget::event(e); } void QmitkRenderWindow::enterEvent(QEvent *e) { // TODO implement new event - QVTKOpenGLWidget::enterEvent(e); + QVTKOpenGLNativeWidget::enterEvent(e); } void QmitkRenderWindow::leaveEvent(QEvent *e) { mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(this->m_Renderer, nullptr, "LeaveRenderWindow"); this->HandleEvent(internalEvent.GetPointer()); if (nullptr != m_MenuWidget) { m_MenuWidget->smoothHide(); } - QVTKOpenGLWidget::leaveEvent(e); + QVTKOpenGLNativeWidget::leaveEvent(e); } void QmitkRenderWindow::resizeGL(int w, int h) { - QVTKOpenGLWidget::resizeGL(w, h); - mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(GetRenderWindow()); + QVTKOpenGLNativeWidget::resizeGL(w, h); + mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(renderWindow()); } void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("application/x-mitk-datanodes")) { event->accept(); } } void QmitkRenderWindow::dropEvent(QDropEvent *event) { QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData()); if (!dataNodeList.empty()) { emit NodesDropped(this, dataNodeList.toVector().toStdVector()); } } void QmitkRenderWindow::AdjustRenderWindowMenuVisibility(const QPoint & /*pos*/) { if (nullptr != m_MenuWidget) { m_MenuWidget->ShowMenu(); m_MenuWidget->MoveWidgetToCorrectPos(1.0f); } } void QmitkRenderWindow::DeferredHideMenu() { MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu"; if (nullptr != m_MenuWidget) { m_MenuWidget->HideMenu(); } } mitk::Point2D QmitkRenderWindow::GetMousePosition(QMouseEvent *me) const { mitk::Point2D point; point[0] = me->x(); // We need to convert the y component, as the display and vtk have other definitions for the y direction point[1] = m_Renderer->GetSizeY() - me->y(); return point; } mitk::Point2D QmitkRenderWindow::GetMousePosition(QWheelEvent *we) const { mitk::Point2D point; point[0] = we->x(); // We need to convert the y component, as the display and vtk have other definitions for the y direction point[1] = m_Renderer->GetSizeY() - we->y(); return point; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetEventButton(QMouseEvent *me) const { mitk::InteractionEvent::MouseButtons eventButton; switch (me->button()) { case Qt::LeftButton: eventButton = mitk::InteractionEvent::LeftMouseButton; break; case Qt::RightButton: eventButton = mitk::InteractionEvent::RightMouseButton; break; case Qt::MidButton: eventButton = mitk::InteractionEvent::MiddleMouseButton; break; default: eventButton = mitk::InteractionEvent::NoButton; break; } return eventButton; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QMouseEvent *me) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (me->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (me->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (me->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } mitk::InteractionEvent::ModifierKeys QmitkRenderWindow::GetModifiers(QInputEvent *me) const { mitk::InteractionEvent::ModifierKeys modifiers = mitk::InteractionEvent::NoKey; if (me->modifiers() & Qt::ALT) { modifiers = modifiers | mitk::InteractionEvent::AltKey; } if (me->modifiers() & Qt::CTRL) { modifiers = modifiers | mitk::InteractionEvent::ControlKey; } if (me->modifiers() & Qt::SHIFT) { modifiers = modifiers | mitk::InteractionEvent::ShiftKey; } return modifiers; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QWheelEvent *we) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (we->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (we->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (we->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } std::string QmitkRenderWindow::GetKeyLetter(QKeyEvent *ke) const { // Converting Qt Key Event to string element. std::string key = ""; int tkey = ke->key(); if (tkey < 128) { // standard ascii letter key = (char)toupper(tkey); } else { // special keys switch (tkey) { case Qt::Key_Return: key = mitk::InteractionEvent::KeyReturn; break; case Qt::Key_Enter: key = mitk::InteractionEvent::KeyEnter; break; case Qt::Key_Escape: key = mitk::InteractionEvent::KeyEsc; break; case Qt::Key_Delete: key = mitk::InteractionEvent::KeyDelete; break; case Qt::Key_Up: key = mitk::InteractionEvent::KeyArrowUp; break; case Qt::Key_Down: key = mitk::InteractionEvent::KeyArrowDown; break; case Qt::Key_Left: key = mitk::InteractionEvent::KeyArrowLeft; break; case Qt::Key_Right: key = mitk::InteractionEvent::KeyArrowRight; break; case Qt::Key_F1: key = mitk::InteractionEvent::KeyF1; break; case Qt::Key_F2: key = mitk::InteractionEvent::KeyF2; break; case Qt::Key_F3: key = mitk::InteractionEvent::KeyF3; break; case Qt::Key_F4: key = mitk::InteractionEvent::KeyF4; break; case Qt::Key_F5: key = mitk::InteractionEvent::KeyF5; break; case Qt::Key_F6: key = mitk::InteractionEvent::KeyF6; break; case Qt::Key_F7: key = mitk::InteractionEvent::KeyF7; break; case Qt::Key_F8: key = mitk::InteractionEvent::KeyF8; break; case Qt::Key_F9: key = mitk::InteractionEvent::KeyF9; break; case Qt::Key_F10: key = mitk::InteractionEvent::KeyF10; break; case Qt::Key_F11: key = mitk::InteractionEvent::KeyF11; break; case Qt::Key_F12: key = mitk::InteractionEvent::KeyF12; break; case Qt::Key_End: key = mitk::InteractionEvent::KeyEnd; break; case Qt::Key_Home: key = mitk::InteractionEvent::KeyPos1; break; case Qt::Key_Insert: key = mitk::InteractionEvent::KeyInsert; break; case Qt::Key_PageDown: key = mitk::InteractionEvent::KeyPageDown; break; case Qt::Key_PageUp: key = mitk::InteractionEvent::KeyPageUp; break; case Qt::Key_Space: key = mitk::InteractionEvent::KeySpace; break; } } return key; } int QmitkRenderWindow::GetDelta(QWheelEvent *we) const { return we->delta(); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp index 2f50f4351a..daaaadefa6 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp @@ -1,254 +1,254 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "QmitkRenderWindowWidget.h" // vtk #include #include QmitkRenderWindowWidget::QmitkRenderWindowWidget(QWidget* parent/* = nullptr*/, const QString& widgetName/* = ""*/, mitk::DataStorage* dataStorage/* = nullptr*/) : QFrame(parent) , m_WidgetName(widgetName) , m_DataStorage(dataStorage) , m_RenderWindow(nullptr) , m_PointSetNode(nullptr) , m_PointSet(nullptr) { this->InitializeGUI(); } QmitkRenderWindowWidget::~QmitkRenderWindowWidget() { auto sliceNavigationController = m_RenderWindow->GetSliceNavigationController(); if (nullptr != sliceNavigationController) { sliceNavigationController->SetCrosshairEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); } if (nullptr != m_DataStorage) { m_DataStorage->Remove(m_PointSetNode); } } void QmitkRenderWindowWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; if (nullptr != m_RenderWindow) { - mitk::BaseRenderer::GetInstance(m_RenderWindow->GetRenderWindow())->SetDataStorage(dataStorage); + mitk::BaseRenderer::GetInstance(m_RenderWindow->renderWindow())->SetDataStorage(dataStorage); } } mitk::SliceNavigationController* QmitkRenderWindowWidget::GetSliceNavigationController() const { return m_RenderWindow->GetSliceNavigationController(); } void QmitkRenderWindowWidget::RequestUpdate() { - mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->GetRenderWindow()); + mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->renderWindow()); } void QmitkRenderWindowWidget::ForceImmediateUpdate() { - mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(m_RenderWindow->GetRenderWindow()); + mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(m_RenderWindow->renderWindow()); } void QmitkRenderWindowWidget::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } m_GradientBackgroundColors.first = upper; m_GradientBackgroundColors.second = lower; vtkRenderer->SetBackground(lower[0], lower[1], lower[2]); vtkRenderer->SetBackground2(upper[0], upper[1], upper[2]); ShowGradientBackground(true); } void QmitkRenderWindowWidget::ShowGradientBackground(bool show) { m_RenderWindow->GetRenderer()->GetVtkRenderer()->SetGradientBackground(show); } bool QmitkRenderWindowWidget::IsGradientBackgroundOn() const { return m_RenderWindow->GetRenderer()->GetVtkRenderer()->GetGradientBackground(); } void QmitkRenderWindowWidget::SetDecorationColor(const mitk::Color& color) { m_DecorationColor = color; m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); QColor hexColor(m_DecorationColor[0] * 255, m_DecorationColor[1] * 255, m_DecorationColor[2] * 255); setStyleSheet("QmitkRenderWindowWidget { border: 2px solid " + hexColor.name(QColor::HexRgb) + "; }"); } void QmitkRenderWindowWidget::ShowColoredRectangle(bool show) { if (show) { setFrameStyle(QFrame::Box | QFrame::Plain); } else { setFrameStyle(NoFrame); } } bool QmitkRenderWindowWidget::IsColoredRectangleVisible() const { return frameStyle() > 0; } void QmitkRenderWindowWidget::ShowCornerAnnotation(bool show) { m_CornerAnnotation->SetVisibility(show); } bool QmitkRenderWindowWidget::IsCornerAnnotationVisible() const { return m_CornerAnnotation->GetVisibility() > 0; } void QmitkRenderWindowWidget::SetCornerAnnotationText(const std::string& cornerAnnotation) { m_CornerAnnotation->SetText(0, cornerAnnotation.c_str()); } std::string QmitkRenderWindowWidget::GetCornerAnnotationText() const { return std::string(m_CornerAnnotation->GetText(0)); } bool QmitkRenderWindowWidget::IsRenderWindowMenuActivated() const { return m_RenderWindow->GetActivateMenuWidgetFlag(); } void QmitkRenderWindowWidget::ActivateCrosshair(bool activate) { if (nullptr == m_DataStorage) { return; } if (activate) { try { m_DataStorage->Add(m_PointSetNode); } catch(std::invalid_argument& /*e*/) { // crosshair already existing return; } } else { m_DataStorage->Remove(m_PointSetNode); } } void QmitkRenderWindowWidget::InitializeGUI() { m_Layout = new QHBoxLayout(this); m_Layout->setMargin(0); setLayout(m_Layout); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setContentsMargins(0, 0, 0, 0); if (nullptr == m_DataStorage) { return; } mitk::RenderingManager::GetInstance()->SetDataStorage(m_DataStorage); // create render window for this render window widget m_RenderWindow = new QmitkRenderWindow(this, m_WidgetName, nullptr); m_RenderWindow->SetLayoutIndex(mitk::BaseRenderer::ViewDirection::SAGITTAL); m_RenderWindow->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); m_RenderWindow->GetSliceNavigationController()->SetCrosshairEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); - connect(m_RenderWindow, &QVTKOpenGLWidget::mouseEvent, this, &QmitkRenderWindowWidget::MouseEvent); + connect(m_RenderWindow, &QmitkRenderWindow::mouseEvent, this, &QmitkRenderWindowWidget::MouseEvent); mitk::TimeGeometry::ConstPointer timeGeometry = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(timeGeometry); m_Layout->addWidget(m_RenderWindow); // add point set as a crosshair m_PointSetNode = mitk::DataNode::New(); m_PointSetNode->SetProperty("name", mitk::StringProperty::New("Crosshair of render window " + m_WidgetName.toStdString())); m_PointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); // crosshair-node should typically be invisible // set the crosshair only visible for this specific renderer m_PointSetNode->SetBoolProperty("fixedLayer", true, m_RenderWindow->GetRenderer()); m_PointSetNode->SetVisibility(true, m_RenderWindow->GetRenderer()); m_PointSetNode->SetVisibility(false); m_PointSet = mitk::PointSet::New(); m_PointSetNode->SetData(m_PointSet); // set colors and corner annotation InitializeDecorations(); } void QmitkRenderWindowWidget::InitializeDecorations() { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } // initialize background color gradients float black[3] = { 0.0f, 0.0f, 0.0f }; SetGradientBackgroundColors(black, black); // initialize decoration color, rectangle and annotation text float white[3] = { 1.0f, 1.0f, 1.0f }; m_DecorationColor = white; setFrameStyle(QFrame::Box | QFrame::Plain); QColor hexColor(m_DecorationColor[0] * 255, m_DecorationColor[1] * 255, m_DecorationColor[2] * 255); setStyleSheet("border: 2px solid " + hexColor.name(QColor::HexRgb)); m_CornerAnnotation = vtkSmartPointer::New(); m_CornerAnnotation->SetText(0, "Sagittal"); m_CornerAnnotation->SetMaximumFontSize(12); m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); if (0 == vtkRenderer->HasViewProp(m_CornerAnnotation)) { vtkRenderer->AddViewProp(m_CornerAnnotation); } } void QmitkRenderWindowWidget::SetCrosshair(mitk::Point3D selectedPoint) { m_PointSet->SetPoint(1, selectedPoint, 0); - mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->GetRenderWindow()); + mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->renderWindow()); } diff --git a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp index 880f13d30f..a16e26f56d 100644 --- a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp @@ -1,811 +1,811 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 SMW_INFO MITK_INFO("widget.stdmulti") #include "QmitkStdMultiWidget.h" #include "QmitkRenderWindowWidget.h" // mitk core #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qt #include #include #include // vtk #include // c++ #include QmitkStdMultiWidget::QmitkStdMultiWidget(QWidget *parent, Qt::WindowFlags f/* = 0*/, const QString &name/* = "stdmulti"*/) : QmitkAbstractMultiWidget(parent, f, name) , m_TimeNavigationController(nullptr) , m_PendingCrosshairPositionEvent(false) { m_TimeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); } QmitkStdMultiWidget::~QmitkStdMultiWidget() { m_TimeNavigationController->Disconnect(GetRenderWindow1()->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(GetRenderWindow2()->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(GetRenderWindow3()->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(GetRenderWindow4()->GetSliceNavigationController()); } void QmitkStdMultiWidget::InitializeMultiWidget() { // yellow is default color for widget4 m_DecorationColorWidget4[0] = 1.0f; m_DecorationColorWidget4[1] = 1.0f; m_DecorationColorWidget4[2] = 0.0f; SetLayout(2, 2); // transfer colors in WorldGeometry-Nodes of the associated Renderer mitk::IntProperty::Pointer layer; // of widget 1 m_PlaneNode1 = - mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); + mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetColor(GetDecorationColor(0)); layer = mitk::IntProperty::New(1000); m_PlaneNode1->SetProperty("layer", layer); // of widget 2 m_PlaneNode2 = - mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); + mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetColor(GetDecorationColor(1)); layer = mitk::IntProperty::New(1000); m_PlaneNode2->SetProperty("layer", layer); // of widget 3 m_PlaneNode3 = - mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); + mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetColor(GetDecorationColor(2)); layer = mitk::IntProperty::New(1000); m_PlaneNode3->SetProperty("layer", layer); // the parent node m_ParentNodeForGeometryPlanes = - mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); + mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); layer = mitk::IntProperty::New(1000); m_ParentNodeForGeometryPlanes->SetProperty("layer", layer); AddDisplayPlaneSubTree(); SetDisplayActionEventHandler(std::make_unique()); auto displayActionEventHandler = GetDisplayActionEventHandler(); if (nullptr != displayActionEventHandler) { displayActionEventHandler->InitActions(); } } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const QString& widgetName) const { if ("axial" == widgetName) { return GetRenderWindow1(); } if ("sagittal" == widgetName) { return GetRenderWindow2(); } if ("coronal" == widgetName) { return GetRenderWindow3(); } if ("3d" == widgetName) { return GetRenderWindow4(); } return QmitkAbstractMultiWidget::GetRenderWindow(widgetName); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const { return GetRenderWindow(static_cast(viewDirection)); } void QmitkStdMultiWidget::SetSelectedPosition(const mitk::Point3D& newPosition, const QString& /*widgetName*/) { GetRenderWindow1()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindow2()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindow3()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); RequestUpdateAll(); } const mitk::Point3D QmitkStdMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const { const mitk::PlaneGeometry* plane1 = GetRenderWindow1()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry* plane2 = GetRenderWindow2()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry* plane3 = GetRenderWindow3()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); mitk::Line3D line; if ((plane1 != nullptr) && (plane2 != nullptr) && (plane1->IntersectionLine(plane2, line))) { mitk::Point3D point; if ((plane3 != nullptr) && (plane3->IntersectionPoint(line, point))) { return point; } } return mitk::Point3D(); } void QmitkStdMultiWidget::SetCrosshairVisibility(bool visible) { if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetVisibility(visible); } if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetVisibility(visible); } if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetVisibility(visible); } RequestUpdateAll(); } bool QmitkStdMultiWidget::GetCrosshairVisibility() const { bool crosshairVisibility = true; if (m_PlaneNode1.IsNotNull()) { bool visibilityProperty = false; m_PlaneNode1->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } if (m_PlaneNode2.IsNotNull()) { bool visibilityProperty = false; crosshairVisibility &= m_PlaneNode2->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } if (m_PlaneNode3.IsNotNull()) { bool visibilityProperty = false; crosshairVisibility &= m_PlaneNode3->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } return crosshairVisibility; } void QmitkStdMultiWidget::ResetCrosshair() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); SetWidgetPlaneMode(mitk::InteractionSchemeSwitcher::MITKStandard); } void QmitkStdMultiWidget::SetWidgetPlaneMode(int userMode) { MITK_DEBUG << "Changing crosshair mode to " << userMode; switch (userMode) { case 0: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKStandard); break; case 1: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationUncoupled); break; case 2: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationCoupled); break; case 3: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKSwivel); break; } } mitk::SliceNavigationController* QmitkStdMultiWidget::GetTimeNavigationController() { return m_TimeNavigationController; } void QmitkStdMultiWidget::AddPlanesToDataStorage() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { dataStorage->Add(m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode1, m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode2, m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode3, m_ParentNodeForGeometryPlanes); } } void QmitkStdMultiWidget::RemovePlanesFromDataStorage() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { dataStorage->Remove(m_PlaneNode1); dataStorage->Remove(m_PlaneNode2); dataStorage->Remove(m_PlaneNode3); dataStorage->Remove(m_ParentNodeForGeometryPlanes); } } void QmitkStdMultiWidget::HandleCrosshairPositionEvent() { if (!m_PendingCrosshairPositionEvent) { m_PendingCrosshairPositionEvent = true; QTimer::singleShot(0, this, SLOT(HandleCrosshairPositionEventDelayed())); } } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(unsigned int number) const { switch (number) { case 0: return GetRenderWindow1(); case 1: return GetRenderWindow2(); case 2: return GetRenderWindow3(); case 3: return GetRenderWindow4(); default: MITK_ERROR << "Requested unknown render window"; break; } return nullptr; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow1() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 0)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow2() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 1)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow3() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 0)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow4() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 1)); } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane1() const { return m_PlaneNode1; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane2() const { return m_PlaneNode2; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane3() const { return m_PlaneNode3; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane(unsigned number) const { switch (number) { case 1: return m_PlaneNode1; case 2: return m_PlaneNode2; case 3: return m_PlaneNode3; default: MITK_ERROR << "Requested unknown render window"; break; } return nullptr; } void QmitkStdMultiWidget::SetDecorationColor(unsigned int widgetNumber, mitk::Color color) { switch (widgetNumber) { case 0: if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetColor(color); } break; case 1: if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetColor(color); } break; case 2: if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetColor(color); } break; case 3: m_DecorationColorWidget4 = color; break; default: MITK_ERROR << "Decoration color for unknown widget!"; break; } } mitk::Color QmitkStdMultiWidget::GetDecorationColor(unsigned int widgetNumber) { // The implementation looks a bit messy here, but it avoids // synchronization of the color of the geometry nodes and an // internal member here. // Default colors were chosen for decent visibility. // Feel free to change your preferences in the workbench. float tmp[3] = { 0.0f, 0.0f, 0.0f }; switch (widgetNumber) { case 0: { if (m_PlaneNode1.IsNotNull()) { if (m_PlaneNode1->GetColor(tmp)) { return dynamic_cast(m_PlaneNode1->GetProperty("color"))->GetColor(); } } float red[3] = { 0.753f, 0.0f, 0.0f }; // This is #C00000 in hex return mitk::Color(red); } case 1: { if (m_PlaneNode2.IsNotNull()) { if (m_PlaneNode2->GetColor(tmp)) { return dynamic_cast(m_PlaneNode2->GetProperty("color"))->GetColor(); } } float green[3] = { 0.0f, 0.69f, 0.0f }; // This is #00B000 in hex return mitk::Color(green); } case 2: { if (m_PlaneNode3.IsNotNull()) { if (m_PlaneNode3->GetColor(tmp)) { return dynamic_cast(m_PlaneNode3->GetProperty("color"))->GetColor(); } } float blue[3] = { 0.0, 0.502f, 1.0f }; // This is #0080FF in hex return mitk::Color(blue); } case 3: { return m_DecorationColorWidget4; } default: MITK_ERROR << "Decoration color for unknown widget!"; float black[3] = { 0.0f, 0.0f, 0.0f }; return mitk::Color(black); } } void QmitkStdMultiWidget::mousePressEvent(QMouseEvent* e) { if (QEvent::MouseButtonPress != e->type()) { return; } auto renderWindowWidget = dynamic_cast(this->sender()); if (nullptr == renderWindowWidget) { return; } auto renderWindowWidgetPointer = GetRenderWindowWidget(renderWindowWidget->GetWidgetName()); SetActiveRenderWindowWidget(renderWindowWidgetPointer); } void QmitkStdMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the Annotation as the StdMultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } void QmitkStdMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } void QmitkStdMultiWidget::HandleCrosshairPositionEventDelayed() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } m_PendingCrosshairPositionEvent = false; // find image with highest layer mitk::TNodePredicateDataType::Pointer isImageData = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = dataStorage->GetSubset(isImageData).GetPointer(); mitk::Point3D crosshairPos = GetSelectedPosition(""); mitk::BaseRenderer* baseRenderer = GetRenderWindow1()->GetSliceNavigationController()->GetRenderer(); auto globalCurrentTimePoint = baseRenderer->GetTime(); mitk::DataNode::Pointer node = mitk::FindTopmostVisibleNode(nodes, crosshairPos, globalCurrentTimePoint, baseRenderer); mitk::DataNode::Pointer topSourceNode; mitk::Image::Pointer image; bool isBinary = false; int component = 0; if (node.IsNotNull()) { node->GetBoolProperty("binary", isBinary); if (isBinary) { mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = dataStorage->GetSources(node, nullptr, true); if (!sourcenodes->empty()) { topSourceNode = mitk::FindTopmostVisibleNode(sourcenodes, crosshairPos, globalCurrentTimePoint, baseRenderer); } if (topSourceNode.IsNotNull()) { image = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } std::string statusText; std::stringstream stream; itk::Index<3> p; unsigned int timestep = baseRenderer->GetTimeStep(); if (image.IsNotNull() && (image->GetTimeSteps() > timestep)) { image->GetGeometry()->WorldToIndex(crosshairPos, p); stream.precision(2); stream << "Position: <" << std::fixed << crosshairPos[0] << ", " << std::fixed << crosshairPos[1] << ", " << std::fixed << crosshairPos[2] << "> mm"; stream << "; Index: <" << p[0] << ", " << p[1] << ", " << p[2] << "> "; mitk::ScalarType pixelValue; mitkPixelTypeMultiplex5(mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(image->GetTimeGeometry()->TimePointToTimeStep(globalCurrentTimePoint)), p, pixelValue, component); if (fabs(pixelValue) > 1000000 || fabs(pixelValue) < 0.01) { stream << "; Time: " << globalCurrentTimePoint << " ms; Pixelvalue: " << std::scientific << pixelValue << " "; } else { stream << "; Time: " << globalCurrentTimePoint << " ms; Pixelvalue: " << pixelValue << " "; } } else { stream << "No image information at this position!"; } statusText = stream.str(); mitk::StatusBar::GetInstance()->DisplayGreyValueText(statusText.c_str()); } void QmitkStdMultiWidget::Fit() { vtkSmartPointer vtkrenderer; - vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetVtkRenderer(); + vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } - vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetVtkRenderer(); + vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } - vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetVtkRenderer(); + vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } - vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetVtkRenderer(); + vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } - mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetCameraController()->Fit(); - mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetCameraController()->Fit(); - mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetCameraController()->Fit(); - mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetCameraController()->Fit(); + mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetCameraController()->Fit(); + mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetCameraController()->Fit(); + mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetCameraController()->Fit(); + mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetCameraController()->Fit(); int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkObject::SetGlobalWarningDisplay(w); } void QmitkStdMultiWidget::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... mitk::PlaneGeometryDataMapper2D::Pointer mapper; // ... of widget 1 - mitk::BaseRenderer* renderer1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow()); + mitk::BaseRenderer* renderer1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow()); m_PlaneNode1 = renderer1->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode1->SetProperty("name", mitk::StringProperty::New(std::string(renderer1->GetName()) + ".plane")); m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 2 - mitk::BaseRenderer* renderer2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow()); + mitk::BaseRenderer* renderer2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow()); m_PlaneNode2 = renderer2->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode2->SetProperty("name", mitk::StringProperty::New(std::string(renderer2->GetName()) + ".plane")); m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 3 - mitk::BaseRenderer *renderer3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow()); + mitk::BaseRenderer *renderer3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow()); m_PlaneNode3 = renderer3->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode3->SetProperty("name", mitk::StringProperty::New(std::string(renderer3->GetName()) + ".plane")); m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_ParentNodeForGeometryPlanes = mitk::DataNode::New(); m_ParentNodeForGeometryPlanes->SetProperty("name", mitk::StringProperty::New("Widgets")); m_ParentNodeForGeometryPlanes->SetProperty("helper object", mitk::BoolProperty::New(true)); } void QmitkStdMultiWidget::EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p) { mitk::Point2D pointOnDisplay; renderer->WorldToDisplay(p, pointOnDisplay); if (pointOnDisplay[0] < renderer->GetVtkRenderer()->GetOrigin()[0] || pointOnDisplay[1] < renderer->GetVtkRenderer()->GetOrigin()[1] || pointOnDisplay[0] > renderer->GetVtkRenderer()->GetOrigin()[0] + renderer->GetViewportSize()[0] || pointOnDisplay[1] > renderer->GetVtkRenderer()->GetOrigin()[1] + renderer->GetViewportSize()[1]) { mitk::Point2D pointOnPlane; renderer->GetCurrentWorldPlaneGeometry()->Map(p, pointOnPlane); renderer->GetCameraController()->MoveCameraToPoint(pointOnPlane); } } void QmitkStdMultiWidget::SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer) { auto dataStorage = GetDataStorage(); if (nullptr != dataStorage) { mitk::DataNode* dataNode = dataStorage->GetNamedNode(widgetName); if (dataNode != nullptr) { dataNode->SetVisibility(visible, renderer); } } } void QmitkStdMultiWidget::SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer) { if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetVisibility(visible, renderer); } if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetVisibility(visible, renderer); } if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetVisibility(visible, renderer); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkStdMultiWidget::SetLayoutImpl() { CreateRenderWindowWidgets(); GetMultiWidgetLayoutManager()->SetLayoutDesign(QmitkMultiWidgetLayoutManager::LayoutDesign::DEFAULT); // Initialize views as axial, sagittal, coronal to all data objects in DataStorage auto geo = GetDataStorage()->ComputeBoundingGeometry3D(GetDataStorage()->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); } void QmitkStdMultiWidget::CreateRenderWindowWidgets() { // create axial render window (widget) QString renderWindowWidgetName = GetNameFromIndex(0, 0); RenderWindowWidgetPointer renderWindowWidget1 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow1 = renderWindowWidget1->GetRenderWindow(); renderWindow1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); renderWindowWidget1->SetDecorationColor(GetDecorationColor(0)); renderWindowWidget1->SetCornerAnnotationText("Axial"); renderWindowWidget1->GetRenderWindow()->SetLayoutIndex(ViewDirection::AXIAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget1); // create sagittal render window (widget) renderWindowWidgetName = GetNameFromIndex(0, 1); RenderWindowWidgetPointer renderWindowWidget2 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow2 = renderWindowWidget2->GetRenderWindow(); renderWindow2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); renderWindowWidget2->SetDecorationColor(GetDecorationColor(1)); renderWindowWidget2->setStyleSheet("border: 0px"); renderWindowWidget2->SetCornerAnnotationText("Sagittal"); renderWindowWidget2->GetRenderWindow()->SetLayoutIndex(ViewDirection::SAGITTAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget2); // create coronal render window (widget) renderWindowWidgetName = GetNameFromIndex(1, 0); RenderWindowWidgetPointer renderWindowWidget3 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow3 = renderWindowWidget3->GetRenderWindow(); renderWindow3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); renderWindowWidget3->SetDecorationColor(GetDecorationColor(2)); renderWindowWidget3->SetCornerAnnotationText("Coronal"); renderWindowWidget3->GetRenderWindow()->SetLayoutIndex(ViewDirection::CORONAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget3); // create 3D render window (widget) renderWindowWidgetName = GetNameFromIndex(1, 1); RenderWindowWidgetPointer renderWindowWidget4 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow4 = renderWindowWidget4->GetRenderWindow(); renderWindow4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Original); renderWindowWidget4->SetDecorationColor(GetDecorationColor(3)); renderWindowWidget4->SetCornerAnnotationText("3D"); renderWindowWidget4->GetRenderWindow()->SetLayoutIndex(ViewDirection::THREE_D); - mitk::BaseRenderer::GetInstance(renderWindowWidget4->GetRenderWindow()->GetRenderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); + mitk::BaseRenderer::GetInstance(renderWindowWidget4->GetRenderWindow()->renderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget4); SetActiveRenderWindowWidget(renderWindowWidget1); // connect to the "time navigation controller": send time via sliceNavigationControllers m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow1->GetSliceNavigationController(), false); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow2->GetSliceNavigationController(), false); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow3->GetSliceNavigationController(), false); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow4->GetSliceNavigationController(), false); renderWindow1->GetSliceNavigationController()->ConnectGeometrySendEvent( - mitk::BaseRenderer::GetInstance(renderWindow4->GetRenderWindow())); + mitk::BaseRenderer::GetInstance(renderWindow4->renderWindow())); // reverse connection between sliceNavigationControllers and timeNavigationController renderWindow1->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); renderWindow2->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); renderWindow3->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); //renderWindow4->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); auto layoutManager = GetMultiWidgetLayoutManager(); connect(renderWindowWidget1.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); connect(renderWindow1, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow1, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow1, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow1, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(renderWindowWidget2.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); connect(renderWindow2, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow2, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow2, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow2, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(renderWindowWidget3.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); connect(renderWindow3, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow3, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow3, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow3, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(renderWindowWidget4.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); connect(renderWindow4, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow4, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow4, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow4, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); } diff --git a/Modules/QtWidgetsExt/CMakeLists.txt b/Modules/QtWidgetsExt/CMakeLists.txt index c2e295c41b..85fdc156a1 100644 --- a/Modules/QtWidgetsExt/CMakeLists.txt +++ b/Modules/QtWidgetsExt/CMakeLists.txt @@ -1,6 +1,6 @@ MITK_CREATE_MODULE( DEPENDS MitkAlgorithmsExt MitkQtWidgets PRIVATE MitkSceneSerializationBase PACKAGE_DEPENDS PUBLIC Qwt CTK|CTKWidgets - PRIVATE Qt5|Concurrent+Svg+Xml + PRIVATE Qt5|Concurrent+Svg+Xml VTK|IOImage ) diff --git a/Modules/Remeshing/CMakeLists.txt b/Modules/Remeshing/CMakeLists.txt index c3da914c8e..2697e18603 100644 --- a/Modules/Remeshing/CMakeLists.txt +++ b/Modules/Remeshing/CMakeLists.txt @@ -1,7 +1,9 @@ mitk_create_module( - DEPENDS MitkCore - PACKAGE_DEPENDS ACVD VTK|vtkIOPLY+vtkIOMINC - ) - -add_subdirectory(Testing) + DEPENDS MitkCore + PACKAGE_DEPENDS OpenMesh|OpenMeshTools +) +if(TARGET ${MODULE_TARGET}) + target_link_libraries(${MODULE_TARGET} PRIVATE OpenMeshTools) + target_compile_definitions(${MODULE_TARGET} PRIVATE -D_USE_MATH_DEFINES) +endif() diff --git a/Modules/Remeshing/Testing/CMakeLists.txt b/Modules/Remeshing/Testing/CMakeLists.txt deleted file mode 100644 index a29ccbc947..0000000000 --- a/Modules/Remeshing/Testing/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -if(MITK_USE_ACVD) - MITK_CREATE_MODULE_TESTS() - - mitkAddCustomModuleTest(mitkACVDTest mitkACVDTest ${MITK_DATA_DIR}/binary.stl 0 1228 1.0 10 0.0 1 0 0) -endif() diff --git a/Modules/Remeshing/Testing/files.cmake b/Modules/Remeshing/Testing/files.cmake deleted file mode 100644 index 055665bf46..0000000000 --- a/Modules/Remeshing/Testing/files.cmake +++ /dev/null @@ -1,6 +0,0 @@ -set(MODULE_TESTS -) - -set(MODULE_CUSTOM_TESTS - mitkACVDTest.cpp -) diff --git a/Modules/Remeshing/Testing/mitkACVDTest.cpp b/Modules/Remeshing/Testing/mitkACVDTest.cpp deleted file mode 100644 index f5bf8d5364..0000000000 --- a/Modules/Remeshing/Testing/mitkACVDTest.cpp +++ /dev/null @@ -1,138 +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 -#include -#include -#include -#include -#include -#include - -#define _MITK_TEST_FOR_EXCEPTION(STATEMENT, EXCEPTION, MESSAGE) \ - MITK_TEST_OUTPUT_NO_ENDL(<< MESSAGE) \ - try \ - { \ - STATEMENT; \ - MITK_TEST_OUTPUT(<< " [FAILED]") \ - mitk::TestManager::GetInstance()->TestFailed(); \ - } \ - catch (const EXCEPTION &e) \ - { \ - MITK_TEST_OUTPUT(<< "\n " << e.GetDescription() << " [PASSED]") \ - mitk::TestManager::GetInstance()->TestPassed(); \ - } - -template -static T lexical_cast(const std::string &string) -{ - std::istringstream sstream(string); - T value; - - sstream >> value; - - if (sstream.fail()) - { - MITK_ERROR << "Lexical cast failed for '" << string << "'!"; - exit(EXIT_FAILURE); - } - - return value; -} - -static void Remesh_SurfaceIsNull_ThrowsException() -{ - mitk::Surface::ConstPointer surface; - _MITK_TEST_FOR_EXCEPTION( - mitk::ACVD::Remesh(surface, 0, 100, 0.0), mitk::Exception, "Remesh_SurfaceIsNull_ThrowsException") -} - -static void Remesh_PolyDataIsNull_ThrowsException() -{ - mitk::Surface::ConstPointer surface = mitk::Surface::New().GetPointer(); - _MITK_TEST_FOR_EXCEPTION( - mitk::ACVD::Remesh(surface, 0, 100, 0.0), mitk::Exception, "Remesh_PolyDataIsNull_ThrowsException") -} - -static void Remesh_SurfaceDoesNotHaveDataAtTimeStep_ThrowsException() -{ - mitk::Surface::ConstPointer surface = mitk::Surface::New().GetPointer(); - _MITK_TEST_FOR_EXCEPTION(mitk::ACVD::Remesh(surface, 1, 100, 0.0), - mitk::Exception, - "Remesh_SurfaceDoesNotHaveDataAtTimeStep_ThrowsException") -} - -static void Remesh_SurfaceHasNoPolygons_ThrowsException() -{ - mitk::Surface::Pointer surface = mitk::Surface::New(); - vtkSmartPointer polyData = vtkSmartPointer::New(); - surface->SetVtkPolyData(polyData); - _MITK_TEST_FOR_EXCEPTION(mitk::ACVD::Remesh(surface.GetPointer(), 0, 100, 0.0), - mitk::Exception, - "Remesh_SurfaceHasNoPolygons_ThrowsException") -} - -static void Remesh_SurfaceIsValid_ReturnsRemeshedSurface(const std::string &filename, - unsigned int t, - int numVertices, - double gradation, - int subsampling, - double edgeSplitting, - int optimizationLevel, - bool forceManifold, - bool boundaryFixing) -{ - auto surface = mitk::IOUtil::Load(filename); - mitk::Surface::Pointer remeshedSurface = mitk::ACVD::Remesh( - surface.GetPointer(), t, numVertices, gradation, subsampling, edgeSplitting, optimizationLevel, forceManifold, boundaryFixing); - MITK_TEST_CONDITION(remeshedSurface.IsNotNull() && remeshedSurface->GetVtkPolyData() != nullptr && - remeshedSurface->GetVtkPolyData()->GetNumberOfPolys() != 0, - "Remesh_SurfaceIsValid_ReturnsRemeshedSurface") -} - -int mitkACVDTest(int argc, char *argv[]) -{ - if (argc != 10) - { - MITK_ERROR << "Invalid argument count!\n" - << "Usage: mitkACVDTest \n" - << " \n" - << " \n" - << " See MITK API documentation of mitk::ACVD::Remesh() for details."; - - return EXIT_FAILURE; - } - - const std::string filename = argv[1]; - const unsigned int t = lexical_cast(argv[2]); - const int numVertices = lexical_cast(argv[3]); - const double gradation = lexical_cast(argv[4]); - const int subsampling = lexical_cast(argv[5]); - const double edgeSplitting = lexical_cast(argv[6]); - const int optimizationLevel = lexical_cast(argv[7]); - const bool forceManifold = lexical_cast(argv[8]); - const bool boundaryFixing = lexical_cast(argv[9]); - - MITK_TEST_BEGIN("mitkACVDTest") - - vtkDebugLeaks::SetExitError(0); - - Remesh_SurfaceIsNull_ThrowsException(); - Remesh_PolyDataIsNull_ThrowsException(); - Remesh_SurfaceDoesNotHaveDataAtTimeStep_ThrowsException(); - Remesh_SurfaceHasNoPolygons_ThrowsException(); - - Remesh_SurfaceIsValid_ReturnsRemeshedSurface( - filename, t, numVertices, gradation, subsampling, edgeSplitting, optimizationLevel, forceManifold, boundaryFixing); - - MITK_TEST_END() -} diff --git a/Modules/Remeshing/files.cmake b/Modules/Remeshing/files.cmake index a9a6a7d8eb..303e7498dd 100644 --- a/Modules/Remeshing/files.cmake +++ b/Modules/Remeshing/files.cmake @@ -1,3 +1,7 @@ +set(H_FILES + include/mitkRemeshing.h +) + set(CPP_FILES - mitkACVD.cpp + mitkRemeshing.cpp ) diff --git a/Modules/Remeshing/include/mitkRemeshing.h b/Modules/Remeshing/include/mitkRemeshing.h new file mode 100644 index 0000000000..ef068d6424 --- /dev/null +++ b/Modules/Remeshing/include/mitkRemeshing.h @@ -0,0 +1,39 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +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 mitkRemeshing_h +#define mitkRemeshing_h + +#include +#include + +namespace mitk +{ + namespace Remeshing + { + /** \brief Reduce the number of vertices of an mitk::Surface. + * + * The decimation is applied separately to all time steps of the input surface. + * The meshes of the resulting surface are guaranteed to consist of triangles only. + * + * \param[in] input Input surface + * \param[in] percent Relative number of vertices after decimation [0, 1] + * \param[in] calculateNormals Calculate normals after decimation (\c true by default) + * \param[in] flipNormals Flip calculated normals (\c false by default) + * + * \return Decimated surface + */ + MITKREMESHING_EXPORT Surface::Pointer Decimate(const Surface* input, double percent, bool calculateNormals = true, bool flipNormals = false); + } +} + +#endif diff --git a/Modules/Remeshing/mitkACVD.cpp b/Modules/Remeshing/mitkACVD.cpp deleted file mode 100644 index f805979d52..0000000000 --- a/Modules/Remeshing/mitkACVD.cpp +++ /dev/null @@ -1,220 +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 "mitkACVD.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct ClustersQuadrics -{ - explicit ClustersQuadrics(int size) : Elements(new double *[size]), Size(size) - { - for (int i = 0; i < size; ++i) - { - Elements[i] = new double[9]; - - for (int j = 0; j < 9; ++j) - Elements[i][j] = 0.0; - } - } - - ~ClustersQuadrics() - { - for (int i = 0; i < Size; ++i) - delete[] Elements[i]; - - delete Elements; - } - - double **Elements; - int Size; - -private: - ClustersQuadrics(const ClustersQuadrics &); - ClustersQuadrics &operator=(const ClustersQuadrics &); -}; - -static void ValidateSurface(mitk::Surface::ConstPointer surface, unsigned int t) -{ - if (surface.IsNull()) - mitkThrow() << "Input surface is nullptr!"; - - if (t >= surface->GetSizeOfPolyDataSeries()) - mitkThrow() << "Input surface doesn't have data at time step " << t << "!"; - - vtkPolyData *polyData = const_cast(surface.GetPointer())->GetVtkPolyData(t); - - if (polyData == nullptr) - mitkThrow() << "PolyData of input surface at time step " << t << " is nullptr!"; - - if (polyData->GetNumberOfPolys() == 0) - mitkThrow() << "Input surface has no polygons at time step " << t << "!"; -} - -mitk::Surface::Pointer mitk::ACVD::Remesh(mitk::Surface::ConstPointer surface, - unsigned int t, - int numVertices, - double gradation, - int subsampling, - double edgeSplitting, - int optimizationLevel, - bool forceManifold, - bool boundaryFixing) -{ - ValidateSurface(surface, t); - - MITK_INFO << "Start remeshing..."; - - vtkSmartPointer surfacePolyData = vtkSmartPointer::New(); - surfacePolyData->DeepCopy(const_cast(surface.GetPointer())->GetVtkPolyData(t)); - - vtkSmartPointer mesh = vtkSmartPointer::New(); - - mesh->CreateFromPolyData(surfacePolyData); - mesh->GetCellData()->Initialize(); - mesh->GetPointData()->Initialize(); - - mesh->DisplayMeshProperties(); - - if (numVertices == 0) - numVertices = surfacePolyData->GetNumberOfPoints(); - - if (edgeSplitting != 0.0) - mesh->SplitLongEdges(edgeSplitting); - - vtkSmartPointer remesher = vtkSmartPointer::New(); - - remesher->GetMetric()->SetGradation(gradation); - remesher->SetBoundaryFixing(boundaryFixing); - remesher->SetConsoleOutput(1); - remesher->SetForceManifold(forceManifold); - remesher->SetInput(mesh); - remesher->SetNumberOfClusters(numVertices); - remesher->SetNumberOfThreads(vtkMultiThreader::GetGlobalDefaultNumberOfThreads()); - remesher->SetSubsamplingThreshold(subsampling); - - remesher->Remesh(); - - // Optimization: Minimize distance between input surface and remeshed surface - if (optimizationLevel != 0) - { - ClustersQuadrics clustersQuadrics(numVertices); - - vtkSmartPointer faceList = vtkSmartPointer::New(); - vtkSmartPointer clustering = remesher->GetClustering(); - vtkSmartPointer remesherInput = remesher->GetInput(); - int clusteringType = remesher->GetClusteringType(); - int numItems = remesher->GetNumberOfItems(); - int numMisclassifiedItems = 0; - - for (int i = 0; i < numItems; ++i) - { - int cluster = clustering->GetValue(i); - - if (cluster >= 0 && cluster < numVertices) - { - if (clusteringType != 0) - { - remesherInput->GetVertexNeighbourFaces(i, faceList); - int numIds = static_cast(faceList->GetNumberOfIds()); - - for (int j = 0; j < numIds; ++j) - vtkQuadricTools::AddTriangleQuadric( - clustersQuadrics.Elements[cluster], remesherInput, faceList->GetId(j), false); - } - else - { - vtkQuadricTools::AddTriangleQuadric(clustersQuadrics.Elements[cluster], remesherInput, i, false); - } - } - else - { - ++numMisclassifiedItems; - } - } - - if (numMisclassifiedItems != 0) - std::cout << numMisclassifiedItems << " items with wrong cluster association" << std::endl; - - vtkSmartPointer remesherOutput = remesher->GetOutput(); - double point[3]; - - for (int i = 0; i < numVertices; ++i) - { - remesherOutput->GetPoint(i, point); - vtkQuadricTools::ComputeRepresentativePoint(clustersQuadrics.Elements[i], point, optimizationLevel); - remesherOutput->SetPointCoordinates(i, point); - } - - std::cout << "After quadrics post-processing:" << std::endl; - remesherOutput->DisplayMeshProperties(); - } - - vtkSmartPointer normals = vtkSmartPointer::New(); - - normals->SetInputData(remesher->GetOutput()); - normals->AutoOrientNormalsOn(); - normals->ComputeCellNormalsOff(); - normals->ComputePointNormalsOn(); - normals->ConsistencyOff(); - normals->FlipNormalsOff(); - normals->NonManifoldTraversalOff(); - normals->SplittingOff(); - - normals->Update(); - - Surface::Pointer remeshedSurface = Surface::New(); - remeshedSurface->SetVtkPolyData(normals->GetOutput()); - - MITK_INFO << "Finished remeshing"; - - return remeshedSurface; -} - -mitk::ACVD::RemeshFilter::RemeshFilter() - : m_TimeStep(0), - m_NumVertices(0), - m_Gradation(1.0), - m_Subsampling(10), - m_EdgeSplitting(0.0), - m_OptimizationLevel(1), - m_ForceManifold(false), - m_BoundaryFixing(false) -{ - Surface::Pointer output = Surface::New(); - this->SetNthOutput(0, output); -} - -mitk::ACVD::RemeshFilter::~RemeshFilter() -{ -} - -void mitk::ACVD::RemeshFilter::GenerateData() -{ - Surface::Pointer output = Remesh(this->GetInput(), - m_TimeStep, - m_NumVertices, - m_Gradation, - m_Subsampling, - m_EdgeSplitting, - m_OptimizationLevel, - m_ForceManifold, - m_BoundaryFixing); - this->SetNthOutput(0, output); -} diff --git a/Modules/Remeshing/mitkACVD.h b/Modules/Remeshing/mitkACVD.h deleted file mode 100644 index ca83919d84..0000000000 --- a/Modules/Remeshing/mitkACVD.h +++ /dev/null @@ -1,102 +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 mitkACVD_h -#define mitkACVD_h - -#include -#include -#include - -namespace mitk -{ - namespace ACVD - { - /** \brief Remesh a surface and store the result in a new surface. - * - * The %ACVD library is used for remeshing which is based on the paper "Approximated Centroidal Voronoi Diagrams for - * Uniform Polygonal Mesh Coarsening" by S. Valette, and J. M. Chassery. - * There are a few rules of thumbs regarding the ranges of parameters to gain high quality remeshed surfaces: - * - *
    - *
  • numVertices is exact, however, if boundaryFixing is enabled, additional vertices are generated at - * boundaries - *
  • %Set gradation to zero in case you want polygons of roughly the same size all over the remeshed surface; - * start with 1 otherwise - *
  • subsampling has direct influence on the quality of the remeshed surface (higher values take more time) - *
  • edgeSplitting is useful for surfaces that contain long and thin triangles but takes a long time - *
  • Leave optimizationLevel set to 1 as greater values result in degenerated polygons - *
  • Irregular shrinking of boundaries during remeshing can be avoided by boundaryFixing, however this results - * in additional, lower quality polygons at boundaries - *
- * - * \param[in] surface Input surface. - * \param[in] t Time step of a four-dimensional input surface, zero otherwise. - * \param[in] numVertices Desired number of vertices in the remeshed surface, set to zero to keep original vertex - * count. - * \param[in] gradation Influence of surface curvature on polygon size. - * \param[in] subsampling Subsample input surface until number of vertices exceeds initial count times this - * parameter. - * \param[in] edgeSplitting Recursively split edges that are longer than the average edge length times this - * parameter. - * \param[in] optimizationLevel Minimize distance between input surface and remeshed surface. - * \param[in] forceManifold - * \param[in] boundaryFixing Keep original surface boundaries by adding additional polygons. - * \return Returns the remeshed surface or nullptr if input surface is invalid. - */ - MITKREMESHING_EXPORT Surface::Pointer Remesh(Surface::ConstPointer surface, - unsigned int t, - int numVertices, - double gradation, - int subsampling = 10, - double edgeSplitting = 0.0, - int optimizationLevel = 1, - bool forceManifold = false, - bool boundaryFixing = false); - - /** \brief Encapsulates mitk::ACVD::Remesh function as filter. - */ - class MITKREMESHING_EXPORT RemeshFilter : public mitk::SurfaceToSurfaceFilter - { - public: - mitkClassMacro(RemeshFilter, SurfaceToSurfaceFilter); - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); - itkSetMacro(TimeStep, unsigned int); - itkSetMacro(NumVertices, int); - itkSetMacro(Gradation, double); - itkSetMacro(Subsampling, int); - itkSetMacro(EdgeSplitting, double); - itkSetMacro(OptimizationLevel, int); - itkSetMacro(ForceManifold, bool); - itkSetMacro(BoundaryFixing, bool); - - protected: - void GenerateData() override; - - private: - RemeshFilter(); - ~RemeshFilter() override; - - unsigned int m_TimeStep; - int m_NumVertices; - double m_Gradation; - int m_Subsampling; - double m_EdgeSplitting; - int m_OptimizationLevel; - bool m_ForceManifold; - bool m_BoundaryFixing; - }; - } -} - -#endif diff --git a/Modules/Remeshing/src/mitkRemeshing.cpp b/Modules/Remeshing/src/mitkRemeshing.cpp new file mode 100644 index 0000000000..dd531cfaaf --- /dev/null +++ b/Modules/Remeshing/src/mitkRemeshing.cpp @@ -0,0 +1,185 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using Mesh = OpenMesh::TriMesh_ArrayKernelT; + +namespace +{ + bool IsValidPolyData(vtkPolyData* polyData) + { + return nullptr != polyData && 0 < polyData->GetNumberOfPoints() && + (0 < polyData->GetNumberOfPolys() || 0 < polyData->GetNumberOfStrips()); + } + + vtkSmartPointer TriangulatePolyData(vtkPolyData* polyData) + { + auto triangleFilter = vtkSmartPointer::New(); + triangleFilter->SetInputData(polyData); + triangleFilter->PassVertsOff(); + triangleFilter->PassLinesOff(); + + triangleFilter->Update(); + + return triangleFilter->GetOutput(); + } + + vtkSmartPointer CalculateNormals(vtkPolyData* polyData, bool flipNormals) + { + auto polyDataNormals = vtkSmartPointer::New(); + polyDataNormals->SetInputData(polyData); + + if (flipNormals) + polyDataNormals->FlipNormalsOn(); + + polyDataNormals->Update(); + + return polyDataNormals->GetOutput(); + } + + Mesh ConvertPolyDataToMesh(vtkPolyData* polyData) + { + Mesh mesh; + + auto* points = polyData->GetPoints(); + const auto numPoints = points->GetNumberOfPoints(); + + for (std::remove_const_t i = 0; i < numPoints; ++i) + mesh.add_vertex(Mesh::Point(points->GetPoint(i))); + + auto* polys = polyData->GetPolys(); + const auto numPolys = polys->GetNumberOfCells(); + + auto ids = vtkSmartPointer::New(); + std::array vertexHandles; + + for (std::remove_const_t i = 0; i < numPolys; ++i) + { + polys->GetCellAtId(i, ids); + + vertexHandles[0] = Mesh::VertexHandle(static_cast(ids->GetId(0))); + vertexHandles[1] = Mesh::VertexHandle(static_cast(ids->GetId(1))); + vertexHandles[2] = Mesh::VertexHandle(static_cast(ids->GetId(2))); + + mesh.add_face(vertexHandles.data(), 3); + } + + return mesh; + } + + vtkSmartPointer ConvertMeshToPolyData(const Mesh& mesh) + { + auto polyData = vtkSmartPointer::New(); + + const auto numVertices = mesh.n_vertices(); + auto points = vtkSmartPointer::New(); + points->SetNumberOfPoints(numVertices); + + for (std::remove_const_t i = 0; i < numVertices; ++i) + points->SetPoint(i, mesh.point(Mesh::VertexHandle(static_cast(i))).data()); + + polyData->SetPoints(points); + + const auto numFaces = mesh.n_faces(); + auto polys = vtkSmartPointer::New(); + + auto ids = vtkSmartPointer::New(); + ids->SetNumberOfIds(3); + Mesh::CFVIter iter; + + for (std::remove_const_t i = 0; i < numFaces; ++i) + { + iter = mesh.cfv_iter(Mesh::FaceHandle(static_cast(i))); + + ids->SetId(0, (iter++)->idx()); + ids->SetId(1, (iter++)->idx()); + ids->SetId(2, iter->idx()); + + polys->InsertNextCell(ids); + } + + polyData->SetPolys(polys); + + return polyData; + } + + mitk::Surface::Pointer ProcessEachTimeStep(const mitk::Surface* input, bool calculateNormals, bool flipNormals, const std::function& ProcessMesh) + { + if (nullptr == input || !input->IsInitialized()) + return nullptr; + + auto output = mitk::Surface::New(); + const auto numTimeSteps = input->GetTimeSteps(); + + for (std::remove_const_t t = 0; t < numTimeSteps; ++t) + { + vtkSmartPointer polyData = input->GetVtkPolyData(t); + + if (IsValidPolyData(polyData)) + { + polyData = TriangulatePolyData(polyData); + + if (IsValidPolyData(polyData)) + { + auto mesh = ConvertPolyDataToMesh(polyData); + ProcessMesh(mesh); + polyData = ConvertMeshToPolyData(mesh); + + if (calculateNormals) + polyData = CalculateNormals(polyData, flipNormals); + + output->SetVtkPolyData(polyData, t); + continue; + } + } + + output->SetVtkPolyData(nullptr, t); + } + + return output; + } +} + +mitk::Surface::Pointer mitk::Remeshing::Decimate(const Surface* input, double percent, bool calculateNormals, bool flipNormals) +{ + return ProcessEachTimeStep(input, calculateNormals, flipNormals, [percent](Mesh& mesh) { + using Decimater = OpenMesh::Decimater::DecimaterT; + using HModQuadric = OpenMesh::Decimater::ModQuadricT::Handle; + + Decimater decimater(mesh); + + HModQuadric hModQuadric; + decimater.add(hModQuadric); + decimater.module(hModQuadric).unset_max_err(); + + decimater.initialize(); + decimater.decimate_to(mesh.n_vertices() * std::max(0.0, std::min(percent, 1.0))); + + mesh.garbage_collection(); + }); +} diff --git a/Modules/SceneSerializationBase/test/mitkPropertySerializationTest.cpp b/Modules/SceneSerializationBase/test/mitkPropertySerializationTest.cpp index 9171a6ce5b..c6cfe3b656 100644 --- a/Modules/SceneSerializationBase/test/mitkPropertySerializationTest.cpp +++ b/Modules/SceneSerializationBase/test/mitkPropertySerializationTest.cpp @@ -1,273 +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 "mitkTestingMacros.h" #include "mitkCoreObjectFactory.h" #include "mitkBaseProperty.h" #include "mitkProperties.h" #include #include #include #include -/* -#include -#include -*/ #include -//#include -//#include #include #include #include #include #include #include #include #include #include #include #include #include "mitkBasePropertySerializer.h" #include "mitkPropertyList.h" #include "mitkPropertyListSerializer.h" #include #include #include #include -/* -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -*/ - void TestAllProperties(const mitk::PropertyList *propList); /**Documentation * \brief Test for all PropertySerializer classes. * */ int mitkPropertySerializationTest(int /* argc */, char * /*argv*/ []) { MITK_TEST_BEGIN("PropertySerializationTest"); mitk::PropertyListSerializer::Pointer serializer = mitk::PropertyListSerializer::New(); // make sure something from the lib is actually used (registration of // serializers) /* build list of properties that will be serialized and deserialized */ mitk::PropertyList::Pointer propList = mitk::PropertyList::New(); propList->SetProperty("booltrue", mitk::BoolProperty::New(true)); propList->SetProperty("boolfalse", mitk::BoolProperty::New(false)); propList->SetProperty("int", mitk::IntProperty::New(-32)); propList->SetProperty("float", mitk::FloatProperty::New(-31.337)); propList->SetProperty("double", mitk::DoubleProperty::New(-31.337)); propList->SetProperty("string", mitk::StringProperty::New("Hello MITK")); mitk::Point3D p3d; mitk::FillVector3D(p3d, 1.0, 2.2, -3.3); propList->SetProperty("p3d", mitk::Point3dProperty::New(p3d)); mitk::Point3I p3i; mitk::FillVector3D(p3i, 1, 2, -3); propList->SetProperty("p3i", mitk::Point3iProperty::New(p3i)); mitk::Point4D p4d; mitk::FillVector4D(p4d, 1.5, 2.6, -3.7, 4.44); propList->SetProperty("p4d", mitk::Point4dProperty::New(p4d)); mitk::Vector3D v3d; mitk::FillVector3D(v3d, 1.0, 2.2, -3.3); propList->SetProperty("v3d", mitk::Vector3DProperty::New(v3d)); propList->SetProperty("annotation", mitk::AnnotationProperty::New("My Annotation", p3d)); propList->SetProperty("clipping", mitk::ClippingProperty::New(p3d, v3d)); propList->SetProperty("color", mitk::ColorProperty::New(1.0, 0.2, 0.2)); - // mitk::EnumerationProperty::Pointer en = mitk::EnumerationProperty::New(); - // en->AddEnum("PC", 1); en->AddEnum("Playstation", 2); en->AddEnum("Wii", 111); en->AddEnum("XBox", 7); - // en->SetValue("XBox"); - // propList->SetProperty("enum", en); - /* - propList->SetProperty("gridrep", mitk::GridRepresentationProperty::New(2)); - propList->SetProperty("gridvol", mitk::GridVolumeMapperProperty::New(0)); - */ propList->SetProperty("modality", mitk::ModalityProperty::New("Color Doppler")); - // propList->SetProperty("OdfNormalizationMethodProperty", mitk::OdfNormalizationMethodProperty::New("Global - // Maximum")); - // propList->SetProperty("OdfScaleByProperty", mitk::OdfScaleByProperty::New("Principal Curvature")); propList->SetProperty("PlaneOrientationProperty", mitk::PlaneOrientationProperty::New("Arrows in positive direction")); propList->SetProperty("VtkInterpolationProperty", mitk::VtkInterpolationProperty::New("Gouraud")); propList->SetProperty("VtkRepresentationProperty", mitk::VtkRepresentationProperty::New("Surface")); propList->SetProperty("VtkResliceInterpolationProperty", mitk::VtkResliceInterpolationProperty::New("Cubic")); propList->SetProperty("VtkScalarModeProperty", mitk::VtkScalarModeProperty::New("PointFieldData")); propList->SetProperty("VtkVolumeRenderingProperty", mitk::VtkVolumeRenderingProperty::New("COMPOSITE")); mitk::BoolLookupTable blt; blt.SetTableValue(0, true); blt.SetTableValue(1, false); blt.SetTableValue(2, true); propList->SetProperty("BoolLookupTableProperty", mitk::BoolLookupTableProperty::New(blt)); mitk::FloatLookupTable flt; flt.SetTableValue(0, 3.1); flt.SetTableValue(1, 3.3); flt.SetTableValue(2, 7.0); propList->SetProperty("FloatLookupTableProperty", mitk::FloatLookupTableProperty::New(flt)); mitk::IntLookupTable ilt; ilt.SetTableValue(0, 3); ilt.SetTableValue(1, 2); ilt.SetTableValue(2, 11); propList->SetProperty("IntLookupTableProperty", mitk::IntLookupTableProperty::New(ilt)); mitk::StringLookupTable slt; slt.SetTableValue(0, "Hello"); slt.SetTableValue(1, "MITK"); slt.SetTableValue(2, "world"); propList->SetProperty("StringLookupTableProperty", mitk::StringLookupTableProperty::New(slt)); propList->SetProperty("GroupTagProperty", mitk::GroupTagProperty::New()); propList->SetProperty("LevelWindowProperty", mitk::LevelWindowProperty::New(mitk::LevelWindow(100.0, 50.0))); mitk::LookupTable::Pointer lt = mitk::LookupTable::New(); lt->ChangeOpacityForAll(0.25); lt->ChangeOpacity(17, 0.88); propList->SetProperty("LookupTableProperty", mitk::LookupTableProperty::New(lt)); propList->SetProperty("StringProperty", mitk::StringProperty::New("Oh why, gruel world")); - // mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); - // tf->SetTransferFunctionMode(1); - // propList->SetProperty("TransferFunctionProperty", mitk::TransferFunctionProperty::New(tf)); MITK_TEST_CONDITION_REQUIRED(propList->GetMap()->size() > 0, "Initialize PropertyList"); TestAllProperties(propList); /* test default property lists of basedata objects */ // activate the following tests after MaterialProperty is deleted mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitk::PointSet::New()); TestAllProperties(node->GetPropertyList()); node->SetData(mitk::Image::New()); TestAllProperties(node->GetPropertyList()); node->SetData(mitk::Surface::New()); TestAllProperties(node->GetPropertyList()); node->SetData(mitk::VtkWidgetRendering::New()); TestAllProperties(node->GetPropertyList()); - /* - node->SetData(mitk::Contour::New()); - TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::ContourSet::New()); - TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::Mesh::New()); - TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::Cone::New()); - TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::Cuboid::New()); - TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::Cylinder::New()); - TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::Ellipsoid::New()); - TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::ExtrudedContour::New()); - TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::Plane::New()); - TestAllProperties(node->GetPropertyList()); - //node->SetData(mitk::TrackingVolume::New()); // TrackingVolume is in IGT Module, it does not have special - properties, therefore we skip it here - //TestAllProperties(node->GetPropertyList()); - node->SetData(mitk::UnstructuredGrid::New()); - TestAllProperties(node->GetPropertyList()); - */ - - /* untested base data types: - BaseDataTestImplementation - RenderWindowFrame - GeometryData - mitk::PlaneGeometryData - GradientBackground - ItkBaseDataAdapter - SlicedData - OdfImage - SeedsImage - TensorImage - BoundingObject - BoundingObjectGroup - */ - MITK_TEST_END(); } void TestAllProperties(const mitk::PropertyList *propList) { assert(propList); /* try to serialize each property in the list, then deserialize again and check for equality */ for (auto it = propList->GetMap()->begin(); it != propList->GetMap()->end(); ++it) { const mitk::BaseProperty *prop = it->second; // construct name of serializer class std::string serializername = std::string(prop->GetNameOfClass()) + "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); MITK_TEST_CONDITION(allSerializers.size() > 0, std::string("Creating serializers for ") + serializername); if (allSerializers.size() == 0) { MITK_TEST_OUTPUT(<< "serialization not possible, skipping " << prop->GetNameOfClass()); continue; } if (allSerializers.size() > 1) { MITK_TEST_OUTPUT(<< "Warning: " << allSerializers.size() << " serializers found for " << prop->GetNameOfClass() << "testing only the first one."); } auto *serializer = dynamic_cast(allSerializers.begin()->GetPointer()); MITK_TEST_CONDITION(serializer != nullptr, serializername + std::string(" is valid")); if (serializer != nullptr) { serializer->SetProperty(prop); TiXmlElement *valueelement = nullptr; try { valueelement = serializer->Serialize(); } catch (...) { } MITK_TEST_CONDITION(valueelement != nullptr, std::string("Serialize property with ") + serializername); if (valueelement == nullptr) { MITK_TEST_OUTPUT(<< "serialization failed, skipping deserialization"); continue; } mitk::BaseProperty::Pointer deserializedProp = serializer->Deserialize(valueelement); MITK_TEST_CONDITION(deserializedProp.IsNotNull(), "serializer created valid property"); if (deserializedProp.IsNotNull()) { MITK_TEST_CONDITION(*(deserializedProp.GetPointer()) == *prop, "deserialized property equals initial property for type " << prop->GetNameOfClass()); } } else { MITK_TEST_OUTPUT(<< "created serializer object is of class " << allSerializers.begin()->GetPointer()->GetNameOfClass()) } } // for all properties } diff --git a/Modules/Segmentation/CMakeLists.txt b/Modules/Segmentation/CMakeLists.txt index 1ec269d597..1528dd107f 100644 --- a/Modules/Segmentation/CMakeLists.txt +++ b/Modules/Segmentation/CMakeLists.txt @@ -1,8 +1,9 @@ MITK_CREATE_MODULE( INCLUDE_DIRS Algorithms Controllers DataManagement Interactions Rendering SegmentationUtilities/BooleanOperations SegmentationUtilities/MorphologicalOperations DEPENDS MitkAlgorithmsExt MitkIpSegmentation MitkIpFunc MitkSurfaceInterpolation MitkGraphAlgorithms MitkContourModel MitkMultilabel PACKAGE_DEPENDS PUBLIC ITK|ITKBinaryMathematicalMorphology+ITKLabelVoting+ITKRegionGrowing+ITKFastMarching+ITKAnisotropicSmoothing+ITKWatersheds + PRIVATE VTK|ImagingGeneral ) add_subdirectory(Testing) diff --git a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp index 5793bd362f..7589742cdf 100644 --- a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp +++ b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp @@ -1,343 +1,343 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkComputeContourSetNormalsFilter.h" #include "mitkIOUtil.h" #include "mitkImagePixelReadAccessor.h" mitk::ComputeContourSetNormalsFilter::ComputeContourSetNormalsFilter() : m_SegmentationBinaryImage(nullptr), m_MaxSpacing(5), m_NegativeNormalCounter(0), m_PositiveNormalCounter(0), m_UseProgressBar(false), m_ProgressStepSize(1) { mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } mitk::ComputeContourSetNormalsFilter::~ComputeContourSetNormalsFilter() { } void mitk::ComputeContourSetNormalsFilter::GenerateData() { unsigned int numberOfInputs = this->GetNumberOfIndexedInputs(); // Iterating over each input for (unsigned int i = 0; i < numberOfInputs; i++) { // Getting the inputs polydata and polygons auto *currentSurface = this->GetInput(i); vtkPolyData *polyData = currentSurface->GetVtkPolyData(); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); - vtkIdType *cell(nullptr); + const vtkIdType *cell(nullptr); vtkIdType cellSize(0); // The array that contains all the vertex normals of the current polygon vtkSmartPointer normals = vtkSmartPointer::New(); normals->SetNumberOfComponents(3); normals->SetNumberOfTuples(polyData->GetNumberOfPoints()); // If the current contour is an inner contour then the direction is -1 // A contour lies inside another one if the pixel values in the direction of the normal is 1 m_NegativeNormalCounter = 0; m_PositiveNormalCounter = 0; vtkIdType offSet(0); // Iterating over each polygon for (existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { if (cellSize < 3) continue; // First we calculate the current polygon's normal double polygonNormal[3] = {0.0}; double p1[3]; double p2[3]; double v1[3]; double v2[3]; existingPoints->GetPoint(cell[0], p1); unsigned int index = cellSize * 0.5; existingPoints->GetPoint(cell[index], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; for (vtkIdType k = 2; k < cellSize; k++) { index = cellSize * 0.25; existingPoints->GetPoint(cell[index], p1); index = cellSize * 0.75; existingPoints->GetPoint(cell[index], p2); v2[0] = p2[0] - p1[0]; v2[1] = p2[1] - p1[1]; v2[2] = p2[2] - p1[2]; vtkMath::Cross(v1, v2, polygonNormal); if (vtkMath::Norm(polygonNormal) != 0) break; } vtkMath::Normalize(polygonNormal); // Now we start computing the normal for each vertex double vertexNormalTemp[3]; existingPoints->GetPoint(cell[0], p1); existingPoints->GetPoint(cell[1], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; vtkMath::Cross(v1, polygonNormal, vertexNormalTemp); vtkMath::Normalize(vertexNormalTemp); double vertexNormal[3]; for (vtkIdType j = 0; j < cellSize - 2; j++) { existingPoints->GetPoint(cell[j + 1], p1); existingPoints->GetPoint(cell[j + 2], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; vtkMath::Cross(v1, polygonNormal, vertexNormal); vtkMath::Normalize(vertexNormal); double finalNormal[3]; finalNormal[0] = (vertexNormal[0] + vertexNormalTemp[0]) * 0.5; finalNormal[1] = (vertexNormal[1] + vertexNormalTemp[1]) * 0.5; finalNormal[2] = (vertexNormal[2] + vertexNormalTemp[2]) * 0.5; vtkMath::Normalize(finalNormal); // Here we determine the direction of the normal if (m_SegmentationBinaryImage) { Point3D worldCoord; worldCoord[0] = p1[0] + finalNormal[0] * m_MaxSpacing; worldCoord[1] = p1[1] + finalNormal[1] * m_MaxSpacing; worldCoord[2] = p1[2] + finalNormal[2] * m_MaxSpacing; double val = 0.0; itk::Index<3> idx; m_SegmentationBinaryImage->GetGeometry()->WorldToIndex(worldCoord, idx); try { if (m_SegmentationBinaryImage->GetImageDescriptor() ->GetChannelDescriptor() .GetPixelType() .GetComponentType() == itk::ImageIOBase::UCHAR) { mitk::ImagePixelReadAccessor readAccess(m_SegmentationBinaryImage); val = readAccess.GetPixelByIndexSafe(idx); } else if (m_SegmentationBinaryImage->GetImageDescriptor() ->GetChannelDescriptor() .GetPixelType() .GetComponentType() == itk::ImageIOBase::USHORT) { mitk::ImagePixelReadAccessor readAccess(m_SegmentationBinaryImage); val = readAccess.GetPixelByIndexSafe(idx); } } catch (const mitk::Exception &e) { // If value is outside the image's region ignore it MITK_WARN << e.what(); } if (val == 0.0) { // MITK_INFO << "val equals zero."; ++m_PositiveNormalCounter; } else { // MITK_INFO << "val does not equal zero."; ++m_NegativeNormalCounter; } } vertexNormalTemp[0] = vertexNormal[0]; vertexNormalTemp[1] = vertexNormal[1]; vertexNormalTemp[2] = vertexNormal[2]; vtkIdType id = cell[j + 1]; normals->SetTuple(id, finalNormal); } existingPoints->GetPoint(cell[0], p1); existingPoints->GetPoint(cell[1], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; vtkMath::Cross(v1, polygonNormal, vertexNormal); vtkMath::Normalize(vertexNormal); vertexNormal[0] = (vertexNormal[0] + vertexNormalTemp[0]) * 0.5; vertexNormal[1] = (vertexNormal[1] + vertexNormalTemp[1]) * 0.5; vertexNormal[2] = (vertexNormal[2] + vertexNormalTemp[2]) * 0.5; vtkMath::Normalize(vertexNormal); vtkIdType id = cell[0]; normals->SetTuple(id, vertexNormal); id = cell[cellSize - 1]; normals->SetTuple(id, vertexNormal); if (m_NegativeNormalCounter > m_PositiveNormalCounter) { for (vtkIdType n = 0; n < cellSize; n++) { double normal[3]; normals->GetTuple(offSet + n, normal); normal[0] = (-1) * normal[0]; normal[1] = (-1) * normal[1]; normal[2] = (-1) * normal[2]; normals->SetTuple(offSet + n, normal); } } m_NegativeNormalCounter = 0; m_PositiveNormalCounter = 0; offSet += cellSize; } // end for all cells Surface::Pointer surface = this->GetOutput(i); surface->GetVtkPolyData()->GetCellData()->SetNormals(normals); } // end for all inputs // Setting progressbar if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(this->m_ProgressStepSize); } mitk::Surface::Pointer mitk::ComputeContourSetNormalsFilter::GetNormalsAsSurface() { // Just for debugging: vtkSmartPointer newPolyData = vtkSmartPointer::New(); vtkSmartPointer newLines = vtkSmartPointer::New(); vtkSmartPointer newPoints = vtkSmartPointer::New(); unsigned int idCounter(0); // Debug end for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); i++) { auto *currentSurface = this->GetOutput(i); vtkPolyData *polyData = currentSurface->GetVtkPolyData(); vtkSmartPointer currentCellNormals = vtkDoubleArray::SafeDownCast(polyData->GetCellData()->GetNormals()); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); - vtkIdType *cell(nullptr); + const vtkIdType *cell(nullptr); vtkIdType cellSize(0); for (existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { for (vtkIdType j = 0; j < cellSize; j++) { double currentNormal[3]; currentCellNormals->GetTuple(cell[j], currentNormal); vtkSmartPointer line = vtkSmartPointer::New(); line->GetPointIds()->SetNumberOfIds(2); double newPoint[3]; double p0[3]; existingPoints->GetPoint(cell[j], p0); newPoint[0] = p0[0] + currentNormal[0]; newPoint[1] = p0[1] + currentNormal[1]; newPoint[2] = p0[2] + currentNormal[2]; line->GetPointIds()->SetId(0, idCounter); newPoints->InsertPoint(idCounter, p0); idCounter++; line->GetPointIds()->SetId(1, idCounter); newPoints->InsertPoint(idCounter, newPoint); idCounter++; newLines->InsertNextCell(line); } // end for all points } // end for all cells } // end for all outputs newPolyData->SetPoints(newPoints); newPolyData->SetLines(newLines); newPolyData->BuildCells(); mitk::Surface::Pointer surface = mitk::Surface::New(); surface->SetVtkPolyData(newPolyData); return surface; } void mitk::ComputeContourSetNormalsFilter::SetMaxSpacing(double maxSpacing) { m_MaxSpacing = maxSpacing; } void mitk::ComputeContourSetNormalsFilter::GenerateOutputInformation() { Superclass::GenerateOutputInformation(); } void mitk::ComputeContourSetNormalsFilter::Reset() { for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++) { this->PopBackInput(); } this->SetNumberOfIndexedInputs(0); this->SetNumberOfIndexedOutputs(0); mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } void mitk::ComputeContourSetNormalsFilter::SetUseProgressBar(bool status) { this->m_UseProgressBar = status; } void mitk::ComputeContourSetNormalsFilter::SetProgressStepSize(unsigned int stepSize) { this->m_ProgressStepSize = stepSize; } diff --git a/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.cpp b/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.cpp index 76bd92b724..87de1560a1 100644 --- a/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.cpp +++ b/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.cpp @@ -1,617 +1,617 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkCreateDistanceImageFromSurfaceFilter.h" #include "mitkImageCast.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkPolyData.h" #include "vtkSmartPointer.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkNeighborhoodIterator.h" #include void mitk::CreateDistanceImageFromSurfaceFilter::CreateEmptyDistanceImage() { // Determine the bounds of the input points in index- and world-coordinates DistanceImageType::PointType minPointInWorldCoordinates, maxPointInWorldCoordinates; DistanceImageType::IndexType minPointInIndexCoordinates, maxPointInIndexCoordinates; DetermineBounds( minPointInWorldCoordinates, maxPointInWorldCoordinates, minPointInIndexCoordinates, maxPointInIndexCoordinates); // Calculate the extent of the region that contains all given points in MM. // To do this, we take the difference between the maximal and minimal // index-coordinates (must not be less than 1) and multiply it with the // spacing of the reference-image. Vector3D extentMM; for (unsigned int dim = 0; dim < 3; ++dim) { extentMM[dim] = (std::abs(maxPointInIndexCoordinates[dim] - minPointInIndexCoordinates[dim])) * m_ReferenceImage->GetSpacing()[dim]; } /* * Now create an empty distance image. The created image will always have the same number of pixels, independent from * the original image (e.g. always consists of 500000 pixels) and will have an isotropic spacing. * The spacing is calculated like the following: * The image's volume = 500000 Pixels = extentX*spacing*extentY*spacing*extentZ*spacing * So the spacing is: spacing = ( extentX*extentY*extentZ / 500000 )^(1/3) */ double basis = (extentMM[0] * extentMM[1] * extentMM[2]) / m_DistanceImageVolume; double exponent = 1.0 / 3.0; m_DistanceImageSpacing = pow(basis, exponent); // calculate the number of pixels of the distance image for each direction unsigned int numberOfXPixel = extentMM[0] / m_DistanceImageSpacing; unsigned int numberOfYPixel = extentMM[1] / m_DistanceImageSpacing; unsigned int numberOfZPixel = extentMM[2] / m_DistanceImageSpacing; // We increase the sizeOfRegion by 4 as we decrease the origin by 2 later. // This expansion of the region is necessary to achieve a complete // interpolation. DistanceImageType::SizeType sizeOfRegion; sizeOfRegion[0] = numberOfXPixel + 8; sizeOfRegion[1] = numberOfYPixel + 8; sizeOfRegion[2] = numberOfZPixel + 8; // The region starts at index 0,0,0 DistanceImageType::IndexType initialOriginAsIndex; initialOriginAsIndex.Fill(0); DistanceImageType::PointType originAsWorld = minPointInWorldCoordinates; DistanceImageType::RegionType lpRegion; lpRegion.SetSize(sizeOfRegion); lpRegion.SetIndex(initialOriginAsIndex); // We initialize the itk::Image with // * origin and direction to have it correctly placed and rotated in the world // * the largest possible region to set the extent to be calculated // * the isotropic spacing that we have calculated above m_DistanceImageITK = DistanceImageType::New(); m_DistanceImageITK->SetOrigin(originAsWorld); m_DistanceImageITK->SetDirection(m_ReferenceImage->GetDirection()); m_DistanceImageITK->SetRegions(lpRegion); m_DistanceImageITK->SetSpacing(m_DistanceImageSpacing); m_DistanceImageITK->Allocate(); // First of all the image is initialized with the value 10*m_DistanceImageSpacing for each pixel m_DistanceImageDefaultBufferValue = 10 * m_DistanceImageSpacing; m_DistanceImageITK->FillBuffer(m_DistanceImageDefaultBufferValue); // Now we move the origin of the distanceImage 2 index-Coordinates // in all directions DistanceImageType::IndexType originAsIndex; m_DistanceImageITK->TransformPhysicalPointToIndex(originAsWorld, originAsIndex); originAsIndex[0] -= 2; originAsIndex[1] -= 2; originAsIndex[2] -= 2; m_DistanceImageITK->TransformIndexToPhysicalPoint(originAsIndex, originAsWorld); m_DistanceImageITK->SetOrigin(originAsWorld); } mitk::CreateDistanceImageFromSurfaceFilter::CreateDistanceImageFromSurfaceFilter() : m_DistanceImageSpacing(0.0), m_DistanceImageDefaultBufferValue(0.0) { m_DistanceImageVolume = 50000; this->m_UseProgressBar = false; this->m_ProgressStepSize = 5; mitk::Image::Pointer output = mitk::Image::New(); this->SetNthOutput(0, output.GetPointer()); } mitk::CreateDistanceImageFromSurfaceFilter::~CreateDistanceImageFromSurfaceFilter() { } void mitk::CreateDistanceImageFromSurfaceFilter::GenerateData() { this->PreprocessContourPoints(); this->CreateEmptyDistanceImage(); // First of all we have to build the equation-system from the existing contour-edge-points this->CreateSolutionMatrixAndFunctionValues(); if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(1); m_Weights = m_SolutionMatrix.partialPivLu().solve(m_FunctionValues); if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(2); // The last step is to create the distance map with the interpolated distance function this->FillDistanceImage(); if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(2); m_Centers.clear(); m_Normals.clear(); } void mitk::CreateDistanceImageFromSurfaceFilter::PreprocessContourPoints() { unsigned int numberOfInputs = this->GetNumberOfIndexedInputs(); if (numberOfInputs == 0) { MITK_ERROR << "mitk::CreateDistanceImageFromSurfaceFilter: No input available. Please set an input!" << std::endl; itkExceptionMacro("mitk::CreateDistanceImageFromSurfaceFilter: No input available. Please set an input!"); return; } // First of all we have to extract the nomals and the surface points. // Duplicated points can be eliminated vtkSmartPointer polyData; vtkSmartPointer currentCellNormals; vtkSmartPointer existingPolys; vtkSmartPointer existingPoints; double p[3]; PointType currentPoint; PointType normal; for (unsigned int i = 0; i < numberOfInputs; i++) { auto currentSurface = this->GetInput(i); polyData = currentSurface->GetVtkPolyData(); if (polyData->GetNumberOfPolys() == 0) { MITK_INFO << "mitk::CreateDistanceImageFromSurfaceFilter: No input-polygons available. Please be sure the input " "surface consists of polygons!" << std::endl; } currentCellNormals = vtkDoubleArray::SafeDownCast(polyData->GetCellData()->GetNormals()); existingPolys = polyData->GetPolys(); existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); - vtkIdType *cell(nullptr); + const vtkIdType *cell(nullptr); vtkIdType cellSize(0); for (existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { for (vtkIdType j = 0; j < cellSize; j++) { existingPoints->GetPoint(cell[j], p); currentPoint.copy_in(p); int count = std::count(m_Centers.begin(), m_Centers.end(), currentPoint); if (count == 0) { double currentNormal[3]; currentCellNormals->GetTuple(cell[j], currentNormal); normal.copy_in(currentNormal); m_Normals.push_back(normal); m_Centers.push_back(currentPoint); } } // end for all points } // end for all cells } // end for all outputs } void mitk::CreateDistanceImageFromSurfaceFilter::CreateSolutionMatrixAndFunctionValues() { // For we can now calculate the exact size of the centers we initialize the data structures unsigned int numberOfCenters = m_Centers.size(); m_Centers.reserve(numberOfCenters * 3); m_FunctionValues.resize(numberOfCenters * 3); m_FunctionValues.fill(0); PointType currentPoint; PointType normal; // Create inner points for (unsigned int i = 0; i < numberOfCenters; i++) { currentPoint = m_Centers.at(i); normal = m_Normals.at(i); currentPoint[0] = currentPoint[0] - normal[0] * m_DistanceImageSpacing; currentPoint[1] = currentPoint[1] - normal[1] * m_DistanceImageSpacing; currentPoint[2] = currentPoint[2] - normal[2] * m_DistanceImageSpacing; m_Centers.push_back(currentPoint); m_FunctionValues[numberOfCenters + i] = -m_DistanceImageSpacing; } // Create outer points for (unsigned int i = 0; i < numberOfCenters; i++) { currentPoint = m_Centers.at(i); normal = m_Normals.at(i); currentPoint[0] = currentPoint[0] + normal[0] * m_DistanceImageSpacing; currentPoint[1] = currentPoint[1] + normal[1] * m_DistanceImageSpacing; currentPoint[2] = currentPoint[2] + normal[2] * m_DistanceImageSpacing; m_Centers.push_back(currentPoint); m_FunctionValues[numberOfCenters * 2 + i] = m_DistanceImageSpacing; } // Now we have created all centers and all function values. Next step is to create the solution matrix numberOfCenters = m_Centers.size(); m_SolutionMatrix.resize(numberOfCenters, numberOfCenters); m_Weights.resize(numberOfCenters); PointType p1; PointType p2; double norm; for (unsigned int i = 0; i < numberOfCenters; i++) { for (unsigned int j = 0; j < numberOfCenters; j++) { // Calculate the RBF value. Currently using Phi(r) = r with r is the euclidian distance between two points p1 = m_Centers.at(i); p2 = m_Centers.at(j); p1 = p1 - p2; norm = p1.two_norm(); m_SolutionMatrix(i, j) = norm; } } } void mitk::CreateDistanceImageFromSurfaceFilter::FillDistanceImage() { /* * Now we must calculate the distance for each pixel. But instead of calculating the distance value * for all of the image's pixels we proceed similar to the region growing algorithm: * * 1. Take the first pixel from the narrowband_point_list and calculate the distance for each neighbor (6er) * 2. If the current index's distance value is below a certain threshold push it into the list * 3. Next iteration take the next index from the list and originAsIndex with 1. again * * This is done until the narrowband_point_list is empty. */ typedef itk::ImageRegionIteratorWithIndex ImageIterator; typedef itk::NeighborhoodIterator NeighborhoodImageIterator; std::queue narrowbandPoints; PointType currentPoint = m_Centers.at(0); double distance = this->CalculateDistanceValue(currentPoint); // create itk::Point from vnl_vector DistanceImageType::PointType currentPointAsPoint; currentPointAsPoint[0] = currentPoint[0]; currentPointAsPoint[1] = currentPoint[1]; currentPointAsPoint[2] = currentPoint[2]; // Transform the input point in world-coordinates to index-coordinates DistanceImageType::IndexType currentIndex; m_DistanceImageITK->TransformPhysicalPointToIndex(currentPointAsPoint, currentIndex); assert( m_DistanceImageITK->GetLargestPossibleRegion().IsInside(currentIndex)); // we are quite certain this should hold narrowbandPoints.push(currentIndex); m_DistanceImageITK->SetPixel(currentIndex, distance); NeighborhoodImageIterator::RadiusType radius; radius.Fill(1); NeighborhoodImageIterator nIt(radius, m_DistanceImageITK, m_DistanceImageITK->GetLargestPossibleRegion()); unsigned int relativeNbIdx[] = {4, 10, 12, 14, 16, 22}; bool isInBounds = false; while (!narrowbandPoints.empty()) { nIt.SetLocation(narrowbandPoints.front()); narrowbandPoints.pop(); unsigned int *relativeNb = &relativeNbIdx[0]; for (int i = 0; i < 6; i++) { nIt.GetPixel(*relativeNb, isInBounds); if (isInBounds && nIt.GetPixel(*relativeNb) == m_DistanceImageDefaultBufferValue) { currentIndex = nIt.GetIndex(*relativeNb); // Transform the currently checked point from index-coordinates to // world-coordinates m_DistanceImageITK->TransformIndexToPhysicalPoint(currentIndex, currentPointAsPoint); // create a vnl_vector currentPoint[0] = currentPointAsPoint[0]; currentPoint[1] = currentPointAsPoint[1]; currentPoint[2] = currentPointAsPoint[2]; // and check the distance distance = this->CalculateDistanceValue(currentPoint); if (std::fabs(distance) <= m_DistanceImageSpacing * 2) { nIt.SetPixel(*relativeNb, distance); narrowbandPoints.push(currentIndex); } } relativeNb++; } } ImageIterator imgRegionIterator(m_DistanceImageITK, m_DistanceImageITK->GetLargestPossibleRegion()); imgRegionIterator.GoToBegin(); double prevPixelVal = 1; DistanceImageType::IndexType _size; _size.Fill(-1); _size += m_DistanceImageITK->GetLargestPossibleRegion().GetSize(); // Set every pixel inside the surface to -m_DistanceImageDefaultBufferValue except the edge point (so that the // received surface is closed) while (!imgRegionIterator.IsAtEnd()) { if (imgRegionIterator.Get() == m_DistanceImageDefaultBufferValue && prevPixelVal < 0) { while (imgRegionIterator.Get() == m_DistanceImageDefaultBufferValue) { if (imgRegionIterator.GetIndex()[0] == _size[0] || imgRegionIterator.GetIndex()[1] == _size[1] || imgRegionIterator.GetIndex()[2] == _size[2] || imgRegionIterator.GetIndex()[0] == 0U || imgRegionIterator.GetIndex()[1] == 0U || imgRegionIterator.GetIndex()[2] == 0U) { imgRegionIterator.Set(m_DistanceImageDefaultBufferValue); prevPixelVal = m_DistanceImageDefaultBufferValue; ++imgRegionIterator; break; } else { imgRegionIterator.Set((-1) * m_DistanceImageDefaultBufferValue); ++imgRegionIterator; prevPixelVal = (-1) * m_DistanceImageDefaultBufferValue; } } } else if (imgRegionIterator.GetIndex()[0] == _size[0] || imgRegionIterator.GetIndex()[1] == _size[1] || imgRegionIterator.GetIndex()[2] == _size[2] || imgRegionIterator.GetIndex()[0] == 0U || imgRegionIterator.GetIndex()[1] == 0U || imgRegionIterator.GetIndex()[2] == 0U) { imgRegionIterator.Set(m_DistanceImageDefaultBufferValue); prevPixelVal = m_DistanceImageDefaultBufferValue; ++imgRegionIterator; } else { prevPixelVal = imgRegionIterator.Get(); ++imgRegionIterator; } } Image::Pointer resultImage = this->GetOutput(); // Cast the created distance-Image from itk::Image to the mitk::Image // that is our output. CastToMitkImage(m_DistanceImageITK, resultImage); } double mitk::CreateDistanceImageFromSurfaceFilter::CalculateDistanceValue(PointType p) { double distanceValue(0); PointType p1; PointType p2; double norm; CenterList::iterator centerIter; unsigned int count(0); for (centerIter = m_Centers.begin(); centerIter != m_Centers.end(); centerIter++) { p1 = *centerIter; p2 = p - p1; norm = p2.two_norm(); distanceValue = distanceValue + (norm * m_Weights[count]); ++count; } return distanceValue; } void mitk::CreateDistanceImageFromSurfaceFilter::GenerateOutputInformation() { } void mitk::CreateDistanceImageFromSurfaceFilter::PrintEquationSystem() { std::stringstream out; out << "Nummber of rows: " << m_SolutionMatrix.rows() << " ****** Number of columns: " << m_SolutionMatrix.cols() << endl; out << "[ "; for (int i = 0; i < m_SolutionMatrix.rows(); i++) { for (int j = 0; j < m_SolutionMatrix.cols(); j++) { out << m_SolutionMatrix(i, j) << " "; } out << ";" << endl; } out << " ]\n\n\n"; for (unsigned int i = 0; i < m_Centers.size(); i++) { out << m_Centers.at(i) << ";" << endl; } std::cout << "Equation system: \n\n\n" << out.str(); } void mitk::CreateDistanceImageFromSurfaceFilter::SetInput(const mitk::Surface *surface) { this->SetInput(0, surface); } void mitk::CreateDistanceImageFromSurfaceFilter::SetInput(unsigned int idx, const mitk::Surface *surface) { if (this->GetInput(idx) != surface) { this->SetNthInput(idx, const_cast(surface)); this->Modified(); } } const mitk::Surface *mitk::CreateDistanceImageFromSurfaceFilter::GetInput() { if (this->GetNumberOfIndexedInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::Surface *mitk::CreateDistanceImageFromSurfaceFilter::GetInput(unsigned int idx) { if (this->GetNumberOfIndexedInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(idx)); } void mitk::CreateDistanceImageFromSurfaceFilter::RemoveInputs(mitk::Surface *input) { DataObjectPointerArraySizeType nb = this->GetNumberOfIndexedInputs(); for (DataObjectPointerArraySizeType i = 0; i < nb; i++) { if (this->GetInput(i) == input) { this->RemoveInput(i); return; } } } void mitk::CreateDistanceImageFromSurfaceFilter::Reset() { for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++) { this->PopBackInput(); } this->SetNumberOfIndexedInputs(0); this->SetNumberOfIndexedOutputs(1); mitk::Image::Pointer output = mitk::Image::New(); this->SetNthOutput(0, output.GetPointer()); } void mitk::CreateDistanceImageFromSurfaceFilter::SetUseProgressBar(bool status) { this->m_UseProgressBar = status; } void mitk::CreateDistanceImageFromSurfaceFilter::SetProgressStepSize(unsigned int stepSize) { this->m_ProgressStepSize = stepSize; } void mitk::CreateDistanceImageFromSurfaceFilter::SetReferenceImage(itk::ImageBase<3>::Pointer referenceImage) { m_ReferenceImage = referenceImage; } void mitk::CreateDistanceImageFromSurfaceFilter::DetermineBounds( DistanceImageType::PointType &minPointInWorldCoordinates, DistanceImageType::PointType &maxPointInWorldCoordinates, DistanceImageType::IndexType &minPointInIndexCoordinates, DistanceImageType::IndexType &maxPointInIndexCoordinates) { PointType firstCenter = m_Centers.at(0); DistanceImageType::PointType tmpPoint; tmpPoint[0] = firstCenter[0]; tmpPoint[1] = firstCenter[1]; tmpPoint[2] = firstCenter[2]; // transform the first point from world-coordinates to index-coordinates itk::ContinuousIndex tmpIndex; m_ReferenceImage->TransformPhysicalPointToContinuousIndex(tmpPoint, tmpIndex); // initialize the variables with this first point DistanceImageType::IndexValueType xmin = tmpIndex[0]; DistanceImageType::IndexValueType ymin = tmpIndex[1]; DistanceImageType::IndexValueType zmin = tmpIndex[2]; DistanceImageType::IndexValueType xmax = tmpIndex[0]; DistanceImageType::IndexValueType ymax = tmpIndex[1]; DistanceImageType::IndexValueType zmax = tmpIndex[2]; // iterate over the rest of the points auto centerIter = m_Centers.begin(); for (++centerIter; centerIter != m_Centers.end(); centerIter++) { tmpPoint[0] = (*centerIter)[0]; tmpPoint[1] = (*centerIter)[1]; tmpPoint[2] = (*centerIter)[2]; // transform each point from world-coordinates to index-coordinates m_ReferenceImage->TransformPhysicalPointToContinuousIndex(tmpPoint, tmpIndex); // and set the variables accordingly to find the minimum // and maximum in all directions in index-coordinates if (xmin > tmpIndex[0]) { xmin = tmpIndex[0]; } if (ymin > tmpIndex[1]) { ymin = tmpIndex[1]; } if (zmin > tmpIndex[2]) { zmin = tmpIndex[2]; } if (xmax < tmpIndex[0]) { xmax = tmpIndex[0]; } if (ymax < tmpIndex[1]) { ymax = tmpIndex[1]; } if (zmax < tmpIndex[2]) { zmax = tmpIndex[2]; } } // put the found coordinates into Index-Points minPointInIndexCoordinates[0] = xmin; minPointInIndexCoordinates[1] = ymin; minPointInIndexCoordinates[2] = zmin; maxPointInIndexCoordinates[0] = xmax; maxPointInIndexCoordinates[1] = ymax; maxPointInIndexCoordinates[2] = zmax; // and transform them into world-coordinates m_ReferenceImage->TransformIndexToPhysicalPoint(minPointInIndexCoordinates, minPointInWorldCoordinates); m_ReferenceImage->TransformIndexToPhysicalPoint(maxPointInIndexCoordinates, maxPointInWorldCoordinates); } diff --git a/Modules/SurfaceInterpolation/mitkReduceContourSetFilter.cpp b/Modules/SurfaceInterpolation/mitkReduceContourSetFilter.cpp index d8b3ccf9f3..23d47270e0 100644 --- a/Modules/SurfaceInterpolation/mitkReduceContourSetFilter.cpp +++ b/Modules/SurfaceInterpolation/mitkReduceContourSetFilter.cpp @@ -1,519 +1,519 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkReduceContourSetFilter.h" mitk::ReduceContourSetFilter::ReduceContourSetFilter() { m_MaxSegmentLenght = 0; m_StepSize = 10; m_Tolerance = -1; m_ReductionType = DOUGLAS_PEUCKER; m_MaxSpacing = -1; m_MinSpacing = -1; this->m_UseProgressBar = false; this->m_ProgressStepSize = 1; m_NumberOfPointsAfterReduction = 0; mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } mitk::ReduceContourSetFilter::~ReduceContourSetFilter() { } void mitk::ReduceContourSetFilter::SetInput(unsigned int idx, const mitk::Surface *surface) { this->SetNthInput(idx, const_cast(surface)); this->Modified(); } void mitk::ReduceContourSetFilter::SetInput(const mitk::Surface *surface) { this->SetInput(0, surface); } void mitk::ReduceContourSetFilter::GenerateData() { unsigned int numberOfInputs = this->GetNumberOfIndexedInputs(); unsigned int numberOfOutputs(0); vtkSmartPointer newPolyData; vtkSmartPointer newPolygons; vtkSmartPointer newPoints; // For the purpose of evaluation // unsigned int numberOfPointsBefore (0); m_NumberOfPointsAfterReduction = 0; for (unsigned int i = 0; i < numberOfInputs; i++) { auto *currentSurface = this->GetInput(i); vtkSmartPointer polyData = currentSurface->GetVtkPolyData(); newPolyData = vtkSmartPointer::New(); newPolygons = vtkSmartPointer::New(); newPoints = vtkSmartPointer::New(); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); - vtkIdType *cell(nullptr); + const vtkIdType *cell(nullptr); vtkIdType cellSize(0); for (existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { bool incorporatePolygon = this->CheckForIntersection(cell, cellSize, existingPoints, /*numberOfIntersections, intersectionPoints, */ i); if (!incorporatePolygon) continue; vtkSmartPointer newPolygon = vtkSmartPointer::New(); if (m_ReductionType == NTH_POINT) { this->ReduceNumberOfPointsByNthPoint(cellSize, cell, existingPoints, newPolygon, newPoints); if (newPolygon->GetPointIds()->GetNumberOfIds() != 0) { newPolygons->InsertNextCell(newPolygon); } } else if (m_ReductionType == DOUGLAS_PEUCKER) { this->ReduceNumberOfPointsByDouglasPeucker(cellSize, cell, existingPoints, newPolygon, newPoints); if (newPolygon->GetPointIds()->GetNumberOfIds() > 3) { newPolygons->InsertNextCell(newPolygon); } } // Again for evaluation // numberOfPointsBefore += cellSize; m_NumberOfPointsAfterReduction += newPolygon->GetPointIds()->GetNumberOfIds(); } if (newPolygons->GetNumberOfCells() != 0) { newPolyData->SetPolys(newPolygons); newPolyData->SetPoints(newPoints); newPolyData->BuildLinks(); this->SetNumberOfIndexedOutputs(numberOfOutputs + 1); mitk::Surface::Pointer surface = mitk::Surface::New(); this->SetNthOutput(numberOfOutputs, surface.GetPointer()); surface->SetVtkPolyData(newPolyData); numberOfOutputs++; } } // MITK_INFO<<"Points before: "<SetNumberOfIndexedOutputs(numberOfOutputs); if (numberOfOutputs == 0) { mitk::Surface::Pointer tmp_output = mitk::Surface::New(); tmp_output->SetVtkPolyData(vtkPolyData::New()); this->SetNthOutput(0, tmp_output.GetPointer()); } // Setting progressbar if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(this->m_ProgressStepSize); } void mitk::ReduceContourSetFilter::ReduceNumberOfPointsByNthPoint( - vtkIdType cellSize, vtkIdType *cell, vtkPoints *points, vtkPolygon *reducedPolygon, vtkPoints *reducedPoints) + vtkIdType cellSize, const vtkIdType *cell, vtkPoints *points, vtkPolygon *reducedPolygon, vtkPoints *reducedPoints) { unsigned int newNumberOfPoints(0); unsigned int mod = cellSize % m_StepSize; if (mod == 0) { newNumberOfPoints = cellSize / m_StepSize; } else { newNumberOfPoints = ((cellSize - mod) / m_StepSize) + 1; } if (newNumberOfPoints <= 3) { return; } reducedPolygon->GetPointIds()->SetNumberOfIds(newNumberOfPoints); reducedPolygon->GetPoints()->SetNumberOfPoints(newNumberOfPoints); for (vtkIdType i = 0; i < cellSize; i++) { if (i % m_StepSize == 0) { double point[3]; points->GetPoint(cell[i], point); vtkIdType id = reducedPoints->InsertNextPoint(point); reducedPolygon->GetPointIds()->SetId(i / m_StepSize, id); } } vtkIdType id = cell[0]; double point[3]; points->GetPoint(id, point); id = reducedPoints->InsertNextPoint(point); reducedPolygon->GetPointIds()->SetId(newNumberOfPoints - 1, id); } void mitk::ReduceContourSetFilter::ReduceNumberOfPointsByDouglasPeucker( - vtkIdType cellSize, vtkIdType *cell, vtkPoints *points, vtkPolygon *reducedPolygon, vtkPoints *reducedPoints) + vtkIdType cellSize, const vtkIdType *cell, vtkPoints *points, vtkPolygon *reducedPolygon, vtkPoints *reducedPoints) { // If the cell is too small to obtain a reduced polygon with the given stepsize return if (cellSize <= static_cast(m_StepSize * 3)) return; /* What we do now is (see the Douglas Peucker Algorithm): 1. Divide the current contour in two line segments (start - middle; middle - end), put them into the stack 2. Fetch first line segment and create the following vectors: - v1 = (start;end) - v2 = (start;currentPoint) -> for each point of the current line segment! 3. Calculate the distance from the currentPoint to v1: a. Determine the length of the orthogonal projection of v2 to v1 by: l = v2 * (normalized v1) b. There a three possibilities for the distance then: d = sqrt(lenght(v2)^2 - l^2) if l > 0 and l < length(v1) d = lenght(v2-v1) if l > 0 and l > lenght(v1) d = length(v2) if l < 0 because v2 is then pointing in a different direction than v1 4. Memorize the point with the biggest distance and create two new line segments with it at the end of the iteration and put it into the stack 5. If the distance value D <= m_Tolerance, then add the start and end index and the corresponding points to the reduced ones */ // First of all set tolerance if none is specified if (m_Tolerance < 0) { if (m_MaxSpacing > 0) { m_Tolerance = m_MinSpacing; } else { m_Tolerance = 1.5; } } std::stack lineSegments; // 1. Divide in line segments LineSegment ls2; ls2.StartIndex = cell[cellSize / 2]; ls2.EndIndex = cell[cellSize - 1]; lineSegments.push(ls2); LineSegment ls1; ls1.StartIndex = cell[0]; ls1.EndIndex = cell[cellSize / 2]; lineSegments.push(ls1); LineSegment currentSegment; double v1[3]; double v2[3]; double tempV[3]; double lenghtV1; double currentMaxDistance(0); vtkIdType currentMaxDistanceIndex(0); double l; double d; vtkIdType pointId(0); // Add the start index to the reduced points. From now on just the end indices will be added pointId = reducedPoints->InsertNextPoint(points->GetPoint(cell[0])); reducedPolygon->GetPointIds()->InsertNextId(pointId); while (!lineSegments.empty()) { currentSegment = lineSegments.top(); lineSegments.pop(); // 2. Create vectors points->GetPoint(currentSegment.EndIndex, tempV); points->GetPoint(currentSegment.StartIndex, v1); v1[0] = tempV[0] - v1[0]; v1[1] = tempV[1] - v1[1]; v1[2] = tempV[2] - v1[2]; lenghtV1 = vtkMath::Norm(v1); vtkMath::Normalize(v1); int range = currentSegment.EndIndex - currentSegment.StartIndex; for (int i = 1; i < abs(range); ++i) { points->GetPoint(currentSegment.StartIndex + i, tempV); points->GetPoint(currentSegment.StartIndex, v2); v2[0] = tempV[0] - v2[0]; v2[1] = tempV[1] - v2[1]; v2[2] = tempV[2] - v2[2]; // 3. Calculate the distance l = vtkMath::Dot(v2, v1); d = vtkMath::Norm(v2); if (l > 0 && l < lenghtV1) { d = sqrt((d * d - l * l)); } else if (l > 0 && l > lenghtV1) { tempV[0] = lenghtV1 * v1[0] - v2[0]; tempV[1] = lenghtV1 * v1[1] - v2[1]; tempV[2] = lenghtV1 * v1[2] - v2[2]; d = vtkMath::Norm(tempV); } // 4. Memorize maximum distance if (d > currentMaxDistance) { currentMaxDistance = d; currentMaxDistanceIndex = currentSegment.StartIndex + i; } } // 4. & 5. if (currentMaxDistance <= m_Tolerance) { // double temp[3]; int segmentLenght = currentSegment.EndIndex - currentSegment.StartIndex; if (segmentLenght > (int)m_MaxSegmentLenght) { m_MaxSegmentLenght = (unsigned int)segmentLenght; } // MITK_INFO<<"Lenght: "< 25) { unsigned int newLenght(segmentLenght); while (newLenght > 25) { newLenght = newLenght * 0.5; } unsigned int divisions = abs(segmentLenght) / newLenght; // MITK_INFO<<"Divisions: "<InsertNextPoint(points->GetPoint(currentSegment.StartIndex + newLenght * i)); reducedPolygon->GetPointIds()->InsertNextId(pointId); } } // MITK_INFO<<"Inserting END: "<InsertNextPoint(points->GetPoint(currentSegment.EndIndex)); reducedPolygon->GetPointIds()->InsertNextId(pointId); } else { ls2.StartIndex = currentMaxDistanceIndex; ls2.EndIndex = currentSegment.EndIndex; lineSegments.push(ls2); ls1.StartIndex = currentSegment.StartIndex; ls1.EndIndex = currentMaxDistanceIndex; lineSegments.push(ls1); } currentMaxDistance = 0; } } bool mitk::ReduceContourSetFilter::CheckForIntersection( - vtkIdType *currentCell, + const vtkIdType *currentCell, vtkIdType currentCellSize, vtkPoints *currentPoints, /* vtkIdType numberOfIntersections, vtkIdType* intersectionPoints,*/ unsigned int currentInputIndex) { /* If we check the current cell for intersections then we have to consider three possibilies: 1. There is another cell among all the other input surfaces which intersects the current polygon: - That means we have to save the intersection points because these points should not be eliminated 2. There current polygon exists just because of an intersection of another polygon with the current plane defined by the current polygon - That means the current polygon should not be incorporated and all of its points should be eliminated 3. There is no intersection - That mean we can just reduce the current polygons points without considering any intersections */ for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++) { // Don't check for intersection with the polygon itself if (i == currentInputIndex) continue; // Get the next polydata to check for intersection vtkSmartPointer poly = this->GetInput(i)->GetVtkPolyData(); vtkSmartPointer polygonArray = poly->GetPolys(); polygonArray->InitTraversal(); vtkIdType anotherInputPolygonSize(0); - vtkIdType *anotherInputPolygonIDs(nullptr); + const vtkIdType *anotherInputPolygonIDs(nullptr); /* The procedure is: - Create the equation of the plane, defined by the points of next input - Calculate the distance of each point of the current polygon to the plane - If the maximum distance is not bigger than 1.5 of the maximum spacing AND the minimal distance is not bigger than 0.5 of the minimum spacing then the current contour is an intersection contour */ for (polygonArray->InitTraversal(); polygonArray->GetNextCell(anotherInputPolygonSize, anotherInputPolygonIDs);) { // Choosing three plane points to calculate the plane vectors double p1[3]; double p2[3]; double p3[3]; // The plane vectors double v1[3]; double v2[3] = {0}; // The plane normal double normal[3]; // Create first Vector poly->GetPoint(anotherInputPolygonIDs[0], p1); poly->GetPoint(anotherInputPolygonIDs[1], p2); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; // Find 3rd point for 2nd vector (The angle between the two plane vectors should be bigger than 30 degrees) double maxDistance(0); double minDistance(10000); for (vtkIdType j = 2; j < anotherInputPolygonSize; j++) { poly->GetPoint(anotherInputPolygonIDs[j], p3); v2[0] = p3[0] - p1[0]; v2[1] = p3[1] - p1[1]; v2[2] = p3[2] - p1[2]; // Calculate the angle between the two vector for the current point double dotV1V2 = vtkMath::Dot(v1, v2); double absV1 = sqrt(vtkMath::Dot(v1, v1)); double absV2 = sqrt(vtkMath::Dot(v2, v2)); double cosV1V2 = dotV1V2 / (absV1 * absV2); double arccos = acos(cosV1V2); double degree = vtkMath::DegreesFromRadians(arccos); // If angle is bigger than 30 degrees break if (degree > 30) break; } // for (to find 3rd point) // Calculate normal of the plane by taking the cross product of the two vectors vtkMath::Cross(v1, v2, normal); vtkMath::Normalize(normal); // Determine position of the plane double lambda = vtkMath::Dot(normal, p1); /* Calculate the distance to the plane for each point of the current polygon If the distance is zero then save the currentPoint as intersection point */ for (vtkIdType k = 0; k < currentCellSize; k++) { double currentPoint[3]; currentPoints->GetPoint(currentCell[k], currentPoint); double tempPoint[3]; tempPoint[0] = normal[0] * currentPoint[0]; tempPoint[1] = normal[1] * currentPoint[1]; tempPoint[2] = normal[2] * currentPoint[2]; double temp = tempPoint[0] + tempPoint[1] + tempPoint[2] - lambda; double distance = fabs(temp); if (distance > maxDistance) { maxDistance = distance; } if (distance < minDistance) { minDistance = distance; } } // for (to calculate distance and intersections with currentPolygon) if (maxDistance < 1.5 * m_MaxSpacing && minDistance < 0.5 * m_MinSpacing) { return false; } // Because we are considering the plane defined by the acual input polygon only one iteration is sufficient // We do not need to consider each cell of the plane break; } // for (to traverse through all cells of actualInputPolyData) } // for (to iterate through all inputs) return true; } void mitk::ReduceContourSetFilter::GenerateOutputInformation() { Superclass::GenerateOutputInformation(); } void mitk::ReduceContourSetFilter::Reset() { for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++) { this->PopBackInput(); } this->SetNumberOfIndexedInputs(0); this->SetNumberOfIndexedOutputs(0); // BUG XXXXX Fix mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); m_NumberOfPointsAfterReduction = 0; } void mitk::ReduceContourSetFilter::SetUseProgressBar(bool status) { this->m_UseProgressBar = status; } void mitk::ReduceContourSetFilter::SetProgressStepSize(unsigned int stepSize) { this->m_ProgressStepSize = stepSize; } diff --git a/Modules/SurfaceInterpolation/mitkReduceContourSetFilter.h b/Modules/SurfaceInterpolation/mitkReduceContourSetFilter.h index 1f18b80580..89c447afe4 100644 --- a/Modules/SurfaceInterpolation/mitkReduceContourSetFilter.h +++ b/Modules/SurfaceInterpolation/mitkReduceContourSetFilter.h @@ -1,134 +1,134 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkReduceContourSetFilter_h_Included #define mitkReduceContourSetFilter_h_Included #include "mitkProgressBar.h" #include "mitkSurface.h" #include "mitkSurfaceToSurfaceFilter.h" #include #include "vtkCellArray.h" #include "vtkMath.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkPolygon.h" #include "vtkSmartPointer.h" #include namespace mitk { /** \brief A filter that reduces the number of points of contours represented by a mitk::Surface The type of the reduction can be set via SetReductionType. The two ways provided by this filter is the \li NTH_POINT Algorithm which reduces the contours according to a certain stepsize \li DOUGLAS_PEUCKER Algorithm which incorpates an error tolerance into the reduction. Stepsize and error tolerance can be set via SetStepSize and SetTolerance. Additional if more than one input contour is provided this filter tries detect contours which occur just because of an intersection. These intersection contours are eliminated. In oder to ensure a correct elimination the min and max spacing of the original image must be provided. The output is a mitk::Surface. $Author: fetzer$ */ class MITKSURFACEINTERPOLATION_EXPORT ReduceContourSetFilter : public SurfaceToSurfaceFilter { public: enum Reduction_Type { NTH_POINT, DOUGLAS_PEUCKER }; struct LineSegment { unsigned int StartIndex; unsigned int EndIndex; }; mitkClassMacro(ReduceContourSetFilter, SurfaceToSurfaceFilter); itkFactorylessNewMacro(Self); itkCloneMacro(Self); itkSetMacro(MinSpacing, double); itkSetMacro(MaxSpacing, double); itkSetMacro(ReductionType, Reduction_Type); itkSetMacro(StepSize, unsigned int); itkSetMacro(Tolerance, double); itkGetMacro(NumberOfPointsAfterReduction, unsigned int); // Resets the filter, i.e. removes all inputs and outputs void Reset(); /** \brief Set whether the mitkProgressBar should be used \a Parameter true for using the progress bar, false otherwise */ void SetUseProgressBar(bool); using itk::ProcessObject::SetInput; void SetInput(const mitk::Surface *surface) override; void SetInput(unsigned int idx, const mitk::Surface *surface) override; /** \brief Set the stepsize which the progress bar should proceed \a Parameter The stepsize for progressing */ void SetProgressStepSize(unsigned int stepSize); protected: ReduceContourSetFilter(); ~ReduceContourSetFilter() override; void GenerateData() override; void GenerateOutputInformation() override; private: void ReduceNumberOfPointsByNthPoint( - vtkIdType cellSize, vtkIdType *cell, vtkPoints *points, vtkPolygon *reducedPolygon, vtkPoints *reducedPoints); + vtkIdType cellSize, const vtkIdType *cell, vtkPoints *points, vtkPolygon *reducedPolygon, vtkPoints *reducedPoints); void ReduceNumberOfPointsByDouglasPeucker( - vtkIdType cellSize, vtkIdType *cell, vtkPoints *points, vtkPolygon *reducedPolygon, vtkPoints *reducedPoints); + vtkIdType cellSize, const vtkIdType *cell, vtkPoints *points, vtkPolygon *reducedPolygon, vtkPoints *reducedPoints); bool CheckForIntersection( - vtkIdType *currentCell, + const vtkIdType *currentCell, vtkIdType currentCellSize, vtkPoints *currentPoints, /*vtkIdType numberOfIntersections, vtkIdType* intersectionPoints,*/ unsigned int currentInputIndex); double m_MinSpacing; double m_MaxSpacing; Reduction_Type m_ReductionType; unsigned int m_StepSize; double m_Tolerance; unsigned int m_MaxSegmentLenght; bool m_UseProgressBar; unsigned int m_ProgressStepSize; unsigned int m_NumberOfPointsAfterReduction; }; // class } // namespace #endif diff --git a/Modules/ToFHardware/Testing/CMakeLists.txt b/Modules/ToFHardware/Testing/CMakeLists.txt index 99276c61d6..17c1070450 100644 --- a/Modules/ToFHardware/Testing/CMakeLists.txt +++ b/Modules/ToFHardware/Testing/CMakeLists.txt @@ -1,15 +1,15 @@ MITK_CREATE_MODULE_TESTS() if(TARGET ${TESTDRIVER}) - mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES VTK|vtkTestingRendering) + mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES VTK|TestingRendering) mitkAddCustomModuleTest(mitkPlayerLoadAndRenderDepthDataTest_KinectDepthImage #testname mitkPlayerLoadAndRenderDepthDataTest #testclassname Kinect_LiverPhantom_DistanceImage.nrrd #input image -V ${MITK_DATA_DIR}/ToF-Data/ReferenceScreenshots/Kinect_LiverPhantom_DistanceImage640x480REF.png #reference image ) mitkAddCustomModuleTest(mitkPlayerLoadAndRenderRGBDataTest_KinectRGBImage mitkPlayerLoadAndRenderRGBDataTest Kinect_LiverPhantom_RGBImage.nrrd -V ${MITK_DATA_DIR}/ToF-Data/ReferenceScreenshots/Kinect_LiverPhantom_RGBImage640x480REF.png) #rendering tests cannot run in parallel SET_PROPERTY(TEST mitkPlayerLoadAndRenderDepthDataTest_KinectDepthImage mitkPlayerLoadAndRenderRGBDataTest_KinectRGBImage PROPERTY RUN_SERIAL TRUE) endif() diff --git a/Modules/TubeGraph/src/Rendering/mitkTubeGraphVtkMapper3D.cpp b/Modules/TubeGraph/src/Rendering/mitkTubeGraphVtkMapper3D.cpp index a93bfd5371..864d163416 100644 --- a/Modules/TubeGraph/src/Rendering/mitkTubeGraphVtkMapper3D.cpp +++ b/Modules/TubeGraph/src/Rendering/mitkTubeGraphVtkMapper3D.cpp @@ -1,753 +1,753 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "mitkTubeGraphVtkMapper3D.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include mitk::TubeGraphVtkMapper3D::TubeGraphVtkMapper3D() { } mitk::TubeGraphVtkMapper3D::~TubeGraphVtkMapper3D() { } const mitk::TubeGraph *mitk::TubeGraphVtkMapper3D::GetInput() { return dynamic_cast(GetDataNode()->GetData()); } vtkProp *mitk::TubeGraphVtkMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { return m_LSH.GetLocalStorage(renderer)->m_vtkTubeGraphAssembly; } void mitk::TubeGraphVtkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { bool renderTubeGraph(false); LocalStorage *ls = m_LSH.GetLocalStorage(renderer); TubeGraph::Pointer tubeGraph = const_cast(this->GetInput()); TubeGraphProperty::Pointer tubeGraphProperty = dynamic_cast(tubeGraph->GetProperty("Tube Graph.Visualization Information").GetPointer()); if (tubeGraph.IsNull() || tubeGraphProperty.IsNull()) { itkWarningMacro(<< "Input of tube graph mapper is nullptr!"); return; } // Check if the tube graph has changed; if the data has changed, generate the spheres and tubes new; if (tubeGraph->GetMTime() > ls->m_lastGenerateDataTime) { this->GenerateTubeGraphData(renderer); renderTubeGraph = true; } else { // Check if the tube graph property has changed; if the property has changed, render the visualization information // new; if (tubeGraphProperty->GetMTime() > ls->m_lastRenderDataTime) { this->RenderTubeGraphPropertyInformation(renderer); renderTubeGraph = true; } } if (renderTubeGraph) { std::vector alreadyRenderedVertexList; // don't render the sphere which is the root of the graph; so add it to the list before; // TODO check both spheres TubeGraph::VertexDescriptorType root = tubeGraph->GetRootVertex(); alreadyRenderedVertexList.push_back(root); for (auto itTubes = ls->m_vtkTubesActorMap.begin(); itTubes != ls->m_vtkTubesActorMap.end(); itTubes++) { if (tubeGraphProperty->IsTubeVisible(itTubes->first)) { // add tube actor to assembly ls->m_vtkTubeGraphAssembly->AddPart(itTubes->second); // render the clipped spheres as end-cups of a tube and connections between tubes if (std::find(alreadyRenderedVertexList.begin(), alreadyRenderedVertexList.end(), itTubes->first.first) == alreadyRenderedVertexList.end()) { auto itSourceSphere = ls->m_vtkSpheresActorMap.find(itTubes->first.first); if (itSourceSphere != ls->m_vtkSpheresActorMap.end()) ls->m_vtkTubeGraphAssembly->AddPart(itSourceSphere->second); alreadyRenderedVertexList.push_back(itSourceSphere->first); } if (std::find(alreadyRenderedVertexList.begin(), alreadyRenderedVertexList.end(), itTubes->first.second) == alreadyRenderedVertexList.end()) { auto itTargetSphere = ls->m_vtkSpheresActorMap.find(itTubes->first.second); if (itTargetSphere != ls->m_vtkSpheresActorMap.end()) ls->m_vtkTubeGraphAssembly->AddPart(itTargetSphere->second); alreadyRenderedVertexList.push_back(itTargetSphere->first); } } } } //// Opacity TODO //{ // float opacity = 1.0f; // if( this->GetDataNode()->GetOpacity(opacity,renderer) ) // ls->m_vtkTubesActor->GetProperty()->SetOpacity( opacity ); //} } void mitk::TubeGraphVtkMapper3D::RenderTubeGraphPropertyInformation(mitk::BaseRenderer *renderer) { MITK_INFO << "Render tube graph property information!"; LocalStorage *ls = m_LSH.GetLocalStorage(renderer); TubeGraph::ConstPointer tubeGraph = this->GetInput(); TubeGraphProperty::Pointer tubeGraphProperty = dynamic_cast(tubeGraph->GetProperty("Tube Graph.Visualization Information").GetPointer()); if (tubeGraphProperty.IsNull()) { MITK_INFO << "No tube graph property!! So no special render information..."; return; } std::vector allVertices = tubeGraph->GetVectorOfAllVertices(); for (auto vertex = allVertices.begin(); vertex != allVertices.end(); ++vertex) { TubeGraph::VertexDescriptorType vertexDesc = tubeGraph->GetVertexDescriptor(*vertex); double sphereColorR = 0; double sphereColorG = 0; double sphereColorB = 0; int numberOfVisibleEdges = 0; std::vector allEdgesOfVertex = tubeGraph->GetAllEdgesOfAVertex(vertexDesc); for (auto edge = allEdgesOfVertex.begin(); edge != allEdgesOfVertex.end(); ++edge) { // get edge descriptor EdgeDescriptorType edgeDesc = tubeGraph->GetEdgeDescriptor(*edge); // get source and target vertex descriptor std::pair soureTargetPair = tubeGraph->GetVerticesOfAnEdge(edgeDesc); TubeGraphVertex source = soureTargetPair.first; TubeGraphVertex target = soureTargetPair.second; // build tube descriptor [sourceId,targetId] TubeGraph::TubeDescriptorType tube; tube.first = tubeGraph->GetVertexDescriptor(source); tube.second = tubeGraph->GetVertexDescriptor(target); if (tubeGraphProperty->IsTubeVisible(tube)) { mitk::Color tubeColor = tubeGraphProperty->GetColorOfTube(tube); vtkSmartPointer scalars = ls->m_vtkTubesActorMap[tube]->GetMapper()->GetInput()->GetPointData()->GetScalars(); double color[3]; scalars->GetTuple(0, color); if (color[0] != tubeColor[0] || color[1] != tubeColor[1] || color[2] != tubeColor[2]) { int numberOfPoints = scalars->GetSize(); vtkSmartPointer colorScalars = vtkSmartPointer::New(); colorScalars->SetName("colorScalars"); colorScalars->SetNumberOfComponents(3); colorScalars->SetNumberOfTuples(numberOfPoints); for (int i = 0; i < numberOfPoints; i++) { scalars->InsertTuple3(i, tubeColor[0], tubeColor[1], tubeColor[2]); } ls->m_vtkTubesActorMap[tube]->GetMapper()->GetInput()->GetPointData()->SetActiveScalars("colorScalars"); } sphereColorR += tubeColor[0]; sphereColorG += tubeColor[1]; sphereColorB += tubeColor[2]; numberOfVisibleEdges++; } } if (numberOfVisibleEdges > 0) { sphereColorR /= 255 * numberOfVisibleEdges; sphereColorG /= 255 * numberOfVisibleEdges; sphereColorB /= 255 * numberOfVisibleEdges; } ls->m_vtkSpheresActorMap[vertexDesc]->GetProperty()->SetColor(sphereColorR, sphereColorG, sphereColorB); } ls->m_lastRenderDataTime.Modified(); } void mitk::TubeGraphVtkMapper3D::GenerateTubeGraphData(mitk::BaseRenderer *renderer) { MITK_INFO << "Render tube graph!"; LocalStorage *ls = m_LSH.GetLocalStorage(renderer); ls->m_vtkTubesActorMap.clear(); ls->m_vtkSpheresActorMap.clear(); TubeGraph::Pointer tubeGraph = const_cast(this->GetInput()); TubeGraphProperty::Pointer tubeGraphProperty = dynamic_cast(tubeGraph->GetProperty("Tube Graph.Visualization Information").GetPointer()); if (tubeGraphProperty.IsNull()) MITK_INFO << "No tube graph property!! So no special render information..."; // render all edges as tubular structures using the vtkTubeFilter std::vector allEdges = tubeGraph->GetVectorOfAllEdges(); for (auto edge = allEdges.begin(); edge != allEdges.end(); ++edge) { this->GeneratePolyDataForTube(*edge, tubeGraph, tubeGraphProperty, renderer); } // Generate all vertices as spheres std::vector allVertices = tubeGraph->GetVectorOfAllVertices(); for (auto vertex = allVertices.begin(); vertex != allVertices.end(); ++vertex) { this->GeneratePolyDataForFurcation(*vertex, tubeGraph, renderer); if (this->ClipStructures()) { this->ClipPolyData(*vertex, tubeGraph, tubeGraphProperty, renderer); } ls->m_lastGenerateDataTime.Modified(); } } void mitk::TubeGraphVtkMapper3D::GeneratePolyDataForFurcation(mitk::TubeGraphVertex &vertex, const mitk::TubeGraph::Pointer &graph, mitk::BaseRenderer *renderer) { LocalStorage *ls = this->m_LSH.GetLocalStorage(renderer); mitk::Point3D coordinates; float diameter = 2; coordinates = (vertex.GetTubeElement())->GetCoordinates(); if (dynamic_cast(vertex.GetTubeElement())) { diameter = (dynamic_cast(vertex.GetTubeElement()))->GetDiameter(); } vtkSmartPointer sphereSource = vtkSmartPointer::New(); sphereSource->SetCenter(coordinates[0], coordinates[1], coordinates[2]); sphereSource->SetRadius(diameter / 2.0f); sphereSource->SetThetaResolution(12); sphereSource->SetPhiResolution(12); sphereSource->Update(); // generate a actor with a mapper for the sphere vtkSmartPointer sphereMapper = vtkSmartPointer::New(); vtkSmartPointer sphereActor = vtkSmartPointer::New(); sphereMapper->SetInputConnection(sphereSource->GetOutputPort()); sphereActor->SetMapper(sphereMapper); ls->m_vtkSpheresActorMap.insert(std::make_pair(graph->GetVertexDescriptor(vertex), sphereActor)); } void mitk::TubeGraphVtkMapper3D::GeneratePolyDataForTube(mitk::TubeGraphEdge &edge, const mitk::TubeGraph::Pointer &graph, const mitk::TubeGraphProperty::Pointer &graphProperty, mitk::BaseRenderer *renderer) { LocalStorage *ls = this->m_LSH.GetLocalStorage(renderer); // get edge descriptor EdgeDescriptorType edgeDesc = graph->GetEdgeDescriptor(edge); // get source and target vertex descriptor std::pair soureTargetPair = graph->GetVerticesOfAnEdge(edgeDesc); TubeGraphVertex source = soureTargetPair.first; TubeGraphVertex target = soureTargetPair.second; // build tube descriptor [sourceId,targetId] TubeGraph::TubeDescriptorType tube; tube.first = graph->GetVertexDescriptor(source); tube.second = graph->GetVertexDescriptor(target); Color color; if (graphProperty.IsNotNull()) { color = graphProperty->GetColorOfTube(tube); } else { color[0] = 150; color[1] = 150; color[2] = 150; } // add 2 points for the source and target vertices. unsigned int numberOfPoints = edge.GetNumberOfElements() + 2; // Initialize the required data-structures for building // an appropriate input to the tube filter vtkSmartPointer points = vtkSmartPointer::New(); points->SetNumberOfPoints(numberOfPoints); vtkSmartPointer radii = vtkSmartPointer::New(); radii->SetName("radii"); radii->SetNumberOfComponents(1); vtkSmartPointer lines = vtkSmartPointer::New(); vtkSmartPointer colorScalars = vtkSmartPointer::New(); colorScalars->SetName("colorScalars"); colorScalars->SetNumberOfComponents(3); // resize the data-arrays radii->SetNumberOfTuples(numberOfPoints); colorScalars->SetNumberOfTuples(numberOfPoints); lines->InsertNextCell(numberOfPoints); // Add the positions of the source node, the elements along the edge and // the target node as lines to a cell. This cell is used as input // for a Tube Filter mitk::Point3D coordinates; float diameter = 2; unsigned int id = 0; // Source Node coordinates = (source.GetTubeElement())->GetCoordinates(); if (dynamic_cast(source.GetTubeElement())) { diameter = (dynamic_cast(source.GetTubeElement()))->GetDiameter(); } points->InsertPoint(id, coordinates[0], coordinates[1], coordinates[2]); radii->InsertTuple1(id, diameter / 2.0f); colorScalars->InsertTuple3(id, color[0], color[1], color[2]); lines->InsertCellPoint(id); ++id; // Iterate along the edge std::vector allElements = edge.GetElementVector(); for (unsigned int index = 0; index < edge.GetNumberOfElements(); index++) { coordinates = allElements[index]->GetCoordinates(); if (dynamic_cast(allElements[index])) { diameter = (dynamic_cast(allElements[index]))->GetDiameter(); } points->InsertPoint(id, coordinates[0], coordinates[1], coordinates[2]); radii->InsertTuple1(id, diameter / 2.0f); colorScalars->InsertTuple3(id, color[0], color[1], color[2]); lines->InsertCellPoint(id); ++id; } // Target Node coordinates = (target.GetTubeElement())->GetCoordinates(); if (dynamic_cast(target.GetTubeElement())) { diameter = (dynamic_cast(target.GetTubeElement()))->GetDiameter(); } points->InsertPoint(id, coordinates[0], coordinates[1], coordinates[2]); radii->InsertTuple1(id, diameter / 2.0f); colorScalars->InsertTuple3(id, color[0], color[1], color[2]); lines->InsertCellPoint(id); ++id; // Initialize poly data from the point set and the cell array // (representing topology) vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(points); polyData->SetLines(lines); polyData->GetPointData()->AddArray(radii); polyData->GetPointData()->AddArray(colorScalars); polyData->GetPointData()->SetActiveScalars(radii->GetName()); // Generate a tube for all lines in the polydata object double *range = radii->GetRange(); assert(range[0] != 0.0f && range[1] != 0.0f); vtkSmartPointer tubeFilter = vtkSmartPointer::New(); tubeFilter->SetInputData(polyData); tubeFilter->SetRadius(range[0]); tubeFilter->SetRadiusFactor(range[1] / range[0]); if (range[0] != range[1]) tubeFilter->SetVaryRadiusToVaryRadiusByScalar(); tubeFilter->SetNumberOfSides(9); tubeFilter->SidesShareVerticesOn(); tubeFilter->CappingOff(); tubeFilter->Update(); tubeFilter->GetOutput()->GetPointData()->SetActiveScalars("colorScalars"); // generate a actor with a mapper for the vtkSmartPointer tubeMapper = vtkSmartPointer::New(); vtkSmartPointer tubeActor = vtkSmartPointer::New(); tubeMapper->SetInputConnection(tubeFilter->GetOutputPort()); tubeActor->SetMapper(tubeMapper); tubeActor->GetProperty()->SetColor(color[0], color[1], color[2]); ls->m_vtkTubesActorMap.insert(std::pair>(tube, tubeActor)); } void mitk::TubeGraphVtkMapper3D::ClipPolyData(mitk::TubeGraphVertex &vertex, const mitk::TubeGraph::Pointer &graph, const mitk::TubeGraphProperty::Pointer &graphProperty, mitk::BaseRenderer *renderer) { LocalStorage *ls = this->m_LSH.GetLocalStorage(renderer); mitk::Point3D centerVertex = vertex.GetTubeElement()->GetCoordinates(); float diameter = 2; if (dynamic_cast(vertex.GetTubeElement())) { diameter = (dynamic_cast(vertex.GetTubeElement()))->GetDiameter(); } TubeGraph::VertexDescriptorType vertexDesc = graph->GetVertexDescriptor(vertex); std::map> cylinderForClipping; // generate for all edges/tubes cylinders. With this structure you can clip the sphere and the other tubes, so that no // fragments are shown in the tube. std::vector allEdgesOfVertex = graph->GetAllEdgesOfAVertex(vertexDesc); for (auto edge = allEdgesOfVertex.begin(); edge != allEdgesOfVertex.end(); ++edge) { // get edge descriptor EdgeDescriptorType edgeDesc = graph->GetEdgeDescriptor(*edge); // get source and target vertex descriptor auto soureTargetPair = graph->GetVerticesOfAnEdge(edgeDesc); TubeGraphVertex source = soureTargetPair.first; TubeGraphVertex target = soureTargetPair.second; // build tube descriptor [sourceId,targetId] TubeGraph::TubeDescriptorType tube; tube.first = graph->GetVertexDescriptor(source); tube.second = graph->GetVertexDescriptor(target); // get reference point in the tube for the direction mitk::Point3D edgeDirectionPoint; // get reference diameter double cylinderDiameter = diameter; float radius = diameter / 2; // if the vertex is the source vertex of the edge get the first element of elementVector; otherwise get the last // element. if (source == vertex) { // if the edge has no element get the other vertex if ((*edge).GetNumberOfElements() != 0) { double lastDistance = 0, distance = 0; unsigned int index = 0; // Get the first element behind the radius of the sphere for (; index < (*edge).GetNumberOfElements(); index++) { mitk::Vector3D diffVec = (*edge).GetTubeElement(index)->GetCoordinates() - centerVertex; distance = std::sqrt(pow(diffVec[0], 2) + pow(diffVec[1], 2) + pow(diffVec[2], 2)); if (distance > radius) break; lastDistance = distance; } // if the last element is not inside the sphere if (index < (*edge).GetNumberOfElements()) { double withinSphereDiameter = diameter, outsideSphereDiameter = diameter, interpolationValue = 0.5; interpolationValue = (radius - lastDistance) / (distance - lastDistance); // if first element is outside of the sphere use sphere diameter and the element diameter for interpolation if (index == 0) { if (dynamic_cast((*edge).GetTubeElement(0))) outsideSphereDiameter = (dynamic_cast((*edge).GetTubeElement(0)))->GetDiameter(); } else { if (dynamic_cast((*edge).GetTubeElement(index - 1))) withinSphereDiameter = (dynamic_cast((*edge).GetTubeElement(index - 1)))->GetDiameter(); if (dynamic_cast((*edge).GetTubeElement(index))) outsideSphereDiameter = (dynamic_cast((*edge).GetTubeElement(index)))->GetDiameter(); } // interpolate the diameter for clipping cylinderDiameter = (1 - interpolationValue) * withinSphereDiameter + interpolationValue * outsideSphereDiameter; } // Get the reference point, so the direction of the tube can be calculated edgeDirectionPoint = (*edge).GetTubeElement(0)->GetCoordinates(); } else { // Get the reference point, so the direction of the tube can be calculated edgeDirectionPoint = target.GetTubeElement()->GetCoordinates(); } } // if vertex is target of the tube else { // if the edge has no element, get the other vertex if ((*edge).GetNumberOfElements() != 0) { double lastDistance = 0, distance = 0; // Get the first element behind the radius of the sphere; now backwards through the element list int index = (*edge).GetNumberOfElements(); for ( ; index >= 0; --index) { mitk::Vector3D diffVec = (*edge).GetTubeElement(index)->GetCoordinates() - centerVertex; distance = std::sqrt(pow(diffVec[0], 2) + pow(diffVec[1], 2) + pow(diffVec[2], 2)); if (distance > radius) break; lastDistance = distance; } if (index >= 0) { double withinSphereDiameter = diameter, outsideSphereDiameter = diameter, interpolationValue = 0.5; interpolationValue = (radius - lastDistance) / (distance - lastDistance); if (index == static_cast((*edge).GetNumberOfElements() - 1)) { if (dynamic_cast( (*edge).GetTubeElement((*edge).GetNumberOfElements() - 1))) outsideSphereDiameter = (dynamic_cast( (*edge).GetTubeElement((*edge).GetNumberOfElements() - 1))) ->GetDiameter(); } else { if (dynamic_cast((*edge).GetTubeElement(index + 1))) withinSphereDiameter = (dynamic_cast((*edge).GetTubeElement(index + 1)))->GetDiameter(); if (dynamic_cast((*edge).GetTubeElement(index))) outsideSphereDiameter = (dynamic_cast((*edge).GetTubeElement(index)))->GetDiameter(); } // interpolate the diameter for clipping cylinderDiameter = (1 - interpolationValue) * withinSphereDiameter + interpolationValue * outsideSphereDiameter; } // Get the reference point, so the direction of the tube can be calculated edgeDirectionPoint = (*edge).GetTubeElement((*edge).GetNumberOfElements() - 1)->GetCoordinates(); } else { // Get the reference point, so the direction of the tube can be calculated edgeDirectionPoint = source.GetTubeElement()->GetCoordinates(); } } //////Calculate the matrix for rotation and translation//// // get the normalized vector for the orientation (tube element direction) mitk::Vector3D vecOrientation; mitk::FillVector3D(vecOrientation, (edgeDirectionPoint[0] - centerVertex[0]), (edgeDirectionPoint[1] - centerVertex[1]), (edgeDirectionPoint[2] - centerVertex[2])); vecOrientation.Normalize(); // generate a random vector mitk::Vector3D vecRandom; mitk::FillVector3D(vecRandom, (rand() % 100 - 50), (rand() % 100 - 50), (rand() % 100 - 50)); // project the random vector on the plane-->orthogonal vector to plane normal; normalize it! mitk::Vector3D vecOrthoToOrientation; vecOrthoToOrientation = vecRandom - (vecRandom * vecOrientation) * vecOrientation; vecOrthoToOrientation.Normalize(); // get the cross product of both orthogonale vectors to get a third one mitk::Vector3D vecCrossProduct; vecCrossProduct = itk::CrossProduct(vecOrientation, vecOrthoToOrientation); vecCrossProduct.Normalize(); // Fill matrix vtkSmartPointer vtkTransformMatrix = vtkSmartPointer::New(); vtkTransformMatrix->Identity(); // 1. column vtkTransformMatrix->SetElement(0, 0, vecOrthoToOrientation[0]); vtkTransformMatrix->SetElement(1, 0, vecOrthoToOrientation[1]); vtkTransformMatrix->SetElement(2, 0, vecOrthoToOrientation[2]); // 2. column vtkTransformMatrix->SetElement(0, 1, vecOrientation[0]); vtkTransformMatrix->SetElement(1, 1, vecOrientation[1]); vtkTransformMatrix->SetElement(2, 1, vecOrientation[2]); // 3. column vtkTransformMatrix->SetElement(0, 2, vecCrossProduct[0]); vtkTransformMatrix->SetElement(1, 2, vecCrossProduct[1]); vtkTransformMatrix->SetElement(2, 2, vecCrossProduct[2]); // 4. column vtkTransformMatrix->SetElement(0, 3, centerVertex[0]); vtkTransformMatrix->SetElement(1, 3, centerVertex[1]); vtkTransformMatrix->SetElement(2, 3, centerVertex[2]); vtkSmartPointer transform = vtkSmartPointer::New(); transform->Concatenate(vtkTransformMatrix); // transform->Translate(centerVertex[0],centerVertex[1],centerVertex[2]); transform->Inverse(); transform->Update(); // Generate plane in center [0,0,0] with n= (0,1,0) as normal vector vtkSmartPointer plane = vtkSmartPointer::New(); plane->SetOrigin(0, 0, 0); plane->SetNormal(0, 1, 0); // Generate a cylinder in center [0,0,0] and the axes of rotation is along the y-axis; radius is vertex diameter/2; vtkSmartPointer cylinder = vtkSmartPointer::New(); cylinder->SetCenter(0, 0, 0); cylinder->SetRadius(cylinderDiameter / 2); // cylinder->SetTransform(transform); // Truncate the infinite cylinder with the plane vtkSmartPointer cutCylinder = vtkSmartPointer::New(); cutCylinder->SetOperationTypeToDifference(); cutCylinder->SetTransform(transform); cutCylinder->AddFunction(cylinder); cutCylinder->AddFunction(plane); cylinderForClipping.insert( std::pair>(tube, cutCylinder)); //// Sample the function // vtkSmartPointer sample = vtkSmartPointer::New(); // sample->SetSampleDimensions(100,100,100); // sample->SetImplicitFunction(cutCylinder); ////double value = 200.0; // double xmin = centerVertex[0]-(2*diameter), xmax = centerVertex[0]+(2*diameter), // ymin = centerVertex[1]-(2*diameter), ymax = centerVertex[1]+(2*diameter), // zmin = centerVertex[2]-(2*diameter), zmax = centerVertex[2]+(2*diameter); // sample->SetModelBounds(xmin, xmax, ymin, ymax, zmin, zmax); // vtkSmartPointer contour =vtkSmartPointer::New(); // contour->SetInputConnection(sample->GetOutputPort()); // contour->SetValue( 0, 0.25); // vtkSmartPointer impMapper = vtkSmartPointer::New(); // impMapper->SetInputConnection (contour->GetOutputPort()); // impMapper->ScalarVisibilityOff(); // vtkSmartPointer impActor = vtkSmartPointer::New(); // impActor->SetMapper(impMapper); // ls->m_vtkTubeGraphAssembly->AddPart(impActor); } double sphereColorR = 0; double sphereColorG = 0; double sphereColorB = 0; for (auto itClipStructure = cylinderForClipping.begin(); itClipStructure != cylinderForClipping.end(); itClipStructure++) { vtkSmartPointer sphereMapper = dynamic_cast(ls->m_vtkSpheresActorMap[vertexDesc]->GetMapper()); if (sphereMapper != nullptr) { // first clip the sphere with the cylinder vtkSmartPointer clipperSphere = vtkSmartPointer::New(); clipperSphere->SetInputData(sphereMapper->GetInput()); clipperSphere->SetClipFunction(itClipStructure->second); clipperSphere->GenerateClippedOutputOn(); clipperSphere->Update(); sphereMapper->SetInputConnection(clipperSphere->GetOutputPort()); sphereMapper->Update(); } mitk::Color tubeColor = graphProperty->GetColorOfTube(itClipStructure->first); sphereColorR += tubeColor[0]; sphereColorG += tubeColor[1]; sphereColorB += tubeColor[2]; // than clip with all other tubes for (auto itTobBeClipped = cylinderForClipping.begin(); itTobBeClipped != cylinderForClipping.end(); itTobBeClipped++) { TubeGraph::TubeDescriptorType toBeClippedTube = itTobBeClipped->first; if (itClipStructure->first != toBeClippedTube) { vtkSmartPointer tubeMapper = dynamic_cast(ls->m_vtkTubesActorMap[toBeClippedTube]->GetMapper()); if (tubeMapper != nullptr) { // first clip the sphere with the cylinder vtkSmartPointer clipperTube = vtkSmartPointer::New(); tubeMapper->Update(); clipperTube->SetInputData(tubeMapper->GetInput()); clipperTube->SetClipFunction(itClipStructure->second); clipperTube->GenerateClippedOutputOn(); clipperTube->Update(); tubeMapper->SetInputConnection(clipperTube->GetOutputPort()); tubeMapper->Update(); } } } } if (cylinderForClipping.size() != 0) { sphereColorR /= 255 * cylinderForClipping.size(); sphereColorG /= 255 * cylinderForClipping.size(); sphereColorB /= 255 * cylinderForClipping.size(); } ls->m_vtkSpheresActorMap[vertexDesc]->GetProperty()->SetColor(sphereColorR, sphereColorG, sphereColorB); } bool mitk::TubeGraphVtkMapper3D::ClipStructures() { DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) { itkWarningMacro(<< "associated node is nullptr!"); return false; } bool clipStructures = false; node->GetBoolProperty("Tube Graph.Clip Structures", clipStructures); return clipStructures; } diff --git a/Plugins/org.mitk.gui.qt.moviemaker/CMakeLists.txt b/Plugins/org.mitk.gui.qt.moviemaker/CMakeLists.txt index d38a3d1797..041e907007 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.moviemaker/CMakeLists.txt @@ -1,10 +1,10 @@ # The project name must correspond to the directory name of your plug-in # and must not contain periods. project(org_mitk_gui_qt_moviemaker) mitk_create_plugin( EXPORT_DIRECTIVE MOVIEMAKER_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkQtWidgetsExt - PACKAGE_DEPENDS VTK|vtkTestingCore + PACKAGE_DEPENDS VTK|TestingCore+IOImage ) diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp index b3191afbf9..c5952656d8 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp @@ -1,155 +1,155 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include #include "mitkScaleLegendAnnotation.h" #include "mitkLayoutAnnotationRenderer.h" #include "mitkManualPlacementAnnotationRenderer.h" #include "mitkTextAnnotation2D.h" #include "QmitkPAUSViewerView.h" const std::string QmitkPAUSViewerView::VIEW_ID = "org.mitk.views.photoacoustics.pausviewer"; QmitkPAUSViewerView::QmitkPAUSViewerView() : m_PADataStorage(mitk::StandaloneDataStorage::New()), m_USDataStorage(mitk::StandaloneDataStorage::New()), m_UltrasoundReference(nullptr) { } QmitkPAUSViewerView::~QmitkPAUSViewerView() { if(m_UltrasoundReference != nullptr) *m_UltrasoundReference = nullptr; } void QmitkPAUSViewerView::InitWindows() { AddOverlays(); } void QmitkPAUSViewerView::SetFocus() { } void QmitkPAUSViewerView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& /*nodes*/) { } void QmitkPAUSViewerView::CreateQtPartControl(QWidget *parent) { m_Controls = new Ui::QmitkPAUSViewerViewControls; m_Controls->setupUi(parent); m_Controls->m_PARenderWindow->GetRenderer()->SetDataStorage(m_PADataStorage); m_Controls->m_USRenderWindow->GetRenderer()->SetDataStorage(m_USDataStorage); } void QmitkPAUSViewerView::SetPADataStorage(mitk::StandaloneDataStorage::Pointer paStore) { if (m_Controls == nullptr) return; m_PADataStorage = paStore; m_Controls->m_PARenderWindow->GetRenderer()->SetDataStorage(m_PADataStorage); m_Controls->m_PALevelWindow->SetDataStorage(m_PADataStorage); } void QmitkPAUSViewerView::SetUSDataStorage(mitk::StandaloneDataStorage::Pointer usStore) { if (m_Controls == nullptr) return; m_USDataStorage = usStore; m_Controls->m_USRenderWindow->GetRenderer()->SetDataStorage(m_USDataStorage); m_Controls->m_USLevelWindow->SetDataStorage(m_USDataStorage); } vtkRenderWindow* QmitkPAUSViewerView::GetPARenderWindow() { if (m_Controls == nullptr) return nullptr; - return m_Controls->m_PARenderWindow->GetRenderWindow(); + return m_Controls->m_PARenderWindow->renderWindow(); } vtkRenderWindow* QmitkPAUSViewerView::GetUSRenderWindow() { if (m_Controls == nullptr) return nullptr; - return m_Controls->m_USRenderWindow->GetRenderWindow(); + return m_Controls->m_USRenderWindow->renderWindow(); } void QmitkPAUSViewerView::AddOverlays() { //if (m_PARenderer == nullptr || /*m_PAOverlayController == nullptr||*/ m_USRenderer == nullptr /*|| m_USOverlayController == nullptr*/) //{ m_PARenderer = mitk::BaseRenderer::GetInstance(GetPARenderWindow()); m_USRenderer = mitk::BaseRenderer::GetInstance(GetUSRenderWindow()); //} MITK_INFO << "1111111111111111111111"; mitk::ScaleLegendAnnotation::Pointer scaleAnnotation = mitk::ScaleLegendAnnotation::New(); //scaleAnnotation->SetLeftAxisVisibility(true); //scaleAnnotation->SetRightAxisVisibility(false); //scaleAnnotation->SetRightAxisVisibility(false); //scaleAnnotation->SetTopAxisVisibility(false); //scaleAnnotation->SetCornerOffsetFactor(0); MITK_INFO << "1111111111111111111111"; // Add Overlays //![TextAnnotation2D] // Create a textAnnotation2D mitk::TextAnnotation2D::Pointer textAnnotation = mitk::TextAnnotation2D::New(); textAnnotation->SetText("Test!"); // set UTF-8 encoded text to render textAnnotation->SetFontSize(40); textAnnotation->SetColor(1, 0, 0); // Set text color to red textAnnotation->SetOpacity(0.5); MITK_INFO << "1111111111111111111111"; // The position of the Annotation can be set to a fixed coordinate on the display. mitk::Point2D pos; pos[0] = 10; pos[1] = 20; textAnnotation->SetPosition2D(pos); MITK_INFO << "1111111111111111111111"; std::string rendererID = m_PARenderer->GetName(); // The LayoutAnnotationRenderer can place the TextAnnotation2D at some defined corner positions mitk::LayoutAnnotationRenderer::AddAnnotation( textAnnotation, rendererID, mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); mitk::LayoutAnnotationRenderer::AddAnnotation( textAnnotation, m_PARenderer.GetPointer(), mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); mitk::ManualPlacementAnnotationRenderer::AddAnnotation( textAnnotation, m_PARenderer.GetPointer()); MITK_INFO << "1111111111111111111111"; mitk::LayoutAnnotationRenderer::AddAnnotation(scaleAnnotation.GetPointer(), m_PARenderer->GetName(), mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); mitk::LayoutAnnotationRenderer::AddAnnotation(scaleAnnotation.GetPointer(), m_USRenderer, mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); MITK_INFO << "1111111111111111111111"; } void QmitkPAUSViewerView::RemoveOverlays() { // m_PAOverlayManager->RemoveAllOverlays(); } void QmitkPAUSViewerView::SetUltrasoundReference(QmitkPAUSViewerView** ultrasoundReference) { m_UltrasoundReference = ultrasoundReference; } diff --git a/Plugins/org.mitk.gui.qt.remeshing/CMakeLists.txt b/Plugins/org.mitk.gui.qt.remeshing/CMakeLists.txt index 0c79a9f4d2..dcfeabfa2f 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.remeshing/CMakeLists.txt @@ -1,10 +1,7 @@ project(org_mitk_gui_qt_remeshing) -include_directories(${CTK_INCLUDE_DIRS}) - mitk_create_plugin( EXPORT_DIRECTIVE REMESHING_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkQtWidgets MitkRemeshing - PACKAGE_DEPENDS Qt5|OpenGL+Xml ) diff --git a/Plugins/org.mitk.gui.qt.remeshing/files.cmake b/Plugins/org.mitk.gui.qt.remeshing/files.cmake index ef654235b4..5f5abb5665 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/files.cmake +++ b/Plugins/org.mitk.gui.qt.remeshing/files.cmake @@ -1,36 +1,36 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES - org_mitk_gui_qt_remeshing_Activator.cpp + QmitkPluginActivator.cpp QmitkRemeshingView.cpp ) set(UI_FILES src/internal/QmitkRemeshingViewControls.ui ) set(MOC_H_FILES - src/internal/org_mitk_gui_qt_remeshing_Activator.h + src/internal/QmitkPluginActivator.h src/internal/QmitkRemeshingView.h ) set(CACHED_RESOURCE_FILES resources/RemeshingIcon.svg plugin.xml ) set(QRC_FILES resources/Remeshing.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach() foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach() diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/org_mitk_gui_qt_remeshing_Activator.cpp b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkPluginActivator.cpp similarity index 70% rename from Plugins/org.mitk.gui.qt.remeshing/src/internal/org_mitk_gui_qt_remeshing_Activator.cpp rename to Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkPluginActivator.cpp index 80e2706759..44cc9e175b 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/org_mitk_gui_qt_remeshing_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkPluginActivator.cpp @@ -1,23 +1,23 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 "org_mitk_gui_qt_remeshing_Activator.h" +#include "QmitkPluginActivator.h" #include "QmitkRemeshingView.h" -void mitk::org_mitk_gui_qt_remeshing_Activator::start(ctkPluginContext* context) +void QmitkPluginActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkRemeshingView, context); } -void mitk::org_mitk_gui_qt_remeshing_Activator::stop(ctkPluginContext*) +void QmitkPluginActivator::stop(ctkPluginContext*) { } diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/org_mitk_gui_qt_remeshing_Activator.h b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkPluginActivator.h similarity index 50% rename from Plugins/org.mitk.gui.qt.remeshing/src/internal/org_mitk_gui_qt_remeshing_Activator.h rename to Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkPluginActivator.h index bde213bb43..eeb34e8cb1 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/org_mitk_gui_qt_remeshing_Activator.h +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkPluginActivator.h @@ -1,32 +1,29 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef org_mitk_gui_qt_remeshing_Activator_h -#define org_mitk_gui_qt_remeshing_Activator_h +#ifndef QmitkPluginActivator_h +#define QmitkPluginActivator_h #include -namespace mitk +class QmitkPluginActivator : public QObject, public ctkPluginActivator { - class org_mitk_gui_qt_remeshing_Activator : public QObject, public ctkPluginActivator - { - Q_OBJECT - Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_remeshing") - Q_INTERFACES(ctkPluginActivator) - - public: - void start(ctkPluginContext* context) override; - void stop(ctkPluginContext* context) override; - }; -} + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_remeshing") + Q_INTERFACES(ctkPluginActivator) + +public: + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; +}; #endif diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp index 9e230b5dfc..9ed0a2ef58 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp @@ -1,163 +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 "QmitkRemeshingView.h" +#include + #include -#include #include #include #include #include #include -#include -#include - -#include -#include +#include const std::string QmitkRemeshingView::VIEW_ID = "org.mitk.views.remeshing"; QmitkRemeshingView::QmitkRemeshingView() + : m_Controls(new Ui::QmitkRemeshingViewControls) { } QmitkRemeshingView::~QmitkRemeshingView() { } void QmitkRemeshingView::CreateQtPartControl(QWidget* parent) { - m_Controls.setupUi(parent); + m_Controls->setupUi(parent); - m_Controls.remeshPushButton->setIcon(berry::QtStyleManager::ThemeIcon(QStringLiteral(":/Remeshing/RemeshingIcon.svg"))); + m_Controls->decimatePushButton->setIcon(berry::QtStyleManager::ThemeIcon(QStringLiteral(":/Remeshing/RemeshingIcon.svg"))); - m_Controls.selectionWidget->SetDataStorage(this->GetDataStorage()); - m_Controls.selectionWidget->SetSelectionIsOptional(true); - m_Controls.selectionWidget->SetEmptyInfo(QStringLiteral("Select a surface")); - m_Controls.selectionWidget->SetAutoSelectNewNodes(true); - m_Controls.selectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New( + m_Controls->selectionWidget->SetDataStorage(this->GetDataStorage()); + m_Controls->selectionWidget->SetSelectionIsOptional(true); + m_Controls->selectionWidget->SetEmptyInfo(QStringLiteral("Select a surface")); + m_Controls->selectionWidget->SetAutoSelectNewNodes(true); + m_Controls->selectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateOr::New( mitk::NodePredicateProperty::New("helper object"), mitk::NodePredicateProperty::New("hidden object"))))); - connect(m_Controls.selectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkRemeshingView::OnSelectedSurfaceChanged); - connect(m_Controls.densitySlider, SIGNAL(valueChanged(int)), this, SLOT(OnDensityChanged(int))); - connect(m_Controls.densitySpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnDensityChanged(int))); - connect(m_Controls.remeshPushButton, SIGNAL(clicked()), this, SLOT(OnRemeshButtonClicked())); + connect(m_Controls->selectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkRemeshingView::OnSurfaceChanged); + connect(m_Controls->polygonCountSlider, SIGNAL(valueChanged(int)), this, SLOT(OnPolygonCountChanged(int))); + connect(m_Controls->polygonCountSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnPolygonCountChanged(int))); + connect(m_Controls->calculateNormalsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnCalculateNormalsChanged(int))); + connect(m_Controls->decimatePushButton, SIGNAL(clicked()), this, SLOT(OnDecimateButtonClicked())); - this->OnSelectedSurfaceChanged(m_Controls.selectionWidget->GetSelectedNodes()); + this->OnSurfaceChanged(m_Controls->selectionWidget->GetSelectedNodes()); } -void QmitkRemeshingView::OnSelectedSurfaceChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes) +void QmitkRemeshingView::OnSurfaceChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes) { - if (!nodes.empty() && nodes.front().IsNotNull()) - { - m_MaxNumberOfVertices = static_cast(static_cast(nodes.front()->GetData())->GetVtkPolyData()->GetNumberOfPoints()); - this->EnableWidgets(true); - } - else - { - m_MaxNumberOfVertices = 0; - this->EnableWidgets(false); - } + this->EnableWidgets(!nodes.empty() && nodes.front().IsNotNull()); } -void QmitkRemeshingView::OnDensityChanged(int density) +void QmitkRemeshingView::OnPolygonCountChanged(int polygonCount) { - if (density != m_Controls.densitySlider->value()) - m_Controls.densitySlider->setValue(density); + if (polygonCount != m_Controls->polygonCountSlider->value()) + m_Controls->polygonCountSlider->setValue(polygonCount); - if (density != m_Controls.densitySpinBox->value()) - m_Controls.densitySpinBox->setValue(density); + if (polygonCount != m_Controls->polygonCountSpinBox->value()) + m_Controls->polygonCountSpinBox->setValue(polygonCount); } -void QmitkRemeshingView::OnRemeshButtonClicked() +void QmitkRemeshingView::OnCalculateNormalsChanged(int checkState) { - mitk::DataNode::Pointer selectedNode = m_Controls.selectionWidget->GetSelectedNode(); - mitk::Surface::ConstPointer surface = static_cast(selectedNode->GetData()); - - int density = m_Controls.densitySpinBox->value(); - int numVertices = std::max(100, static_cast(m_MaxNumberOfVertices * (density * 0.01))); - - double gradation = m_Controls.remeshingComboBox->currentText() == QStringLiteral("Adaptive") - ? 1.0 - : 0.0; - - const QString quality = m_Controls.qualityComboBox->currentText(); - int subsampling; - - if (QStringLiteral("High (slow)") == quality) - { - subsampling = 50; - } - else if (QStringLiteral("Maximum (very slow)") == quality) - { - subsampling = 500; - } - else // The default is "Medium (fast)". - { - subsampling = 10; - } - - bool boundaryFixing = m_Controls.preserveEdgesCheckBox->isChecked(); + m_Controls->flipNormalsCheckBox->setEnabled(Qt::Unchecked != checkState); +} - mitk::ACVD::RemeshFilter::Pointer remesher = mitk::ACVD::RemeshFilter::New(); - remesher->SetInput(surface); - remesher->SetTimeStep(0); - remesher->SetNumVertices(numVertices); - remesher->SetGradation(gradation); - remesher->SetSubsampling(subsampling); - remesher->SetEdgeSplitting(0.0); - remesher->SetOptimizationLevel(1.0); - remesher->SetForceManifold(false); - remesher->SetBoundaryFixing(boundaryFixing); +void QmitkRemeshingView::OnDecimateButtonClicked() +{ + mitk::DataNode::Pointer selectedNode = m_Controls->selectionWidget->GetSelectedNode(); + mitk::Surface::ConstPointer input = static_cast(selectedNode->GetData()); + mitk::Surface::Pointer output; try { - remesher->Update(); + output = mitk::Remeshing::Decimate(input, + 0.01 * m_Controls->polygonCountSpinBox->value(), + m_Controls->calculateNormalsCheckBox->isChecked(), + m_Controls->flipNormalsCheckBox->isChecked()); } catch(const mitk::Exception& exception) { MITK_ERROR << exception.GetDescription(); return; } - mitk::Surface::Pointer remeshedSurface = remesher->GetOutput(); + if (output.IsNull()) + return; - mitk::DataNode::Pointer newNode = mitk::DataNode::New(); - newNode->SetName(QString("%1 (%2%)").arg(selectedNode->GetName().c_str()).arg(density).toStdString()); - newNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); - newNode->SetData(remeshedSurface); + auto newNode = mitk::DataNode::New(); + newNode->SetName(QString("%1 (decimated)").arg(selectedNode->GetName().c_str()).toStdString()); + newNode->SetData(output); this->GetDataStorage()->Add(newNode, selectedNode); } void QmitkRemeshingView::EnableWidgets(bool enable) { - m_Controls.densitySlider->setEnabled(enable); - m_Controls.densitySpinBox->setEnabled(enable); - m_Controls.remeshingComboBox->setEnabled(enable); - m_Controls.qualityComboBox->setEnabled(enable); - m_Controls.preserveEdgesCheckBox->setEnabled(enable); - m_Controls.remeshPushButton->setEnabled(enable); - - m_Controls.explanationLabel->setVisible(enable); + m_Controls->polygonCountSlider->setEnabled(enable); + m_Controls->polygonCountSpinBox->setEnabled(enable); + m_Controls->calculateNormalsCheckBox->setEnabled(enable); + m_Controls->flipNormalsCheckBox->setEnabled(enable && m_Controls->calculateNormalsCheckBox->isChecked()); + m_Controls->decimatePushButton->setEnabled(enable); } void QmitkRemeshingView::SetFocus() { - m_Controls.selectionWidget->setFocus(); + m_Controls->selectionWidget->setFocus(); } diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h index 33b384f4d6..679f1679ec 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h @@ -1,45 +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 QmitkRemeshingView_h #define QmitkRemeshingView_h #include #include -#include + +namespace Ui +{ + class QmitkRemeshingViewControls; +} class QmitkRemeshingView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; QmitkRemeshingView(); ~QmitkRemeshingView() override; void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; private slots: - void OnSelectedSurfaceChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes); - void OnDensityChanged(int numVertices); - void OnRemeshButtonClicked(); + void OnSurfaceChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes); + void OnPolygonCountChanged(int polygonCount); + void OnCalculateNormalsChanged(int checkState); + void OnDecimateButtonClicked(); private: void EnableWidgets(bool enable); - Ui::QmitkRemeshingViewControls m_Controls; - int m_MaxNumberOfVertices; + Ui::QmitkRemeshingViewControls* m_Controls; }; #endif diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingViewControls.ui b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingViewControls.ui index 105b8e2ba4..d06d2ff7fc 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingViewControls.ui @@ -1,244 +1,172 @@ QmitkRemeshingViewControls true 0 0 253 573 Remeshing 0 0 Surface - - - - - 0 - 40 - + + + + Flip normals - + 0 0 - Density + Polygon count - + 0 0 1 100 10 - 100 + 50 Qt::Horizontal + + + + + 0 + 40 + + + + - + % 1 100 1 - 100 - - - - - - - - 0 - 0 - - - - Remeshing + 50 - - - - Adaptive - - - - - Regular - - - - - - - - - 0 - 0 - - + - Quality - - - - - - - 0 - - - - Medium (fast) - - - - - High (slow) - - - - - Maximum (very slow) - - - - - - - - - 0 - 0 - - - - Preserve Edges + Calculate normals true - + true - Remesh + Decimate :/Remeshing/RemeshingIcon.svg:/Remeshing/RemeshingIcon.svg 24 24 - - - - <html><head/><body><p><span style=" font-weight:600;">Density:</span> The density of the resulting surface compared to the input surface. For example, a density of 50% will effectively halve the number of vertices. It's not uncommen to choose values as low as 10% for overly dense input surfaces. The minimum number of output vertices is at least 100, though.</p><p><span style=" font-weight:600;">Remeshing:</span> Adaptive remeshing results in higher density in curvy areas and less density in flat areas. This remeshing strategy can preserve fine shape details even when the overall density is heavily reduced. Regular remeshing evenly distributes the density regardless of the local shape of the surface.</p><p><span style=" font-weight:600;">Quality</span>: While medium quality is sufficient for the vast majority of use cases, you can increase this setting to further optimize the mesh quality in terms of uniformly shaped triangles. However, computation time and memory consumption increase dramatically compared to very small improvements.</p><p><span style=" font-weight:600;">Preserve Edges:</span> If the input surface contains holes or edges, they will be preserved very accurately by default at the cost of less uniform triangles at their direct neighborhood.</p></body></html> - - - true - - - Qt::Vertical 20 40 QmitkSingleNodeSelectionWidget QWidget
QmitkSingleNodeSelectionWidget.h
1
- densitySpinBox - preserveEdgesCheckBox - remeshPushButton + polygonCountSpinBox + decimatePushButton
diff --git a/Plugins/org.mitk.gui.qt.remeshing/target_libraries.cmake b/Plugins/org.mitk.gui.qt.remeshing/target_libraries.cmake deleted file mode 100644 index 6c71bbbf08..0000000000 --- a/Plugins/org.mitk.gui.qt.remeshing/target_libraries.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(target_libraries - CTKWidgets -) diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp index 698f380ad3..33520df2fe 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp @@ -1,526 +1,526 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) 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 #include #include // Qmitk #include "QmitkToFUtilView.h" // Qt #include #include #include #include #include // MITK #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include // ITK #include #include const std::string QmitkToFUtilView::VIEW_ID = "org.mitk.views.tofutil"; //Constructor QmitkToFUtilView::QmitkToFUtilView() : QmitkAbstractView() , m_Controls(nullptr) , m_Framerateoutput(false) , m_MitkDistanceImage(nullptr), m_MitkAmplitudeImage(nullptr), m_MitkIntensityImage(nullptr), m_Surface(nullptr) , m_DistanceImageNode(nullptr), m_AmplitudeImageNode(nullptr), m_IntensityImageNode(nullptr), m_RGBImageNode(nullptr), m_SurfaceNode(nullptr) , m_ToFImageRecorder(nullptr), m_ToFImageGrabber(nullptr), m_ToFDistanceImageToSurfaceFilter(nullptr), m_ToFCompositeFilter(nullptr) , m_2DDisplayCount(0) , m_RealTimeClock(nullptr) , m_StepsForFramerate(100) , m_2DTimeBefore(0.0) , m_2DTimeAfter(0.0) , m_CameraIntrinsics(nullptr) { this->m_Frametimer = new QTimer(this); this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); } //Destructor, specifically calling OnToFCameraStopped() and OnToFCammeraDiconnected() QmitkToFUtilView::~QmitkToFUtilView() { OnToFCameraStopped(); OnToFCameraDisconnected(); } //Createing the PartControl Signal-Slot principal void QmitkToFUtilView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkToFUtilViewControls; m_Controls->setupUi( parent ); //Looking for Input and Defining reaction connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(KinectAcquisitionModeChanged()), this, SLOT(OnKinectAcquisitionModeChanged()) ); // Todo in Widget2 connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraConnected()), this, SLOT(OnToFCameraConnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraDisconnected()), this, SLOT(OnToFCameraDisconnected()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStarted()), this, SLOT(OnToFCameraStarted()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStopped()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStarted()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStopped()), this, SLOT(OnToFCameraStarted()) ); } } //SetFocus-Method -> actually seting Focus to the Recorder void QmitkToFUtilView::SetFocus() { m_Controls->m_ToFRecorderWidget->setFocus(); } //Activated-Method->Generating RenderWindow void QmitkToFUtilView::Activated() { //get the current RenderWindowPart or open a new one if there is none if (this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN)) { mitk::ILinkedRenderWindowPart* linkedRenderWindowPart = dynamic_cast(this->GetRenderWindowPart()); if (linkedRenderWindowPart == nullptr) { MITK_ERROR << "No linked render window part avaiable!!!"; } else { linkedRenderWindowPart->EnableSlicingPlanes(false); } GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOn(); GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOn(); GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOn(); mitk::RenderingManager::GetInstance()->InitializeViews(); this->UseToFVisibilitySettings(true); if (this->m_ToFCompositeFilter) { m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); } if (this->GetDataStorage()) { m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); } if (this->m_ToFImageGrabber.IsNull()) { m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); m_Controls->m_ToFMeasurementWidget->setEnabled(false); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(false); } } } //ZomnnieView-Method -> Resetting GUI to default. Why not just QmitkToFUtilView()?! void QmitkToFUtilView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer /*zombieView*/) { ResetGUIToDefault(); } void QmitkToFUtilView::Deactivated() { } void QmitkToFUtilView::Visible() { } //Reset of the ToFUtilView void QmitkToFUtilView::Hidden() { ResetGUIToDefault(); } void QmitkToFUtilView::OnToFCameraConnected() { MITK_DEBUG <<"OnToFCameraConnected"; this->m_2DDisplayCount = 0; this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); // initialize surface generation this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); // initialize ToFImageRecorder and ToFRecorderWidget this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); this->m_ToFImageRecorder->SetCameraDevice(this->m_ToFImageGrabber->GetCameraDevice()); m_Controls->m_ToFRecorderWidget->SetParameter(this->m_ToFImageGrabber, this->m_ToFImageRecorder); m_Controls->m_ToFRecorderWidget->setEnabled(true); m_Controls->m_ToFRecorderWidget->ResetGUIToInitial(); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); // initialize ToFCompositeFilterWidget this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); if (this->m_ToFCompositeFilter) { m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); } if (this->GetDataStorage()) { m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); } if ( this->GetRenderWindowPart() ) // initialize measurement widget m_Controls->m_ToFMeasurementWidget->InitializeWidget(this->GetRenderWindowPart()->GetQmitkRenderWindows(),this->GetDataStorage(), this->m_ToFDistanceImageToSurfaceFilter->GetCameraIntrinsics()); else MITK_WARN << "No render window part available!!! MeasurementWidget will not work."; this->m_RealTimeClock = mitk::RealTimeClock::New(); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); this->RequestRenderWindowUpdate(); } void QmitkToFUtilView::ResetGUIToDefault() { if(this->GetRenderWindowPart()) { mitk::ILinkedRenderWindowPart* linkedRenderWindowPart = dynamic_cast(this->GetRenderWindowPart()); if(linkedRenderWindowPart == nullptr) { MITK_ERROR << "No linked render window part avaiable!!!"; } else { linkedRenderWindowPart->EnableSlicingPlanes(true); } GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOff(); GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOff(); GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOff(); this->UseToFVisibilitySettings(false); //global reinit mitk::RenderingManager::GetInstance()->InitializeViews(); this->RequestRenderWindowUpdate(); } } void QmitkToFUtilView::OnToFCameraDisconnected() { this->GetDataStorage()->Remove(m_DistanceImageNode); if(m_RGBImageNode) this->GetDataStorage()->Remove(m_RGBImageNode); if(m_AmplitudeImageNode) this->GetDataStorage()->Remove(m_AmplitudeImageNode); if(m_IntensityImageNode) this->GetDataStorage()->Remove(m_IntensityImageNode); if(m_SurfaceNode) this->GetDataStorage()->Remove(m_SurfaceNode); m_Controls->m_ToFRecorderWidget->OnStop(); m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFMeasurementWidget->setEnabled(false); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(false); //clean up measurement widget m_Controls->m_ToFMeasurementWidget->CleanUpWidget(); } void QmitkToFUtilView::OnKinectAcquisitionModeChanged() { if (m_ToFCompositeFilter.IsNotNull()&&m_ToFImageGrabber.IsNotNull()) { if (m_SelectedCamera.contains("Kinect")) { if (m_ToFImageGrabber->GetBoolProperty("RGB")) { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); this->m_ToFDistanceImageToSurfaceFilter->SetInput(3,this->m_ToFImageGrabber->GetOutput(3)); } else if (m_ToFImageGrabber->GetBoolProperty("IR")) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); } } this->UseToFVisibilitySettings(true); } } void QmitkToFUtilView::OnToFCameraStarted() { if (m_ToFImageGrabber.IsNotNull()) { // initialize camera intrinsics if (this->m_ToFImageGrabber->GetProperty("CameraIntrinsics")) { m_CameraIntrinsics = dynamic_cast(this->m_ToFImageGrabber->GetProperty("CameraIntrinsics"))->GetValue(); MITK_INFO << m_CameraIntrinsics->ToString(); } else { m_CameraIntrinsics = nullptr; MITK_ERROR << "No camera intrinsics were found!"; } // set camera intrinsics if ( m_CameraIntrinsics.IsNotNull() ) { this->m_ToFDistanceImageToSurfaceFilter->SetCameraIntrinsics(m_CameraIntrinsics); } // initial update of image grabber this->m_ToFImageGrabber->Update(); bool hasRGBImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasRGBImage",hasRGBImage); bool hasIntensityImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasIntensityImage",hasIntensityImage); bool hasAmplitudeImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasAmplitudeImage",hasAmplitudeImage); this->m_ToFCompositeFilter->SetInput(0,this->m_ToFImageGrabber->GetOutput(0)); if(hasAmplitudeImage) this->m_ToFCompositeFilter->SetInput(1,this->m_ToFImageGrabber->GetOutput(1)); if(hasIntensityImage) this->m_ToFCompositeFilter->SetInput(2,this->m_ToFImageGrabber->GetOutput(2)); // initial update of composite filter this->m_ToFCompositeFilter->Update(); this->m_MitkDistanceImage = m_ToFCompositeFilter->GetOutput(); this->m_DistanceImageNode = ReplaceNodeData("Distance image",m_MitkDistanceImage); std::string rgbFileName; m_ToFImageGrabber->GetCameraDevice()->GetStringProperty("RGBImageFileName",rgbFileName); if(hasRGBImage || (rgbFileName!="")) { if(m_ToFImageGrabber->GetBoolProperty("IR")) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); } else { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); } } else { this->m_RGBImageNode = nullptr; } if(hasAmplitudeImage) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); } if(hasIntensityImage) { this->m_MitkIntensityImage = m_ToFCompositeFilter->GetOutput(2); this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); } this->m_ToFDistanceImageToSurfaceFilter->SetInput(0,m_MitkDistanceImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(1,m_MitkAmplitudeImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(2,m_MitkIntensityImage); this->UseToFVisibilitySettings(true); this->m_SurfaceNode = ReplaceNodeData("Surface", nullptr); m_Controls->m_ToFCompositeFilterWidget->UpdateFilterParameter(); // initialize visualization widget m_Controls->m_ToFVisualisationSettingsWidget->Initialize(this->m_DistanceImageNode, this->m_AmplitudeImageNode, this->m_IntensityImageNode, this->m_SurfaceNode); m_Controls->m_ToFSurfaceGenerationWidget->Initialize(m_ToFDistanceImageToSurfaceFilter, m_ToFImageGrabber, m_CameraIntrinsics, m_SurfaceNode, GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderer()->GetVtkRenderer()->GetActiveCamera()); // set distance image to measurement widget m_Controls->m_ToFMeasurementWidget->SetDistanceImage(m_MitkDistanceImage); this->m_Frametimer->start(50); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(true); m_Controls->m_ToFCompositeFilterWidget->setEnabled(true); m_Controls->m_ToFMeasurementWidget->setEnabled(true); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(true); } } void QmitkToFUtilView::OnToFCameraStopped() { m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); this->m_Frametimer->stop(); } void QmitkToFUtilView::OnUpdateCamera() { if(!m_Controls->m_ToFSurfaceGenerationWidget->UpdateSurface()) { // update pipeline this->m_MitkDistanceImage->Update(); } this->RequestRenderWindowUpdate(); if (m_Framerateoutput) { this->m_2DDisplayCount++; if ((this->m_2DDisplayCount % this->m_StepsForFramerate) == 0) { this->m_2DTimeAfter = this->m_RealTimeClock->GetCurrentStamp() - this->m_2DTimeBefore; MITK_INFO << " 2D-Display-framerate (fps): " << this->m_StepsForFramerate / (this->m_2DTimeAfter / 1000); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); } } } void QmitkToFUtilView::OnChangeCoronalWindowOutput(int index) { this->OnToFCameraStopped(); if(index == 0) { if(this->m_IntensityImageNode.IsNotNull()) this->m_IntensityImageNode->SetVisibility(false); if(this->m_RGBImageNode.IsNotNull()) this->m_RGBImageNode->SetVisibility(true); } else if(index == 1) { if(this->m_IntensityImageNode.IsNotNull()) this->m_IntensityImageNode->SetVisibility(true); if(this->m_RGBImageNode.IsNotNull()) this->m_RGBImageNode->SetVisibility(false); } this->RequestRenderWindowUpdate(); this->OnToFCameraStarted(); } mitk::DataNode::Pointer QmitkToFUtilView::ReplaceNodeData( std::string nodeName, mitk::BaseData* data ) { mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetName(nodeName); node->SetBoolProperty("binary",false); node->SetData(data); this->GetDataStorage()->Add(node); } else { node->SetData(data); } return node; } void QmitkToFUtilView::UseToFVisibilitySettings(bool useToF) { //We need this property for every node. mitk::RenderingModeProperty::Pointer renderingModePropertyForTransferFunction = mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR); // set node properties if (m_DistanceImageNode.IsNotNull()) { this->m_DistanceImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); - this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow() ) ); - this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->renderWindow() ) ); + this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->renderWindow() ) ); + this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->renderWindow() ) ); this->m_DistanceImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if (m_AmplitudeImageNode.IsNotNull()) { - this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); - this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow() ) ); - this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->renderWindow() ) ); + this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->renderWindow() ) ); + this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->renderWindow() ) ); this->m_AmplitudeImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if (m_IntensityImageNode.IsNotNull()) { this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); - this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); - this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->renderWindow() ) ); + this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->renderWindow() ) ); + this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->renderWindow() ) ); this->m_IntensityImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if ((m_RGBImageNode.IsNotNull())) { this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); - this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); - this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->renderWindow() ) ); + this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->renderWindow() ) ); + this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->renderWindow() ) ); } // initialize images if (m_MitkDistanceImage.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( this->m_MitkDistanceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS, true); } if(this->m_SurfaceNode.IsNotNull()) { QHash renderWindowHashMap = this->GetRenderWindowPart()->GetQmitkRenderWindows(); QHashIterator i(renderWindowHashMap); while (i.hasNext()){ i.next(); - this->m_SurfaceNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(i.value()->GetRenderWindow()) ); + this->m_SurfaceNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(i.value()->renderWindow()) ); } - this->m_SurfaceNode->SetVisibility( true, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + this->m_SurfaceNode->SetVisibility( true, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->renderWindow() ) ); } //disable/enable gradient background this->GetRenderWindowPart()->EnableDecorations(!useToF, QStringList(QString("background"))); if((this->m_RGBImageNode.IsNotNull())) { bool RGBImageHasDifferentResolution = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("RGBImageHasDifferentResolution",RGBImageHasDifferentResolution); if(RGBImageHasDifferentResolution) { //update the display geometry by using the RBG image node. Only for renderwindow coronal - mitk::RenderingManager::GetInstance()->InitializeView( GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow(), this->m_RGBImageNode->GetData()->GetGeometry() ); + mitk::RenderingManager::GetInstance()->InitializeView( GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->renderWindow(), this->m_RGBImageNode->GetData()->GetGeometry() ); } } }