diff --git a/CMake/mitkFunctionCheckC++0xHashSizeT.cmake b/CMake/mitkFunctionCheckC++0xHashSizeT.cmake deleted file mode 100644 index 2340101f30..0000000000 --- a/CMake/mitkFunctionCheckC++0xHashSizeT.cmake +++ /dev/null @@ -1,13 +0,0 @@ - -function(mitkFunctionCheckCxx0xHashSizeT var_has_feature) - - CHECK_CXX_SOURCE_COMPILES( - " - #include - int main() { std::hash h; return 0; } - " - ${var_has_feature} - ) - - set(${var_has_feature} "${${var_has_feature}}" PARENT_SCOPE) -endfunction() diff --git a/CMake/mitkFunctionCheckC++0xHashString.cmake b/CMake/mitkFunctionCheckC++0xHashString.cmake deleted file mode 100644 index 4c473b753b..0000000000 --- a/CMake/mitkFunctionCheckC++0xHashString.cmake +++ /dev/null @@ -1,14 +0,0 @@ - -function(mitkFunctionCheckCxx0xHashString var_has_feature) - - CHECK_CXX_SOURCE_COMPILES( - " - #include - #include - int main() { std::hash h; return 0; } - " - ${var_has_feature} - ) - - set(${var_has_feature} "${${var_has_feature}}" PARENT_SCOPE) -endfunction() diff --git a/CMake/mitkFunctionCheckC++0xUnorderedMap.cmake b/CMake/mitkFunctionCheckC++0xUnorderedMap.cmake deleted file mode 100644 index 8308f60916..0000000000 --- a/CMake/mitkFunctionCheckC++0xUnorderedMap.cmake +++ /dev/null @@ -1,13 +0,0 @@ - -function(mitkFunctionCheckCxx0xUnorderedMap var_has_feature) - - CHECK_CXX_SOURCE_COMPILES( - " - #include - int main() { std::unordered_map um; return 0; } - " - ${var_has_feature} - ) - - set(${var_has_feature} "${${var_has_feature}}" PARENT_SCOPE) -endfunction() diff --git a/CMake/mitkFunctionCheckC++0xUnorderedSet.cmake b/CMake/mitkFunctionCheckC++0xUnorderedSet.cmake deleted file mode 100644 index 2bedf7bd09..0000000000 --- a/CMake/mitkFunctionCheckC++0xUnorderedSet.cmake +++ /dev/null @@ -1,13 +0,0 @@ - -function(mitkFunctionCheckCxx0xUnorderedSet var_has_feature) - - CHECK_CXX_SOURCE_COMPILES( - " - #include - int main() { std::unordered_set us; return 0; } - " - ${var_has_feature} - ) - - set(${var_has_feature} "${${var_has_feature}}" PARENT_SCOPE) -endfunction() diff --git a/CMake/mitkFunctionCheckItkHashSizeT.cmake b/CMake/mitkFunctionCheckItkHashSizeT.cmake deleted file mode 100644 index 03481e6990..0000000000 --- a/CMake/mitkFunctionCheckItkHashSizeT.cmake +++ /dev/null @@ -1,13 +0,0 @@ - -function(mitkFunctionCheckItkHashSizeT var_has_feature) - - CHECK_CXX_SOURCE_COMPILES( - " - #include - int main() { itk::hash h; return 0; } - " - ${var_has_feature} - ) - - set(${var_has_feature} "${${var_has_feature}}" PARENT_SCOPE) -endfunction() diff --git a/CMake/mitkFunctionCheckItkHashString.cmake b/CMake/mitkFunctionCheckItkHashString.cmake deleted file mode 100644 index 3d2a9a388a..0000000000 --- a/CMake/mitkFunctionCheckItkHashString.cmake +++ /dev/null @@ -1,14 +0,0 @@ - -function(mitkFunctionCheckItkHashString var_has_feature) - - CHECK_CXX_SOURCE_COMPILES( - " - #include - #include - int main() { itk::hash h; return 0; } - " - ${var_has_feature} - ) - - set(${var_has_feature} "${${var_has_feature}}" PARENT_SCOPE) -endfunction() diff --git a/CMake/mitkSetupC++0xVariables.cmake b/CMake/mitkSetupC++0xVariables.cmake deleted file mode 100644 index 6c60783f30..0000000000 --- a/CMake/mitkSetupC++0xVariables.cmake +++ /dev/null @@ -1,55 +0,0 @@ -if(MSVC10) - set(MITK_USE_C++0x 1) -else() - option(MITK_USE_C++0x "Enable C++0x features in MITK. This is experimental." OFF) - mark_as_advanced(MITK_USE_C++0x) -endif() - -# Begin checking fo C++0x features -if(MITK_USE_C++0x) - if(CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_REQUIRED_FLAGS "-std=c++0x") - endif() - - include(mitkFunctionCheckC++0xHashString) - mitkFunctionCheckCxx0xHashString(MITK_HAS_HASH_STRING_0x) - - include(mitkFunctionCheckC++0xHashSizeT) - mitkFunctionCheckCxx0xHashSizeT(MITK_HAS_HASH_SIZE_T_0x) - - include(mitkFunctionCheckC++0xUnorderedMap) - mitkFunctionCheckCxx0xUnorderedMap(MITK_HAS_UNORDERED_MAP_H_0x) - - include(mitkFunctionCheckC++0xUnorderedSet) - mitkFunctionCheckCxx0xUnorderedMap(MITK_HAS_UNORDERED_SET_H_0x) - - set(MITK_HAS_VAR_SUFFIX "_0x") - set(CMAKE_REQUIRED_FLAGS "") - -else() - - set(CMAKE_REQUIRED_FLAGS "") - - include(mitkFunctionCheckItkHashString) - mitkFunctionCheckItkHashString(MITK_HAS_HASH_STRING_def) - - include(mitkFunctionCheckItkHashSizeT) - mitkFunctionCheckItkHashSizeT(MITK_HAS_HASH_SIZE_T_def) - - set(MITK_HAS_UNORDERED_MAP_H_def ) - set(MITK_HAS_UNORDERED_SET_H_def ) - - set(MITK_HAS_VAR_SUFFIX "_def") - -endif() - -foreach(var - MITK_HAS_HASH_STRING - MITK_HAS_HASH_SIZE_T - MITK_HAS_UNORDERED_MAP_H - MITK_HAS_UNORDERED_SET_H - ) - set(${var} ${${var}${MITK_HAS_VAR_SUFFIX}}) -endforeach() - -# End checking C++0x features diff --git a/CMakeLists.txt b/CMakeLists.txt index abf1e8704d..69a2afc50d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1022 +1,1016 @@ if(MITK_USE_QT AND DESIRED_QT_VERSION MATCHES 5) cmake_minimum_required(VERSION 2.8.9) elseif(APPLE) # With XCode 4.3, the SDK location changed. Older CMake # versions are not able to find it. cmake_minimum_required(VERSION 2.8.8) else() cmake_minimum_required(VERSION 2.8.5) endif() #----------------------------------------------------------------------------- # Include ctest launchers for dashboard in case of makefile generator #----------------------------------------------------------------------------- if(${CMAKE_VERSION} VERSION_GREATER "2.8.9") include(CTestUseLaunchers) endif() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Build MITK and the projects it depends on via SuperBuild.cmake." ON) if(MITK_USE_SUPERBUILD) project(MITK-superbuild) set(MITK_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(MITK_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(MITK) endif() #----------------------------------------------------------------------------- # Warn if source or build path is too long #----------------------------------------------------------------------------- if(WIN32) set(_src_dir_length_max 50) set(_bin_dir_length_max 50) if(MITK_USE_SUPERBUILD) set(_src_dir_length_max 43) # _src_dir_length_max - strlen(ITK-src) set(_bin_dir_length_max 40) # _bin_dir_length_max - strlen(MITK-build) endif() string(LENGTH "${MITK_SOURCE_DIR}" _src_n) string(LENGTH "${MITK_BINARY_DIR}" _bin_n) # The warnings should be converted to errors if(_src_n GREATER _src_dir_length_max) message(WARNING "MITK source code directory path length is too long (${_src_n} > ${_src_dir_length_max})." "Please move the MITK source code directory to a directory with a shorter path." ) endif() if(_bin_n GREATER _bin_dir_length_max) message(WARNING "MITK build directory path length is too long (${_bin_n} > ${_bin_dir_length_max})." "Please move the MITK build directory to a directory with a shorter path." ) endif() endif() #----------------------------------------------------------------------------- # See http://cmake.org/cmake/help/cmake-2-8-docs.html#section_Policies for details #----------------------------------------------------------------------------- set(project_policies CMP0001 # NEW: CMAKE_BACKWARDS_COMPATIBILITY should no longer be used. CMP0002 # NEW: Logical target names must be globally unique. CMP0003 # NEW: Libraries linked via full path no longer produce linker search paths. CMP0004 # NEW: Libraries linked may NOT have leading or trailing whitespace. CMP0005 # NEW: Preprocessor definition values are now escaped automatically. CMP0006 # NEW: Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION. CMP0007 # NEW: List command no longer ignores empty elements. CMP0008 # NEW: Libraries linked by full-path must have a valid library file name. CMP0009 # NEW: FILE GLOB_RECURSE calls should not follow symlinks by default. CMP0010 # NEW: Bad variable reference syntax is an error. CMP0011 # NEW: Included scripts do automatic cmake_policy PUSH and POP. CMP0012 # NEW: if() recognizes numbers and boolean constants. CMP0013 # NEW: Duplicate binary directories are not allowed. CMP0014 # NEW: Input directories must have CMakeLists.txt CMP0020 # NEW: Automatically link Qt executables to qtmain target on Windows ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(mitkMacroEmptyExternalProject) include(mitkFunctionGenerateProjectXml) include(mitkFunctionSuppressWarnings) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_USE_SUPERBUILD) set(output_dir ${MITK_BINARY_DIR}/bin) if(NOT DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_BINARY_DIR}/MITK-build/bin) endif() else() if(NOT DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(output_dir ${MITK_BINARY_DIR}/bin) else() set(output_dir ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) endif() endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${output_dir} CACHE INTERNAL "Single output directory for building all libraries.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Additional MITK Options (also shown during superbuild) #----------------------------------------------------------------------------- option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) set(MITK_BUILD_TUTORIAL OFF CACHE INTERNAL "Deprecated! Use MITK_BUILD_EXAMPLES instead!") option(MITK_BUILD_EXAMPLES "Build the MITK Examples" ${MITK_BUILD_TUTORIAL}) option(MITK_USE_ACVD "Use Approximated Centroidal Voronoi Diagrams" OFF) option(MITK_USE_GLEW "Use the GLEW library" ON) option(MITK_USE_Boost "Use the Boost C++ library" OFF) option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) option(MITK_USE_CTK "Use CTK in MITK" ${MITK_USE_BLUEBERRY}) option(MITK_USE_QT "Use Nokia's Qt library" ${MITK_USE_CTK}) set(DESIRED_QT_VERSION 4 CACHE STRING "Pick a version of Qt to use: 4 or 5") set(MITK_DESIRED_QT_VERSION ${DESIRED_QT_VERSION}) option(MITK_USE_DCMTK "EXPERIMENTAL, superbuild only: Use DCMTK in MITK" ${MITK_USE_CTK}) option(MITK_USE_OpenCV "Use Intel's OpenCV library" OFF) option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) option(MITK_USE_Poco "Use the Poco library" ON) option(MITK_USE_SOFA "Use Simulation Open Framework Architecture" OFF) option(MITK_USE_Python "Use Python wrapping in MITK" OFF) set(MITK_USE_CableSwig ${MITK_USE_Python}) option(MITK_ENABLE_PIC_READER "Enable support for reading the DKFZ pic file format." ON) mark_as_advanced(MITK_BUILD_ALL_APPS MITK_USE_GLEW MITK_USE_CTK MITK_USE_DCMTK MITK_ENABLE_PIC_READER ) if(MITK_USE_Python) FIND_PACKAGE(PythonLibs REQUIRED) FIND_PACKAGE(PythonInterp REQUIRED) endif() if(MITK_USE_Boost) option(MITK_USE_SYSTEM_Boost "Use the system Boost" OFF) set(MITK_USE_Boost_LIBRARIES "" CACHE STRING "A semi-colon separated list of required Boost libraries") endif() if(MITK_USE_BLUEBERRY) if(NOT DESIRED_QT_VERSION MATCHES 4) message("Forcing MITK_USE_BLUEBERRY to OFF because of DESIRED_QT_VERSION ${DESIRED_QT_VERSION}") set(MITK_USE_BLUEBERRY OFF CACHE BOOL "Build the BlueBerry application platform" FORCE) endif() endif() if(MITK_USE_BLUEBERRY) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) mark_as_advanced(MITK_BUILD_ALL_PLUGINS) if(NOT MITK_USE_CTK) message("Forcing MITK_USE_CTK to ON because of MITK_USE_BLUEBERRY") set(MITK_USE_CTK ON CACHE BOOL "Use CTK in MITK" FORCE) endif() endif() if(MITK_USE_CTK) if(NOT MITK_USE_QT) message("Forcing MITK_USE_QT to ON because of MITK_USE_CTK") set(MITK_USE_QT ON CACHE BOOL "Use Nokia's Qt library in MITK" FORCE) else() if(NOT DESIRED_QT_VERSION MATCHES 4) message("Forcing MITK_USE_CTK to OFF because of DESIRED_QT_VERSION ${DESIRED_QT_VERSION}") set(MITK_USE_CTK OFF CACHE BOOL "Use CTK in MITK" FORCE) endif() endif() if(NOT MITK_USE_DCMTK) message("Setting MITK_USE_DCMTK to ON because DCMTK needs to be build for CTK") set(MITK_USE_DCMTK ON CACHE BOOL "Use DCMTK in MITK" FORCE) endif() endif() if(MITK_USE_QT) # find the package at the very beginning, so that QT4_FOUND is available if(DESIRED_QT_VERSION MATCHES 4) set(MITK_QT4_MINIMUM_VERSION 4.6.2) find_package(Qt4 ${MITK_QT4_MINIMUM_VERSION} REQUIRED) set(MITK_USE_Qt4 TRUE) set(MITK_USE_Qt5 FALSE) endif(DESIRED_QT_VERSION MATCHES 4) if(DESIRED_QT_VERSION MATCHES 5) set(MITK_QT5_MINIMUM_VERSION 5.0.0) set(MITK_USE_Qt4 FALSE) set(MITK_USE_Qt5 TRUE) endif(DESIRED_QT_VERSION MATCHES 5) endif() if(MITK_USE_SOFA) # SOFA requires at least CMake 2.8.8 set(SOFA_CMAKE_VERSION 2.8.8) if(${CMAKE_VERSION} VERSION_LESS ${SOFA_CMAKE_VERSION}) set(MITK_USE_SOFA OFF CACHE BOOL "" FORCE) message(WARNING "Switched off MITK_USE_SOFA\n Minimum required CMake version: ${SOFA_CMAKE_VERSION}\n Installed CMake version: ${CMAKE_VERSION}") endif() # SOFA doesn't support Clang if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(MITK_USE_SOFA OFF CACHE BOOL "" FORCE) message(WARNING "Switched off MITK_USE_SOFA\n Clang is not supported, use GCC instead.") endif() # SOFA/ITK combination requires at least MSVC 2010 if(MSVC_VERSION AND MSVC_VERSION LESS 1600) set(MITK_USE_SOFA OFF CACHE BOOL "" FORCE) message(WARNING "Switched off MITK_USE_SOFA\n MSVC versions less than 2010 are not supported.") endif() # SOFA requires boost library if(MITK_USE_SOFA AND NOT MITK_USE_Boost) message("Forcing MITK_USE_Boost to ON because of MITK_USE_SOFA") set(MITK_USE_Boost ON CACHE BOOL "" FORCE) endif() # SOFA requires boost system library list(FIND MITK_USE_Boost_LIBRARIES system _result) if(_result LESS 0) message("Adding 'system' to MITK_USE_Boost_LIBRARIES.") list(APPEND MITK_USE_Boost_LIBRARIES system) endif() # SOFA requires boost thread library list(FIND MITK_USE_Boost_LIBRARIES thread _result) if(_result LESS 0) message("Adding 'thread' to MITK_USE_Boost_LIBRARIES.") list(APPEND MITK_USE_Boost_LIBRARIES thread) endif() set(MITK_USE_Boost_LIBRARIES ${MITK_USE_Boost_LIBRARIES} CACHE STRING "" FORCE) endif() # Customize the default pixel types for multiplex macros set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") mark_as_advanced(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS ) # consistency checks if(NOT MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES) set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES) set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES) set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) if(MITK_USE_BLUEBERRY) list(APPEND CTEST_PROJECT_SUBPROJECTS BlueBerry) endif() list(APPEND CTEST_PROJECT_SUBPROJECTS MITK-Core MITK-CoreUI MITK-IGT MITK-ToF MITK-DTI MITK-Registration MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CheckCXXSourceCompiles) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionGetGccVersion) include(MacroParseArguments) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkFunctionOrganizeSources) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionCreateWindowsBatchScript) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionCompileSnippets) include(mitkFunctionUseModules) include(mitkMacroCreateModuleConf) include(mitkMacroCreateModule) include(mitkMacroCreateExecutable) include(mitkMacroCheckModule) include(mitkMacroCreateModuleTests) include(mitkFunctionAddCustomModuleTest) include(mitkMacroUseModule) include(mitkMacroMultiplexPicType) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) #----------------------------------------------------------------------------- # Prerequesites #----------------------------------------------------------------------------- find_package(ITK REQUIRED) find_package(VTK REQUIRED) find_package(GDCM PATHS ${ITK_GDCM_DIR} REQUIRED) #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- # ASK THE USER TO SHOW THE CONSOLE WINDOW FOR CoreApp and mitkWorkbench option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING 1) endif() endif() #----------------------------------------------------------------------------- # Get MITK version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK) mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK) #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on Mac OSX all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) list(GET target_info_list 0 app_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) set(MACOSX_BUNDLE_NAMES ${MACOSX_BUNDLE_NAMES} ${app_name}) endif() endforeach() endif() #----------------------------------------------------------------------------- # Set symbol visibility Flags #----------------------------------------------------------------------------- # MinGW does not export all symbols automatically, so no need to set flags if(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW) set(VISIBILITY_CXX_FLAGS ) #"-fvisibility=hidden -fvisibility-inlines-hidden") endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # MITK C/CXX Flags #----------------------------------------------------------------------------- set(MITK_C_FLAGS "${COVERAGE_C_FLAGS}") set(MITK_C_FLAGS_DEBUG ) set(MITK_C_FLAGS_RELEASE ) set(MITK_CXX_FLAGS "${VISIBILITY_CXX_FLAGS} ${COVERAGE_CXX_FLAGS}") set(MITK_CXX_FLAGS_DEBUG ) set(MITK_CXX_FLAGS_RELEASE ) set(MITK_EXE_LINKER_FLAGS ) set(MITK_SHARED_LINKER_FLAGS ) -include(mitkSetupC++0xVariables) - if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -D_WIN32_WINNT=0x0501 -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} /wd4231") # warning C4231: nonstandard extension used : 'extern' before template explicit instantiation endif() if(NOT MSVC_VERSION) foreach(_flag -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Wno-error=gnu -Wno-error=unknown-pragmas # The strict-overflow warning is generated by ITK template code -Wno-error=strict-overflow -Woverloaded-virtual -Wstrict-null-sentinel #-Wold-style-cast #-Wsign-promo # the following two lines should be removed after ITK-3097 has # been resolved, see also MITK bug 15279 -Wno-unused-local-typedefs -Wno-array-bounds -fdiagnostics-show-option ) mitkFunctionCheckCAndCXXCompilerFlags(${_flag} MITK_C_FLAGS MITK_CXX_FLAGS) endforeach() endif() mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) -if(MITK_USE_C++0x) - mitkFunctionCheckCompilerFlags("-std=c++0x" MITK_CXX_FLAGS) -endif() - if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) # With older version of gcc supporting the flag -fstack-protector-all, an extra dependency to libssp.so # is introduced. If gcc is smaller than 4.4.0 and the build type is Release let's not include the flag. # Doing so should allow to build package made for distribution using older linux distro. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) mitkFunctionCheckCAndCXXCompilerFlags("-fstack-protector-all" MITK_C_FLAGS MITK_CXX_FLAGS) endif() if(MINGW) # suppress warnings about auto imported symbols set(MITK_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import ${MITK_SHARED_LINKER_FLAGS}") endif() set(MITK_CXX_FLAGS_RELEASE "-D_FORTIFY_SOURCE=2 ${MITK_CXX_FLAGS_RELEASE}") endif() set(MITK_MODULE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(MITK_EXE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) #----------------------------------------------------------------------------- # MITK Packages #----------------------------------------------------------------------------- set(MITK_MODULES_PACKAGE_DEPENDS_DIR ${MITK_SOURCE_DIR}/CMake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR} ${MITK_MODULES_PACKAGE_DEPENDS_DIR}/Qt) #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) option(MITK_ENABLE_RENDERING_TESTING OFF "Enable the MITK rendering tests. Requires x-server in Linux.") #Rendering testing does not work for Linux nightlies, thus it is disabled per default #and activated for Mac and Windows. if(WIN32 OR APPLE) set(MITK_ENABLE_RENDERING_TESTING ON) endif() mark_as_advanced( MITK_ENABLE_RENDERING_TESTING ) # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch( std::exception & excp ) { fprintf(stderr,\"%s\\n\",excp.what()); return EXIT_FAILURE; } catch( ... ) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; } ") set(MITK_TEST_OUTPUT_DIR "${MITK_BINARY_DIR}/test_output") if(NOT EXISTS ${MITK_TEST_OUTPUT_DIR}) file(MAKE_DIRECTORY ${MITK_TEST_OUTPUT_DIR}) endif() # Test the external project template if(MITK_USE_BLUEBERRY) include(mitkTestProjectTemplate) endif() # Test the package target include(mitkPackageTest) endif() configure_file(mitkTestingConfig.h.in ${MITK_BINARY_DIR}/mitkTestingConfig.h) #----------------------------------------------------------------------------- # MITK_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If MITK_SUPERBUILD_BINARY_DIR isn't defined, it means MITK is *NOT* build using Superbuild. # In that specific case, MITK_SUPERBUILD_BINARY_DIR should default to MITK_BINARY_DIR if(NOT DEFINED MITK_SUPERBUILD_BINARY_DIR) set(MITK_SUPERBUILD_BINARY_DIR ${MITK_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Compile Utilities and set-up MITK variables #----------------------------------------------------------------------------- include(mitkSetupVariables) #----------------------------------------------------------------------------- # Cleanup #----------------------------------------------------------------------------- file(GLOB _MODULES_CONF_FILES ${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME}/*.cmake) if(_MODULES_CONF_FILES) file(REMOVE ${_MODULES_CONF_FILES}) endif() add_subdirectory(Utilities) if(MITK_USE_BLUEBERRY) # We need to hack a little bit because MITK applications may need # to enable certain BlueBerry plug-ins. However, these plug-ins # are validated separately from the MITK plug-ins and know nothing # about potential MITK plug-in dependencies of the applications. Hence # we cannot pass the MITK application list to the BlueBerry # ctkMacroSetupPlugins call but need to extract the BlueBerry dependencies # from the applications and set them explicitly. include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) # check if the application is enabled and if target_libraries.cmake exists if((${option_name} OR MITK_BUILD_ALL_APPS) AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/target_libraries.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/target_libraries.cmake") foreach(_target_dep ${target_libraries}) if(_target_dep MATCHES org_blueberry_) string(REPLACE _ . _app_bb_dep ${_target_dep}) # explicitly set the build option for the BlueBerry plug-in set(BLUEBERRY_BUILD_${_app_bb_dep} ON CACHE BOOL "Build the ${_app_bb_dep} plug-in") endif() endforeach() endif() endforeach() set(mbilog_DIR "${mbilog_BINARY_DIR}") if(MITK_BUILD_ALL_PLUGINS) set(BLUEBERRY_BUILD_ALL_PLUGINS ON) endif() set(BLUEBERRY_XPDOC_OUTPUT_DIR ${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/) add_subdirectory(BlueBerry) set(BlueBerry_DIR ${CMAKE_CURRENT_BINARY_DIR}/BlueBerry CACHE PATH "The directory containing a CMake configuration file for BlueBerry" FORCE) include(mitkMacroCreateCTKPlugin) endif() #----------------------------------------------------------------------------- # Set C/CXX and linker flags for MITK code #----------------------------------------------------------------------------- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MITK_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MITK_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MITK_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MITK_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MITK_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MITK_C_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MITK_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MITK_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MITK_MODULE_LINKER_FLAGS}") #----------------------------------------------------------------------------- # Add custom targets representing CDash subprojects #----------------------------------------------------------------------------- foreach(subproject ${CTEST_PROJECT_SUBPROJECTS}) if(NOT TARGET ${subproject} AND NOT subproject MATCHES "Unlabeled") add_custom_target(${subproject}) endif() endforeach() #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Core) add_subdirectory(Modules) if(MITK_USE_BLUEBERRY) find_package(BlueBerry REQUIRED) set(MITK_DEFAULT_SUBPROJECTS MITK-Plugins) # Plug-in testing (needs some work to be enabled again) if(BUILD_TESTING) include(berryTestingHelpers) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp") get_target_property(_is_macosx_bundle CoreApp MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp.app/Contents/MacOS/CoreApp") endif() set(BLUEBERRY_TEST_APP_ID "org.mitk.qt.coreapplication") endif() include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") set(mitk_plugins_fullpath ) foreach(mitk_plugin ${MITK_EXT_PLUGINS}) list(APPEND mitk_plugins_fullpath Plugins/${mitk_plugin}) endforeach() if(EXISTS ${MITK_PRIVATE_MODULES}/PluginList.cmake) include(${MITK_PRIVATE_MODULES}/PluginList.cmake) foreach(mitk_plugin ${MITK_PRIVATE_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PRIVATE_MODULES}/${mitk_plugin}) endforeach() endif() if(MITK_BUILD_EXAMPLES) include("${CMAKE_CURRENT_SOURCE_DIR}/Examples/Plugins/PluginList.cmake") set(mitk_example_plugins_fullpath ) foreach(mitk_example_plugin ${MITK_EXAMPLE_PLUGINS}) list(APPEND mitk_example_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) list(APPEND mitk_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) endforeach() endif() # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_[a-zA-Z0-9_]+$") set(re_ctkplugin_bb "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk re_ctkplugin_bb OUTPUT_VARIABLE ${varname}) endmacro() # Get infos about application directories and build options include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") set(mitk_apps_fullpath ) foreach(mitk_app ${MITK_APPS}) list(APPEND mitk_apps_fullpath "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${mitk_app}") endforeach() if (mitk_plugins_fullpath) ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) endif() set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() # 11.3.13, change, muellerm: activate python bundle if python and blueberry is active if( MITK_USE_Python ) set(MITK_BUILD_org.mitk.gui.qt.python ON) endif() endif() #----------------------------------------------------------------------------- # Python Wrapping #----------------------------------------------------------------------------- option(MITK_USE_Python "Build Python integration for MITK (requires CableSwig)." OFF) #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(Documentation) #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables # These are the default variables, which can be overwritten ( see below ) include(mitkSetupCPack) set(use_default_config ON) # MITK_APPS is set in Applications/AppList.cmake (included somewhere above # if MITK_USE_BLUEBERRY is set to ON). if(MITK_APPS) set(activated_apps_no 0) list(LENGTH MITK_APPS app_count) # Check how many apps have been enabled # If more than one app has been activated, the we use the # default CPack configuration. Otherwise that apps configuration # will be used, if present. foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS)) # Corner case if there is only one app in total set(use_project_cpack ON) elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS) # Only one app is enabled (no "build all" flag set) set(use_project_cpack ON) else() # Less or more then one app is enabled set(use_project_cpack OFF) endif() foreach(mitk_app ${MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) # check whether application specific configuration files will be used if(use_project_cpack) # use files if they exist if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/Applications/${target_dir}/CPackConfig.cmake") configure_file(${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in ${CPACK_PROJECT_CONFIG_FILE} @ONLY) set(use_default_config OFF) endif() endif() # add link to the list list(APPEND CPACK_CREATE_DESKTOP_LINKS "${target_dir}") endif() endforeach() endif() # if no application specific configuration file was used, use default if(use_default_config) configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake") endif() # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake") file(REMOVE ${MITK_EXPORTS_FILE}) set(targets_to_export) get_property(module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) if(module_targets) list(APPEND targets_to_export ${module_targets}) endif() if(MITK_USE_BLUEBERRY) if(MITK_PLUGIN_LIBRARIES) list(APPEND targets_to_export ${MITK_PLUGIN_LIBRARIES}) endif() endif() export(TARGETS ${targets_to_export} APPEND FILE ${MITK_EXPORTS_FILE}) set(MITK_EXPORTED_TARGET_PROPERTIES ) foreach(target_to_export ${targets_to_export}) get_target_property(autoload_targets ${target_to_export} MITK_AUTOLOAD_TARGETS) if(autoload_targets) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_TARGETS \"${autoload_targets}\")") endif() get_target_property(autoload_dir ${target_to_export} MITK_AUTOLOAD_DIRECTORY) if(autoload_dir) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_DIRECTORY \"${autoload_dir}\")") endif() endforeach() get_property(MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS_CONFIG GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY) set(VISIBILITY_AVAILABLE 0) set(visibility_test_flag "") mitkFunctionCheckCompilerFlags("-fvisibility=hidden" visibility_test_flag) if(visibility_test_flag) # The compiler understands -fvisiblity=hidden (probably gcc >= 4 or Clang) set(VISIBILITY_AVAILABLE 1) endif() configure_file(mitkExportMacros.h.in ${MITK_BINARY_DIR}/mitkExportMacros.h) configure_file(mitkVersion.h.in ${MITK_BINARY_DIR}/mitkVersion.h) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc) set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) file(GLOB _MODULES_CONF_FILES RELATIVE ${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME} ${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME}/*.cmake) set(MITK_MODULE_NAMES) foreach(_module ${_MODULES_CONF_FILES}) string(REPLACE Config.cmake "" _module_name ${_module}) list(APPEND MITK_MODULE_NAMES ${_module_name}) endforeach() configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY) # If we are under Windows, create two batch files which correctly # set up the environment for the application and for Visual Studio if(WIN32) include(mitkFunctionCreateWindowsBatchScript) set(VS_SOLUTION_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.sln") foreach(VS_BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript("${MITK_SOURCE_DIR}/CMake/StartVS.bat.in" ${PROJECT_BINARY_DIR}/StartVS_${VS_BUILD_TYPE}.bat ${VS_BUILD_TYPE}) endforeach() endif(WIN32) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) #----------------------------------------------------------------------------- # MITK Examples #----------------------------------------------------------------------------- if(MITK_BUILD_EXAMPLES) # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Examples) endif() diff --git a/Modules/ClippingTools/CMakeLists.txt b/Modules/ClippingTools/CMakeLists.txt index 746174ecc3..a2f442c2a1 100644 --- a/Modules/ClippingTools/CMakeLists.txt +++ b/Modules/ClippingTools/CMakeLists.txt @@ -1,3 +1,4 @@ MITK_CREATE_MODULE(ClippingTools -DEPENDS Mitk Segmentation + DEPENDS Mitk Segmentation + WARNINGS_AS_ERRORS ) diff --git a/Modules/ContourModel/Algorithms/mitkContourModelSubDivisionFilter.cpp b/Modules/ContourModel/Algorithms/mitkContourModelSubDivisionFilter.cpp index dd587e4064..11b17e57ca 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelSubDivisionFilter.cpp +++ b/Modules/ContourModel/Algorithms/mitkContourModelSubDivisionFilter.cpp @@ -1,217 +1,217 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelSubDivisionFilter.h" #include #include mitk::ContourModelSubDivisionFilter::ContourModelSubDivisionFilter() { OutputType::Pointer output = dynamic_cast ( this->MakeOutput( 0 ).GetPointer() ); this->SetNumberOfRequiredInputs(1); this->SetNumberOfIndexedOutputs( 1 ); this->SetNthOutput(0, output.GetPointer()); this->m_InterpolationIterations = 4; } mitk::ContourModelSubDivisionFilter::~ContourModelSubDivisionFilter() { } void mitk::ContourModelSubDivisionFilter::SetInput ( const mitk::ContourModelSubDivisionFilter::InputType* input ) { this->SetInput( 0, input ); } void mitk::ContourModelSubDivisionFilter::SetInput ( unsigned int idx, const mitk::ContourModelSubDivisionFilter::InputType* input ) { if ( idx + 1 > this->GetNumberOfInputs() ) { this->SetNumberOfRequiredInputs(idx + 1); } if ( input != static_cast ( this->ProcessObject::GetInput ( idx ) ) ) { this->ProcessObject::SetNthInput ( idx, const_cast ( input ) ); this->Modified(); } } const mitk::ContourModelSubDivisionFilter::InputType* mitk::ContourModelSubDivisionFilter::GetInput( void ) { if (this->GetNumberOfInputs() < 1) return NULL; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::ContourModelSubDivisionFilter::InputType* mitk::ContourModelSubDivisionFilter::GetInput( unsigned int idx ) { if (this->GetNumberOfInputs() < 1) return NULL; return static_cast(this->ProcessObject::GetInput(idx)); } void mitk::ContourModelSubDivisionFilter::GenerateData() { mitk::ContourModel::Pointer input = const_cast(this->GetInput(0)); - mitk::ContourModelSubDivisionFilter::OutputType::Pointer outputContour = this->GetOutput(); + //mitk::ContourModelSubDivisionFilter::OutputType::Pointer outputContour = this->GetOutput(); mitk::ContourModel::Pointer contour(input); - unsigned int timestep = input->GetTimeSteps(); + int timestep = static_cast(input->GetTimeSteps()); for ( int currentTimestep = 0; currentTimestep < timestep; currentTimestep++) { if( input->GetNumberOfVertices(currentTimestep) >= 4) { for( int iterations = 0; iterations < this->m_InterpolationIterations; iterations++) { InputType::VertexIterator it = contour->IteratorBegin(); InputType::VertexIterator end = contour->IteratorEnd(); InputType::VertexIterator first = contour->IteratorBegin(); InputType::VertexIterator last = contour->IteratorEnd()-1; //tempory contour to store result of a subdivision iteration mitk::ContourModel::Pointer tempContour = mitk::ContourModel::New(); //insert subpoints while ( it != end ) { //add the current point to the temp contour tempContour->AddVertex((*it)->Coordinates, (*it)->IsControlPoint, currentTimestep); //control points for interpolation InputType::VertexIterator Ci = it; InputType::VertexIterator CiPlus1; InputType::VertexIterator CiPlus2; InputType::VertexIterator CiMinus1; //consider all possible cases if( it == first) { if( input->IsClosed(currentTimestep) ) { CiPlus1 = it + 1; CiPlus2 = it + 2; CiMinus1 = last; } else { CiPlus1 = it + 1; CiPlus2 = it + 2; CiMinus1 = it; } } else if( it == last ) { if( input->IsClosed(currentTimestep) ) { CiPlus1 = first; CiPlus2 = first + 1; CiMinus1 = it -1; } else { //don't add point after last break; } } else if( it == (last - 1) ) { if( input->IsClosed(currentTimestep) ) { CiPlus1 = it + 1; CiPlus2 = first; CiMinus1 = it -1; } else { CiPlus1 = it + 1; CiPlus2 = it + 1; CiMinus1 = it -1; } } else { CiPlus1 = it + 1; CiPlus2 = it + 2; CiMinus1 = it -1; } /* F2i = Ci * F2i+1 = -1/16Ci-1 + 9/16Ci + 9/16Ci+1 - 1/16Ci+2 */ mitk::Point3D subpoint; mitk::Point3D a; a[0]=(-1.0/16.0) * (*CiMinus1)->Coordinates[0]; a[1]=(-1.0/16.0) * (*CiMinus1)->Coordinates[1]; a[2]= (-1.0/16.0) * (*CiMinus1)->Coordinates[2]; mitk::Point3D b; b[0]=(9.0/16.0) * (*Ci)->Coordinates[0]; b[1]=(9.0/16.0) * (*Ci)->Coordinates[1]; b[2]= (9.0/16.0) * (*Ci)->Coordinates[2]; mitk::Point3D c; c[0]=(9.0/16.0) * (*CiPlus1)->Coordinates[0]; c[1]=(9.0/16.0) * (*CiPlus1)->Coordinates[1]; c[2]= (9.0/16.0) * (*CiPlus1)->Coordinates[2]; mitk::Point3D d; d[0]=(-1.0/16.0) * (*CiPlus2)->Coordinates[0]; d[1]=(-1.0/16.0) * (*CiPlus2)->Coordinates[1]; d[2]= (-1.0/16.0) * (*CiPlus2)->Coordinates[2]; subpoint[0] = a[0] + b[0] + c[0] + d[0]; subpoint[1] = a[1] + b[1] + c[1] + d[1]; subpoint[2] = a[2] + b[2] + c[2] + d[2]; InputType::VertexType subdivisionPoint(subpoint,false); //add the new subdivision point to our tempContour tempContour->AddVertex(subdivisionPoint.Coordinates, currentTimestep); it++; } //set the interpolated contour as the contour for the next iteration contour = tempContour; } } else { //filter not executeable - set input to output contour = input; } } //somehow the isClosed property is not set via copy constructor contour->SetClosed(input->IsClosed()); this->SetNthOutput(0, contour); } diff --git a/Modules/ContourModel/Algorithms/mitkContourModelSubDivisionFilter.h b/Modules/ContourModel/Algorithms/mitkContourModelSubDivisionFilter.h index f3fdc5adbc..76fa850e32 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelSubDivisionFilter.h +++ b/Modules/ContourModel/Algorithms/mitkContourModelSubDivisionFilter.h @@ -1,85 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _mitkContourModelSubDivisionFilter_h__ #define _mitkContourModelSubDivisionFilter_h__ #include "mitkCommon.h" #include "ContourModelExports.h" #include "mitkContourModel.h" #include "mitkContourModelSource.h" namespace mitk { /** * * \brief This filter interpolates a subdivision curve between control points of the contour. * For inserting subpoints Dyn-Levin-Gregory (DLG) interpolation scheme is used. * Interpolating a cruve subdivision is done by: * F2i = Ci * F2i+1 = -1/16Ci-1 + 9/16Ci + 9/16Ci+1 - 1/16Ci+2 * * The number of interpolation iterations can be set via SetNumberOfIterations(int) which are 4 by dafault. * * \ingroup ContourModelFilters * \ingroup Process */ class ContourModel_EXPORT ContourModelSubDivisionFilter : public ContourModelSource { public: mitkClassMacro(ContourModelSubDivisionFilter, ContourModelSource); itkNewMacro(Self); typedef ContourModel OutputType; typedef OutputType::Pointer OutputTypePointer; typedef mitk::ContourModel InputType; /** * \brief Set the number of iterations for inserting new interpolated control points. * */ void SetNumberOfIterations( int iterations) { this->m_InterpolationIterations = iterations; } + using Superclass::SetInput; + virtual void SetInput( const InputType *input); virtual void SetInput( unsigned int idx, const InputType * input); const InputType* GetInput(void); const InputType* GetInput(unsigned int idx); protected: ContourModelSubDivisionFilter(); virtual ~ContourModelSubDivisionFilter(); void GenerateOutputInformation() {}; void GenerateData(); int m_InterpolationIterations; }; } #endif diff --git a/Modules/ContourModel/Algorithms/mitkContourModelToPointSetFilter.cpp b/Modules/ContourModel/Algorithms/mitkContourModelToPointSetFilter.cpp index 966032ed29..85a057ed2f 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelToPointSetFilter.cpp +++ b/Modules/ContourModel/Algorithms/mitkContourModelToPointSetFilter.cpp @@ -1,65 +1,65 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelToPointSetFilter.h" #include #include mitk::ContourModelToPointSetFilter::ContourModelToPointSetFilter() { itk::DataObject::Pointer output = this->MakeOutput(0); this->SetNumberOfRequiredInputs(1); this->SetNumberOfRequiredOutputs( 1 ); this->SetNthOutput(0, output.GetPointer()); } mitk::ContourModelToPointSetFilter::~ContourModelToPointSetFilter() { } void mitk::ContourModelToPointSetFilter::GenerateData() { mitk::ContourModel::Pointer inputContour = static_cast(this->GetInput(0)); mitk::ContourModelToPointSetFilter::OutputType* outputPointSet = this->GetOutput(); InputType::VertexIterator it = inputContour->IteratorBegin(); InputType::VertexIterator end = inputContour->IteratorEnd(); unsigned int pointId = 0; - unsigned int timestep = inputContour->GetTimeSteps(); + std::size_t timestep = inputContour->GetTimeSteps(); - for ( int i = 0; i < timestep; i++) + for ( std::size_t i = 0; i < timestep; i++) { while ( it <= end ) { mitk::Point3D p = (*it)->Coordinates; mitk::PointOperation popInsert( mitk::OpINSERT, inputContour->GetTimeGeometry()->TimeStepToTimePoint(timestep), p, pointId++, false ); outputPointSet->ExecuteOperation( &popInsert ); it++; } } } diff --git a/Modules/ContourModel/Algorithms/mitkContourModelToSurfaceFilter.h b/Modules/ContourModel/Algorithms/mitkContourModelToSurfaceFilter.h index d542ef087f..65267aa7e8 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelToSurfaceFilter.h +++ b/Modules/ContourModel/Algorithms/mitkContourModelToSurfaceFilter.h @@ -1,63 +1,64 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_CONTOURMODEL_TO_Surface_FILTER_H_ #define _MITK_CONTOURMODEL_TO_Surface_FILTER_H_ #include "mitkCommon.h" #include "ContourModelExports.h" #include "mitkContourModel.h" #include "mitkContourModelSource.h" #include namespace mitk { class ContourModel_EXPORT ContourModelToSurfaceFilter : public SurfaceSource { public: /** Standard class typedefs. */ mitkClassMacro( ContourModelToSurfaceFilter, SurfaceSource ); /** Method for creation through the object factory. */ itkNewMacro(Self); typedef mitk::Surface OutputType; typedef mitk::ContourModel InputType; void GenerateOutputInformation(); /** Set/Get the image input of this process object. */ + using Superclass::SetInput; virtual void SetInput( const InputType *input); virtual void SetInput( unsigned int idx, const InputType * input); const InputType * GetInput(void); const InputType * GetInput(unsigned int idx); protected: ContourModelToSurfaceFilter(); ~ContourModelToSurfaceFilter(); virtual void GenerateData(); }; } #endif diff --git a/Modules/ContourModel/Algorithms/mitkContourObjectFactory.cpp b/Modules/ContourModel/Algorithms/mitkContourObjectFactory.cpp index 34333a079c..689bb6fbe0 100644 --- a/Modules/ContourModel/Algorithms/mitkContourObjectFactory.cpp +++ b/Modules/ContourModel/Algorithms/mitkContourObjectFactory.cpp @@ -1,179 +1,178 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourObjectFactory.h" #include "mitkProperties.h" #include "mitkBaseRenderer.h" #include "mitkDataNode.h" #include "mitkCoreObjectFactory.h" #include "mitkContourModel.h" #include "mitkContourModelSet.h" #include "mitkContourModelIOFactory.h" #include "mitkContourModelWriterFactory.h" #include "mitkContourModelWriter.h" #include "mitkContourModelSetWriter.h" #include "mitkContourModelMapper2D.h" #include "mitkContourModelGLMapper2D.h" #include "mitkContourModelSetGLMapper2D.h" #include "mitkContourModelMapper3D.h" #include "mitkContourModelSetMapper3D.h" mitk::ContourObjectFactory::ContourObjectFactory() : CoreObjectFactoryBase() , m_ContourModelIOFactory(mitk::ContourModelIOFactory::New().GetPointer()) , m_ContourModelWriterFactory(mitk::ContourModelWriterFactory::New().GetPointer()) { static bool alreadyDone = false; if (!alreadyDone) { MITK_DEBUG << "ContourObjectFactory c'tor" << std::endl; itk::ObjectFactoryBase::RegisterFactory( m_ContourModelIOFactory ); itk::ObjectFactoryBase::RegisterFactory( m_ContourModelWriterFactory ); this->m_FileWriters.push_back(mitk::ContourModelWriter::New().GetPointer()); this->m_FileWriters.push_back(mitk::ContourModelSetWriter::New().GetPointer()); CreateFileExtensionsMap(); alreadyDone = true; } } mitk::ContourObjectFactory::~ContourObjectFactory() { itk::ObjectFactoryBase::UnRegisterFactory(m_ContourModelIOFactory); itk::ObjectFactoryBase::UnRegisterFactory(m_ContourModelWriterFactory); } mitk::Mapper::Pointer mitk::ContourObjectFactory::CreateMapper(mitk::DataNode* node, MapperSlotId id) { mitk::Mapper::Pointer newMapper=NULL; - mitk::BaseData *data = node->GetData(); if ( id == mitk::BaseRenderer::Standard2D ) { std::string classname("ContourModel"); if( dynamic_cast(node->GetData())!=NULL ) { newMapper = mitk::ContourModelGLMapper2D::New(); newMapper->SetDataNode(node); } else if( dynamic_cast(node->GetData())!=NULL ) { newMapper = mitk::ContourModelSetGLMapper2D::New(); newMapper->SetDataNode(node); } } else if ( id == mitk::BaseRenderer::Standard3D ) { if( dynamic_cast(node->GetData())!=NULL ) { newMapper = mitk::ContourModelMapper3D::New(); newMapper->SetDataNode(node); } else if( dynamic_cast(node->GetData())!=NULL ) { newMapper = mitk::ContourModelSetMapper3D::New(); newMapper->SetDataNode(node); } } return newMapper; } void mitk::ContourObjectFactory::SetDefaultProperties(mitk::DataNode* node) { if(node==NULL) return; mitk::DataNode::Pointer nodePointer = node; if(node->GetData() ==NULL) return; if( dynamic_cast(node->GetData())!=NULL ) { mitk::ContourModelGLMapper2D::SetDefaultProperties(node); mitk::ContourModelMapper3D::SetDefaultProperties(node); } else if( dynamic_cast(node->GetData())!=NULL ) { mitk::ContourModelSetGLMapper2D::SetDefaultProperties(node); mitk::ContourModelSetMapper3D::SetDefaultProperties(node); } } const char* mitk::ContourObjectFactory::GetFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_FileExtensionsMap, fileExtension); return fileExtension.c_str(); }; mitk::CoreObjectFactoryBase::MultimapType mitk::ContourObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } mitk::CoreObjectFactoryBase::MultimapType mitk::ContourObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } void mitk::ContourObjectFactory::CreateFileExtensionsMap() { m_SaveFileExtensionsMap.insert(std::pair("*.cnt", "Contour Files")); m_FileExtensionsMap.insert(std::pair("*.cnt", "Contour File")); m_SaveFileExtensionsMap.insert(std::pair("*.cnt_set", "ContourModelSet Files")); m_FileExtensionsMap.insert(std::pair("*.cnt_set", "ContourModelSet File")); } const char* mitk::ContourObjectFactory::GetSaveFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension); return fileExtension.c_str(); } void mitk::ContourObjectFactory::RegisterIOFactories() { } struct RegisterContourObjectFactory{ RegisterContourObjectFactory() : m_Factory( mitk::ContourObjectFactory::New() ) { mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory( m_Factory ); } ~RegisterContourObjectFactory() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory( m_Factory ); } mitk::ContourObjectFactory::Pointer m_Factory; }; static RegisterContourObjectFactory registerContourObjectFactory; diff --git a/Modules/ContourModel/Algorithms/mitkImageToContourModelFilter.h b/Modules/ContourModel/Algorithms/mitkImageToContourModelFilter.h index a644251a11..5bc5dd58c0 100644 --- a/Modules/ContourModel/Algorithms/mitkImageToContourModelFilter.h +++ b/Modules/ContourModel/Algorithms/mitkImageToContourModelFilter.h @@ -1,66 +1,68 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _mitkImageToContourModelFilter_h__ #define _mitkImageToContourModelFilter_h__ #include "mitkCommon.h" #include "ContourModelExports.h" #include "mitkContourModel.h" #include "mitkContourModelSource.h" #include namespace mitk { /** * * \brief Base class for all filters with mitk::Image as input and mitk::ContourModel * * \ingroup ContourModelFilters * \ingroup Process */ class ContourModel_EXPORT ImageToContourModelFilter : public ContourModelSource { public: mitkClassMacro(ImageToContourModelFilter, ContourModelSource); itkNewMacro(Self); typedef mitk::Image InputType; + using Superclass::SetInput; + virtual void SetInput( const InputType *input); virtual void SetInput( unsigned int idx, const InputType * input); const InputType* GetInput(void); const InputType* GetInput(unsigned int idx); protected: ImageToContourModelFilter(); virtual ~ImageToContourModelFilter(); void GenerateData(); }; } #endif diff --git a/Modules/ContourModel/CMakeLists.txt b/Modules/ContourModel/CMakeLists.txt index ad52a7262f..5b20df8d66 100644 --- a/Modules/ContourModel/CMakeLists.txt +++ b/Modules/ContourModel/CMakeLists.txt @@ -1,6 +1,7 @@ MITK_CREATE_MODULE( ContourModel INCLUDE_DIRS Algorithms DataManagement IO Rendering DEPENDS Mitk + WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/ContourModel/DataManagement/mitkContourElement.cpp b/Modules/ContourModel/DataManagement/mitkContourElement.cpp index a74cb96723..0c44833ce4 100644 --- a/Modules/ContourModel/DataManagement/mitkContourElement.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourElement.cpp @@ -1,515 +1,517 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include mitk::ContourElement::ContourElement() { this->m_Vertices = new VertexListType(); this->m_IsClosed = false; } mitk::ContourElement::ContourElement(const mitk::ContourElement &other) : - m_Vertices(other.m_Vertices), m_IsClosed(other.m_IsClosed) + itk::LightObject(), + m_Vertices(other.m_Vertices), + m_IsClosed(other.m_IsClosed) { } mitk::ContourElement::~ContourElement() { delete this->m_Vertices; } void mitk::ContourElement::AddVertex(mitk::Point3D &vertex, bool isControlPoint) { this->m_Vertices->push_back(new VertexType(vertex, isControlPoint)); } void mitk::ContourElement::AddVertex(VertexType &vertex) { this->m_Vertices->push_back(&vertex); } void mitk::ContourElement::AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint) { this->m_Vertices->push_front(new VertexType(vertex, isControlPoint)); } void mitk::ContourElement::AddVertexAtFront(VertexType &vertex) { this->m_Vertices->push_front(&vertex); } void mitk::ContourElement::InsertVertexAtIndex(mitk::Point3D &vertex, bool isControlPoint, int index) { if(index >= 0 && this->GetSize() > index) { VertexIterator _where = this->m_Vertices->begin(); _where += index; this->m_Vertices->insert(_where, new VertexType(vertex, isControlPoint)); } } void mitk::ContourElement::SetVertexAt(int pointId, const Point3D &point) { if(pointId >= 0 && this->GetSize() > pointId) { this->m_Vertices->at(pointId)->Coordinates = point; } } void mitk::ContourElement::SetVertexAt(int pointId, const VertexType* vertex) { if(pointId >= 0 && this->GetSize() > pointId) { this->m_Vertices->at(pointId)->Coordinates = vertex->Coordinates; this->m_Vertices->at(pointId)->IsControlPoint = vertex->IsControlPoint; } } mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(int index) { return this->m_Vertices->at(index); } bool mitk::ContourElement::IsEmpty() { return this->m_Vertices->empty(); } mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(const mitk::Point3D &point, float eps) { /* current version iterates over the whole deque - should some kind of an octree with spatial query*/ if(eps > 0) { //currently no method with better performance is available return BruteForceGetVertexAt(point, eps); }//if eps < 0 return NULL; } mitk::ContourElement::VertexType* mitk::ContourElement::BruteForceGetVertexAt(const mitk::Point3D &point, float eps) { if(eps > 0) { std::deque< std::pair > nearestlist; ConstVertexIterator it = this->m_Vertices->begin(); ConstVertexIterator end = this->m_Vertices->end(); while(it != end) { mitk::Point3D currentPoint = (*it)->Coordinates; double distance = currentPoint.EuclideanDistanceTo(point); if(distance < eps) { //if list is emtpy, add point to list if(nearestlist.size() < 1) { nearestlist.push_front(std::pair( (*it)->Coordinates.EuclideanDistanceTo(point), (*it) )); } //found an approximate point - check if current is closer then first in nearestlist else if( distance < nearestlist.front().first ) { //found even closer vertex nearestlist.push_front(std::pair( (*it)->Coordinates.EuclideanDistanceTo(point), (*it) )); } }//if distance > eps it++; }//while if(nearestlist.size() > 0) { /*++++++++++++++++++++ return the nearest active point if one was found++++++++++++++++++*/ std::deque< std::pair >::iterator it = nearestlist.begin(); std::deque< std::pair >::iterator end = nearestlist.end(); while(it != end) { if( (*it).second->IsControlPoint ) { return (*it).second; } it++; } /*---------------------------------------------------------------------------------------*/ //return closest point return nearestlist.front().second; } } return NULL; } /*mitk::ContourElement::VertexType* mitk::ContourElement::OptimizedGetVertexAt(const mitk::Point3D &point, float eps) { if( (eps > 0) && (this->m_Vertices->size()>0) ) { int k = 1; int dim = 3; int nPoints = this->m_Vertices->size(); ANNpointArray pointsArray; ANNpoint queryPoint; ANNidxArray indexArray; ANNdistArray distanceArray; ANNkd_tree* kdTree; queryPoint = annAllocPt(dim); pointsArray = annAllocPts(nPoints, dim); indexArray = new ANNidx[k]; distanceArray = new ANNdist[k]; int i = 0; //fill points array with our control points for(VertexIterator it = this->m_Vertices->begin(); it != this->m_Vertices->end(); it++, i++) { mitk::Point3D cur = (*it)->Coordinates; pointsArray[i][0]= cur[0]; pointsArray[i][1]= cur[1]; pointsArray[i][2]= cur[2]; } //create the kd tree kdTree = new ANNkd_tree(pointsArray,nPoints, dim); //fill mitk::Point3D into ANN query point queryPoint[0] = point[0]; queryPoint[1] = point[1]; queryPoint[2] = point[2]; //k nearest neighbour search kdTree->annkSearch(queryPoint, k, indexArray, distanceArray, eps); VertexType* ret = NULL; try { ret = this->m_Vertices->at(indexArray[0]); } catch(std::out_of_range ex) { //ret stays NULL return ret; } //clean up ANN delete [] indexArray; delete [] distanceArray; delete kdTree; annClose(); return ret; } return NULL; } */ mitk::ContourElement::VertexListType* mitk::ContourElement::GetVertexList() { return this->m_Vertices; } bool mitk::ContourElement::IsClosed() { return this->m_IsClosed; } bool mitk::ContourElement::IsNearContour(const mitk::Point3D &point, float eps) { ConstVertexIterator it1 = this->m_Vertices->begin(); ConstVertexIterator it2 = this->m_Vertices->begin(); it2 ++; // it2 runs one position ahead ConstVertexIterator end = this->m_Vertices->end(); int counter = 0; for (; it1 != end; it1++, it2++, counter++) { if (it2 == end) it2 = this->m_Vertices->begin(); mitk::Point3D v1 = (*it1)->Coordinates; mitk::Point3D v2 = (*it2)->Coordinates; const float l2 = v1.SquaredEuclideanDistanceTo(v2); mitk::Vector3D p_v1 = point - v1; mitk::Vector3D v2_v1 = v2 - v1; double tc = (p_v1 * v2_v1) / l2; // take into account we have line segments and not (infinite) lines if (tc < 0.0) tc = 0.0; if (tc > 1.0) tc = 1.0; mitk::Point3D crossPoint = v1 + v2_v1 * tc; double distance = point.SquaredEuclideanDistanceTo(crossPoint); if (distance < eps) { return true; } } return false; } void mitk::ContourElement::Close() { this->m_IsClosed = true; } void mitk::ContourElement::Open() { this->m_IsClosed = false; } void mitk::ContourElement::SetClosed( bool isClosed) { isClosed ? this->Close() : this->Open(); } mitk::ContourElement::VertexListType* mitk::ContourElement::GetControlVertices() { VertexListType* newVertices = new VertexListType(); VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); while(it != end) { if((*it)->IsControlPoint) { newVertices->push_back((*it)); } it++; } return newVertices; } void mitk::ContourElement::Concatenate(mitk::ContourElement* other, bool check) { if( other->GetSize() > 0) { ConstVertexIterator otherIt = other->m_Vertices->begin(); ConstVertexIterator otherEnd = other->m_Vertices->end(); while(otherIt != otherEnd) { if (check) { ConstVertexIterator thisIt = this->m_Vertices->begin(); ConstVertexIterator thisEnd = this->m_Vertices->end(); bool found = false; while(thisIt != thisEnd) { if ( (*thisIt)->Coordinates == (*otherIt)->Coordinates ) { found = true; break; } thisIt++; } if (!found) this->m_Vertices->push_back(*otherIt); } else { this->m_Vertices->push_back(*otherIt); } otherIt++; } } } bool mitk::ContourElement::RemoveVertex(const VertexType *vertex) { VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); //search for vertex and remove it if exists while(it != end) { if((*it) == vertex) { this->m_Vertices->erase(it); return true; } it++; } return false; } int mitk::ContourElement::GetIndex(const VertexType *vertex) { VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); int index = 0; //search for vertex while(it != end) { if((*it) == vertex) { return index; } it++; ++index; } return -1;//not found } bool mitk::ContourElement::RemoveVertexAt(int index) { - if( index >= 0 && index < this->m_Vertices->size() ) + if( index >= 0 && static_cast(index) < this->m_Vertices->size() ) { this->m_Vertices->erase(this->m_Vertices->begin()+index); return true; } else { return false; } } bool mitk::ContourElement::RemoveVertexAt(mitk::Point3D &point, float eps) { /* current version iterates over the whole deque - should be some kind of an octree with spatial query*/ if(eps > 0){ VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); while(it != end) { mitk::Point3D currentPoint = (*it)->Coordinates; if(currentPoint.EuclideanDistanceTo(point) < eps) { //approximate point found //now erase it this->m_Vertices->erase(it); return true; } it++; } } return false; } void mitk::ContourElement::Clear() { this->m_Vertices->clear(); } //---------------------------------------------------------------------- void mitk::ContourElement::RedistributeControlVertices(const VertexType* selected, int period) { int counter = 0; VertexIterator _where = this->m_Vertices->begin(); if (selected != NULL) { while (_where != this->m_Vertices->end()) { if ((*_where) == selected) { break; } _where++; } } VertexIterator _iter = _where; while (_iter != this->m_Vertices->end()) { div_t divresult; divresult = div (counter,period); (*_iter)->IsControlPoint = (divresult.rem == 0); counter++; _iter++; } _iter = _where; counter = 0; while (_iter != this->m_Vertices->begin()) { div_t divresult; divresult = div (counter,period); (*_iter)->IsControlPoint = (divresult.rem == 0); counter++; _iter--; } } diff --git a/Modules/ContourModel/DataManagement/mitkContourModel.cpp b/Modules/ContourModel/DataManagement/mitkContourModel.cpp index 93d0a3df61..e269a20678 100644 --- a/Modules/ContourModel/DataManagement/mitkContourModel.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourModel.cpp @@ -1,707 +1,709 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include mitk::ContourModel::ContourModel() : m_UpdateBoundingBox(true) { //set to initial state this->InitializeEmpty(); } mitk::ContourModel::ContourModel(const mitk::ContourModel &other) : -m_ContourSeries(other.m_ContourSeries), m_lineInterpolation(other.m_lineInterpolation) + mitk::BaseData(other), + m_ContourSeries(other.m_ContourSeries), + m_lineInterpolation(other.m_lineInterpolation) { m_SelectedVertex = NULL; } mitk::ContourModel::~ContourModel() { m_SelectedVertex = NULL; this->m_ContourSeries.clear();//TODO check destruction } void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep) ) { this->AddVertex(vertex, false, timestep); } } void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, bool isControlPoint, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertex(vertex, isControlPoint); this->InvokeEvent( ContourModelSizeChangeEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::AddVertex(VertexType &vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertex(vertex); this->InvokeEvent( ContourModelSizeChangeEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::AddVertex(const VertexType* vertex, int timestep) { if(vertex != NULL) { this->m_ContourSeries[timestep]->AddVertex(*const_cast(vertex)); } } void mitk::ContourModel::AddVertexAtFront(mitk::Point3D &vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep) ) { this->AddVertexAtFront(vertex, false, timestep); } } void mitk::ContourModel::AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertexAtFront(vertex, isControlPoint); this->InvokeEvent( ContourModelSizeChangeEvent() ); this->Modified(); this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::AddVertexAtFront(VertexType &vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertexAtFront(vertex); this->InvokeEvent( ContourModelSizeChangeEvent() ); this->Modified(); this->m_UpdateBoundingBox = true; } } bool mitk::ContourModel::SetVertexAt(int pointId, const Point3D &point, unsigned int timestep) { if(!this->IsEmptyTimeStep(timestep)) { if(pointId >= 0 && this->m_ContourSeries[timestep]->GetSize() > pointId) { this->m_ContourSeries[timestep]->SetVertexAt( pointId, point ); this->Modified(); this->m_UpdateBoundingBox = true; return true; } return false; } return false; } bool mitk::ContourModel::SetVertexAt(int pointId, const VertexType *vertex, unsigned int timestep) { if(vertex==NULL) return false; if(!this->IsEmptyTimeStep(timestep)) { if(pointId >= 0 && this->m_ContourSeries[timestep]->GetSize() > pointId) { this->m_ContourSeries[timestep]->SetVertexAt( pointId, vertex ); this->Modified(); this->m_UpdateBoundingBox = true; return true; } return false; } return false; } void mitk::ContourModel::InsertVertexAtIndex(mitk::Point3D &vertex, int index, bool isControlPoint, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { if(index >= 0 && this->m_ContourSeries[timestep]->GetSize() > index) { this->m_ContourSeries[timestep]->InsertVertexAtIndex(vertex, isControlPoint, index); this->InvokeEvent( ContourModelSizeChangeEvent() ); this->Modified(); this->m_UpdateBoundingBox = true; } } } bool mitk::ContourModel::IsEmpty( int timestep) const { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsEmpty(); } return true; } bool mitk::ContourModel::IsEmpty() const { return this->IsEmpty(0); } int mitk::ContourModel::GetNumberOfVertices( int timestep) const { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->GetSize(); } return -1; } const mitk::ContourModel::VertexType* mitk::ContourModel::GetVertexAt(int index, int timestep) const { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->GetVertexAt(index); } return NULL; } int mitk::ContourModel::GetIndex(const VertexType *vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->GetIndex(vertex); } return -1; } void mitk::ContourModel::Close( int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->Close(); this->InvokeEvent( ContourModelClosedEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::Open( int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->Open(); this->InvokeEvent( ContourModelClosedEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::SetClosed(bool isClosed, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->SetClosed(isClosed); this->InvokeEvent( ContourModelClosedEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } bool mitk::ContourModel::IsEmptyTimeStep(unsigned int t) const { return (this->m_ContourSeries.size() <= t); } bool mitk::ContourModel::IsNearContour(mitk::Point3D &point, float eps, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsNearContour(point, eps); } return false; } void mitk::ContourModel::Concatenate(mitk::ContourModel* other, int timestep, bool check) { if(!this->IsEmptyTimeStep(timestep)) { if( !this->m_ContourSeries[timestep]->IsClosed() ) { this->m_ContourSeries[timestep]->Concatenate(other->m_ContourSeries[timestep], check); this->InvokeEvent( ContourModelSizeChangeEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } } mitk::ContourModel::VertexIterator mitk::ContourModel::Begin( int timestep) { return this->IteratorBegin(timestep); } mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorBegin( int timestep) { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IteratorBegin(); } else { mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps() << " timesteps available."; } } mitk::ContourModel::VertexIterator mitk::ContourModel::End( int timestep) { return this->IteratorEnd(timestep); } mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorEnd( int timestep) { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IteratorEnd(); } else { mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps() << " timesteps available."; } } bool mitk::ContourModel::IsClosed( int timestep) { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsClosed(); } return false; } bool mitk::ContourModel::SelectVertexAt(mitk::Point3D &point, float eps, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps); } return this->m_SelectedVertex != NULL; } bool mitk::ContourModel::SelectVertexAt(int index, int timestep) { if(!this->IsEmptyTimeStep(timestep) && index >= 0) { return (this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(index)); } return false; } bool mitk::ContourModel::SetControlVertexAt(mitk::Point3D &point, float eps, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { VertexType* vertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps); if (vertex != NULL) { vertex->IsControlPoint = true; return true; } } return false; } bool mitk::ContourModel::SetControlVertexAt(int index, int timestep) { if(!this->IsEmptyTimeStep(timestep) && index >= 0) { VertexType* vertex = this->m_ContourSeries[timestep]->GetVertexAt(index); if (vertex != NULL) { vertex->IsControlPoint = true; return true; } } return false; } bool mitk::ContourModel::RemoveVertex(const VertexType *vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { if(this->m_ContourSeries[timestep]->RemoveVertex(vertex)) { this->Modified();this->m_UpdateBoundingBox = true; this->InvokeEvent( ContourModelSizeChangeEvent() ); return true; } } return false; } bool mitk::ContourModel::RemoveVertexAt(int index, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { if(this->m_ContourSeries[timestep]->RemoveVertexAt(index)) { this->Modified();this->m_UpdateBoundingBox = true; this->InvokeEvent( ContourModelSizeChangeEvent() ); return true; } } return false; } bool mitk::ContourModel::RemoveVertexAt(mitk::Point3D &point, float eps, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { if(this->m_ContourSeries[timestep]->RemoveVertexAt(point, eps)) { this->Modified();this->m_UpdateBoundingBox = true; this->InvokeEvent( ContourModelSizeChangeEvent() ); return true; } } return false; } void mitk::ContourModel::ShiftSelectedVertex(mitk::Vector3D &translate) { if(this->m_SelectedVertex) { this->ShiftVertex(this->m_SelectedVertex,translate); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::ShiftContour(mitk::Vector3D &translate, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { VertexListType* vList = this->m_ContourSeries[timestep]->GetVertexList(); VertexIterator it = vList->begin(); VertexIterator end = vList->end(); //shift all vertices while(it != end) { this->ShiftVertex((*it),translate); it++; } this->Modified();this->m_UpdateBoundingBox = true; this->InvokeEvent( ContourModelShiftEvent() ); } } void mitk::ContourModel::ShiftVertex(VertexType* vertex, mitk::Vector3D &vector) { vertex->Coordinates[0] += vector[0]; vertex->Coordinates[1] += vector[1]; vertex->Coordinates[2] += vector[2]; } void mitk::ContourModel::Clear(int timestep) { if(!this->IsEmptyTimeStep(timestep)) { //clear data at timestep this->m_ContourSeries[timestep]->Clear(); this->InitializeEmpty(); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::Expand(unsigned int timeSteps ) { - int oldSize = this->m_ContourSeries.size(); + std::size_t oldSize = this->m_ContourSeries.size(); - if( timeSteps > oldSize ) + if( static_cast(timeSteps) > oldSize ) { Superclass::Expand(timeSteps); //insert contours for each new timestep - for( int i = oldSize; i < timeSteps; i++) + for( std::size_t i = oldSize; i < static_cast(timeSteps); i++) { m_ContourSeries.push_back(mitk::ContourElement::New()); } this->InvokeEvent( ContourModelExpandTimeBoundsEvent() ); } } void mitk::ContourModel::SetRequestedRegionToLargestPossibleRegion () { //no support for regions } bool mitk::ContourModel::RequestedRegionIsOutsideOfTheBufferedRegion () { //no support for regions return false; } bool mitk::ContourModel::VerifyRequestedRegion () { //no support for regions return true; } const mitk::Geometry3D * mitk::ContourModel::GetUpdatedGeometry (int t) { return Superclass::GetUpdatedGeometry(t); } mitk::Geometry3D* mitk::ContourModel::GetGeometry (int t)const { return Superclass::GetGeometry(t); } -void mitk::ContourModel::SetRequestedRegion( const itk::DataObject *data) +void mitk::ContourModel::SetRequestedRegion( const itk::DataObject* /*data*/) { //no support for regions } void mitk::ContourModel::Clear() { //clear data and set to initial state again this->ClearData(); this->InitializeEmpty(); this->Modified();this->m_UpdateBoundingBox = true; } void mitk::ContourModel::RedistributeControlVertices(int period, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->RedistributeControlVertices(this->GetSelectedVertex(), period); this->InvokeEvent( ContourModelClosedEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::ClearData() { //call the superclass, this releases the data of BaseData Superclass::ClearData(); //clear out the time resolved contours this->m_ContourSeries.clear(); } void mitk::ContourModel::Initialize() { this->InitializeEmpty(); this->Modified();this->m_UpdateBoundingBox = true; } void mitk::ContourModel::Initialize(mitk::ContourModel &other) { - unsigned int numberOfTimesteps = other.GetTimeGeometry()->CountTimeSteps(); + mitk::TimeStepType numberOfTimesteps = other.GetTimeGeometry()->CountTimeSteps(); this->InitializeTimeGeometry(numberOfTimesteps); - for(int currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) + for(mitk::TimeStepType currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) { this->m_ContourSeries.push_back(mitk::ContourElement::New()); this->SetClosed(other.IsClosed(currentTimestep),currentTimestep); } m_SelectedVertex = NULL; this->m_lineInterpolation = other.m_lineInterpolation; this->Modified();this->m_UpdateBoundingBox = true; } void mitk::ContourModel::InitializeEmpty() { //clear data at timesteps this->m_ContourSeries.resize(0); this->m_ContourSeries.push_back(mitk::ContourElement::New()); //set number of timesteps to one this->InitializeTimeGeometry(1); m_SelectedVertex = NULL; this->m_lineInterpolation = ContourModel::LINEAR; } void mitk::ContourModel::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } if(this->m_UpdateBoundingBox) { //update the bounds of the geometry according to the stored vertices ScalarType mitkBounds[6]; //calculate the boundingbox at each timestep typedef itk::BoundingBox BoundingBoxType; typedef BoundingBoxType::PointsContainer PointsContainer; int timesteps = this->GetTimeSteps(); //iterate over the timesteps for(int currenTimeStep = 0; currenTimeStep < timesteps; currenTimeStep++) { if( dynamic_cast< mitk::PlaneGeometry* >(this->GetGeometry(currenTimeStep)) ) { //do not update bounds for 2D geometries, as they are unfortunately defined with min bounds 0! return; } else {//we have a 3D geometry -> let's update bounds //only update bounds if the contour was modified if (this->GetMTime() > this->GetGeometry(currenTimeStep)->GetBoundingBox()->GetMTime()) { mitkBounds[0] = 0.0; mitkBounds[1] = 0.0; mitkBounds[2] = 0.0; mitkBounds[3] = 0.0; mitkBounds[4] = 0.0; mitkBounds[5] = 0.0; BoundingBoxType::Pointer boundingBox = BoundingBoxType::New(); PointsContainer::Pointer points = PointsContainer::New(); VertexIterator it = this->IteratorBegin(currenTimeStep); VertexIterator end = this->IteratorEnd(currenTimeStep); //fill the boundingbox with the points while(it != end) { Point3D currentP = (*it)->Coordinates; BoundingBoxType::PointType p; p.CastFrom(currentP); points->InsertElement(points->Size(), p); it++; } //construct the new boundingBox boundingBox->SetPoints(points); boundingBox->ComputeBoundingBox(); BoundingBoxType::BoundsArrayType tmp = boundingBox->GetBounds(); mitkBounds[0] = tmp[0]; mitkBounds[1] = tmp[1]; mitkBounds[2] = tmp[2]; mitkBounds[3] = tmp[3]; mitkBounds[4] = tmp[4]; mitkBounds[5] = tmp[5]; //set boundingBox at current timestep Geometry3D* geometry3d = this->GetGeometry(currenTimeStep); geometry3d->SetBounds(mitkBounds); } } } this->m_UpdateBoundingBox = false; } GetTimeGeometry()->Update(); } -void mitk::ContourModel::ExecuteOperation(mitk::Operation* operation) +void mitk::ContourModel::ExecuteOperation(mitk::Operation* /*operation*/) { //not supported yet } diff --git a/Modules/ContourModel/DataManagement/mitkContourModelSet.cpp b/Modules/ContourModel/DataManagement/mitkContourModelSet.cpp index 85aae21158..21dc6fef9a 100644 --- a/Modules/ContourModel/DataManagement/mitkContourModelSet.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourModelSet.cpp @@ -1,213 +1,214 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include mitk::ContourModelSet::ContourModelSet() : m_Contours(), m_UpdateBoundingBox(true) { this->InitializeEmpty(); } mitk::ContourModelSet::ContourModelSet(const mitk::ContourModelSet &other) : + mitk::BaseData(other), m_Contours(other.m_Contours) { - this->InitializeTimeSlicedGeometry(1); + this->InitializeTimeGeometry(1); } mitk::ContourModelSet::~ContourModelSet() { this->m_Contours.clear(); } void mitk::ContourModelSet::InitializeEmpty() { - this->InitializeTimeSlicedGeometry(1); + this->InitializeTimeGeometry(1); m_Contours.resize(0); } void mitk::ContourModelSet::AddContourModel(mitk::ContourModel &contourModel) { this->m_Contours.push_back(&contourModel); m_UpdateBoundingBox = true; } void mitk::ContourModelSet::AddContourModel(mitk::ContourModel::Pointer contourModel) { this->m_Contours.push_back(contourModel); m_UpdateBoundingBox = true; } mitk::ContourModel* mitk::ContourModelSet::GetContourModelAt(int index) { - if( index >= 0 && index < this->m_Contours.size() ) + if( index >= 0 && static_cast(index) < this->m_Contours.size() ) { return this->m_Contours.at(index).GetPointer(); } else { return NULL; } } -bool mitk::ContourModelSet::IsEmpty() +bool mitk::ContourModelSet::IsEmpty() const { return this->m_Contours.empty(); } mitk::ContourModelSet::ContourModelListType* mitk::ContourModelSet::GetContourModelList() { return &(this->m_Contours); } bool mitk::ContourModelSet::RemoveContourModel(mitk::ContourModel* contourModel) { ContourModelSetIterator it = this->m_Contours.begin(); ContourModelSetIterator end = this->m_Contours.end(); //search for ContourModel and remove it if exists while(it != end) { if((*it) == contourModel) { this->m_Contours.erase(it); m_UpdateBoundingBox = true; return true; } it++; } return false; } bool mitk::ContourModelSet::RemoveContourModelAt(int index) { - if( index >= 0 && index < this->m_Contours.size() ) + if( index >= 0 && static_cast(index) < this->m_Contours.size() ) { this->m_Contours.erase(this->m_Contours.begin()+index); m_UpdateBoundingBox = true; return true; } else { return false; } } void mitk::ContourModelSet::Clear() { this->m_Contours.clear(); m_UpdateBoundingBox = true; } void mitk::ContourModelSet::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } if(this->m_UpdateBoundingBox) { //update the bounds of the geometry according to the stored vertices mitk::ScalarType mitkBounds[6]; //calculate the boundingbox at each timestep typedef itk::BoundingBox BoundingBoxType; typedef BoundingBoxType::PointsContainer PointsContainer; int timesteps = this->GetTimeSteps(); //iterate over the timesteps for(int currenTimeStep = 0; currenTimeStep < timesteps; currenTimeStep++) { //only update bounds if the contour was modified if (this->GetMTime() > this->GetGeometry(currenTimeStep)->GetBoundingBox()->GetMTime()) { mitkBounds[0] = 0.0; mitkBounds[1] = 0.0; mitkBounds[2] = 0.0; mitkBounds[3] = 0.0; mitkBounds[4] = 0.0; mitkBounds[5] = 0.0; BoundingBoxType::Pointer boundingBox = BoundingBoxType::New(); PointsContainer::Pointer points = PointsContainer::New(); mitk::ContourModelSet::ContourModelSetIterator contoursIt = this->Begin(); mitk::ContourModelSet::ContourModelSetIterator contoursEnd = this->End(); while(contoursIt!=contoursEnd) { mitk::ContourModel::VertexIterator it = contoursIt->GetPointer()->Begin(currenTimeStep); mitk::ContourModel::VertexIterator end = contoursIt->GetPointer()->End(currenTimeStep); //fill the boundingbox with the points while(it != end) { Point3D currentP = (*it)->Coordinates; BoundingBoxType::PointType p; p.CastFrom(currentP); points->InsertElement(points->Size(), p); it++; } ++contoursIt; } //construct the new boundingBox boundingBox->SetPoints(points); boundingBox->ComputeBoundingBox(); BoundingBoxType::BoundsArrayType tmp = boundingBox->GetBounds(); mitkBounds[0] = tmp[0]; mitkBounds[1] = tmp[1]; mitkBounds[2] = tmp[2]; mitkBounds[3] = tmp[3]; mitkBounds[4] = tmp[4]; mitkBounds[5] = tmp[5]; //set boundingBox at current timestep Geometry3D* geometry3d = this->GetGeometry(currenTimeStep); geometry3d->SetBounds(mitkBounds); } } this->m_UpdateBoundingBox = false; } GetTimeGeometry()->Update(); } diff --git a/Modules/ContourModel/DataManagement/mitkContourModelSet.h b/Modules/ContourModel/DataManagement/mitkContourModelSet.h index c056403688..40705fe3b0 100644 --- a/Modules/ContourModel/DataManagement/mitkContourModelSet.h +++ b/Modules/ContourModel/DataManagement/mitkContourModelSet.h @@ -1,143 +1,143 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _mitkContourModelSet_H_ #define _mitkContourModelSet_H_ #include "mitkCommon.h" #include "ContourModelExports.h" #include "mitkContourModel.h" #include namespace mitk { /** \brief */ class ContourModel_EXPORT ContourModelSet : public mitk::BaseData { public: mitkClassMacro(ContourModelSet, mitk::BaseData); itkNewMacro(ContourModelSet); mitkCloneMacro(ContourModelSet); typedef std::deque ContourModelListType; typedef ContourModelListType::iterator ContourModelSetIterator; // start of inline methods /** \brief Return an iterator a the front. */ virtual ContourModelSetIterator Begin() { return this->m_Contours.begin(); } /** \brief Return an iterator a the front. */ virtual ContourModelSetIterator End() { return this->m_Contours.end(); } /** \brief Returns the number of contained contours. */ virtual int GetSize() { return this->m_Contours.size(); } // end of inline methods /** \brief Add a ContourModel to the container. */ virtual void AddContourModel(mitk::ContourModel &contourModel); /** \brief Add a ContourModel to the container. */ virtual void AddContourModel(mitk::ContourModel::Pointer contourModel); /** \brief Returns the ContourModel a given index \param index */ virtual mitk::ContourModel* GetContourModelAt(int index); /** \brief Returns the container of the contours. */ ContourModelListType* GetContourModelList(); /** \brief Returns a bool whether the container is empty or not. */ - bool IsEmpty(); + bool IsEmpty() const; /** \brief Remove the given ContourModel from the container if exists. \param ContourModel - the ContourModel to be removed. */ virtual bool RemoveContourModel(mitk::ContourModel* contourModel); /** \brief Remove a ContourModel at given index within the container if exists. \param index - the index where the ContourModel should be removed. */ virtual bool RemoveContourModelAt(int index); /** \brief Clear the storage container. */ virtual void Clear(); //////////////// inherit from mitk::BaseData //////////////////// /* NO support for regions ! */ void SetRequestedRegionToLargestPossibleRegion(){} bool RequestedRegionIsOutsideOfTheBufferedRegion(){return false;} bool VerifyRequestedRegion(){return true;} void SetRequestedRegion(const itk::DataObject* ){} /** \brief Update the OutputInformation of a ContourModel object The BoundingBox of the contour will be updated, if necessary. */ virtual void UpdateOutputInformation(); //////////////// END inherit from mitk::BaseData //////////////////// protected: ContourModelSet(); ContourModelSet(const mitk::ContourModelSet &other); virtual ~ContourModelSet(); //inherit from BaseData. Initial state with no contours and a single timestep. virtual void InitializeEmpty(); ContourModelListType m_Contours; //only update the bounding geometry if necessary bool m_UpdateBoundingBox; }; } // namespace mitk #endif // _mitkContourModelSet_H_ diff --git a/Modules/ContourModel/IO/mitkContourModelReader.cpp b/Modules/ContourModel/IO/mitkContourModelReader.cpp index aadc1f0194..831b13ebcc 100644 --- a/Modules/ContourModel/IO/mitkContourModelReader.cpp +++ b/Modules/ContourModel/IO/mitkContourModelReader.cpp @@ -1,218 +1,217 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelReader.h" #include #include #include mitk::ContourModelReader::ContourModelReader() { m_Success = false; } mitk::ContourModelReader::~ContourModelReader() {} void mitk::ContourModelReader::GenerateData() { std::locale::global(std::locale("C")); m_Success = false; if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ); return ; } if ( ! this->CanReadFile( m_FileName.c_str() ) ) { itkWarningMacro( << "Sorry, can't read file " << m_FileName << "!" ); return ; } try{ TiXmlDocument doc(m_FileName.c_str()); bool loadOkay = doc.LoadFile(); if (loadOkay) { TiXmlHandle docHandle( &doc ); /*++++ handle n contourModels within data tags ++++*/ unsigned int contourCounter(0); for( TiXmlElement* currentContourElement = docHandle.FirstChildElement("contourModel").ToElement(); currentContourElement != NULL; currentContourElement = currentContourElement->NextSiblingElement()) { mitk::ContourModel::Pointer newContourModel = mitk::ContourModel::New(); if(currentContourElement->FirstChildElement("data")->FirstChildElement("timestep") != NULL) { //handle geometry information //TiXmlElement* currentGeometryInfo = currentContourElement->FirstChildElement("head")->FirstChildElement("geometryInformation")->ToElement(); ///////////// NOT SUPPORTED YET //////////////// /*++++ handle n timesteps within timestep tags ++++*/ for( TiXmlElement* currentTimeSeries = currentContourElement->FirstChildElement("data")->FirstChildElement("timestep")->ToElement(); currentTimeSeries != NULL; currentTimeSeries = currentTimeSeries->NextSiblingElement()) { unsigned int currentTimeStep(0); currentTimeStep = atoi(currentTimeSeries->Attribute("n")); this->ReadPoints(newContourModel, currentTimeSeries, currentTimeStep); int isClosed; currentTimeSeries->QueryIntAttribute("isClosed", &isClosed); if( isClosed ) { newContourModel->Close(currentTimeStep); } } /*++++ END handle n timesteps within timestep tags ++++*/ } else { //this should not happen MITK_WARN << "wrong file format!"; //newContourModel = this->ReadPoint(newContourModel, currentContourElement, 0); } newContourModel->UpdateOutputInformation(); this->SetNthOutput( contourCounter, newContourModel ); contourCounter++; } /*++++ END handle n contourModels within data tags ++++*/ } else { MITK_WARN << "XML parser error!"; } }catch(...) { MITK_ERROR << "Cannot read contourModel."; m_Success = false; } m_Success = true; } void mitk::ContourModelReader::ReadPoints(mitk::ContourModel::Pointer newContourModel, TiXmlElement* currentTimeSeries, unsigned int currentTimeStep) { //check if the timesteps in contourModel have to be expanded if(currentTimeStep != newContourModel->GetTimeSteps()) { newContourModel->Expand(currentTimeStep+1); } //read all points within controlPoints tag if(currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point") != NULL) { for( TiXmlElement* currentPoint = currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point")->ToElement(); currentPoint != NULL; currentPoint = currentPoint->NextSiblingElement()) { - mitk::PointSpecificationType spec((mitk::PointSpecificationType) 0); double x(0.0); double y(0.0); double z(0.0); x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); int isActivePoint; currentPoint->QueryIntAttribute("isActive", &isActivePoint); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newContourModel->AddVertex(point, isActivePoint,currentTimeStep); } } else { //nothing to read } } void mitk::ContourModelReader::GenerateOutputInformation() { } int mitk::ContourModelReader::CanReadFile ( const char *name ) { std::ifstream in( name ); bool isGood = in.good(); in.close(); return isGood; } bool mitk::ContourModelReader::CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern) { // First check the extension if( filename == "" ) { //MITK_INFO<<"No filename specified."<GetNumberOfOutputs(); this->SetNumberOfIndexedOutputs( num ); for ( unsigned int i = prevNum; i < num; ++i ) { this->SetNthOutput( i, this->MakeOutput( i ).GetPointer() ); } } bool mitk::ContourModelReader::GetSuccess() const { return m_Success; } diff --git a/Modules/ContourModel/IO/mitkContourModelSetReader.cpp b/Modules/ContourModel/IO/mitkContourModelSetReader.cpp index 62edb257c3..1d82e1d319 100644 --- a/Modules/ContourModel/IO/mitkContourModelSetReader.cpp +++ b/Modules/ContourModel/IO/mitkContourModelSetReader.cpp @@ -1,172 +1,171 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelSetReader.h" #include "mitkContourModelReader.h" #include #include #include mitk::ContourModelSetReader::ContourModelSetReader() { m_Success = false; } mitk::ContourModelSetReader::~ContourModelSetReader() {} void mitk::ContourModelSetReader::GenerateData() { std::locale::global(std::locale("C")); m_Success = false; if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ); return ; } if ( ! this->CanReadFile( m_FileName.c_str() ) ) { itkWarningMacro( << "Sorry, can't read file " << m_FileName << "!" ); return ; } try{ mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New(); this->SetNthOutput(0,contourSet); mitk::ContourModelReader::Pointer reader = mitk::ContourModelReader::New(); reader->SetFileName( this->GetFileName() ); reader->Update(); for(unsigned int i = 0; i < reader->GetNumberOfOutputs(); ++i) { contourSet->AddContourModel( reader->GetOutput(i) ); } }catch(...) { MITK_ERROR << "Cannot read contourModel."; } m_Success = true; } void mitk::ContourModelSetReader::ReadPoints(mitk::ContourModel::Pointer newContourModel, TiXmlElement* currentTimeSeries, unsigned int currentTimeStep) { //check if the timesteps in contourModel have to be expanded if(currentTimeStep != newContourModel->GetTimeSteps()) { newContourModel->Expand(currentTimeStep+1); } //read all points within controlPoints tag if(currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point") != NULL) { for( TiXmlElement* currentPoint = currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point")->ToElement(); currentPoint != NULL; currentPoint = currentPoint->NextSiblingElement()) { - mitk::PointSpecificationType spec((mitk::PointSpecificationType) 0); double x(0.0); double y(0.0); double z(0.0); x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); int isActivePoint; currentPoint->QueryIntAttribute("isActive", &isActivePoint); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newContourModel->AddVertex(point, isActivePoint,currentTimeStep); } } else { //nothing to read } } void mitk::ContourModelSetReader::GenerateOutputInformation() { } int mitk::ContourModelSetReader::CanReadFile ( const char *name ) { std::ifstream in( name ); bool isGood = in.good(); in.close(); return isGood; } bool mitk::ContourModelSetReader::CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern) { // First check the extension if( filename == "" ) { //MITK_INFO<<"No filename specified."<GetNumberOfOutputs(); this->SetNumberOfIndexedOutputs( num ); for ( unsigned int i = prevNum; i < num; ++i ) { this->SetNthOutput( i, this->MakeOutput( i ).GetPointer() ); } } bool mitk::ContourModelSetReader::GetSuccess() const { return m_Success; } diff --git a/Modules/ContourModel/IO/mitkContourModelSetWriter.cpp b/Modules/ContourModel/IO/mitkContourModelSetWriter.cpp index 8b7e728bd5..cc9c7e1312 100644 --- a/Modules/ContourModel/IO/mitkContourModelSetWriter.cpp +++ b/Modules/ContourModel/IO/mitkContourModelSetWriter.cpp @@ -1,172 +1,172 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelSetWriter.h" #include "mitkContourModelWriter.h" mitk::ContourModelSetWriter::ContourModelSetWriter() : m_FileName(""), m_FilePrefix(""), m_FilePattern("") { this->SetNumberOfRequiredInputs( 1 ); - this->SetNumberOfOutputs( 1 ); + this->SetNumberOfIndexedOutputs( 1 ); this->SetNthOutput( 0, mitk::ContourModel::New().GetPointer() ); m_Success = false; } mitk::ContourModelSetWriter::~ContourModelSetWriter() {} void mitk::ContourModelSetWriter::GenerateData() { //Use regular ContourModel writer to write each contour of the set to a single file. //Just use a different file extension .cnt_set mitk::ContourModelWriter::Pointer writer = mitk::ContourModelWriter::New(); writer->SetFileName(this->GetFileName()); if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set! Setting filename to default." ); m_FileName = GetDefaultFilename(); } InputType::Pointer contourModelSet = this->GetInput(); // // for each contour object set input of writer // - for ( unsigned int i = 0 ; i < contourModelSet->GetSize(); ++i ) + for ( int i = 0 ; i < contourModelSet->GetSize(); ++i ) { mitk::ContourModel* contour = contourModelSet->GetContourModelAt(i); writer->SetInput( i, contour ); } writer->Update(); m_Success = true; m_MimeType = "application/MITK.ContourModel"; } void mitk::ContourModelSetWriter::ResizeInputs( const unsigned int& num ) { unsigned int prevNum = this->GetNumberOfInputs(); - this->SetNumberOfInputs( num ); + this->SetNumberOfIndexedInputs( num ); for ( unsigned int i = prevNum; i < num; ++i ) { this->SetNthInput( i, mitk::ContourModel::New().GetPointer() ); } } void mitk::ContourModelSetWriter::SetInput( InputType* contourModel ) { this->ProcessObject::SetNthInput( 0, contourModel ); } void mitk::ContourModelSetWriter::SetInput( const unsigned int& id, InputType* contourModel ) { if ( id >= this->GetNumberOfInputs() ) this->ResizeInputs( id + 1 ); this->ProcessObject::SetNthInput( id, contourModel ); } mitk::ContourModelSet* mitk::ContourModelSetWriter::GetInput() { if ( this->GetNumberOfInputs() < 1 ) { return 0; } else { return dynamic_cast ( this->GetInput( 0 ) ); } } mitk::ContourModelSet* mitk::ContourModelSetWriter::GetInput( const unsigned int& num ) { return dynamic_cast ( this->ProcessObject::GetInput( num ) ); } bool mitk::ContourModelSetWriter::GetSuccess() const { return m_Success; } bool mitk::ContourModelSetWriter::CanWriteDataType( DataNode* input ) { if ( input ) { mitk::BaseData* data = input->GetData(); if ( data ) { mitk::ContourModel::Pointer contourModel = dynamic_cast( data ); if( contourModel.IsNotNull() ) { //this writer has no "SetDefaultExtension()" - function m_Extension = ".cnt_set"; return true; } } } return false; } void mitk::ContourModelSetWriter::SetInput( DataNode* input ) { if( input && CanWriteDataType( input ) ) this->ProcessObject::SetNthInput( 0, dynamic_cast( input->GetData() ) ); } std::vector mitk::ContourModelSetWriter::GetPossibleFileExtensions() { std::vector possibleFileExtensions; possibleFileExtensions.push_back(".cnt_set"); return possibleFileExtensions; } std::string mitk::ContourModelSetWriter::GetFileExtension() { return m_Extension; } std::string mitk::ContourModelSetWriter::GetWritenMIMEType() { return "application/MITK.ContourModelSet"; } diff --git a/Modules/ContourModel/IO/mitkContourModelSetWriter.h b/Modules/ContourModel/IO/mitkContourModelSetWriter.h index dc07e17c0d..140ce927ef 100644 --- a/Modules/ContourModel/IO/mitkContourModelSetWriter.h +++ b/Modules/ContourModel/IO/mitkContourModelSetWriter.h @@ -1,196 +1,198 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_CONTOURMODELSET_WRITER__H_ #define _MITK_CONTOURMODELSET_WRITER__H_ #include "ContourModelExports.h" #include #include #include #include namespace mitk { /** * @brief XML-based writer for mitk::ContourModelSet * * Uses the regular ContourModel writer to write each contour of the ContourModelSet to a single file. * * @ingroup PSIO * @ingroup Process */ class ContourModel_EXPORT ContourModelSetWriter : public mitk::FileWriterWithInformation { public: mitkClassMacro( ContourModelSetWriter, mitk::FileWriter ); mitkWriterMacro; itkNewMacro( Self ); typedef mitk::ContourModelSet InputType; typedef InputType::Pointer InputTypePointer; /** * Sets the filename of the file to write. * @param FileName the name of the file to write. */ itkSetStringMacro( FileName ); /** * @returns the name of the file to be written to disk. */ itkGetStringMacro( FileName ); /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePrefix ); /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePrefix ); /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePattern ); /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePattern ); /** * Sets the 0'th input object for the filter. * @param input the first input for the filter. */ void SetInput( InputType* input ); /** * Sets the n'th input object for the filter. If num is * larger than GetNumberOfInputs() the number of inputs is * resized appropriately. * @param input the n'th input for the filter. */ void SetInput( const unsigned int& num, InputType* input); /** * @returns the 0'th input object of the filter. */ ContourModelSet* GetInput(); /** * @param num the index of the desired output object. * @returns the n'th input object of the filter. */ ContourModelSet* GetInput( const unsigned int& num ); /** * @brief Return the possible file extensions for the data type associated with the writer */ virtual std::vector GetPossibleFileExtensions(); /** * @brief Return the extension to be added to the filename. */ virtual std::string GetFileExtension(); /** * @brief Check if the Writer can write the Content of the */ virtual bool CanWriteDataType( DataNode* ); /** * @brief Return the MimeType of the saved File. */ virtual std::string GetWritenMIMEType(); + using Superclass::SetInput; + /** * @brief Set the DataTreenode as Input. Important: The Writer always have a SetInput-Function. */ virtual void SetInput( DataNode* ); /** * @returns whether the last write attempt was successful or not. */ bool GetSuccess() const; /*++++++ FileWriterWithInformation methods +++++++*/ virtual const char *GetDefaultFilename() { return "ContourModelSet.cnt_set"; } virtual const char *GetFileDialogPattern() { return "MITK ContourModelSet (*.cnt_set)"; } virtual const char *GetDefaultExtension() { return ".cnt_set"; } virtual bool CanWriteBaseDataType(BaseData::Pointer data) { return (dynamic_cast(data.GetPointer()) != NULL); }; virtual void DoWrite(BaseData::Pointer data) { if (this->CanWriteBaseDataType(data)) { this->SetInput(dynamic_cast(data.GetPointer())); this->Update(); } } protected: /** * Constructor. */ ContourModelSetWriter(); /** * Virtual destructor. */ virtual ~ContourModelSetWriter(); /** * Writes the XML file */ virtual void GenerateData(); /** * Resizes the number of inputs of the writer. * The inputs are initialized by empty ContourModels * @param num the new number of inputs */ virtual void ResizeInputs( const unsigned int& num ); std::string m_FileName; std::string m_FilePrefix; std::string m_FilePattern; std::string m_Extension; std::string m_MimeType; bool m_Success; }; } #endif diff --git a/Modules/ContourModel/IO/mitkContourModelWriter.cpp b/Modules/ContourModel/IO/mitkContourModelWriter.cpp index b577e4b0e0..a1c2bfd33f 100644 --- a/Modules/ContourModel/IO/mitkContourModelWriter.cpp +++ b/Modules/ContourModel/IO/mitkContourModelWriter.cpp @@ -1,483 +1,483 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelWriter.h" #include #include #include /* * The xml file will look like: * * * * * * * * * * * * * * * * * * * */ // // Initialization of the xml tags. // const char* mitk::ContourModelWriter::XML_CONTOURMODEL = "contourModel" ; const char* mitk::ContourModelWriter::XML_HEAD = "head" ; const char* mitk::ContourModelWriter::XML_GEOMETRY_INFO = "geometryInfo" ; const char* mitk::ContourModelWriter::XML_DATA = "data"; const char* mitk::ContourModelWriter::XML_TIME_STEP = "timestep"; const char* mitk::ContourModelWriter::XML_CONTROL_POINTS = "controlPoints" ; const char* mitk::ContourModelWriter::XML_POINT = "point" ; const char* mitk::ContourModelWriter::XML_X = "x" ; const char* mitk::ContourModelWriter::XML_Y = "y" ; const char* mitk::ContourModelWriter::XML_Z = "z" ; mitk::ContourModelWriter::ContourModelWriter() : m_FileName(""), m_FilePrefix(""), m_FilePattern("") { this->SetNumberOfRequiredInputs( 1 ); - this->SetNumberOfOutputs( 1 ); + this->SetNumberOfIndexedOutputs( 1 ); this->SetNthOutput( 0, mitk::ContourModel::New().GetPointer() ); m_Indent = 2; m_IndentDepth = 0; m_Success = false; } mitk::ContourModelWriter::~ContourModelWriter() {} void mitk::ContourModelWriter::GenerateData() { m_Success = false; m_IndentDepth = 0; // // Opening the file to write to // if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ); return ; } std::ofstream out( m_FileName.c_str() ); if ( !out.good() ) { itkExceptionMacro(<< "File " << m_FileName << " could not be opened!"); itkWarningMacro( << "Sorry, file " << m_FileName << " could not be opened!" ); out.close(); return ; } std::locale previousLocale(out.getloc()); std::locale I("C"); out.imbue(I); /*+++++++++++ Here the actual xml writing begins +++++++++*/ /*++++ ++++*/ WriteXMLHeader( out ); // // for each input object write its xml representation to // the stream // for ( unsigned int i = 0 ; i < this->GetNumberOfInputs(); ++i ) { InputType::Pointer contourModel = this->GetInput( i ); assert( contourModel.IsNotNull() ); WriteXML( contourModel.GetPointer(), out ); } out.imbue(previousLocale); if ( !out.good() ) // some error during output { out.close(); throw std::ios_base::failure("Some error during contour writing."); } out.close(); m_Success = true; m_MimeType = "application/MITK.ContourModel"; } void mitk::ContourModelWriter::WriteXML( mitk::ContourModel* contourModel, std::ofstream& out ) { /*++++ ++++*/ WriteStartElement( XML_CONTOURMODEL, out ); /*++++ ++++*/ WriteStartElement( XML_HEAD, out); /*++++ ++++*/ WriteStartElement( XML_GEOMETRY_INFO, out); WriteGeometryInformation( contourModel->GetTimeGeometry(), out);; /*++++ ++++*/ WriteEndElement( XML_GEOMETRY_INFO, out); /*++++ ++++*/ WriteEndElement( XML_HEAD, out); /*++++ ++++*/ WriteStartElement( XML_DATA, out); unsigned int timecount = contourModel->GetTimeSteps(); for(unsigned int i=0; i< timecount; i++) { /*++++ ++++*/ std::vector at; at.push_back("n"); std::vector val; val.push_back(ConvertToString(i)); at.push_back("isClosed"); val.push_back(ConvertToString(contourModel->IsClosed())); WriteStartElementWithAttribut( XML_TIME_STEP, at, val, out ); /*++++ ++++*/ WriteStartElement(XML_CONTROL_POINTS, out); mitk::ContourModel::VertexIterator it = contourModel->IteratorBegin(); mitk::ContourModel::VertexIterator end = contourModel->IteratorEnd(); while(it != end) { mitk::ContourModel::VertexType* v = *it; /*++++ ++++*/ std::vector attr; attr.push_back("IsControlPoint"); std::vector value; value.push_back(ConvertToString(v->IsControlPoint)); WriteStartElementWithAttribut( XML_POINT, attr, value, out ); /*++++ ++++*/ WriteStartElement( XML_X, out ); WriteCharacterData( ConvertToString(v->Coordinates[0] ).c_str(), out ); /*++++ ++++*/ WriteEndElement( XML_X, out, false ); /*++++ ++++*/ WriteStartElement( XML_Y, out ); WriteCharacterData( ConvertToString( v->Coordinates[1] ).c_str(), out ); /*++++ ++++*/ WriteEndElement( XML_Y, out, false ); /*++++ ++++*/ WriteStartElement( XML_Z, out ); WriteCharacterData( ConvertToString( v->Coordinates[2] ).c_str(), out ); /*++++ ++++*/ WriteEndElement( XML_Z, out, false ); /*++++ ++++*/ WriteEndElement( XML_POINT, out ); it++; } /*++++ ++++*/ WriteEndElement(XML_CONTROL_POINTS, out); /*++++ ++++*/ WriteEndElement( XML_TIME_STEP, out ); } /*++++ ++++*/ WriteEndElement( XML_DATA, out ); /*++++ ++++*/ WriteEndElement( XML_CONTOURMODEL, out ); } -void mitk::ContourModelWriter::WriteGeometryInformation( mitk::TimeGeometry* geometry, std::ofstream& out ) +void mitk::ContourModelWriter::WriteGeometryInformation( mitk::TimeGeometry* /*geometry*/, std::ofstream& out ) { WriteCharacterData("", out); } void mitk::ContourModelWriter::ResizeInputs( const unsigned int& num ) { unsigned int prevNum = this->GetNumberOfInputs(); - this->SetNumberOfInputs( num ); + this->SetNumberOfIndexedInputs( num ); for ( unsigned int i = prevNum; i < num; ++i ) { this->SetNthInput( i, mitk::ContourModel::New().GetPointer() ); } } void mitk::ContourModelWriter::SetInput( InputType* contourModel ) { this->ProcessObject::SetNthInput( 0, contourModel ); } void mitk::ContourModelWriter::SetInput( const unsigned int& id, InputType* contourModel ) { if ( id >= this->GetNumberOfInputs() ) this->ResizeInputs( id + 1 ); this->ProcessObject::SetNthInput( id, contourModel ); } mitk::ContourModel* mitk::ContourModelWriter::GetInput() { if ( this->GetNumberOfInputs() < 1 ) { return 0; } else { return dynamic_cast ( this->GetInput( 0 ) ); } } mitk::ContourModel* mitk::ContourModelWriter::GetInput( const unsigned int& num ) { return dynamic_cast ( this->ProcessObject::GetInput( num ) ); } template < typename T> std::string mitk::ContourModelWriter::ConvertToString( T value ) { std::ostringstream o; std::locale I("C"); o.imbue(I); if ( o << value ) { return o.str(); } else return "conversion error"; } void mitk::ContourModelWriter::WriteXMLHeader( std::ofstream &file ) { file << ""; } void mitk::ContourModelWriter::WriteStartElement( const char *const tag, std::ofstream &file ) { file << std::endl; WriteIndent( file ); file << '<' << tag << '>'; m_IndentDepth++; } void mitk::ContourModelWriter::WriteStartElementWithAttribut( const char *const tag, std::vector attributes, std::vector values, std::ofstream &file ) { file << std::endl; WriteIndent( file ); file << '<' << tag; unsigned int attributesSize = attributes.size(); unsigned int valuesSize = values.size(); if( attributesSize == valuesSize){ std::vector::iterator attributesIt = attributes.begin(); std::vector::iterator end = attributes.end(); std::vector::iterator valuesIt = values.begin(); while(attributesIt != end) { file << ' '; WriteCharacterData( *attributesIt, file); file << '=' << '"'; WriteCharacterData( *valuesIt, file); file << '"'; attributesIt++; valuesIt++; } } file << '>'; m_IndentDepth++; } void mitk::ContourModelWriter::WriteEndElement( const char *const tag, std::ofstream &file, const bool& indent ) { m_IndentDepth--; if ( indent ) { file << std::endl; WriteIndent( file ); } file << '<' << '/' << tag << '>'; } void mitk::ContourModelWriter::WriteCharacterData( const char *const data, std::ofstream &file ) { file << data; } void mitk::ContourModelWriter::WriteStartElement( std::string &tag, std::ofstream &file ) { WriteStartElement( tag.c_str(), file ); } void mitk::ContourModelWriter::WriteEndElement( std::string &tag, std::ofstream &file, const bool& indent ) { WriteEndElement( tag.c_str(), file, indent ); } void mitk::ContourModelWriter::WriteCharacterData( std::string &data, std::ofstream &file ) { WriteCharacterData( data.c_str(), file ); } void mitk::ContourModelWriter::WriteIndent( std::ofstream& file ) { std::string spaces( m_IndentDepth * m_Indent, ' ' ); file << spaces.c_str(); } bool mitk::ContourModelWriter::GetSuccess() const { return m_Success; } bool mitk::ContourModelWriter::CanWriteDataType( DataNode* input ) { if ( input ) { mitk::BaseData* data = input->GetData(); if ( data ) { mitk::ContourModel::Pointer contourModel = dynamic_cast( data ); if( contourModel.IsNotNull() ) { //this writer has no "SetDefaultExtension()" - function m_Extension = ".cnt"; return true; } } } return false; } void mitk::ContourModelWriter::SetInput( DataNode* input ) { if( input && CanWriteDataType( input ) ) this->ProcessObject::SetNthInput( 0, dynamic_cast( input->GetData() ) ); } std::string mitk::ContourModelWriter::GetWritenMIMEType() { return m_MimeType; } std::vector mitk::ContourModelWriter::GetPossibleFileExtensions() { std::vector possibleFileExtensions; possibleFileExtensions.push_back(".cnt"); return possibleFileExtensions; } std::string mitk::ContourModelWriter::GetFileExtension() { return m_Extension; } diff --git a/Modules/ContourModel/IO/mitkContourModelWriter.h b/Modules/ContourModel/IO/mitkContourModelWriter.h index b2f0a9cb27..ea83b93381 100644 --- a/Modules/ContourModel/IO/mitkContourModelWriter.h +++ b/Modules/ContourModel/IO/mitkContourModelWriter.h @@ -1,319 +1,321 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_CONTOURMODEL_WRITER__H_ #define _MITK_CONTOURMODEL_WRITER__H_ #include "ContourModelExports.h" #include #include #include //DEPRECATED #include namespace mitk { /** * @brief XML-based writer for mitk::ContourModels * * XML-based writer for mitk::ContourModels. Multiple ContourModels can be written in * a single XML file by simply setting multiple inputs to the filter. * * The xml file will look like: * * * * * * * * * * * * * * * * * * * * * @ingroup PSIO * @ingroup Process */ class ContourModel_EXPORT ContourModelWriter : public mitk::FileWriterWithInformation { public: mitkClassMacro( ContourModelWriter, mitk::FileWriter ); mitkWriterMacro; itkNewMacro( Self ); typedef mitk::ContourModel InputType; typedef InputType::Pointer InputTypePointer; /** * Sets the filename of the file to write. * @param FileName the name of the file to write. */ itkSetStringMacro( FileName ); /** * @returns the name of the file to be written to disk. */ itkGetStringMacro( FileName ); /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePrefix ); /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePrefix ); /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePattern ); /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePattern ); /** * Sets the 0'th input object for the filter. * @param input the first input for the filter. */ void SetInput( InputType* input ); /** * Sets the n'th input object for the filter. If num is * larger than GetNumberOfInputs() the number of inputs is * resized appropriately. * @param input the n'th input for the filter. */ void SetInput( const unsigned int& num, InputType* input); /** * @returns the 0'th input object of the filter. */ ContourModel* GetInput(); /** * @param num the index of the desired output object. * @returns the n'th input object of the filter. */ ContourModel* GetInput( const unsigned int& num ); /** * @brief Return the possible file extensions for the data type associated with the writer */ virtual std::vector GetPossibleFileExtensions(); /** * @brief Return the extension to be added to the filename. */ virtual std::string GetFileExtension(); /** * @brief Check if the Writer can write the Content of the */ virtual bool CanWriteDataType( DataNode* ); /** * @brief Return the MimeType of the saved File. */ virtual std::string GetWritenMIMEType(); + using Superclass::SetInput; + /** * @brief Set the DataTreenode as Input. Important: The Writer always have a SetInput-Function. */ virtual void SetInput( DataNode* ); /** * @returns whether the last write attempt was successful or not. */ bool GetSuccess() const; /*++++++ FileWriterWithInformation methods +++++++*/ virtual const char *GetDefaultFilename() { return "ContourModel.cnt"; } virtual const char *GetFileDialogPattern() { return "MITK ContourModel (*.cnt)"; } virtual const char *GetDefaultExtension() { return ".cnt"; } virtual bool CanWriteBaseDataType(BaseData::Pointer data) { return (dynamic_cast(data.GetPointer()) != NULL); }; virtual void DoWrite(BaseData::Pointer data) { if (this->CanWriteBaseDataType(data)) { this->SetInput(dynamic_cast(data.GetPointer())); this->Update(); } } protected: /** * Constructor. */ ContourModelWriter(); /** * Virtual destructor. */ virtual ~ContourModelWriter(); /** * Writes the XML file */ virtual void GenerateData(); /** * Resizes the number of inputs of the writer. * The inputs are initialized by empty ContourModels * @param num the new number of inputs */ virtual void ResizeInputs( const unsigned int& num ); /** * Converts an arbitrary type to a string. The type has to * support the << operator. This works fine at least for integral * data types as float, int, long etc. * @param value the value to convert * @returns the string representation of value */ template < typename T> std::string ConvertToString( T value ); /** * Writes an XML representation of the given point set to * an outstream. The XML-Header an root node is not included! * @param contourModel the point set to be converted to xml * @param out the stream to write to. */ void WriteXML( mitk::ContourModel* contourModel, std::ofstream& out ); /** * Writes the geometry information of the TimeGeometry to an outstream. * The root tag is not included. * @param geometry the TimeGeometry of the contour. * @param the stream to write to. */ void WriteGeometryInformation( mitk::TimeGeometry* geometry, std::ofstream& out ); /** * Writes the geometry information of the TimeGeometry to an outstream. * The root tag is not included. * @param geometry the TimeGeometry of the contour. * @param the stream to write to. * * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(void WriteGeometryInformation( mitk::TimeSlicedGeometry* geometry, std::ofstream& out )); /** * Writes an standard xml header to the given stream. * @param file the stream in which the header is written. */ void WriteXMLHeader( std::ofstream &file ); /** Write a start element tag */ void WriteStartElement( const char *const tag, std::ofstream &file ); void WriteStartElementWithAttribut( const char *const tag, std::vector attributes, std::vector values, std::ofstream &file ); /** * Write an end element tag * End-Elements following character data should pass indent = false. */ void WriteEndElement( const char *const tag, std::ofstream &file, const bool& indent = true ); /** Write character data inside a tag. */ void WriteCharacterData( const char *const data, std::ofstream &file ); /** Write a start element tag */ void WriteStartElement( std::string &tag, std::ofstream &file ); /** Write an end element tag */ void WriteEndElement( std::string &tag, std::ofstream &file, const bool& indent = true ); /** Write character data inside a tag. */ void WriteCharacterData( std::string &data, std::ofstream &file ); /** Writes empty spaces to the stream according to m_IndentDepth and m_Indent */ void WriteIndent( std::ofstream& file ); std::string m_FileName; std::string m_FilePrefix; std::string m_FilePattern; std::string m_Extension; std::string m_MimeType; unsigned int m_IndentDepth; unsigned int m_Indent; bool m_Success; public: static const char* XML_CONTOURMODEL; static const char* XML_HEAD; static const char* XML_GEOMETRY_INFO; static const char* XML_DATA; static const char* XML_TIME_STEP; static const char* XML_CONTROL_POINTS; static const char* XML_POINT; static const char* XML_X; static const char* XML_Y; static const char* XML_Z; }; } #endif diff --git a/Modules/ContourModel/Rendering/mitkContourModelGLMapper2DBase.cpp b/Modules/ContourModel/Rendering/mitkContourModelGLMapper2DBase.cpp index 54f76fa1c2..073936ea1e 100644 --- a/Modules/ContourModel/Rendering/mitkContourModelGLMapper2DBase.cpp +++ b/Modules/ContourModel/Rendering/mitkContourModelGLMapper2DBase.cpp @@ -1,329 +1,329 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelSetGLMapper2D.h" #include "mitkPlaneGeometry.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkContourModelSet.h" #include #include "mitkGL.h" mitk::ContourModelGLMapper2DBase::ContourModelGLMapper2DBase() { } mitk::ContourModelGLMapper2DBase::~ContourModelGLMapper2DBase() { } void mitk::ContourModelGLMapper2DBase::DrawContour(mitk::ContourModel* renderingContour, mitk::BaseRenderer* renderer) { if(!renderingContour) return; mitk::DataNode* dataNode = this->GetDataNode(); renderingContour->UpdateOutputInformation(); unsigned int timestep = renderer->GetTimeStep(); if ( !renderingContour->IsEmptyTimeStep(timestep) ) { mitk::DisplayGeometry::Pointer displayGeometry = renderer->GetDisplayGeometry(); assert(displayGeometry.IsNotNull()); //apply color and opacity read from the PropertyList - ApplyProperties(renderer); + ApplyColorAndOpacityProperties(renderer); mitk::ColorProperty::Pointer colorprop = dynamic_cast(dataNode->GetProperty("contour.color", renderer)); float opacity = 0.5; dataNode->GetFloatProperty("opacity", opacity, renderer); if(colorprop) { //set the color of the contour double red = colorprop->GetColor().GetRed(); double green = colorprop->GetColor().GetGreen(); double blue = colorprop->GetColor().GetBlue(); glColor4f(red, green, blue, opacity); } mitk::ColorProperty::Pointer selectedcolor = dynamic_cast(dataNode->GetProperty("contour.points.color", renderer)); if(!selectedcolor) { selectedcolor = mitk::ColorProperty::New(1.0,0.0,0.1); } vtkLinearTransform* transform = dataNode->GetVtkTransform(); // ContourModel::OutputType point; mitk::Point3D point; mitk::Point3D p, projected_p; float vtkp[3]; float lineWidth = 3.0; bool drawit=false; bool isHovering = false; dataNode->GetBoolProperty("contour.hovering", isHovering); if (isHovering) dataNode->GetFloatProperty("contour.hovering.width", lineWidth); else dataNode->GetFloatProperty("contour.width", lineWidth); bool showSegments = false; dataNode->GetBoolProperty("contour.segments.show", showSegments); bool showControlPoints = false; dataNode->GetBoolProperty("contour.controlpoints.show", showControlPoints); bool showPoints = false; dataNode->GetBoolProperty("contour.points.show", showPoints); bool showPointsNumbers = false; dataNode->GetBoolProperty("contour.points.text", showPointsNumbers); bool showControlPointsNumbers = false; dataNode->GetBoolProperty("contour.controlpoints.text", showControlPointsNumbers); bool projectmode=false; dataNode->GetVisibility(projectmode, renderer, "contour.project-onto-plane"); mitk::ContourModel::VertexIterator pointsIt = renderingContour->IteratorBegin(timestep); Point2D pt2d; // projected_p in display coordinates Point2D lastPt2d; int index = 0; mitk::ScalarType maxDiff = 0.25; while ( pointsIt != renderingContour->IteratorEnd(timestep) ) { lastPt2d = pt2d; point = (*pointsIt)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); Vector3D diff=p-projected_p; ScalarType scalardiff = diff.GetNorm(); //project to plane if(projectmode) { drawit=true; } else if(scalardiffIteratorBegin(timestep)) ) { glLineWidth(lineWidth); glBegin (GL_LINES); glVertex2f(pt2d[0], pt2d[1]); glVertex2f(lastPt2d[0], lastPt2d[1]); glEnd(); glLineWidth(1); } } if (showControlPoints) { //draw ontrol points if ((*pointsIt)->IsControlPoint) { float pointsize = 4; Point2D tmp; Vector2D horz,vert; horz[1]=0; vert[0]=0; horz[0]=pointsize; vert[1]=pointsize; glColor3f(selectedcolor->GetColor().GetRed(), selectedcolor->GetColor().GetBlue(), selectedcolor->GetColor().GetGreen()); glLineWidth(1); //a rectangle around the point with the selected color 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(); glLineWidth(1); //the actual point in the specified color to see the usual color of the point glColor3f(colorprop->GetColor().GetRed(),colorprop->GetColor().GetGreen(),colorprop->GetColor().GetBlue()); glPointSize(1); glBegin (GL_POINTS); tmp=pt2d; glVertex2dv(&tmp[0]); glEnd (); } } if (showPoints) { float pointsize = 3; Point2D tmp; Vector2D horz,vert; horz[1]=0; vert[0]=0; horz[0]=pointsize; vert[1]=pointsize; glColor3f(0.0, 0.0, 0.0); glLineWidth(1); //a rectangle around the point with the selected color 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(); glLineWidth(1); //the actual point in the specified color to see the usual color of the point glColor3f(colorprop->GetColor().GetRed(),colorprop->GetColor().GetGreen(),colorprop->GetColor().GetBlue()); glPointSize(1); glBegin (GL_POINTS); tmp=pt2d; glVertex2dv(&tmp[0]); glEnd (); } if (showPointsNumbers) { std::string l; std::stringstream ss; ss << index; l.append(ss.str()); mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); float rgb[3]; rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0; OpenGLrenderer->WriteSimpleText(l, pt2d[0] + 2, pt2d[1] + 2,rgb[0], rgb[1],rgb[2]); } if (showControlPointsNumbers && (*pointsIt)->IsControlPoint) { std::string l; std::stringstream ss; ss << index; l.append(ss.str()); mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); float rgb[3]; rgb[0] = 1.0; rgb[1] = 1.0; rgb[2] = 0.0; OpenGLrenderer->WriteSimpleText(l, pt2d[0] + 2, pt2d[1] + 2,rgb[0], rgb[1],rgb[2]); } index++; } pointsIt++; }//end while iterate over controlpoints //close contour if necessary if(renderingContour->IsClosed(timestep) && drawit && showSegments) { lastPt2d = pt2d; point = renderingContour->GetVertexAt(0,timestep)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); glLineWidth(lineWidth); glBegin (GL_LINES); glVertex2f(lastPt2d[0], lastPt2d[1]); glVertex2f( pt2d[0], pt2d[1] ); glEnd(); glLineWidth(1); } //draw selected vertex if exists if(renderingContour->GetSelectedVertex()) { //transform selected vertex point = renderingContour->GetSelectedVertex()->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); Vector3D diff=p-projected_p; ScalarType scalardiff = diff.GetNorm(); //---------------------------------- //draw point if close to plane if(scalardiff #include "mitkGL.h" mitk::ContourModelSetGLMapper2D::ContourModelSetGLMapper2D() { } mitk::ContourModelSetGLMapper2D::~ContourModelSetGLMapper2D() { } void mitk::ContourModelSetGLMapper2D::Paint(mitk::BaseRenderer * renderer) { BaseLocalStorage *ls = m_LSH.GetLocalStorage(renderer); mitk::DataNode* dataNode = this->GetDataNode(); bool visible = true; dataNode->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; mitk::ContourModelSet* input = this->GetInput(); mitk::ContourModelSet::ContourModelSetIterator it = input->Begin(); mitk::ContourModelSet::ContourModelSetIterator end = input->End(); while(it!=end) { this->DrawContour(it->GetPointer(), renderer); ++it; } if(input->GetSize() < 1) return; ls->UpdateGenerateDataTime(); } mitk::ContourModelSet* mitk::ContourModelSetGLMapper2D::GetInput(void) { return const_cast(static_cast ( GetDataNode()->GetData() )); } void mitk::ContourModelSetGLMapper2D::DrawContour(mitk::ContourModel* renderingContour, mitk::BaseRenderer* renderer) { if(!renderingContour) return; mitk::DataNode* dataNode = this->GetDataNode(); renderingContour->UpdateOutputInformation(); unsigned int timestep = renderer->GetTimeStep(); if ( !renderingContour->IsEmptyTimeStep(timestep) ) { mitk::DisplayGeometry::Pointer displayGeometry = renderer->GetDisplayGeometry(); assert(displayGeometry.IsNotNull()); //apply color and opacity read from the PropertyList - ApplyProperties(renderer); + ApplyColorAndOpacityProperties(renderer); mitk::ColorProperty::Pointer colorprop = dynamic_cast(dataNode->GetProperty("contour.color", renderer)); float opacity = 0.5; dataNode->GetFloatProperty("opacity", opacity, renderer); if(colorprop) { //set the color of the contour double red = colorprop->GetColor().GetRed(); double green = colorprop->GetColor().GetGreen(); double blue = colorprop->GetColor().GetBlue(); glColor4f(red, green, blue, opacity); } mitk::ColorProperty::Pointer selectedcolor = dynamic_cast(dataNode->GetProperty("contour.points.color", renderer)); if(!selectedcolor) { selectedcolor = mitk::ColorProperty::New(1.0,0.0,0.1); } vtkLinearTransform* transform = dataNode->GetVtkTransform(); // ContourModel::OutputType point; mitk::Point3D point; mitk::Point3D p, projected_p; float vtkp[3]; float lineWidth = 3.0; bool drawit=false; bool isHovering = false; dataNode->GetBoolProperty("contour.hovering", isHovering); if (isHovering) dataNode->GetFloatProperty("contour.hovering.width", lineWidth); else dataNode->GetFloatProperty("contour.width", lineWidth); bool showSegments = false; dataNode->GetBoolProperty("contour.segments.show", showSegments); bool showControlPoints = false; dataNode->GetBoolProperty("contour.controlpoints.show", showControlPoints); bool showPoints = false; dataNode->GetBoolProperty("contour.points.show", showPoints); bool showPointsNumbers = false; dataNode->GetBoolProperty("contour.points.text", showPointsNumbers); bool showControlPointsNumbers = false; dataNode->GetBoolProperty("contour.controlpoints.text", showControlPointsNumbers); bool projectmode=false; dataNode->GetVisibility(projectmode, renderer, "contour.project-onto-plane"); mitk::ContourModel::VertexIterator pointsIt = renderingContour->IteratorBegin(timestep); Point2D pt2d; // projected_p in display coordinates Point2D lastPt2d; int index = 0; mitk::ScalarType maxDiff = 0.25; while ( pointsIt != renderingContour->IteratorEnd(timestep) ) { lastPt2d = pt2d; point = (*pointsIt)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); Vector3D diff=p-projected_p; ScalarType scalardiff = diff.GetNorm(); //project to plane if(projectmode) { drawit=true; } else if(scalardiffIteratorBegin(timestep)) ) { glLineWidth(lineWidth); glBegin (GL_LINES); glVertex2f(pt2d[0], pt2d[1]); glVertex2f(lastPt2d[0], lastPt2d[1]); glEnd(); glLineWidth(1); } } if (showControlPoints) { //draw ontrol points if ((*pointsIt)->IsControlPoint) { float pointsize = 4; Point2D tmp; Vector2D horz,vert; horz[1]=0; vert[0]=0; horz[0]=pointsize; vert[1]=pointsize; glColor3f(selectedcolor->GetColor().GetRed(), selectedcolor->GetColor().GetBlue(), selectedcolor->GetColor().GetGreen()); glLineWidth(1); //a rectangle around the point with the selected color 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(); glLineWidth(1); //the actual point in the specified color to see the usual color of the point glColor3f(colorprop->GetColor().GetRed(),colorprop->GetColor().GetGreen(),colorprop->GetColor().GetBlue()); glPointSize(1); glBegin (GL_POINTS); tmp=pt2d; glVertex2dv(&tmp[0]); glEnd (); } } if (showPoints) { float pointsize = 3; Point2D tmp; Vector2D horz,vert; horz[1]=0; vert[0]=0; horz[0]=pointsize; vert[1]=pointsize; glColor3f(0.0, 0.0, 0.0); glLineWidth(1); //a rectangle around the point with the selected color 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(); glLineWidth(1); //the actual point in the specified color to see the usual color of the point glColor3f(colorprop->GetColor().GetRed(),colorprop->GetColor().GetGreen(),colorprop->GetColor().GetBlue()); glPointSize(1); glBegin (GL_POINTS); tmp=pt2d; glVertex2dv(&tmp[0]); glEnd (); } if (showPointsNumbers) { std::string l; std::stringstream ss; ss << index; l.append(ss.str()); mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); float rgb[3]; rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0; OpenGLrenderer->WriteSimpleText(l, pt2d[0] + 2, pt2d[1] + 2,rgb[0], rgb[1],rgb[2]); } if (showControlPointsNumbers && (*pointsIt)->IsControlPoint) { std::string l; std::stringstream ss; ss << index; l.append(ss.str()); mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); float rgb[3]; rgb[0] = 1.0; rgb[1] = 1.0; rgb[2] = 0.0; OpenGLrenderer->WriteSimpleText(l, pt2d[0] + 2, pt2d[1] + 2,rgb[0], rgb[1],rgb[2]); } index++; } pointsIt++; }//end while iterate over controlpoints //close contour if necessary if(renderingContour->IsClosed(timestep) && drawit && showSegments) { lastPt2d = pt2d; point = renderingContour->GetVertexAt(0,timestep)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); glLineWidth(lineWidth); glBegin (GL_LINES); glVertex2f(lastPt2d[0], lastPt2d[1]); glVertex2f( pt2d[0], pt2d[1] ); glEnd(); glLineWidth(1); } //draw selected vertex if exists if(renderingContour->GetSelectedVertex()) { //transform selected vertex point = renderingContour->GetSelectedVertex()->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); Vector3D diff=p-projected_p; ScalarType scalardiff = diff.GetNorm(); //---------------------------------- //draw point if close to plane if(scalardiffAddProperty( "contour.color", ColorProperty::New(0.9, 1.0, 0.1), renderer, overwrite ); node->AddProperty( "contour.points.color", ColorProperty::New(1.0, 0.0, 0.1), renderer, overwrite ); node->AddProperty( "contour.points.show", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "contour.segments.show", mitk::BoolProperty::New( true ), renderer, overwrite ); node->AddProperty( "contour.controlpoints.show", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "contour.width", mitk::FloatProperty::New( 1.0 ), renderer, overwrite ); node->AddProperty( "contour.hovering.width", mitk::FloatProperty::New( 3.0 ), renderer, overwrite ); node->AddProperty( "contour.hovering", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "contour.points.text", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "contour.controlpoints.text", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "contour.project-onto-plane", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite ); Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Modules/ContourModel/Testing/mitkContourModelIOTest.cpp b/Modules/ContourModel/Testing/mitkContourModelIOTest.cpp index f071e88745..c44ec88997 100644 --- a/Modules/ContourModel/Testing/mitkContourModelIOTest.cpp +++ b/Modules/ContourModel/Testing/mitkContourModelIOTest.cpp @@ -1,121 +1,121 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "mitkTestingConfig.h" #include #include #include #include #include static void TestContourModel(mitk::ContourModel* contour, std::string fileName) { mitk::ContourModelWriter::Pointer writer = mitk::ContourModelWriter::New(); writer->SetInput(contour); std::string filename = std::string( MITK_TEST_OUTPUT_DIR ) + fileName; writer->SetFileName(filename); writer->Update(); MITK_TEST_CONDITION(writer->GetSuccess(),"write file"); mitk::ContourModelReader::Pointer reader = mitk::ContourModelReader::New(); reader->SetFileName(filename); reader->Update(); MITK_TEST_CONDITION(reader->GetSuccess(), "read file"); mitk::ContourModel::Pointer contour2 = reader->GetOutput(); MITK_TEST_CONDITION_REQUIRED(contour2.IsNotNull(),"contour is not null"); MITK_TEST_CONDITION_REQUIRED(contour->GetNumberOfVertices() == contour2->GetNumberOfVertices(),"contours have the same number of vertices"); mitk::ContourModel::VertexIterator it = contour2->IteratorBegin(); mitk::ContourModel::VertexIterator end = contour2->IteratorEnd(); mitk::ContourModel::VertexIterator it2 = contour2->IteratorBegin(); bool areEqual = true; while(it != end) { areEqual &= ((*it)->Coordinates == (*it2)->Coordinates); it++; it2++; } MITK_TEST_CONDITION(areEqual, "contours are equal"); } static void TestContourModelIO_OneTimeStep() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); mitk::Point3D p3; p3[0] = -2; p3[1] = 10; p3[2] = 0; contour->AddVertex(p3); mitk::Point3D p4; p4[0] = -3; p4[1] = 6; p4[2] = -5; contour->AddVertex(p4); TestContourModel(contour.GetPointer(), "/contour.cnt"); } static void TestContourModelIO_EmptyContourModel() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); TestContourModel(contour.GetPointer(), "/contourEmpty.cnt"); } -int mitkContourModelIOTest(int argc, char* argv[]) +int mitkContourModelIOTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("mitkContourModelIOTest") TestContourModelIO_OneTimeStep(); TestContourModelIO_EmptyContourModel(); MITK_TEST_END() } diff --git a/Modules/ContourModel/Testing/mitkContourModelSetTest.cpp b/Modules/ContourModel/Testing/mitkContourModelSetTest.cpp index 2355b37132..de97f446da 100644 --- a/Modules/ContourModel/Testing/mitkContourModelSetTest.cpp +++ b/Modules/ContourModel/Testing/mitkContourModelSetTest.cpp @@ -1,75 +1,75 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include static void TestAddVertex() { mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New(); mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); contourSet->AddContourModel(contour); MITK_TEST_CONDITION(contourSet->GetSize() > 0, "Add a contour, size increased"); } static void TestRemoveContourAtIndex() { mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New(); mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); contourSet->AddContourModel(contour); contourSet->RemoveContourModelAt(0); MITK_TEST_CONDITION(contourSet->GetSize() == 0, "removed contour by index"); contourSet->AddContourModel(contour); contourSet->RemoveContourModel(contour); MITK_TEST_CONDITION(contourSet->GetSize() == 0, "removed contour by object"); } static void TestEmptyContour() { mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New(); MITK_TEST_CONDITION(contourSet->Begin() == contourSet->End(), "test iterator of emtpy contour"); MITK_TEST_CONDITION(contourSet->GetSize() == 0, "test numberof vertices of empty contour"); } -int mitkContourModelSetTest(int argc, char* argv[]) +int mitkContourModelSetTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("mitkContourModelSetTest") TestEmptyContour(); TestAddVertex(); TestRemoveContourAtIndex(); MITK_TEST_END() } diff --git a/Modules/ContourModel/Testing/mitkContourModelTest.cpp b/Modules/ContourModel/Testing/mitkContourModelTest.cpp index 73f077fb46..b4ad3c6dd5 100644 --- a/Modules/ContourModel/Testing/mitkContourModelTest.cpp +++ b/Modules/ContourModel/Testing/mitkContourModelTest.cpp @@ -1,458 +1,459 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include //Add a vertex to the contour and see if size changed static void TestAddVertex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); MITK_TEST_CONDITION(contour->GetNumberOfVertices() > 0, "Add a Vertex, size increased"); } //Select a vertex by index. successful if the selected vertex member of the contour is no longer set to null static void TestSelectVertexAtIndex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); contour->SelectVertexAt(0); MITK_TEST_CONDITION(contour->GetSelectedVertex() != NULL, "Vertex was selected at index"); } //Select a vertex by worldposition. successful if the selected vertex member of the contour is no longer set to null static void TestSelectVertexAtWorldposition() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); //same point is used here so the epsilon can be chosen very small contour->SelectVertexAt(p, 0.01); MITK_TEST_CONDITION(contour->GetSelectedVertex() != NULL, "Vertex was selected at position"); } //Move a vertex by a translation vector static void TestMoveSelectedVertex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); //Same point is used here so the epsilon can be chosen very small contour->SelectVertexAt(p, 0.01); mitk::Vector3D v; v[0] = 1; v[1] = 3; v[2] = -1; contour->ShiftSelectedVertex(v); const mitk::ContourModel::VertexType* vertex = contour->GetSelectedVertex(); bool correctlyMoved = false; correctlyMoved = (vertex->Coordinates)[0] == (v[0]) && (vertex->Coordinates)[1] == (v[1]) && (vertex->Coordinates)[2] == (v[2]); MITK_TEST_CONDITION(correctlyMoved, "Vertex has been moved"); } //Test to move the whole contour +/* static void TestMoveContour() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 0; contour->AddVertex(p2); mitk::Vector3D v; v[0] = 1; v[1] = 3; v[2] = -1; contour->ShiftContour(v); mitk::ContourModel::VertexIterator it = contour->IteratorBegin(); mitk::ContourModel::VertexIterator end = contour->IteratorEnd(); bool correctlyMoved = false; while(it != end) { correctlyMoved &= (*it)->Coordinates[0] == (v[0]) && (*it)->Coordinates[1] == (v[1]) && (*it)->Coordinates[2] == (v[2]); } MITK_TEST_CONDITION(correctlyMoved, "Contour has been moved"); } - +*/ //Remove a vertex by index static void TestRemoveVertexAtIndex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); contour->RemoveVertexAt(0); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 0, "removed vertex"); } //Remove a vertex by position static void TestRemoveVertexAtWorldPosition() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); contour->RemoveVertexAt(p, 0.01); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 0, "removed vertex"); } //Check closeable contour static void TestIsclosed() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); contour->Close(); MITK_TEST_CONDITION(contour->IsClosed(), "closed contour"); //no vertices should be added to a closed contour int oldNumberOfVertices = contour->GetNumberOfVertices(); mitk::Point3D p3; p3[0] = p3[1] = p3[2] = 4; contour->AddVertex(p3); int newNumberOfVertices = contour->GetNumberOfVertices(); MITK_TEST_CONDITION(oldNumberOfVertices != newNumberOfVertices, "vertices added to closed contour"); } //Test concatenating two contours static void TestConcatenate() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); mitk::ContourModel::Pointer contour2 = mitk::ContourModel::New(); mitk::Point3D p3; p3[0] = -2; p3[1] = 10; p3[2] = 0; contour2->AddVertex(p3); mitk::Point3D p4; p4[0] = -3; p4[1] = 6; p4[2] = -5; contour2->AddVertex(p4); contour->Concatenate(contour2); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 4, "two contours were concatenated"); } //Try to select a vertex at position (within a epsilon of course) where no vertex is. //So the selected verted member should be null. static void TestSelectVertexAtWrongPosition() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); MITK_TEST_CONDITION_REQUIRED(contour->GetSelectedVertex() == NULL, "selected vertex is NULL"); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 2; contour->SelectVertexAt(p2, 0.1); MITK_TEST_CONDITION(contour->GetSelectedVertex() == NULL, "Vertex was not selected"); } static void TestInsertVertex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); mitk::Point3D pointToInsert; pointToInsert[0] = pointToInsert[1] = pointToInsert[2] = 10; contour->InsertVertexAtIndex(pointToInsert, 1); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 3, "test insert vertex"); MITK_TEST_CONDITION(contour->GetVertexAt(1)->Coordinates == pointToInsert, "compare inserted vertex"); } //try to access an invalid timestep static void TestInvalidTimeStep() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); int invalidTimeStep = 42; MITK_TEST_CONDITION_REQUIRED(contour->IsEmptyTimeStep(invalidTimeStep), "invalid timestep required"); MITK_TEST_FOR_EXCEPTION(std::exception, contour->IteratorBegin(-1)); contour->Close(invalidTimeStep); MITK_TEST_CONDITION(contour->IsClosed() == false, "test close for timestep 0"); MITK_TEST_CONDITION(contour->IsClosed(invalidTimeStep) == false, "test close at invalid timestep"); contour->SetClosed(true, invalidTimeStep); MITK_TEST_CONDITION(contour->GetNumberOfVertices(invalidTimeStep) == -1, "test number of vertices at invalid timestep"); contour->AddVertex(p2, invalidTimeStep); MITK_TEST_CONDITION(contour->GetNumberOfVertices(invalidTimeStep) == -1, "test add vertex at invalid timestep"); contour->InsertVertexAtIndex(p2, 0, false, invalidTimeStep); MITK_TEST_CONDITION(contour->GetNumberOfVertices(invalidTimeStep) == -1, "test insert vertex at invalid timestep"); - MITK_TEST_CONDITION(contour->SelectVertexAt(0, invalidTimeStep) == NULL, "test select vertex at invalid timestep"); + MITK_TEST_CONDITION(contour->SelectVertexAt(0, invalidTimeStep) == false, "test select vertex at invalid timestep"); MITK_TEST_CONDITION(contour->RemoveVertexAt(0, invalidTimeStep) == false, "test remove vertex at invalid timestep"); } static void TestEmptyContour() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); MITK_TEST_CONDITION(contour->IteratorBegin() == contour->IteratorEnd(), "test iterator of emtpy contour"); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 0, "test numberof vertices of empty contour"); } static void TestSetVertices() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D newCoordinates; newCoordinates[0] = newCoordinates[1] = newCoordinates[2] = 1; contour->SetVertexAt(0, newCoordinates ); MITK_TEST_EQUAL(contour->GetVertexAt(0)->Coordinates, newCoordinates, "set coordinates" ); mitk::ContourModel::Pointer contour2 = mitk::ContourModel::New(); mitk::Point3D p3; p3[0] = -2; p3[1] = 10; p3[2] = 0; contour2->AddVertex(p3); mitk::Point3D p4; p4[0] = -3; p4[1] = 6; p4[2] = -5; contour2->AddVertex(p4); contour->AddVertex(p); contour->SetVertexAt(1, contour2->GetVertexAt(1)); MITK_TEST_EQUAL(contour->GetVertexAt(1)->Coordinates, contour2->GetVertexAt(1)->Coordinates, "Use setter and getter combination"); } static void TestContourModelAPI() { mitk::ContourModel::Pointer contour1 = mitk::ContourModel::New(); mitk::Point3D p1; p1[0] = -2; p1[1] = 10; p1[2] = 0; contour1->AddVertex(p1); //adding vertices should always copy the content and not store pointers or references. MITK_TEST_CONDITION( &p1 != &(contour1->GetVertexAt(0)->Coordinates), "copied point" ); mitk::Point3D p2; p2[0] = -3; p2[1] = 6; p2[2] = -5; contour1->AddVertex(p2); //test use of setter and getter with const and non-const pointers const mitk::ContourModel::VertexType* vertex = contour1->GetVertexAt(1); MITK_TEST_CONDITION(contour1->GetIndex(vertex) == 1, "Get index"); mitk::ContourModel::VertexType* nonConstVertex = const_cast(vertex); MITK_TEST_CONDITION(contour1->GetIndex(nonConstVertex) == 1, "Get index non-const"); mitk::ContourModel::Pointer contour2 = mitk::ContourModel::New(); contour2->AddVertex(contour1->GetVertexAt(0)); MITK_TEST_CONDITION(contour2->GetNumberOfVertices() == 1, "Add call with another contour"); } -int mitkContourModelTest(int argc, char* argv[]) +int mitkContourModelTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("mitkContourModelTest") TestAddVertex(); TestSelectVertexAtIndex(); TestSelectVertexAtWorldposition(); TestMoveSelectedVertex(); TestRemoveVertexAtIndex(); TestRemoveVertexAtWorldPosition(); TestIsclosed(); TestConcatenate(); TestInvalidTimeStep(); TestInsertVertex(); TestEmptyContour(); TestSetVertices(); TestSelectVertexAtWrongPosition(); TestContourModelAPI(); MITK_TEST_END() } diff --git a/Modules/GPGPU/CMakeLists.txt b/Modules/GPGPU/CMakeLists.txt index a07e5d5d6c..77bb6396f6 100644 --- a/Modules/GPGPU/CMakeLists.txt +++ b/Modules/GPGPU/CMakeLists.txt @@ -1,19 +1,20 @@ if(APPLE) message(STATUS "Module GPGPU is not ported to MacOS yet") else(APPLE) set(package_deps) if(UNIX) list(APPEND package_deps X11) endif() MITK_CREATE_MODULE(mitkGPGPU # INCLUDE_DIRS . DEPENDS Mitk PACKAGE_DEPENDS ${package_deps} GLEW EXPORT_DEFINE GPGPU_DLL_API QT4_MODULES QtCore QtGui + WARNINGS_AS_ERRORS ) endif(APPLE) diff --git a/Modules/GraphAlgorithms/CMakeLists.txt b/Modules/GraphAlgorithms/CMakeLists.txt index cea6dbb745..135cf950e2 100644 --- a/Modules/GraphAlgorithms/CMakeLists.txt +++ b/Modules/GraphAlgorithms/CMakeLists.txt @@ -1,2 +1,4 @@ MITK_CREATE_MODULE(MitkGraphAlgorithms -DEPENDS Mitk ImageStatistics ) + DEPENDS Mitk ImageStatistics + WARNINGS_AS_ERRORS +) diff --git a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp index 4175f5bc7c..dda4cb7317 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp +++ b/Modules/IGT/Algorithms/mitkNavigationDataEvaluationFilter.cpp @@ -1,314 +1,314 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataEvaluationFilter.h" #include #define _USE_MATH_DEFINES #include mitk::NavigationDataEvaluationFilter::NavigationDataEvaluationFilter() : mitk::NavigationDataToNavigationDataFilter() { } mitk::NavigationDataEvaluationFilter::~NavigationDataEvaluationFilter() { } void mitk::NavigationDataEvaluationFilter::GenerateData() { this->CreateOutputsForAllInputs(); // make sure that we have the same number of outputs as inputs this->CreateMembersForAllInputs(); /* update outputs with tracking data from tools */ for (unsigned int i = 0; i < this->GetNumberOfOutputs() ; ++i) { //first copy outputs to inputs mitk::NavigationData* output = this->GetOutput(i); assert(output); const mitk::NavigationData* input = this->GetInput(i); assert(input); if (input->IsDataValid() == false) {output->SetDataValid(false);} else {output->Graft(input);} //then save statistics if(input->IsDataValid()) { m_LoggedPositions[i].push_back(input->GetPosition()); m_LoggedQuaternions[i].push_back(input->GetOrientation()); } else { m_InvalidSamples[i]++; } } } void mitk::NavigationDataEvaluationFilter::CreateMembersForAllInputs() { while(this->m_LoggedPositions.size() < this->GetNumberOfInputs()) { std::pair > newElement(m_LoggedPositions.size(),std::vector()); m_LoggedPositions.insert(newElement); } while(this->m_LoggedQuaternions.size() < this->GetNumberOfInputs()) { std::pair > newElement(m_LoggedQuaternions.size(),std::vector()); m_LoggedQuaternions.insert(newElement); } while(this->m_InvalidSamples.size() < this->GetNumberOfInputs()) { std::pair newElement(m_InvalidSamples.size(),0); m_InvalidSamples.insert(newElement); } } void mitk::NavigationDataEvaluationFilter::ResetStatistic() { for (unsigned int i = 0; i < m_LoggedPositions.size(); i++) m_LoggedPositions[i] = std::vector(); for (unsigned int i = 0; i < m_LoggedQuaternions.size(); i++) m_LoggedQuaternions[i] = std::vector(); for (unsigned int i = 0; i < m_InvalidSamples.size(); i++) m_InvalidSamples[i] = 0; } int mitk::NavigationDataEvaluationFilter::GetNumberOfAnalysedNavigationData(int input) { return this->m_LoggedPositions[input].size(); } mitk::Point3D mitk::NavigationDataEvaluationFilter::GetPositionMean(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionMean(); } mitk::Vector3D mitk::NavigationDataEvaluationFilter::GetPositionStandardDeviation(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionStandardDeviation(); } mitk::Vector3D mitk::NavigationDataEvaluationFilter::GetPositionSampleStandardDeviation(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionSampleStandardDeviation(); } mitk::Quaternion mitk::NavigationDataEvaluationFilter::GetQuaternionMean(int input) { return GetMean(m_LoggedQuaternions[input]); } mitk::Quaternion mitk::NavigationDataEvaluationFilter::GetQuaternionStandardDeviation(int input) { mitk::Quaternion returnValue; std::vector list1 = std::vector(); std::vector list2 = std::vector(); std::vector list3 = std::vector(); std::vector list4 = std::vector(); for (unsigned int i=0; iGetStabw(list1); returnValue[1] = myCalculator->GetStabw(list2); returnValue[2] = myCalculator->GetStabw(list3); returnValue[3] = myCalculator->GetStabw(list4); return returnValue; } mitk::Vector3D mitk::NavigationDataEvaluationFilter::GetEulerAnglesMean(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(QuaternionsToEulerAngles(m_LoggedQuaternions[input]))); mitk::Vector3D returnValue; returnValue[0] = myCalculator->GetPositionMean()[0]; returnValue[1] = myCalculator->GetPositionMean()[1]; returnValue[2] = myCalculator->GetPositionMean()[2]; return returnValue; } double mitk::NavigationDataEvaluationFilter::GetEulerAnglesRMS(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(QuaternionsToEulerAngles(m_LoggedQuaternions[input]))); return myCalculator->GetPositionErrorRMS(); } double mitk::NavigationDataEvaluationFilter::GetEulerAnglesRMSDegree(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(QuaternionsToEulerAnglesGrad(m_LoggedQuaternions[input]))); return myCalculator->GetPositionErrorRMS(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorMean(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorMean(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorStandardDeviation(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorStandardDeviation(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorSampleStandardDeviation(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorSampleStandardDeviation(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorRMS(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorRMS(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorMedian(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorMedian(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorMax(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorMax(); } double mitk::NavigationDataEvaluationFilter::GetPositionErrorMin(int input) { mitk::PointSetStatisticsCalculator::Pointer myCalculator = mitk::PointSetStatisticsCalculator::New(VectorToPointSet(m_LoggedPositions[input])); return myCalculator->GetPositionErrorMin(); } int mitk::NavigationDataEvaluationFilter::GetNumberOfInvalidSamples(int input) { return m_InvalidSamples[input]; } double mitk::NavigationDataEvaluationFilter::GetPercentageOfInvalidSamples(int input) { return (m_InvalidSamples[input]/(m_InvalidSamples[input]+((double)m_LoggedPositions[input].size())))*100.0; } mitk::Quaternion mitk::NavigationDataEvaluationFilter::GetMean(std::vector list) { //calculate mean mitk::Quaternion mean; mean[0] = 0; mean[1] = 0; mean[2] = 0; mean[3] = 0; for (unsigned int i=0; i pSet) { mitk::PointSet::Pointer returnValue = mitk::PointSet::New(); for (unsigned int i=0; iInsertPoint(i,pSet.at(i)); return returnValue; } mitk::PointSet::Pointer mitk::NavigationDataEvaluationFilter::VectorToPointSet(std::vector pSet) { mitk::PointSet::Pointer returnValue = mitk::PointSet::New(); for (unsigned int i=0; iInsertPoint(i,thisPoint); } return returnValue; } std::vector mitk::NavigationDataEvaluationFilter::QuaternionsToEulerAngles(std::vector quaterions) { std::vector returnValue = std::vector(); for (unsigned int i=0; i mitk::NavigationDataEvaluationFilter::QuaternionsToEulerAnglesGrad(std::vector quaterions) { double PI = M_PI; std::vector returnValue = std::vector(); std::vector eulerAnglesRadians = QuaternionsToEulerAngles(quaterions); for (unsigned int i=0; iSetNumberOfRequiredOutputs(1); this->SetNthOutput(0, output.GetPointer()); } mitk::NavigationDataToNavigationDataFilter::~NavigationDataToNavigationDataFilter() { } void mitk::NavigationDataToNavigationDataFilter::SetInput( const NavigationData* nd ) { this->SetInput(0, nd); } void mitk::NavigationDataToNavigationDataFilter::SetInput( unsigned int idx, const NavigationData* nd ) { if ( nd == NULL ) // if an input is set to NULL, remove it this->RemoveInput(idx); else this->ProcessObject::SetNthInput(idx, const_cast(nd)); // ProcessObject is not const-correct so a const_cast is required here this->CreateOutputsForAllInputs(); } const mitk::NavigationData* mitk::NavigationDataToNavigationDataFilter::GetInput( void ) const { if (this->GetNumberOfInputs() < 1) return NULL; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::NavigationData* mitk::NavigationDataToNavigationDataFilter::GetInput( unsigned int idx ) const { if (this->GetNumberOfInputs() < 1) return NULL; return static_cast(this->ProcessObject::GetInput(idx)); } const mitk::NavigationData* mitk::NavigationDataToNavigationDataFilter::GetInput(std::string navDataName) const { const DataObjectPointerArray& inputs = const_cast(this)->GetInputs(); for (DataObjectPointerArray::const_iterator it = inputs.begin(); it != inputs.end(); ++it) if (std::string(navDataName) == (static_cast(it->GetPointer()))->GetName()) return static_cast(it->GetPointer()); return NULL; } itk::ProcessObject::DataObjectPointerArraySizeType mitk::NavigationDataToNavigationDataFilter::GetInputIndex( std::string navDataName ) { DataObjectPointerArray outputs = this->GetInputs(); for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i) if (navDataName == (static_cast(outputs.at(i).GetPointer()))->GetName()) return i; throw std::invalid_argument("output name does not exist"); } void mitk::NavigationDataToNavigationDataFilter::ConnectTo(mitk::NavigationDataSource* UpstreamFilter) { - for (int i = 0; i < UpstreamFilter->GetNumberOfOutputs(); i++) + for (DataObjectPointerArraySizeType i = 0; i < UpstreamFilter->GetNumberOfOutputs(); i++) { this->SetInput(i, UpstreamFilter->GetOutput(i)); } } void mitk::NavigationDataToNavigationDataFilter::CreateOutputsForAllInputs() { this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); // create outputs for all inputs for (unsigned int idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx) if (this->GetOutput(idx) == NULL) { mitk::NavigationData::Pointer newOutput = mitk::NavigationData::New(); this->SetNthOutput(idx, newOutput); } this->Modified(); } diff --git a/Modules/IGT/Algorithms/mitkNavigationDataToNavigationDataFilter.h b/Modules/IGT/Algorithms/mitkNavigationDataToNavigationDataFilter.h index 2a412e35fd..d80f9433aa 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataToNavigationDataFilter.h +++ b/Modules/IGT/Algorithms/mitkNavigationDataToNavigationDataFilter.h @@ -1,108 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKNNAVIGATIONDATATONAVIGATIONDATAFILTER_H_HEADER_INCLUDED_ #define MITKNNAVIGATIONDATATONAVIGATIONDATAFILTER_H_HEADER_INCLUDED_ #include namespace mitk { /**Documentation * \brief NavigationDataToNavigationDataFilter is the base class of all filters that receive * NavigationDatas as input and produce NavigationDatas as output * * Base class that for all navigation filters that receive NavigationData objects as input * and produce NavigationData objects as output. * This class defines the input-interface for NavigationDataFilters. * * \ingroup IGT */ class MitkIGT_EXPORT NavigationDataToNavigationDataFilter : public NavigationDataSource { public: mitkClassMacro(NavigationDataToNavigationDataFilter, NavigationDataSource); + using Superclass::SetInput; + /** * \brief Set the input of this filter * * \warning: this will set the number of outputs to the number of inputs, * deleting any extra outputs that might have been initialized. * Subclasses that have a different number of outputs than inputs * must overwrite the SetInput methods. */ virtual void SetInput( const NavigationData* nd); /** * \brief Set input with id idx of this filter * * \warning: this will set the number of outputs to the number of inputs, * deleting any extra outputs that might have been initialized. * Subclasses that have a different number of outputs than inputs * must overwrite the SetInput methods. * If the last input is set to NULL, the number of inputs will be decreased by one * (-> removing the last input). If other inputs are set to NULL, the number of inputs * will not change. */ virtual void SetInput( unsigned int idx, const NavigationData* nd); /** * \brief Get the input of this filter */ const NavigationData* GetInput(void) const; /** * \brief Get the input with id idx of this filter */ const NavigationData* GetInput(unsigned int idx) const; /** * \brief Get the input with name navDataName of this filter */ const NavigationData* GetInput(std::string navDataName) const; /** *\brief return the index of the input with name navDataName, throw std::invalid_argument exception if that name was not found * * \warning if a subclass has inputs that have different data type than mitk::NavigationData, they have to overwrite this method */ DataObjectPointerArraySizeType GetInputIndex(std::string navDataName); /** *\brief Connects the input of this filter to the outputs of the given NavigationDataSource * * This method does not support smartpointer. use FilterX.GetPointer() to retrieve a dumbpointer. * E.g. calling Filter2->ConnectTo(Filter1) will result in a Pipeline where NavigationData flows from Filter1 to Filter2. */ virtual void ConnectTo(mitk::NavigationDataSource * UpstreamFilter); protected: NavigationDataToNavigationDataFilter(); virtual ~NavigationDataToNavigationDataFilter(); /** * \brief Create an output for each input * * This Method sets the number of outputs to the number of inputs * and creates missing outputs objects. * \warning any additional outputs that exist before the method is called are deleted */ void CreateOutputsForAllInputs(); }; } // namespace mitk #endif /* MITKNAVIGATIONDATATONAVIGATIONDATAFILTER_H_HEADER_INCLUDED_ */ diff --git a/Modules/IGT/Algorithms/mitkNavigationDataToPointSetFilter.h b/Modules/IGT/Algorithms/mitkNavigationDataToPointSetFilter.h index d8f4c56e1e..b7c7ef85af 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataToPointSetFilter.h +++ b/Modules/IGT/Algorithms/mitkNavigationDataToPointSetFilter.h @@ -1,156 +1,158 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITKNAVIGATIONDATATOPOINTSETFILTER_H__ #define _MITKNAVIGATIONDATATOPOINTSETFILTER_H__ #include "mitkCommon.h" #include "mitkPointSet.h" #include "mitkPointSetSource.h" #include "mitkNavigationData.h" namespace mitk { /**Documentation * * \brief This filter creates mitk::PointSet objects from mitk::NavigaitionData objects * * This filter has two modes that can be set with SetOperationMode(). * - Mode3D: every input NavigationData is processed into one output pointset. For each call to Update() a point with the ND position will be added to the PointSet * - Mode4D: one output pointset is generated that contains one point for each input NavigationData. Each call to Update() adds a new timestep to the PointSet that contains new positions for the points. * * \ingroup IGT * */ class MitkIGT_EXPORT NavigationDataToPointSetFilter : public PointSetSource { public: mitkClassMacro(NavigationDataToPointSetFilter, PointSetSource); itkNewMacro(Self); /**Documentation * \brief There are two different operation modes. * * - Mode3D: every input NavigationData is processed into one output pointset that contains a point with the ND position for each Update() * - Mode3DMean: a defined number of input NavigationData is used to generate a mean position and processed into one output pointset that contains a point with the ND position for each Update() * - Mode4D: one output pointset is generated that contains one point for each input NavigationData. Each call to Update() adds a new timestep to the PointSet that contains new positions for the points. * The RingBufferSize limits the number of timesteps in the 4D mode. It currently does _not_ limit the number of points in the 3D mode. */ enum OperationMode { Mode3D, Mode3DMean, Mode4D }; /**Documentation * \brief Sets the size for the ring buffer. * * The size determines the maximum number of timesteps in 4D mode and the number of points in 3D mode of the output PointSet */ itkSetMacro(RingBufferSize, unsigned int) /** * \brief Sets the number of Navigation Data, which should be averaged. */ itkSetMacro(NumberForMean, unsigned int) /** * \brief Gets the number of Navigation Data, which should be averaged. */ itkGetMacro(NumberForMean, unsigned int); /** * \brief filter execute method */ virtual void GenerateData(); + using Superclass::SetInput; + /** * \brief Sets one input NavigationData */ virtual void SetInput(const mitk::NavigationData *NavigationData); /** * \brief Sets the input NavigationData at a specific index */ virtual void SetInput(unsigned int idx, const NavigationData* nd); /** * \brief Returns the input of this filter */ const mitk::NavigationData* GetInput(); /** * \brief Returns the input number idx of this filter */ const mitk::NavigationData* GetInput(unsigned int idx); /** * \brief Sets the mode of this filter. * * See OperationMode for the behavior in the different modes * \warn A call to this method will change the number of outputs of the filter. * After calling this method, all previously acquired pointers to outputs are invalid * Always set the operation mode first, then get the outputs with GetOutput() */ virtual void SetOperationMode(OperationMode mode); /** * \brief returns the mode of this filter. * * See OperationMode for the behavior in the different modes */ itkGetConstMacro(OperationMode, OperationMode); void GenerateOutputInformation() {}; ///< empty implementation to prevent calling of the superclass method that would try to copy information from the input NavigationData to the output PointSet, which makes no sense! protected: NavigationDataToPointSetFilter(); virtual ~NavigationDataToPointSetFilter(); /** * \brief Generates the output for Mode3D * */ virtual void GenerateDataMode3D(); /** * \brief Generates the output for Mode3DMean * */ virtual void GenerateDataMode3DMean(); /** * \brief Generates the output for Mode4D */ virtual void GenerateDataMode4D(); /** * \brief create output objects according to OperationMode for all inputs */ virtual void CreateOutputsForAllInputs(); OperationMode m_OperationMode; ///< Stores the mode. See enum OperationMode unsigned int m_RingBufferSize; ///< Stores the ringbuffer size unsigned int m_CurrentTimeStep; ///< Indicates the current timestamp unsigned int m_NumberForMean; ///< Number of Navigation Data, which should be averaged }; } // namespace mitk #endif // _MITKNAVIGATIONDATATOPOINTSETFILTER_H__ diff --git a/Modules/IGT/CMakeLists.txt b/Modules/IGT/CMakeLists.txt index 61126fba61..cef332e937 100644 --- a/Modules/IGT/CMakeLists.txt +++ b/Modules/IGT/CMakeLists.txt @@ -1,50 +1,51 @@ include(MITKIGTHardware.cmake) if(MITK_USE_MICRON_TRACKER) set(INCLUDE_DIRS_INTERNAL ${INCLUDE_DIRS_INTERNAL} ${MITK_MICRON_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_MICRON_TRACKER_LIB}) endif(MITK_USE_MICRON_TRACKER) if(MITK_USE_MICROBIRD_TRACKER) set(INCLUDE_DIRS_INTERNAL ${INCLUDE_DIRS_INTERNAL} ${MITK_USE_MICROBIRD_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_USE_MICROBIRD_TRACKER_LIB}) endif(MITK_USE_MICROBIRD_TRACKER) MITK_CREATE_MODULE(MitkIGT SUBPROJECTS MITK-IGT INCLUDE_DIRS Algorithms Common DataManagement ExceptionHandling IO Rendering TrackingDevices INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} DEPENDS Mitk ImageStatistics SceneSerialization MitkIGTBase PACKAGE_DEPENDS tinyxml ADDITIONAL_LIBS "${ADDITIONAL_LIBS}" + WARNINGS_AS_ERRORS ) if(MitkIGT_IS_ENABLED) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/ClaronMicron.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/IntuitiveDaVinci.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAurora.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAurora_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAuroraCompactFG_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAuroraPlanarFG_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAuroraTabletopFG_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAuroraTabletopFG_Prototype_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIPolarisOldModel.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIPolarisSpectra.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIPolarisSpectraExtendedPyramid.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIPolarisVicra.stl ) endif() MITK_CHECK_MODULE(_RESULT MitkIGT) if(_RESULT) message(STATUS "IGTTutorialStep1 won't be built. Missing: ${_RESULT}") else(_RESULT) ## create IGT config configure_file(mitkIGTConfig.h.in ${PROJECT_BINARY_DIR}/mitkIGTConfig.h @ONLY) # add test programm for serial communication classADD_EXECUTABLE(SerialCommunicationTest IGTTrackingDevices/mitkSerialCommunicationTest.cpp)target_link_libraries(SerialCommunicationTest mitkIGT Mitk tinyxml PocoXML) add_subdirectory(Tutorial) add_subdirectory(Testing) endif(_RESULT) diff --git a/Modules/IGT/Common/mitkIGTTimeStamp.cpp b/Modules/IGT/Common/mitkIGTTimeStamp.cpp index 1c086a271b..3ff1a2b10a 100644 --- a/Modules/IGT/Common/mitkIGTTimeStamp.cpp +++ b/Modules/IGT/Common/mitkIGTTimeStamp.cpp @@ -1,156 +1,156 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkIGTTimeStamp.h" #include #include "mitkRealTimeClock.h" mitk::IGTTimeStamp::Pointer mitk::IGTTimeStamp::s_Instance = NULL; mitk::IGTTimeStamp::IGTTimeStamp() : itk::Object() , m_Time(-1.0), m_ReferenceTime(0.0) { } mitk::IGTTimeStamp::~IGTTimeStamp() { } mitk::IGTTimeStamp* mitk::IGTTimeStamp::CreateInstance() { return mitk::IGTTimeStamp::GetInstance(); } mitk::IGTTimeStamp* mitk::IGTTimeStamp::GetInstance() { if (IGTTimeStamp::s_Instance.IsNull()) { mitk::IGTTimeStamp::Pointer ts = new mitk::IGTTimeStamp; s_Instance = ts; return s_Instance; } else return s_Instance; } void mitk::IGTTimeStamp::Start(itk::Object::Pointer device) { if (m_RealTimeClock.IsNull()) { Initialize(); } if ( s_Instance.IsNotNull() ) { if (m_DeviceMap.empty()) { m_ReferenceTime = GetCurrentStamp(); m_Time = 0.0; } m_DeviceMap.insert( std::pair(device, this->GetElapsed()) ); } else { itkGenericOutputMacro("Trying to use mitk::TimeStamp::Start() " << "without an available singleton instance. Either no instance has " << "been created (use TimeStamp::CreateInstance) or it has already " << "been destroyed."); } } void mitk::IGTTimeStamp::Stop(itk::Object::Pointer device) { if ( s_Instance.IsNotNull() ) { m_MapIterator = m_DeviceMap.find(device); if ( m_MapIterator != m_DeviceMap.end() ) { m_DeviceMap.erase( m_MapIterator ); } if (m_DeviceMap.empty()) { - m_ReferenceTime = NULL; + m_ReferenceTime = 0; m_Time = -1; } } else { itkGenericOutputMacro("Trying to use mitk::TimeStamp::Stop() " << "without an available singleton instance. Either no instance has " << "been created (use TimeStamp::CreateInstance) or it has already " << "been destroyed."); } } double mitk::IGTTimeStamp::GetElapsed() { if (m_Time > -1) { m_Time = GetCurrentStamp(); m_Time = m_Time - m_ReferenceTime; } return (double) m_Time; } double mitk::IGTTimeStamp::GetElapsed(itk::Object::Pointer device) { double offset = this->GetOffset( device ); if ( offset > -1 ) { double time = this->GetElapsed(); return (double) time - this->GetOffset(device); } else { return (double) -1; } } double mitk::IGTTimeStamp::GetCurrentStamp() { if (m_RealTimeClock.IsNotNull()) { return m_RealTimeClock->GetCurrentStamp(); } else return 0.0; } void mitk::IGTTimeStamp::SetRealTimeClock(mitk::RealTimeClock::Pointer Clock) { m_RealTimeClock = Clock; } double mitk::IGTTimeStamp::GetOffset(itk::Object::Pointer Device) { m_MapIterator = m_DeviceMap.find(Device); if ( m_MapIterator != m_DeviceMap.end() ) { return m_MapIterator->second; } else { return -1.0; } } void mitk::IGTTimeStamp::Initialize() { if ( m_RealTimeClock.IsNull() ) m_RealTimeClock = mitk::RealTimeClock::New(); } diff --git a/Modules/IGT/Common/mitkTrackingTypes.cpp b/Modules/IGT/Common/mitkTrackingTypes.cpp new file mode 100644 index 0000000000..89bcbcee5c --- /dev/null +++ b/Modules/IGT/Common/mitkTrackingTypes.cpp @@ -0,0 +1,48 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkTrackingTypes.h" + +namespace mitk +{ + + std::vector GetDeviceDataForLine(TrackingDeviceType Type) + { + std::vector Result; + int size = (sizeof (TrackingDeviceList) / sizeof*(TrackingDeviceList)); + for(int i=0; i < size; i++) + { + if(TrackingDeviceList[i].Line == Type ) Result.push_back(TrackingDeviceList[i]); + } + return Result; + } + + TrackingDeviceData GetFirstCompatibleDeviceDataForLine(TrackingDeviceType Type) + { + return GetDeviceDataForLine(Type).front(); + } + + TrackingDeviceData GetDeviceDataByName(const std::string& modelName) + { + int size = (sizeof (TrackingDeviceList) / sizeof*(TrackingDeviceList)); + for(int i=0; i < size; i++) + { + if(TrackingDeviceList[i].Model == modelName) return TrackingDeviceList[i]; + } + return DeviceDataInvalid; + } + +} // namespace mitk diff --git a/Modules/IGT/Common/mitkTrackingTypes.h b/Modules/IGT/Common/mitkTrackingTypes.h index 66baf26b72..c280f2e049 100644 --- a/Modules/IGT/Common/mitkTrackingTypes.h +++ b/Modules/IGT/Common/mitkTrackingTypes.h @@ -1,251 +1,233 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKTRACKINGTYPES_H_HEADER_INCLUDED_ #define MITKTRACKINGTYPES_H_HEADER_INCLUDED_ +#include + #include #include -//#include namespace mitk { /**Documentation * \brief Error codes of NDI tracking devices */ enum NDIErrorCode { NDIOKAY = 0, NDIERROR = 1, SERIALINTERFACENOTSET, SERIALSENDERROR, SERIALRECEIVEERROR, SROMFILETOOLARGE, SROMFILETOOSMALL, NDICRCERROR, // reply has crc error, local computer detected the error NDIINVALIDCOMMAND, NDICOMMANDTOOLONG, NDICOMMANDTOOSHORT, NDICRCDOESNOTMATCH, // command had crc error, tracking device detected the error NDITIMEOUT, NDIUNABLETOSETNEWCOMMPARAMETERS, NDIINCORRECTNUMBEROFPARAMETERS, NDIINVALIDPORTHANDLE, NDIINVALIDTRACKINGPRIORITY, NDIINVALIDLED, NDIINVALIDLEDSTATE, NDICOMMANDINVALIDINCURRENTMODE, NDINOTOOLFORPORT, NDIPORTNOTINITIALIZED, NDISYSTEMNOTINITIALIZED, NDIUNABLETOSTOPTRACKING, NDIUNABLETOSTARTTRACKING, NDIINITIALIZATIONFAILED, NDIINVALIDVOLUMEPARAMETERS, NDICANTSTARTDIAGNOSTICMODE, NDICANTINITIRDIAGNOSTICS, NDIFAILURETOWRITESROM, NDIENABLEDTOOLSNOTSUPPORTED, NDICOMMANDPARAMETEROUTOFRANGE, NDINOMEMORYAVAILABLE, NDIPORTHANDLENOTALLOCATED, NDIPORTHASBECOMEUNOCCUPIED, NDIOUTOFHANDLES, NDIINCOMPATIBLEFIRMWAREVERSIONS, NDIINVALIDPORTDESCRIPTION, NDIINVALIDOPERATIONFORDEVICE, NDIWARNING, NDIUNKNOWNERROR, NDIUNEXPECTEDREPLY, UNKNOWNHANDLERETURNED, TRACKINGDEVICERESET, TRACKINGDEVICENOTSET }; /**Documentation * \brief identifier for tracking device. The way it is currently used * represents a product line rather than an actal type. Refactoring is a future option. */ enum TrackingDeviceType { NDIPolaris, ///< Polaris: optical Tracker from NDI NDIAurora, ///< Aurora: electromagnetic Tracker from NDI ClaronMicron, ///< Micron Tracker: optical Tracker from Claron IntuitiveDaVinci, ///< Intuitive Surgical: DaVinci Telemanipulator API Interface AscensionMicroBird, ///< Ascension microBird / PCIBird family VirtualTracker, ///< Virtual Tracking device class that produces random tracking coordinates TrackingSystemNotSpecified,///< entry for not specified or initialized tracking system TrackingSystemInvalid ///< entry for invalid state (mainly for testing) }; /**Documentation * \brief Error codes of NDI tracking devices */ enum OperationMode { ToolTracking6D, ToolTracking5D, MarkerTracking3D, HybridTracking }; /** * /brief This structure defines key variables of a device model and type. * It is specifically used to find out which models belong to which vendor, and what volume * to use for a specific Model. Leaving VolumeModelLocation set to null will instruct the Generator * to generate a field to the best of his ability. HardwareCode stands for a hexadecimal string, * that represents the tracking volume. "X" stands for "hardwarecode is not known" or "tracking device has * no hardware code". For NDI devices it is used in the SetVolume() Method in mitkNDITrackingDevice.cpp. * The Pyramid Volume has the hardwarecode "4", but it is not supported yet. */ struct TrackingDeviceData { TrackingDeviceType Line; std::string Model; std::string VolumeModelLocation; std::string HardwareCode; }; /** * Here all supported devices are defined. Dont forget to introduce new Devices into the TrackingDeviceList Array at the bottom! * If a model does not have a corresponding tracking volume yet, pass an empty string to denote "No Model". pass "cube" to render * a default cube of 400x400 px. You can define additional magic strings in the TrackingVolumeGenerator. */ //############## NDI Aurora device data ############# static TrackingDeviceData DeviceDataAuroraCompact = {NDIAurora, "Aurora Compact", "NDIAuroraCompactFG_Dome.stl", "A"}; static TrackingDeviceData DeviceDataAuroraPlanarCube = {NDIAurora, "Aurora Planar (Cube)", "NDIAurora.stl", "9"}; static TrackingDeviceData DeviceDataAuroraPlanarDome = {NDIAurora, "Aurora Planar (Dome)","NDIAuroraPlanarFG_Dome.stl", "A"}; static TrackingDeviceData DeviceDataAuroraTabletop = {NDIAurora, "Aurora Tabletop", "NDIAuroraTabletopFG_Dome.stl", "A"}; // The following entry is for the tabletop prototype, which had an lower barrier of 8cm. The new version has a lower barrier of 12cm. //static TrackingDeviceData DeviceDataAuroraTabletopPrototype = {NDIAurora, "Aurora Tabletop Prototype", "NDIAuroraTabletopFG_Prototype_Dome.stl"}; //############## NDI Polaris device data ############ static TrackingDeviceData DeviceDataPolarisOldModel = {NDIPolaris, "Polaris (Old Model)", "NDIPolarisOldModel.stl", "0"}; //full hardware code of polaris spectra: 5-240000-153200-095000+057200+039800+056946+024303+029773+999999+99999924 static TrackingDeviceData DeviceDataPolarisSpectra = {NDIPolaris, "Polaris Spectra", "NDIPolarisSpectra.stl", "5-2"}; //full hardware code of polaris spectra (extended pyramid): 5-300000-153200-095000+057200+039800+056946+024303+029773+999999+07350024 static TrackingDeviceData DeviceDataSpectraExtendedPyramid = {NDIPolaris, "Polaris Spectra (Extended Pyramid)", "NDIPolarisSpectraExtendedPyramid.stl","5-3"}; static TrackingDeviceData DeviceDataPolarisVicra = {NDIPolaris, "Polaris Vicra", "NDIPolarisVicra.stl","7"}; //############## other device data ################## static TrackingDeviceData DeviceDataDaVinci = {IntuitiveDaVinci, "Intuitive DaVinci", "IntuitiveDaVinci.stl","X"}; - static TrackingDeviceData DeviceDataMicroBird = {AscensionMicroBird, "Ascension MicroBird", "X"}; + static TrackingDeviceData DeviceDataMicroBird = {AscensionMicroBird, "Ascension MicroBird", "", "X"}; static TrackingDeviceData DeviceDataVirtualTracker = {VirtualTracker, "Virtual Tracker", "cube","X"}; static TrackingDeviceData DeviceDataMicronTrackerH40 = {ClaronMicron, "Micron Tracker H40", "ClaronMicron.stl", "X"}; static TrackingDeviceData DeviceDataUnspecified = {TrackingSystemNotSpecified, "Unspecified System", "cube","X"}; // Careful when changing the "invalid" device: The mitkTrackingTypeTest is using it's data. static TrackingDeviceData DeviceDataInvalid = {TrackingSystemInvalid, "Invalid Tracking System", "", "X"}; //This list should hold all devices defined above! static TrackingDeviceData TrackingDeviceList[] = {DeviceDataAuroraPlanarCube, DeviceDataAuroraPlanarDome, DeviceDataAuroraCompact, DeviceDataAuroraTabletop, DeviceDataMicronTrackerH40, DeviceDataPolarisSpectra, DeviceDataPolarisVicra, DeviceDataDaVinci, DeviceDataMicroBird, DeviceDataVirtualTracker, DeviceDataUnspecified, DeviceDataSpectraExtendedPyramid, DeviceDataInvalid, DeviceDataPolarisOldModel}; /** * /brief Returns all devices compatibel to the given Line of Devices */ - static std::vector GetDeviceDataForLine(TrackingDeviceType Type){ - std::vector Result; - int size = (sizeof (TrackingDeviceList) / sizeof*(TrackingDeviceList)); - for(int i=0; i < size; i++) - { - if(TrackingDeviceList[i].Line == Type ) Result.push_back(TrackingDeviceList[i]); - } - return Result; - } + MitkIGT_EXPORT std::vector GetDeviceDataForLine(TrackingDeviceType Type); /** * /brief Returns the first TracingDeviceData mathing a given line. Useful for backward compatibility * with the old way to manage Devices */ - static TrackingDeviceData GetFirstCompatibleDeviceDataForLine(TrackingDeviceType Type){ - - return GetDeviceDataForLine(Type).front(); - } + MitkIGT_EXPORT TrackingDeviceData GetFirstCompatibleDeviceDataForLine(TrackingDeviceType Type); /** * /brief Returns the device Data set matching the model name or the invalid device, if none was found */ - static TrackingDeviceData GetDeviceDataByName(std::string modelName){ - - int size = (sizeof (TrackingDeviceList) / sizeof*(TrackingDeviceList)); - for(int i=0; i < size; i++) - { - if(TrackingDeviceList[i].Model == modelName) return TrackingDeviceList[i]; - } - return DeviceDataInvalid; - } + MitkIGT_EXPORT TrackingDeviceData GetDeviceDataByName(const std::string& modelName); /**Documentation * \brief activation rate of IR illuminator for NDI Polaris tracking device */ enum IlluminationActivationRate { Hz20 = 20, Hz30 = 30, Hz60 = 60 }; /**Documentation * \brief Data transfer mode for NDI tracking devices */ enum DataTransferMode { TX = 0, BX = 1 }; /**Documentation * \brief Query mode for NDI tracking devices */ enum PHSRQueryType { ALL = 0x00, FREED = 0x01, OCCUPIED = 0x02, INITIALIZED = 0x03, ENABLED = 0x04 }; typedef itk::Point MarkerPointType; typedef std::vector MarkerPointContainerType; /** * \brief Defines the tools (arms) of the daVinci system: * PSM1 - Patient side manipulator 1 * PSM2 - Patient side manipulator 2 * ECM - Endoscopic camera manipulator * MTML - Left master target manipulator * MTMR - Right master target manipulator * PSM - Patient side manipulator 3 (if not existent, its data will always be zero) **/ enum DaVinciToolType { PSM1 = 0, PSM2 = 1, ECM = 2, MTML = 3, MTMR = 4, PSM = 5, //UIEvents = 6, }; } // namespace mitk #endif /* MITKTRACKINGTYPES_H_HEADER_INCLUDED_ */ diff --git a/Modules/IGT/DataManagement/mitkNavigationDataSource.cpp b/Modules/IGT/DataManagement/mitkNavigationDataSource.cpp index 381329b9a3..615175b1d6 100644 --- a/Modules/IGT/DataManagement/mitkNavigationDataSource.cpp +++ b/Modules/IGT/DataManagement/mitkNavigationDataSource.cpp @@ -1,153 +1,156 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataSource.h" #include "mitkUIDGenerator.h" //Microservices #include #include #include #include const std::string mitk::NavigationDataSource::US_INTERFACE_NAME = "org.mitk.services.NavigationDataSource"; const std::string mitk::NavigationDataSource::US_PROPKEY_DEVICENAME = US_INTERFACE_NAME + ".devicename"; const std::string mitk::NavigationDataSource::US_PROPKEY_ID = US_INTERFACE_NAME + ".id"; const std::string mitk::NavigationDataSource::US_PROPKEY_ISACTIVE = US_INTERFACE_NAME + ".isActive"; mitk::NavigationDataSource::NavigationDataSource() : itk::ProcessObject(), m_Name("NavigationDataSource (no defined type)") { } mitk::NavigationDataSource::~NavigationDataSource() { } mitk::NavigationData* mitk::NavigationDataSource::GetOutput() { if (this->GetNumberOfIndexedOutputs() < 1) return NULL; return static_cast(this->ProcessObject::GetPrimaryOutput()); } mitk::NavigationData* mitk::NavigationDataSource::GetOutput(DataObjectPointerArraySizeType idx) { NavigationData* out = dynamic_cast( this->ProcessObject::GetOutput(idx) ); if ( out == NULL && this->ProcessObject::GetOutput(idx) != NULL ) { itkWarningMacro (<< "Unable to convert output number " << idx << " to type " << typeid( NavigationData ).name () ); } return out; } mitk::NavigationData* mitk::NavigationDataSource::GetOutput(const std::string& navDataName) { + /* DataObjectPointerArray outputs = this->GetOutputs(); for (DataObjectPointerArray::iterator it = outputs.begin(); it != outputs.end(); ++it) if (navDataName == (static_cast(it->GetPointer()))->GetName()) return static_cast(it->GetPointer()); return NULL; + */ + return static_cast(this->ProcessObject::GetOutput(navDataName)); } itk::ProcessObject::DataObjectPointerArraySizeType mitk::NavigationDataSource::GetOutputIndex( std::string navDataName ) { DataObjectPointerArray outputs = this->GetOutputs(); for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i) if (navDataName == (static_cast(outputs.at(i).GetPointer()))->GetName()) return i; throw std::invalid_argument("output name does not exist"); } void mitk::NavigationDataSource::RegisterAsMicroservice(){ // Get Context us::ModuleContext* context = us::GetModuleContext(); // Define ServiceProps us::ServiceProperties props; mitk::UIDGenerator uidGen = mitk::UIDGenerator ("org.mitk.services.NavigationDataSource.id_", 16); props[ US_PROPKEY_ID ] = uidGen.GetUID(); props[ US_PROPKEY_DEVICENAME ] = m_Name; m_ServiceRegistration = context->RegisterService(this, props); } void mitk::NavigationDataSource::UnRegisterMicroservice(){ m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } std::string mitk::NavigationDataSource::GetMicroserviceID(){ return this->m_ServiceRegistration.GetReference().GetProperty(US_PROPKEY_ID).ToString(); } void mitk::NavigationDataSource::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::NavigationDataSource::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfIndexedOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter only has " << this->GetNumberOfIndexedOutputs() << " Outputs."); } if ( !graft ) { itkExceptionMacro(<<"Requested to graft output with a NULL pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a NULL pointer" ); } // Call Graft on NavigationData to copy member data output->Graft( graft ); } itk::DataObject::Pointer mitk::NavigationDataSource::MakeOutput ( DataObjectPointerArraySizeType /*idx*/ ) { return mitk::NavigationData::New().GetPointer(); } itk::DataObject::Pointer mitk::NavigationDataSource::MakeOutput( const DataObjectIdentifierType & name ) { itkDebugMacro("MakeOutput(" << name << ")"); if( this->IsIndexedOutputName(name) ) { return this->MakeOutput( this->MakeIndexFromOutputName(name) ); } return static_cast(mitk::NavigationData::New().GetPointer()); } mitk::PropertyList::ConstPointer mitk::NavigationDataSource::GetParameters() const { mitk::PropertyList::Pointer p = mitk::PropertyList::New(); // add properties to p like this: //p->SetProperty("MyFilter_MyParameter", mitk::PropertyDataType::New(m_MyParameter)); return mitk::PropertyList::ConstPointer(p); } diff --git a/Modules/IGT/DataManagement/mitkNavigationTool.cpp b/Modules/IGT/DataManagement/mitkNavigationTool.cpp index 01cd4a934c..3021d3c729 100644 --- a/Modules/IGT/DataManagement/mitkNavigationTool.cpp +++ b/Modules/IGT/DataManagement/mitkNavigationTool.cpp @@ -1,128 +1,128 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationTool.h" #include "mitkIGTException.h" #include "mitkNavigationData.h" #include "Poco/File.h" -mitk::NavigationTool::NavigationTool() : m_Type(mitk::NavigationTool::Unknown), - m_Identifier("None"), - m_TrackingDeviceType(mitk::TrackingSystemNotSpecified), +mitk::NavigationTool::NavigationTool() : m_Identifier("None"), + m_Type(mitk::NavigationTool::Unknown), m_CalibrationFile("none"), m_SerialNumber(""), + m_TrackingDeviceType(mitk::TrackingSystemNotSpecified), m_ToolRegistrationLandmarks(mitk::PointSet::New()), m_ToolCalibrationLandmarks(mitk::PointSet::New()), m_ToolTipOrientation(mitk::Quaternion(0,0,0,1)) { m_ToolTipPosition[0] = 0; m_ToolTipPosition[1] = 0; m_ToolTipPosition[2] = 0; } mitk::NavigationTool::~NavigationTool() { } mitk::AffineTransform3D::Pointer mitk::NavigationTool::GetToolTipTransform() { mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New(); returnValue->SetPosition(this->m_ToolTipPosition); returnValue->SetOrientation(this->m_ToolTipOrientation); return returnValue->GetAffineTransform3D(); } void mitk::NavigationTool::Graft( const DataObject *data ) { // Attempt to cast data to an NavigationData const Self* nd; try { nd = dynamic_cast( data ); } catch( ... ) { mitkThrowException(mitk::IGTException) << "mitk::NavigationData::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ; } if (!nd) { // pointer could not be cast back down mitkThrowException(mitk::IGTException) << "mitk::NavigationData::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ; } // Now copy anything that is needed m_Identifier = nd->GetIdentifier(); m_Type = nd->GetType(); m_DataNode->SetName(nd->GetDataNode()->GetName()); m_DataNode->SetData(nd->GetDataNode()->GetData()); m_SpatialObject = nd->GetSpatialObject(); m_TrackingTool = nd->GetTrackingTool(); m_CalibrationFile = nd->GetCalibrationFile(); m_SerialNumber = nd->GetSerialNumber(); m_TrackingDeviceType = nd->GetTrackingDeviceType(); m_ToolRegistrationLandmarks = nd->GetToolRegistrationLandmarks(); m_ToolCalibrationLandmarks = nd->GetToolCalibrationLandmarks(); m_ToolTipPosition = nd->GetToolTipPosition(); m_ToolTipOrientation = nd->GetToolTipOrientation(); } bool mitk::NavigationTool::IsToolTipSet() { if( (m_ToolTipPosition[0] == 0) && (m_ToolTipPosition[1] == 0) && (m_ToolTipPosition[2] == 0) && (m_ToolTipOrientation.x() == 0) && (m_ToolTipOrientation.y() == 0) && (m_ToolTipOrientation.z() == 0) && (m_ToolTipOrientation.r() == 1)) return false; else return true; } void mitk::NavigationTool::SetCalibrationFile(const std::string filename) { //check if file does exist: if (filename=="") { m_CalibrationFile = "none"; } else { Poco::File myFile(filename); if (myFile.exists()) m_CalibrationFile = filename; else m_CalibrationFile = "none"; } } std::string mitk::NavigationTool::GetToolName() { if (this->m_DataNode.IsNull()) {return "";} else {return m_DataNode->GetName();} } mitk::Surface::Pointer mitk::NavigationTool::GetToolSurface() { if (this->m_DataNode.IsNull()) {return NULL;} else if (this->m_DataNode->GetData() == NULL) {return NULL;} else {return dynamic_cast(m_DataNode->GetData());} } diff --git a/Modules/IGT/DataManagement/mitkTrackingDeviceSource.cpp b/Modules/IGT/DataManagement/mitkTrackingDeviceSource.cpp index c8701193a9..bc7b5c929d 100644 --- a/Modules/IGT/DataManagement/mitkTrackingDeviceSource.cpp +++ b/Modules/IGT/DataManagement/mitkTrackingDeviceSource.cpp @@ -1,213 +1,213 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTrackingDeviceSource.h" #include "mitkTrackingDevice.h" #include "mitkTrackingTool.h" #include "mitkIGTTimeStamp.h" #include "mitkIGTException.h" mitk::TrackingDeviceSource::TrackingDeviceSource() : mitk::NavigationDataSource(), m_TrackingDevice(NULL) { } mitk::TrackingDeviceSource::~TrackingDeviceSource() { if (m_TrackingDevice.IsNotNull()) { if (m_TrackingDevice->GetState() == mitk::TrackingDevice::Tracking) { this->StopTracking(); } if (m_TrackingDevice->GetState() == mitk::TrackingDevice::Ready) { this->Disconnect(); } m_TrackingDevice = NULL; } } void mitk::TrackingDeviceSource::GenerateData() { if (m_TrackingDevice.IsNull()) return; if (m_TrackingDevice->GetToolCount() < 1) return; if (this->GetNumberOfIndexedOutputs() != m_TrackingDevice->GetToolCount()) // mismatch between tools and outputs. What should we do? Were tools added to the tracking device after SetTrackingDevice() was called? { //check this: TODO: ////this might happen if a tool is plugged into an aurora during tracking. //this->CreateOutputs(); std::stringstream ss; ss << "mitk::TrackingDeviceSource: not enough outputs available for all tools. " << this->GetNumberOfOutputs() << " outputs available, but " << m_TrackingDevice->GetToolCount() << " tools available in the tracking device."; throw std::out_of_range(ss.str()); } /* update outputs with tracking data from tools */ unsigned int toolCount = m_TrackingDevice->GetToolCount(); for (unsigned int i = 0; i < toolCount; ++i) { mitk::NavigationData* nd = this->GetOutput(i); assert(nd); mitk::TrackingTool* t = m_TrackingDevice->GetTool(i); assert(t); if ((t->IsEnabled() == false) || (t->IsDataValid() == false)) { nd->SetDataValid(false); continue; } nd->SetDataValid(true); mitk::NavigationData::PositionType p; t->GetPosition(p); nd->SetPosition(p); mitk::NavigationData::OrientationType o; t->GetOrientation(o); nd->SetOrientation(o); nd->SetOrientationAccuracy(t->GetTrackingError()); nd->SetPositionAccuracy(t->GetTrackingError()); nd->SetIGTTimeStamp(t->GetIGTTimeStamp()); //for backward compatibility: check if the timestamp was set, if not create a default timestamp if (nd->GetIGTTimeStamp()==0) nd->SetIGTTimeStamp(mitk::IGTTimeStamp::GetInstance()->GetElapsed()); } } void mitk::TrackingDeviceSource::SetTrackingDevice( mitk::TrackingDevice* td ) { MITK_DEBUG << "Setting TrackingDevice to " << td; if (this->m_TrackingDevice.GetPointer() != td) { this->m_TrackingDevice = td; this->CreateOutputs(); std::stringstream name; // create a human readable name for the source name << td->GetData().Model << " Tracking Source"; this->SetName(name.str()); } } void mitk::TrackingDeviceSource::CreateOutputs(){ //if outputs are set then delete them if (this->GetNumberOfOutputs() > 0) { for (int numOP = this->GetNumberOfOutputs() -1; numOP >= 0; numOP--) - this->RemoveOutput(this->GetOutput(numOP)); + this->RemoveOutput(numOP); this->Modified(); } //fill the outputs if a valid tracking device is set if (m_TrackingDevice.IsNull()) return; this->SetNumberOfIndexedOutputs(m_TrackingDevice->GetToolCount()); // create outputs for all tools unsigned int numberOfOutputs = this->GetNumberOfIndexedOutputs(); MITK_DEBUG << "Number of tools at start of method CreateOutputs(): " << m_TrackingDevice->GetToolCount(); MITK_DEBUG << "Number of outputs at start of method CreateOutputs(): " << numberOfOutputs; for (unsigned int idx = 0; idx < m_TrackingDevice->GetToolCount(); ++idx) { if (this->GetOutput(idx) == NULL) { DataObjectPointer newOutput = this->MakeOutput(idx); static_cast(newOutput.GetPointer())->SetName(m_TrackingDevice->GetTool(idx)->GetToolName()); // set NavigationData name to ToolName this->SetNthOutput(idx, newOutput); this->Modified(); } } } void mitk::TrackingDeviceSource::Connect() { if (m_TrackingDevice.IsNull()) throw std::invalid_argument("mitk::TrackingDeviceSource: No tracking device set"); if (this->IsConnected()) return; try {m_TrackingDevice->OpenConnection();} catch (mitk::IGTException &e) { throw std::runtime_error(std::string("mitk::TrackingDeviceSource: Could not open connection to tracking device. Error: ") + e.GetDescription()); } /* NDI Aurora needs a connection to discover tools that are connected to it. Therefore we need to create outputs for these tools now */ //if (m_TrackingDevice->GetType() == mitk::NDIAurora) //this->CreateOutputs(); } void mitk::TrackingDeviceSource::StartTracking() { if (m_TrackingDevice.IsNull()) throw std::invalid_argument("mitk::TrackingDeviceSource: No tracking device set"); if (m_TrackingDevice->GetState() == mitk::TrackingDevice::Tracking) return; if (m_TrackingDevice->StartTracking() == false) throw std::runtime_error("mitk::TrackingDeviceSource: Could not start tracking"); } void mitk::TrackingDeviceSource::Disconnect() { if (m_TrackingDevice.IsNull()) throw std::invalid_argument("mitk::TrackingDeviceSource: No tracking device set"); if (m_TrackingDevice->CloseConnection() == false) throw std::runtime_error("mitk::TrackingDeviceSource: Could not close connection to tracking device"); } void mitk::TrackingDeviceSource::StopTracking() { if (m_TrackingDevice.IsNull()) throw std::invalid_argument("mitk::TrackingDeviceSource: No tracking device set"); if (m_TrackingDevice->StopTracking() == false) throw std::runtime_error("mitk::TrackingDeviceSource: Could not stop tracking"); } void mitk::TrackingDeviceSource::UpdateOutputInformation() { if(this->GetTrackingDevice()->GetToolCount() != this->GetNumberOfIndexedOutputs()) this->CreateOutputs(); this->Modified(); // make sure that we need to be updated Superclass::UpdateOutputInformation(); } //unsigned int mitk::TrackingDeviceSource::GetToolCount() //{ // if (m_TrackingDevice) // return m_TrackingDevice->GetToolCount(); // return 0; //} bool mitk::TrackingDeviceSource::IsConnected() { if (m_TrackingDevice.IsNull()) return false; return (m_TrackingDevice->GetState() == mitk::TrackingDevice::Ready) || (m_TrackingDevice->GetState() == mitk::TrackingDevice::Tracking); } bool mitk::TrackingDeviceSource::IsTracking() { if (m_TrackingDevice.IsNull()) return false; return m_TrackingDevice->GetState() == mitk::TrackingDevice::Tracking; -} \ No newline at end of file +} diff --git a/Modules/IGT/IO/mitkNavigationDataPlayer.cpp b/Modules/IGT/IO/mitkNavigationDataPlayer.cpp index eddacc6619..04a7c3a564 100644 --- a/Modules/IGT/IO/mitkNavigationDataPlayer.cpp +++ b/Modules/IGT/IO/mitkNavigationDataPlayer.cpp @@ -1,550 +1,549 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataPlayer.h" #include #include #include //includes for exceptions #include "mitkIGTException.h" #include "mitkIGTIOException.h" mitk::NavigationDataPlayer::NavigationDataPlayer() : mitk::NavigationDataPlayerBase() { - m_NumberOfOutputs = 0; m_Pause = false; m_Playing = false; m_Stream = NULL; m_PlayerMode = NormalFile; m_FileName = ""; m_FileVersion = 1; m_Playing = false; m_Pause = false; m_NumberOfOutputs = 0; m_StartPlayingTimeStamp = 0.0; m_PauseTimeStamp = 0.0; m_parentElement = NULL; m_currentNode = NULL; m_StreamEnd = false; m_StreamSetOutsideFromClass = false; //To get a start time mitk::IGTTimeStamp::GetInstance()->Start(this); } mitk::NavigationDataPlayer::~NavigationDataPlayer() { StopPlaying(); delete m_parentElement; } void mitk::NavigationDataPlayer::GenerateData() { //Only produce new output if the player is started if (!m_Playing) //m_Playing==true means player has started { //The output is not valid anymore for (unsigned int index = 0; index < m_NumberOfOutputs; index++) { mitk::NavigationData* output = this->GetOutput(index); assert(output); mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType position; mitk::NavigationData::OrientationType orientation(0.0,0.0,0.0,0.0); position.Fill(0.0); nd->SetPosition(position); nd->SetOrientation(orientation); nd->SetDataValid(false); output->Graft(nd); } return; } //first of all get current time TimeStampType now = mitk::IGTTimeStamp::GetInstance()->GetElapsed(); //now we make a little time arithmetic //to get the elapsed time since the start of the player TimeStampType timeSinceStart = now - m_StartPlayingTimeStamp; //init the vectors std::vector< NavigationData::Pointer > nextCandidates; std::vector< NavigationData::Pointer > lastCandidates; std::vector< NavigationData::TimeStampType > currentTimeOfData; for (unsigned int index=0; index < m_NumberOfOutputs; index++) { nextCandidates.push_back(m_NextToPlayNavigationData.at(index)); lastCandidates.push_back(m_NextToPlayNavigationData.at(index)); currentTimeOfData.push_back(timeSinceStart + m_StartTimeOfData.at(index)); } if (m_NextToPlayNavigationData.size() != m_NumberOfOutputs) { MITK_ERROR << "Mismatch in data"; return; } // Now we try to find next NavigationData in the stream: // This means we step through the stream of NavigationDatas until we find // a NavigationData which has a current timestamp (currentTimeOfData) greater // than the current playing time. Then we store the data in // m_NextToPlayNavigationData and take the last data (lastCandidates) for the // output of this filter. // // The loop will stop when a suitable NavigationData is found or we reach EOF. // The timestamps of each recorded NavigationData should be equal // therefore we take always the time from the first. while( nextCandidates[0]->GetIGTTimeStamp() < currentTimeOfData[0]) { for (unsigned int index=0; index < m_NumberOfOutputs; index++) { lastCandidates[index] = nextCandidates.at(index); switch(m_FileVersion) // m_FileVersion indicates which XML encoding is used { case 1: nextCandidates[index] = ReadVersion1(); break; default: //this case should not happen! therefore return at this point MITK_ERROR << "File encoding format was not stored, aborting!"; return; break; } //check if the input stream delivered a correct NavigationData object for (unsigned int i = 0; i < m_NumberOfOutputs; i++) { if (nextCandidates.at(index).IsNull()) //Stops playing because there is now more nextCandidate, the file ended for all outputs { m_StreamEnd = true; StopPlaying(); return; //the case if no NavigationData is found, e.g. EOF, bad stream } } } } //Now lastCandidates stores the new output and nextCandidates is stored to the m_NextToPlay vector for (unsigned int index = 0; index < m_NumberOfOutputs; index++) { mitk::NavigationData* output = this->GetOutput(index); assert(output); output->Graft(lastCandidates.at(index)); m_NextToPlayNavigationData[index] = nextCandidates.at(index); } } void mitk::NavigationDataPlayer::UpdateOutputInformation() { this->Modified(); // make sure that we need to be updated Superclass::UpdateOutputInformation(); } void mitk::NavigationDataPlayer::InitPlayer() { if (m_Stream == NULL) { StreamInvalid("Playing not possible. Wrong file name or path?"); return; } if (!m_Stream->good()) { StreamInvalid("Playing not possible. Stream is not good!"); return; } //first get the file version m_FileVersion = GetFileVersion(m_Stream); //check if we have a valid version: m_FileVersion has to be always bigger than 1 for playing if (m_FileVersion < 1) { StreamInvalid("Playing not possible. Invalid file version!"); return; } if(m_NumberOfOutputs == 0) {m_NumberOfOutputs = GetNumberOfNavigationDatas(m_Stream);} //with the information about the tracked tool number we can generate the output if (m_NumberOfOutputs > 0) { //Generate the output only if there are changes to the amount of outputs //This happens when the player is stopped and start again with different file - if (this->GetNumberOfOutputs() != m_NumberOfOutputs) {SetNumberOfOutputs(m_NumberOfOutputs);} + if (this->GetNumberOfOutputs() != m_NumberOfOutputs) {SetNumberOfIndexedOutputs(m_NumberOfOutputs);} //initialize the player with first data GetFirstData(); //set stream valid m_ErrorMessage = ""; m_StreamValid = true; } else { StreamInvalid("The input stream seems to have NavigationData incompatible format"); return; } } unsigned int mitk::NavigationDataPlayer::GetFileVersion(std::istream* stream) { if (stream==NULL) { MITK_ERROR << "No input stream set!"; mitkThrowException(mitk::IGTException)<<"No input stream set!"; } if (!stream->good()) { MITK_ERROR << "Stream is not good!"; mitkThrowException(mitk::IGTException)<<"Stream is not good!"; } int version = 1; TiXmlDeclaration* dec = new TiXmlDeclaration(); *stream >> *dec; if(strcmp(dec->Version(),"") == 0) { MITK_ERROR << "The input stream seems to have XML incompatible format"; mitkThrowException(mitk::IGTIOException) << "The input stream seems to have XML incompatible format"; } m_parentElement = new TiXmlElement(""); *stream >> *m_parentElement; //2nd line this is the file version std::string tempValue = m_parentElement->Value(); if(tempValue != "Version") { if(tempValue == "Data"){ m_parentElement->QueryIntAttribute("version",&version); } } else { m_parentElement->QueryIntAttribute("Ver",&version); } if (version > 0) return version; else return 0; } unsigned int mitk::NavigationDataPlayer::GetNumberOfNavigationDatas(std::istream* stream) { if (stream == NULL) { MITK_ERROR << "No input stream set!"; mitkThrowException(mitk::IGTException)<<"No input stream set!"; } if (!stream->good()) { MITK_ERROR << "Stream not good!"; mitkThrowException(mitk::IGTException)<<"Stream not good!"; } //If something has changed in a future version of the XML definition e.g. navigationcount or addional parameters //catch this here with a select case block (see GenerateData() method) int numberOfTools = 0; std::string tempValue = m_parentElement->Value(); if(tempValue == "Version"){ *stream >> *m_parentElement; } m_parentElement->QueryIntAttribute("ToolCount",&numberOfTools); if (numberOfTools > 0) return numberOfTools; return 0; } mitk::NavigationData::Pointer mitk::NavigationDataPlayer::ReadVersion1() { if (m_Stream == NULL) { m_Playing = false; MITK_ERROR << "Playing not possible. Wrong file name or path? "; mitkThrowException(mitk::IGTException) << "Playing not possible. Wrong file name or path? "; } if (!m_Stream->good()) { m_Playing = false; MITK_ERROR << "Playing not possible. Stream is not good!"; mitkThrowException(mitk::IGTException) << "Playing not possible. Stream is not good!"; } /*TiXmlElement* elem = new TiXmlElement(""); m_currentNode = m_parentElement->IterateChildren(m_currentNode); if(m_currentNode) { elem = m_currentNode->ToElement(); }*/ TiXmlElement* elem; m_currentNode = m_parentElement->IterateChildren(m_currentNode); bool delElem; if(m_currentNode) { elem = m_currentNode->ToElement(); if(elem==NULL) { mitkThrowException(mitk::IGTException) << "Cannot find element: Is this file damaged?"; } delElem = false; } else { elem = new TiXmlElement(""); delElem = true; } mitk::NavigationData::Pointer nd = this->ReadNavigationData(elem); if(delElem) delete elem; return nd; } void mitk::NavigationDataPlayer::StartPlaying() { if (m_Stream == NULL) { m_Playing = false; //Perhaps the SetStream method was not called so we do this when a FileName is set with SetStream(PlayerMode) if (m_FileName != "") { //The PlayerMode is initialized with LastSetStream //CreateStreamFromFilename also calls InitPlayer() try { CreateStreamFromFilename(); } catch(mitk::IGTIOException e) { MITK_ERROR << "Cannot create stream from filename, please check the stream"; throw e; //TODO replace by macro } catch(mitk::IGTException e2) { MITK_ERROR << "Cannot open the file, please check the file"; throw e2; //TODO replace by macro } } //now check again if (m_Stream == NULL) { StopPlaying(); MITK_ERROR << "Playing not possible. Wrong file name or path?"; mitkThrowException(mitk::IGTException) << "Playing not possible. Wrong file name or path?"; } } if (!m_Playing && m_Stream->good()) { m_Playing = true; m_StartPlayingTimeStamp = mitk::IGTTimeStamp::GetInstance()->GetElapsed(); } else { MITK_ERROR << "Player already started or stream is not good!"; StopPlaying(); } } void mitk::NavigationDataPlayer::StopPlaying() { //re init all data!! for playing again with different data //only PlayerMode and FileName are not changed m_Pause = false; m_Playing = false; if (!m_StreamSetOutsideFromClass) {delete m_Stream;} m_Stream = NULL; m_FileVersion = 1; m_Playing = false; m_Pause = false; m_StartPlayingTimeStamp = 0.0; m_PauseTimeStamp = 0.0; m_NextToPlayNavigationData.clear(); m_StartTimeOfData.clear(); } void mitk::NavigationDataPlayer::GetFirstData() { //Here we read the first lines of input (dependend on the number of inputs) for (unsigned int index=0; index < m_NumberOfOutputs; index++) { //Here we init the vector for later use m_NextToPlayNavigationData.push_back(NULL); m_StartTimeOfData.push_back(0.0); mitk::NavigationData::Pointer nd = this->GetOutput(index); switch(m_FileVersion) { case 1: m_NextToPlayNavigationData[index] = ReadVersion1(); //check if there is valid data in it if (m_NextToPlayNavigationData[index].IsNull()) { m_StreamEnd = true; StopPlaying(); mitkThrowException(mitk::IGTIOException) << "XML File is corrupt or has no NavigationData."; } //Have a look it the output was set already without this check the pipline will disconnect after a start/stop cycle if (nd.IsNull()) {this->SetNthOutput(index, m_NextToPlayNavigationData[index]);} m_StartTimeOfData[index] = m_NextToPlayNavigationData[index]->GetIGTTimeStamp(); break; default: //this case should not happen! therefore the return at this point return; break; } } } void mitk::NavigationDataPlayer::Pause() { //player runs and pause was called -> pause the player if(m_Playing && !m_Pause) { m_Playing = false; m_Pause = true; m_PauseTimeStamp = mitk::IGTTimeStamp::GetInstance()->GetElapsed(); } else { MITK_ERROR << "Player is either not started or already is paused" << std::endl; } } void mitk::NavigationDataPlayer::Resume() { //player is in pause mode -> play at the last position if(!m_Playing && m_Pause) { m_Playing = true; m_Pause = false; mitk::NavigationData::TimeStampType now = mitk::IGTTimeStamp::GetInstance()->GetElapsed(); // in this case m_StartPlayingTimeStamp is set to the total elapsed time with NO playback m_StartPlayingTimeStamp = now - (m_PauseTimeStamp - m_StartPlayingTimeStamp); } else { MITK_ERROR << "Player is not paused!" << std::endl; } } void mitk::NavigationDataPlayer::CreateStreamFromFilename() { m_Stream = NULL; if (!itksys::SystemTools::FileExists(m_FileName.c_str())) { mitkThrowException(mitk::IGTIOException) << "File does not exist!"; } switch(m_PlayerMode) { case NormalFile: m_Stream = new std::ifstream(m_FileName.c_str()); m_StreamSetOutsideFromClass = false; break; case ZipFile: m_Stream = NULL; MITK_ERROR << "Sorry no ZipFile support yet"; break; default: m_Stream = NULL; mitkThrowException(mitk::IGTException) << "The stream is NULL"; break; } this->Modified(); InitPlayer(); } void mitk::NavigationDataPlayer::SetStream( std::istream* stream ) { if ( (stream == NULL) || (!stream->good())) { // throw an exception for stream=NULL or it is not good mitkThrowException(mitk::IGTException) << "The stream is NULL or it is not good"; m_StreamEnd = true; return; } m_Stream = stream; m_StreamSetOutsideFromClass = true; this->Modified(); InitPlayer(); } bool mitk::NavigationDataPlayer::IsAtEnd() { return this->m_StreamEnd; } void mitk::NavigationDataPlayer::StreamInvalid(std::string message) { m_StreamEnd = true; StopPlaying(); m_ErrorMessage = message; m_StreamValid = false; mitkThrowException(mitk::IGTIOException) << "Invalid stream!"; -} \ No newline at end of file +} diff --git a/Modules/IGT/IO/mitkNavigationDataSequentialPlayer.cpp b/Modules/IGT/IO/mitkNavigationDataSequentialPlayer.cpp index df453b3da1..82557229d8 100644 --- a/Modules/IGT/IO/mitkNavigationDataSequentialPlayer.cpp +++ b/Modules/IGT/IO/mitkNavigationDataSequentialPlayer.cpp @@ -1,226 +1,226 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataSequentialPlayer.h" #include //for the pause #include #include //Exceptions #include "mitkIGTException.h" #include "mitkIGTIOException.h" mitk::NavigationDataSequentialPlayer::NavigationDataSequentialPlayer() : mitk::NavigationDataPlayerBase() , m_Doc(new TiXmlDocument) , m_DataElem(0) , m_CurrentElem(0) , m_Repeat(false) , m_NumberOfSnapshots(0) , m_LastGoTo(0) { } mitk::NavigationDataSequentialPlayer::~NavigationDataSequentialPlayer() { delete m_Doc; } void mitk::NavigationDataSequentialPlayer::ReinitXML() { m_DataElem = m_Doc->FirstChildElement("Data"); int toolcount; if(!m_DataElem) { MITK_WARN << "Data element not found"; mitkThrowException(mitk::IGTException) << "Data element not found"; } else { m_DataElem->QueryIntAttribute("ToolCount", &toolcount); this->SetNumberOfRequiredOutputs(toolcount); mitk::NavigationData::Pointer emptyNd = mitk::NavigationData::New(); mitk::NavigationData::PositionType position; mitk::NavigationData::OrientationType orientation(0.0,0.0,0.0,0.0); position.Fill(0.0); emptyNd->SetPosition(position); emptyNd->SetOrientation(orientation); emptyNd->SetDataValid(false); mitk::NavigationData::Pointer tmp; for (unsigned int index = 0; index < this->GetNumberOfRequiredOutputs(); index++) { tmp = mitk::NavigationData::New(); tmp->Graft(emptyNd); this->SetNthOutput(index, tmp.GetPointer()); } // find out _NumberOfSnapshots m_NumberOfSnapshots = 0; TiXmlElement* nextND = m_DataElem->FirstChildElement("NavigationData"); while(nextND) { ++m_NumberOfSnapshots; nextND = nextND->NextSiblingElement("NavigationData"); } // e.g. 12 nd found and 2 tools used => number of snapshots is 12:2=6 m_NumberOfSnapshots = m_NumberOfSnapshots/toolcount; } } void mitk::NavigationDataSequentialPlayer::GoToSnapshot(unsigned int i) { if(!m_Repeat && (this->GetNumberOfSnapshots() numOfUpdateCalls = 4 if(m_LastGoTo <= i) numOfUpdateCalls = i - m_LastGoTo; // goto(4), m_LastGoTo=7 => numOfUpdateCalls = 7 else { if(!m_Repeat) { std::stringstream message; message <<"Cannot go back to snapshot " << i << " because the " << this->GetNameOfClass() << " is configured to not repeat the" << " navigation data."; MITK_WARN << message.str(); mitkThrowException(mitk::IGTException) << message.str(); } else { numOfUpdateCalls = (m_NumberOfSnapshots - m_LastGoTo) + i; } } for(int j=0; jUpdate(); m_LastGoTo = i; } void mitk::NavigationDataSequentialPlayer:: SetFileName(const std::string& _FileName) { m_FileName = _FileName; if(!m_Doc->LoadFile(m_FileName)) { - this->SetNumberOfOutputs(0); + this->SetNumberOfIndexedOutputs(0); std::ostringstream s; s << "File " << _FileName << " could not be loaded"; mitkThrowException(mitk::IGTIOException)<ReinitXML(); } this->Modified(); } void mitk::NavigationDataSequentialPlayer:: SetXMLString(const std::string& _XMLString) { m_XMLString = _XMLString; if((m_Doc->Parse( m_XMLString.c_str()))== NULL) { this->ReinitXML(); } else { //if the string is not an XML string std::ostringstream s; s << "String" << _XMLString << " is not an XML string"; mitkThrowException(mitk::IGTIOException)<Modified(); } void mitk::NavigationDataSequentialPlayer::GenerateData() { assert(m_DataElem); // very important: go through the tools (there could be more than one) mitk::NavigationData::Pointer tmp; for (unsigned int index = 0; index < this->GetNumberOfIndexedOutputs(); index++) { // go to the first element if(!m_CurrentElem) m_CurrentElem = m_DataElem->FirstChildElement("NavigationData"); // go to the next element else { m_CurrentElem = m_CurrentElem->NextSiblingElement(); } // if repeat is on: go back to the first element (prior calls delivered NULL // elem) if(!m_CurrentElem && m_Repeat) m_CurrentElem = m_DataElem->FirstChildElement("NavigationData"); mitk::NavigationData* output = this->GetOutput(index); tmp = this->ReadVersion1(); if(tmp.IsNotNull()) { output->Graft(tmp); m_StreamValid = true; } else // no valid output { output->SetDataValid(false); m_StreamValid = false; m_ErrorMessage = "Error: Cannot parse input file."; mitkThrowException(mitk::IGTException)<ReadNavigationData(elem); } void mitk::NavigationDataSequentialPlayer::UpdateOutputInformation() { this->Modified(); // make sure that we need to be updated Superclass::UpdateOutputInformation(); } diff --git a/Modules/IGT/IO/mitkNavigationDataSequentialPlayer.h b/Modules/IGT/IO/mitkNavigationDataSequentialPlayer.h index 389634b835..6669cd0266 100644 --- a/Modules/IGT/IO/mitkNavigationDataSequentialPlayer.h +++ b/Modules/IGT/IO/mitkNavigationDataSequentialPlayer.h @@ -1,122 +1,122 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKNavigationDataSequentialPlayer_H_HEADER_INCLUDED_ #define MITKNavigationDataSequentialPlayer_H_HEADER_INCLUDED_ #include #include "tinyxml.h" namespace mitk { /**Documentation * \brief This class is a slightly changed reimplementation of the * NavigationDataPlayer which does not care about timestamps and just * outputs the navigationdatas in their sequential order * * \ingroup IGT */ class MitkIGT_EXPORT NavigationDataSequentialPlayer : public NavigationDataPlayerBase { public: mitkClassMacro(NavigationDataSequentialPlayer, NavigationDataPlayerBase); itkNewMacro(Self); /** * \brief sets the file name and path (if XMLString is set, this is neglected) * @throw mitk::IGTIOException Throws an exception if the given file cannot be loaded. */ void SetFileName(const std::string& _FileName); /** * \brief returns the file name and path */ itkGetStringMacro(FileName); /** * \brief sets a xml string (by this, the xml string is not read from file) * @throw mitk::IGTExcepton Throws an mitk::IGTExcepton if the string to set is not an XMLString */ void SetXMLString(const std::string& _XMLString); /** * \brief returns the current xml string */ itkGetStringMacro(XMLString); /** * @brief Set to true if the data player should repeat the outputs. */ itkSetMacro(Repeat, bool); /** * @return Returns if the data player should repeat the outputs. */ itkGetMacro(Repeat, bool); /** * @return Returns the number of navigation data snapshots available in the file */ itkGetMacro(NumberOfSnapshots, unsigned int); /** * advance the output to the i-th snapshot * e.g. if you want to have the NavData of snapshot * 17 then you can call GoToSnapshot(17). index begins at 1! * you can then also go back to snapshot 1 with GoToSnapshot(1) * * @throw mitk::IGTException Throws an exception if cannot go back to particular snapshot. */ void GoToSnapshot(unsigned int i); /** * \brief Used for pipeline update just to tell the pipeline * that we always have to update */ virtual void UpdateOutputInformation(); protected: NavigationDataSequentialPlayer(); virtual ~NavigationDataSequentialPlayer(); /** * @throw mitk::IGTException Throws an exception if data element is not found. */ void ReinitXML(); mitk::NavigationData::Pointer ReadVersion1(); /** * @throw mitk::IGTException Throws an exception if cannot parse input file */ virtual void GenerateData(); std::string m_FileName; std::string m_XMLString; TiXmlDocument* m_Doc; TiXmlElement* m_DataElem; TiXmlElement* m_CurrentElem; bool m_Repeat; unsigned int m_NumberOfSnapshots; - int m_LastGoTo; + unsigned int m_LastGoTo; }; } // namespace mitk #endif /* MITKNavigationDataSequentialPlayer_H_HEADER_INCLUDED_ */ diff --git a/Modules/IGT/Rendering/mitkNavigationDataObjectVisualizationFilter.cpp b/Modules/IGT/Rendering/mitkNavigationDataObjectVisualizationFilter.cpp index 24c305f668..a1501ec1c5 100644 --- a/Modules/IGT/Rendering/mitkNavigationDataObjectVisualizationFilter.cpp +++ b/Modules/IGT/Rendering/mitkNavigationDataObjectVisualizationFilter.cpp @@ -1,247 +1,247 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataObjectVisualizationFilter.h" #include "mitkDataStorage.h" mitk::NavigationDataObjectVisualizationFilter::NavigationDataObjectVisualizationFilter() : NavigationDataToNavigationDataFilter(), m_RepresentationList(), m_TransformPosition(), m_TransformOrientation(), m_RotationMode(RotationStandard) { } mitk::NavigationDataObjectVisualizationFilter::~NavigationDataObjectVisualizationFilter() { m_RepresentationList.clear(); m_OffsetList.clear(); } const mitk::BaseData* mitk::NavigationDataObjectVisualizationFilter::GetRepresentationObject(unsigned int idx) { RepresentationPointerMap::const_iterator iter = m_RepresentationList.find(idx); if (iter != m_RepresentationList.end()) return iter->second; return NULL; } mitk::AffineTransform3D::Pointer mitk::NavigationDataObjectVisualizationFilter::GetOffset(int index) { OffsetPointerMap::const_iterator iter = m_OffsetList.find(index); if (iter != m_OffsetList.end()) return iter->second; return NULL; } void mitk::NavigationDataObjectVisualizationFilter::SetRepresentationObject(unsigned int idx, BaseData* data) { m_RepresentationList[idx] = RepresentationPointer(data); } void mitk::NavigationDataObjectVisualizationFilter::SetOffset(int index, mitk::AffineTransform3D::Pointer offset) { m_OffsetList[index] = offset; } void mitk::NavigationDataObjectVisualizationFilter::SetRotationMode(RotationMode r) { m_RotationMode = r; } void mitk::NavigationDataObjectVisualizationFilter::GenerateData() { /*get each input, lookup the associated BaseData and transfer the data*/ DataObjectPointerArray inputs = this->GetInputs(); //get all inputs for (unsigned int index=0; index < inputs.size(); index++) { //get the needed variables const mitk::NavigationData* nd = this->GetInput(index); assert(nd); mitk::NavigationData* output = this->GetOutput(index); assert(output); //check if the data is valid if (!nd->IsDataValid()) { output->SetDataValid(false); continue; } output->Graft(nd); // copy all information from input to output const mitk::BaseData* data = this->GetRepresentationObject(index); if (data == NULL) { MITK_WARN << "No BaseData associated with input " << index; continue; } //get the transform from data mitk::AffineTransform3D::Pointer affineTransform = data->GetGeometry()->GetIndexToWorldTransform(); if (affineTransform.IsNull()) { MITK_WARN << "AffineTransform IndexToWorldTransform not initialized!"; continue; } //check for offset mitk::AffineTransform3D::Pointer offset = this->GetOffset(index); //store the current scaling to set it after transformation mitk::Vector3D spacing = data->GetGeometry()->GetSpacing(); //clear spacing of data to be able to set it again afterwards ScalarType scale[] = {1.0, 1.0, 1.0}; data->GetGeometry()->SetSpacing(scale); /*now bring quaternion to affineTransform by using vnl_Quaternion*/ affineTransform->SetIdentity(); if (this->GetTransformOrientation(index) == true) { mitk::NavigationData::OrientationType orientation = nd->GetOrientation(); /* because of an itk bug, the transform can not be calculated with float data type. To use it in the mitk geometry classes, it has to be transfered to mitk::ScalarType which is float */ static AffineTransform3D::MatrixType m; //convert quaternion to rotation matrix depending on the rotation mode if(m_RotationMode == RotationStandard) { //calculate the transform from the quaternions static itk::QuaternionRigidTransform::Pointer quatTransform = itk::QuaternionRigidTransform::New(); // convert mitk::ScalarType quaternion to double quaternion because of itk bug vnl_quaternion doubleQuaternion(orientation.x(), orientation.y(), orientation.z(), orientation.r()); quatTransform->SetIdentity(); quatTransform->SetRotation(doubleQuaternion); quatTransform->Modified(); mitk::TransferMatrix(quatTransform->GetMatrix(), m); } else if(m_RotationMode == RotationTransposed) { vnl_matrix_fixed rot = orientation.rotation_matrix_transpose(); for(int i=0; i<3; i++) for (int j=0; j<3; j++) m[i][j] = rot[i][j]; } affineTransform->SetMatrix(m); } if (this->GetTransformPosition(index) == true) { ///*set the offset by convert from itkPoint to itkVector and setting offset of transform*/ mitk::Vector3D pos; - pos.Set_vnl_vector(nd->GetPosition().Get_vnl_vector()); + pos.SetVnlVector(nd->GetPosition().GetVnlVector()); affineTransform->SetOffset(pos); } affineTransform->Modified(); //set the transform to data if(offset.IsNotNull()) //first use offset if there is one. { mitk::AffineTransform3D::Pointer overallTransform = mitk::AffineTransform3D::New(); overallTransform->SetIdentity(); overallTransform->Compose(offset); overallTransform->Compose(affineTransform); data->GetGeometry()->SetIndexToWorldTransform(overallTransform); } else { data->GetGeometry()->SetIndexToWorldTransform(affineTransform); } //set the original spacing to keep scaling of the geometrical object data->GetGeometry()->SetSpacing(spacing); data->GetGeometry()->TransferItkToVtkTransform(); // update VTK Transform for rendering too data->GetGeometry()->Modified(); data->Modified(); output->SetDataValid(true); // operation was successful, therefore data of output is valid. } } void mitk::NavigationDataObjectVisualizationFilter::SetTransformPosition( unsigned int index, bool applyTransform ) { itkDebugMacro("setting TransformPosition for index " << index << " to " << applyTransform); BooleanInputMap::const_iterator it = this->m_TransformPosition.find(index); if ((it != this->m_TransformPosition.end()) && (it->second == applyTransform)) return; this->m_TransformPosition[index] = applyTransform; this->Modified(); } bool mitk::NavigationDataObjectVisualizationFilter::GetTransformPosition( unsigned int index ) const { itkDebugMacro("returning TransformPosition for index " << index); BooleanInputMap::const_iterator it = this->m_TransformPosition.find(index); if (it != this->m_TransformPosition.end()) return it->second; else return true; // default to true } void mitk::NavigationDataObjectVisualizationFilter::TransformPositionOn( unsigned int index ) { this->SetTransformPosition(index, true); } void mitk::NavigationDataObjectVisualizationFilter::TransformPositionOff( unsigned int index ) { this->SetTransformPosition(index, false); } void mitk::NavigationDataObjectVisualizationFilter::SetTransformOrientation( unsigned int index, bool applyTransform ) { itkDebugMacro("setting TransformOrientation for index " << index << " to " << applyTransform); BooleanInputMap::const_iterator it = this->m_TransformOrientation.find(index); if ((it != this->m_TransformOrientation.end()) && (it->second == applyTransform)) return; this->m_TransformOrientation[index] = applyTransform; this->Modified(); \ } bool mitk::NavigationDataObjectVisualizationFilter::GetTransformOrientation( unsigned int index ) const { itkDebugMacro("returning TransformOrientation for index " << index); BooleanInputMap::const_iterator it = this->m_TransformOrientation.find(index); if (it != this->m_TransformOrientation.end()) return it->second; else return true; // default to true } void mitk::NavigationDataObjectVisualizationFilter::TransformOrientationOn( unsigned int index ) { this->SetTransformOrientation(index, true); } void mitk::NavigationDataObjectVisualizationFilter::TransformOrientationOff( unsigned int index ) { this->SetTransformOrientation(index, false); } diff --git a/Modules/IGT/Testing/mitkClaronTrackingDeviceTest.cpp b/Modules/IGT/Testing/mitkClaronTrackingDeviceTest.cpp index c6167c039a..4f9f337dbd 100644 --- a/Modules/IGT/Testing/mitkClaronTrackingDeviceTest.cpp +++ b/Modules/IGT/Testing/mitkClaronTrackingDeviceTest.cpp @@ -1,149 +1,152 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkClaronTrackingDevice.h" #include "mitkClaronTool.h" #include "mitkTestingMacros.h" #include "mitkIGTConfig.h" #include "mitkIGTException.h" - +#ifdef WIN32 static bool TestIsMicronTrackerInstalled() { mitk::ClaronTrackingDevice::Pointer myClaronTrackingDevice = mitk::ClaronTrackingDevice::New(); bool returnValue = myClaronTrackingDevice->IsMicronTrackerInstalled(); if (returnValue) {MITK_TEST_OUTPUT(<< "MicronTracker is installed on this system!")} else {MITK_TEST_OUTPUT(<< "MicronTracker is not installed on this system!")} return returnValue; } +#endif static void TestInstantiation() { // let's create an object of our class mitk::ClaronTrackingDevice::Pointer testInstance; testInstance = mitk::ClaronTrackingDevice::New(); MITK_TEST_CONDITION_REQUIRED(testInstance.IsNotNull(),"Testing instantiation:") } static void TestToolConfiguration() { std::string toolFileName(MITK_IGT_DATA_DIR); toolFileName.append("/ClaronTool"); mitk::ClaronTrackingDevice::Pointer testInstance = mitk::ClaronTrackingDevice::New(); MITK_TEST_CONDITION(testInstance->AddTool("Tool1", toolFileName.c_str()) != NULL, "Testing AddTool() for tool 1"); MITK_TEST_CONDITION(testInstance->GetToolCount() == 1, "Testing adding tool 1"); MITK_TEST_CONDITION(testInstance->AddTool("Tool2", toolFileName.c_str()) != NULL, "Testing AddTool() for tool 2"); MITK_TEST_CONDITION(testInstance->GetToolCount() == 2, "Testing adding tool 2"); MITK_TEST_CONDITION(testInstance->AddTool("Tool3", toolFileName.c_str()) != NULL, "Testing AddTool() for tool 3"); MITK_TEST_CONDITION(testInstance->GetToolCount() == 3, "Testing adding tool 3"); //std::vector myTools = testInstance->GetAllTools(); MITK_TEST_CONDITION(testInstance->GetTool(0)->GetToolName() == std::string("Tool1"), "Testing GetTool() for tool 1"); MITK_TEST_CONDITION(testInstance->GetTool(1)->GetToolName() == std::string("Tool2"), "Testing GetTool() for tool 2"); MITK_TEST_CONDITION(testInstance->GetTool(2)->GetToolName() == std::string("Tool3"), "Testing GetTool() for tool 3"); //Testing 100 tools (maximum by MicronTracker) testInstance = NULL; testInstance = mitk::ClaronTrackingDevice::New(); for (unsigned int i = 0; i < 100; i++) testInstance->AddTool("Tool", toolFileName.c_str()); MITK_TEST_CONDITION(testInstance->GetToolCount() == 100, "Testing adding 100 tools"); bool failed = false; unsigned int max = 100; testInstance = mitk::ClaronTrackingDevice::New(); for (unsigned int i = 0; i < max; i++) testInstance->AddTool("Tool", toolFileName.c_str()); if ((testInstance->GetToolCount() != max)) failed = true; MITK_TEST_CONDITION(!failed, "Testing tool configuration (maximum of 100 tools):"); } +#ifdef WIN32 static void TestAllMethodsOnSystemsWithoutMicronTracker() { //In this case we won't receive valid data but defined invalid return values. //initialize mitk::ClaronTrackingDevice::Pointer myClaronTrackingDevice = mitk::ClaronTrackingDevice::New(); //OpenConnection MITK_TEST_OUTPUT(<<"Testing behavior of method OpenConnection() (Errors should occur because MicronTracker is not activated)."); MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::IGTException) myClaronTrackingDevice->OpenConnection(); MITK_TEST_FOR_EXCEPTION_END(mitk::IGTException) std::string toolFileName(MITK_IGT_DATA_DIR); toolFileName.append("/ClaronTool"); //add a few tools myClaronTrackingDevice->AddTool("Tool1", toolFileName.c_str()); myClaronTrackingDevice->AddTool("Tool2", toolFileName.c_str()); myClaronTrackingDevice->AddTool("Tool3", toolFileName.c_str()); //test IsMicronTrackerInstalled MITK_TEST_CONDITION(!myClaronTrackingDevice->IsMicronTrackerInstalled(),"Testing method IsMicronTrackerInstalled().\n") //test getToolCount int toolCount = myClaronTrackingDevice->GetToolCount(); MITK_TEST_CONDITION((toolCount==3), "Testing method GetToolCount().\n"); //test getTool mitk::TrackingTool* myTool = myClaronTrackingDevice->GetTool(2); MITK_TEST_CONDITION((std::string(myTool->GetToolName()) == "Tool3"), "Testing method GetTool().\n"); //StartTracking MITK_TEST_CONDITION( (!myClaronTrackingDevice->StartTracking()), "Testing behavior of method StartTracking().\n"); //StopTracking MITK_TEST_CONDITION( (myClaronTrackingDevice->StopTracking()), "Testing behavior of method StopTracking().\n"); //CloseConnection MITK_TEST_CONDITION( (myClaronTrackingDevice->CloseConnection()), "Testing behavior of method CloseConnection().\n"); } +#endif /** * This function is testing methods of the class ClaronTrackingDevice which are independent from the hardware. For more tests we would need * the MicronTracker hardware, so only a few simple tests, which can run without the hardware are tested here. More tests can be found in the * class ClaronTrackingDeviceHardwareTests which tests the interaction with the hardware. */ int mitkClaronTrackingDeviceTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("ClaronTrackingDevice"); TestInstantiation(); TestToolConfiguration(); /* The following tests don't run under linux environments. This is or could be caused by the fact that the MicronTracker interface * is developed under windows and not tested under linux yet (26.2.2009). So - in my opinion - the best approach is to first test * the MicronTracker code under linux (and make the necessary changes of course) and in parallel write the linux tests or make this * tests runnable under linux. */ #ifdef WIN32 if (TestIsMicronTrackerInstalled()) { MITK_TEST_OUTPUT(<< "... MicronTracker is installed on your System, so we don't run any further tests. (All tests run on systems without MicronTracker)"); } else { MITK_TEST_OUTPUT(<< ".Test"); TestAllMethodsOnSystemsWithoutMicronTracker(); } #endif MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkNavigationDataObjectVisualizationFilterTest.cpp b/Modules/IGT/Testing/mitkNavigationDataObjectVisualizationFilterTest.cpp index 9f05190d04..67d257c8d3 100644 --- a/Modules/IGT/Testing/mitkNavigationDataObjectVisualizationFilterTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataObjectVisualizationFilterTest.cpp @@ -1,315 +1,315 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataObjectVisualizationFilter.h" #include "mitkNavigationData.h" #include "mitkTestingMacros.h" #include #include #include "mitkSurface.h" /**Documentation * test for the class "NavigationDataObjectVisualizationFilter". */ int mitkNavigationDataObjectVisualizationFilterTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationDataObjectVisualizationFilter") // let's create an object of our class mitk::NavigationDataObjectVisualizationFilter::Pointer myFilter = mitk::NavigationDataObjectVisualizationFilter::New(); // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(),"Testing instantiation"); /* create helper objects: navigation data with position as origin, zero quaternion, zero error and data valid */ mitk::NavigationData::PositionType initialPos1, initialPos2; mitk::FillVector3D(initialPos1, 1.1, 2.2, 3.3); mitk::FillVector3D(initialPos2, 5.0, 6.0, 7.0); mitk::NavigationData::OrientationType initialOri1(0.1, 0.2, 0.3, 0.4); mitk::NavigationData::OrientationType initialOri2(0.5, 0.6, 0.7, 0.8); mitk::ScalarType initialError1(0.0); mitk::ScalarType initialError2(5.0); bool initialValid1(true); bool initialValid2(true); mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->SetPosition(initialPos1); nd1->SetOrientation(initialOri1); nd1->SetPositionAccuracy(initialError1); nd1->SetDataValid(initialValid1); mitk::NavigationData::Pointer nd2 = mitk::NavigationData::New(); nd2->SetPosition(initialPos2); nd2->SetOrientation(initialOri2); nd2->SetPositionAccuracy(initialError2); nd2->SetDataValid(initialValid2); myFilter->SetInput(nd1); myFilter->SetInput(1, nd2); //testing the input MITK_TEST_CONDITION(myFilter->GetInput() == nd1, "Testing Set-/GetInput() input 1 without index"); MITK_TEST_CONDITION(myFilter->GetInput(0) == nd1, "Testing Set-/GetInput() input 1"); MITK_TEST_CONDITION(myFilter->GetInput(1) == nd2, "Testing Set-/GetInput() input 2"); MITK_TEST_CONDITION(myFilter->GetNumberOfToolRepresentations() == 0, "Testing GetNumberOfToolRepresentations()"); //testing getting the output mitk::NavigationData* output = myFilter->GetOutput(); MITK_TEST_CONDITION_REQUIRED(output != NULL, "Testing GetOutput()"); MITK_TEST_CONDITION_REQUIRED(output == myFilter->GetOutput(), "Testing GetOutput() == GetOutput()"); MITK_TEST_CONDITION_REQUIRED(output != myFilter->GetOutput(1), "Testing GetOutput() != GetOutput(1)"); // Test setting BaseData mitk::Surface::Pointer mitkToolData1 = mitk::Surface::New(); mitk::Surface::Pointer mitkToolData2 = mitk::Surface::New(); //dummy for test; will not be set but used to test find mitk::Surface::Pointer mitkToolDataDummy = mitk::Surface::New(); //and the Dummy NavigationData for this mitk::NavigationData::PositionType initialPosDummy; mitk::FillVector3D(initialPosDummy, 8.8, 9.9, 10.10); mitk::NavigationData::OrientationType initialOriDummy(1.1, 2.2, 3.3, 4.4); mitk::ScalarType initialErrorDummy(10.0); bool initialValidDummy(true); mitk::NavigationData::Pointer ndDummy = mitk::NavigationData::New(); ndDummy->SetPosition(initialPosDummy); ndDummy->SetOrientation(initialOriDummy); ndDummy->SetPositionAccuracy(initialErrorDummy); ndDummy->SetDataValid(initialValidDummy); //now we have ndDummy and mitkToolDataDummy to test with //setting nodes myFilter->SetRepresentationObject(0, mitkToolData1); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(0) == mitkToolData1, "Testing SetRepresentationObject()/GetRepresentationObject() node 1"); MITK_TEST_CONDITION(myFilter->GetNumberOfToolRepresentations() == 1, "Testing GetNumberOfToolRepresentations() after adding first tool"); myFilter->SetRepresentationObject(1, mitkToolData2); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(1) == mitkToolData2, "Testing SetRepresentationObject() node 2"); MITK_TEST_CONDITION(myFilter->GetNumberOfToolRepresentations() == 2, "Testing GetNumberOfToolRepresentations() after adding second tool"); //getting nodes MITK_TEST_CONDITION(myFilter->GetRepresentationObject(0) == mitkToolData1, "Testing GetRepresentationObject() node 1"); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(0) != mitkToolDataDummy, "Testing GetRepresentationObject() != Dummy node"); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(1) == mitkToolData2, "Testing GetRepresentationObject() node 2"); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(1) != mitkToolDataDummy, "Testing GetRepresentationObject() != Dummy node"); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(111) == NULL, "Testing GetRepresentationObject() with out of range parameter"); //Process myFilter->Update(); //now check it there are data connected to the nodes with the according orientation and offsets mitk::AffineTransform3D::Pointer affineTransform1 = mitkToolData1->GetGeometry()->GetIndexToWorldTransform(); mitk::AffineTransform3D::OutputVectorType offset1 = affineTransform1->GetOffset(); - MITK_TEST_CONDITION(offset1.Get_vnl_vector()==initialPos1.Get_vnl_vector(), "Testing Offset position 1"); + MITK_TEST_CONDITION(offset1.GetVnlVector()==initialPos1.GetVnlVector(), "Testing Offset position 1"); mitk::AffineTransform3D::Pointer affineTransform2 = mitkToolData2->GetGeometry()->GetIndexToWorldTransform(); mitk::AffineTransform3D::OutputVectorType offset2 = affineTransform2->GetOffset(); - MITK_TEST_CONDITION(offset2.Get_vnl_vector()==initialPos2.Get_vnl_vector(), "Testing Offset position 2"); + MITK_TEST_CONDITION(offset2.GetVnlVector()==initialPos2.GetVnlVector(), "Testing Offset position 2"); mitk::AffineTransform3D::MatrixType::InternalMatrixType m1 = affineTransform1->GetMatrix().GetVnlMatrix(); MITK_TEST_OUTPUT( << "\n initOrient1="<GetVnlMatrix():\n "<< m1); mitk::AffineTransform3D::MatrixType::InternalMatrixType m2 = affineTransform2->GetMatrix().GetVnlMatrix(); MITK_TEST_OUTPUT( << "\n initOrient2=" << initialOri2 << " affineTransform2->GetVnlMatrix():\n " << m2); //messing with SetRepresentationObject //setting nodes myFilter->SetRepresentationObject(0, mitkToolData2); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(0) == mitkToolData2, "Twisting mitkToolData by using SetRepresentationObject() NavigationData 1 with ToolData 2"); MITK_TEST_CONDITION(myFilter->GetNumberOfToolRepresentations() == 2, "Testing GetNumberOfToolRepresentations() == 1"); myFilter->SetRepresentationObject(1, mitkToolData1); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(1) == mitkToolData1, "Twisting mitkToolData by using SetRepresentationObject() NavigationData 2 with ToolData 1"); MITK_TEST_CONDITION(myFilter->GetNumberOfToolRepresentations() == 2, "Testing GetNumberOfToolRepresentations() == 2"); //getting nodes MITK_TEST_CONDITION(myFilter->GetRepresentationObject(0) == mitkToolData2, "Testing switched BaseData of NavigationData 1 "); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(0) != mitkToolDataDummy, "Testing GetRepresentationObject() != Dummy node"); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(1) == mitkToolData1, "Testing switched BaseData NavigationData 2"); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(1) != mitkToolDataDummy, "Testing GetRepresentationObject() != Dummy node"); //processing update through pipeline myFilter->Update(); //now check it there are data connected to the nodes with the according orientation and offsets mitk::AffineTransform3D::Pointer affineTransform1Second = mitkToolData1->GetGeometry()->GetIndexToWorldTransform(); MITK_TEST_CONDITION(affineTransform1 == affineTransform1Second, "Testing affineTransform1 after second update"); mitk::AffineTransform3D::OutputVectorType offset1Second = affineTransform1->GetOffset(); MITK_TEST_CONDITION(offset1 == offset1Second, "Testing offset1 after second update"); - MITK_TEST_CONDITION(offset1Second.Get_vnl_vector()==offset1.Get_vnl_vector(), "Testing offset1 equals first update"); + MITK_TEST_CONDITION(offset1Second.GetVnlVector()==offset1.GetVnlVector(), "Testing offset1 equals first update"); mitk::AffineTransform3D::Pointer affineTransform2Second = mitkToolData2->GetGeometry()->GetIndexToWorldTransform(); MITK_TEST_CONDITION(affineTransform2 == affineTransform2Second, "Testing affineTransform2 after second update"); mitk::AffineTransform3D::OutputVectorType offset2Second = affineTransform2->GetOffset(); MITK_TEST_CONDITION(offset2 == offset2Second, "Testing offset2 after second update"); - MITK_TEST_CONDITION(offset2Second.Get_vnl_vector()==offset2.Get_vnl_vector(), "Testing offset2 equals first update"); + MITK_TEST_CONDITION(offset2Second.GetVnlVector()==offset2.GetVnlVector(), "Testing offset2 equals first update"); mitk::AffineTransform3D::MatrixType::InternalMatrixType m1Second= affineTransform1Second->GetMatrix().GetVnlMatrix(); MITK_TEST_OUTPUT( <<"\n after second update initOrient1="<GetVnlMatrix():\n "<< m1Second); mitk::AffineTransform3D::MatrixType::InternalMatrixType m2Second= affineTransform2Second->GetMatrix().GetVnlMatrix(); MITK_TEST_OUTPUT( << "\n after second update initOrient2="<GetVnlMatrix():\n "<< m2Second); //testing adding a third input myFilter->SetInput(2,ndDummy); MITK_TEST_CONDITION(myFilter->GetNumberOfInputs() == 3, "Adding new input and testing GetNumberOfInputs == 3"); MITK_TEST_CONDITION(myFilter->GetNumberOfOutputs() == 3, "testing GetNumberOfOutputs == 3"); MITK_TEST_CONDITION(myFilter->GetInput(2) == ndDummy, "Testing Input == newly added input"); MITK_TEST_CONDITION_REQUIRED(myFilter->GetOutput(2) != NULL, "Testing GetOutput(2) != NULL"); MITK_TEST_CONDITION_REQUIRED(myFilter->GetOutput(2) != myFilter->GetOutput(1), "Testing GetOutput(2) != GetOutput(1)"); myFilter->SetRepresentationObject(2, mitkToolDataDummy); MITK_TEST_CONDITION(myFilter->GetNumberOfToolRepresentations() == 3, "Testing GetNumberOfToolRepresentations() after adding latest tool"); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(2) == mitkToolDataDummy, "Testing Set-/GetRepresentationObject() equals was set"); //last time processing update through pipeline myFilter->Update(); //now check for the new values mitk::AffineTransform3D::Pointer affineTransformDummy = mitkToolDataDummy->GetGeometry()->GetIndexToWorldTransform(); mitk::AffineTransform3D::OutputVectorType offsetDummy = affineTransformDummy->GetOffset(); - MITK_TEST_CONDITION(offsetDummy.Get_vnl_vector()==initialPosDummy.Get_vnl_vector(), "Testing Offset latest added tool"); + MITK_TEST_CONDITION(offsetDummy.GetVnlVector()==initialPosDummy.GetVnlVector(), "Testing Offset latest added tool"); mitk::AffineTransform3D::MatrixType::InternalMatrixType m1Latest= affineTransformDummy->GetMatrix().GetVnlMatrix(); MITK_TEST_OUTPUT( << "\n latest initOrient="<GetVnlMatrix():\n "<< m1Latest); mitk::Surface::Pointer anotherSurface = mitk::Surface::New(); myFilter->SetRepresentationObject(0, anotherSurface); MITK_TEST_CONDITION(myFilter->GetRepresentationObject(0) == anotherSurface, "Overwriting BaseData index 0"); // test Set/GetTransformPosition() myFilter->SetTransformPosition(0,true); MITK_TEST_CONDITION(myFilter->GetTransformPosition(0)==true,"test Set/GetTransformPosition(0,true)"); myFilter->SetTransformPosition(1,true); MITK_TEST_CONDITION(myFilter->GetTransformPosition(1)==true,"test Set/GetTransformPosition(1,true)"); myFilter->SetTransformPosition(2,true); MITK_TEST_CONDITION(myFilter->GetTransformPosition(2)==true,"test Set/GetTransformPosition(2,true)"); myFilter->SetTransformPosition(3,true); MITK_TEST_CONDITION(myFilter->GetTransformPosition(3)==true,"test Set/GetTransformPosition(3,true)"); myFilter->SetTransformPosition(0,false); MITK_TEST_CONDITION(myFilter->GetTransformPosition(0)==false,"test Set/GetTransformPosition(0,false)"); myFilter->SetTransformPosition(1,false); MITK_TEST_CONDITION(myFilter->GetTransformPosition(1)==false,"test Set/GetTransformPosition(1,false)"); myFilter->SetTransformPosition(2,false); MITK_TEST_CONDITION(myFilter->GetTransformPosition(2)==false,"test Set/GetTransformPosition(2,false)"); myFilter->SetTransformPosition(3,false); MITK_TEST_CONDITION(myFilter->GetTransformPosition(3)==false,"test Set/GetTransformPosition(3,false)"); // test Set/GetTransformOrientation() myFilter->SetTransformOrientation(0,true); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(0)==true,"test Set/GetTransformOrientation(0,true)"); myFilter->SetTransformOrientation(1,true); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(1)==true,"test Set/GetTransformOrientation(1,true)"); myFilter->SetTransformOrientation(2,true); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(2)==true,"test Set/GetTransformOrientation(2,true)"); myFilter->SetTransformOrientation(3,true); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(3)==true,"test Set/GetTransformOrientation(3,true)"); myFilter->SetTransformOrientation(0,false); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(0)==false,"test Set/GetTransformOrientation(0,false)"); myFilter->SetTransformOrientation(1,false); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(1)==false,"test Set/GetTransformOrientation(1,false)"); myFilter->SetTransformOrientation(2,false); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(2)==false,"test Set/GetTransformOrientation(2,false)"); myFilter->SetTransformOrientation(3,false); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(3)==false,"test Set/GetTransformOrientation(3,false)"); // test the convenience methods to set/getTransformOrientation/Position myFilter->TransformOrientationOn(0); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(0)==true,"test TransformOrientationOn()"); myFilter->TransformOrientationOff(0); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(0)==false,"test TransformOrientationOff()"); myFilter->TransformOrientationOff(1); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(1)==false,"test TransformOrientationOff()"); myFilter->TransformOrientationOn(1); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(1)==true,"test TransformOrientationOn()"); myFilter->TransformOrientationOn(2); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(2)==true,"test TransformOrientationOn()"); myFilter->TransformOrientationOff(2); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(2)==false,"test TransformOrientationOff()"); myFilter->TransformOrientationOn(3); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(3)==true,"test TransformOrientationOn()"); myFilter->TransformOrientationOff(3); MITK_TEST_CONDITION(myFilter->GetTransformOrientation(3)==false,"test TransformOrientationOff()"); myFilter->TransformPositionOn(0); MITK_TEST_CONDITION(myFilter->GetTransformPosition(0)==true,"test TransformPositionOn()"); myFilter->TransformPositionOff(0); MITK_TEST_CONDITION(myFilter->GetTransformPosition(0)==false,"test TransformPositionOff()"); myFilter->TransformPositionOff(1); MITK_TEST_CONDITION(myFilter->GetTransformPosition(1)==false,"test TransformPositionOff()"); myFilter->TransformPositionOn(1); MITK_TEST_CONDITION(myFilter->GetTransformPosition(1)==true,"test TransformPositionOn()"); myFilter->TransformPositionOn(2); MITK_TEST_CONDITION(myFilter->GetTransformPosition(2)==true,"test TransformPositionOn()"); myFilter->TransformPositionOff(2); MITK_TEST_CONDITION(myFilter->GetTransformPosition(2)==false,"test TransformPositionOff()"); myFilter->TransformPositionOn(3); MITK_TEST_CONDITION(myFilter->GetTransformPosition(3)==true,"test TransformPositionOn()"); myFilter->TransformPositionOff(3); MITK_TEST_CONDITION(myFilter->GetTransformPosition(3)==false,"test TransformPositionOff()"); // update position and orientation mitk::NavigationData::PositionType updatedPos1, updatedPos2, zero; mitk::FillVector3D(updatedPos1, 3.2, 1.5, 2.8); mitk::FillVector3D(updatedPos2, 4.3, 5.2, 6.0); mitk::FillVector3D(zero, 0.0, 0.0, 0.0); mitk::NavigationData::OrientationType updatedOri1(0.7, 0.5, 0.1, 0.4); mitk::NavigationData::OrientationType updatedOri2(0.2, 0.7, 0.6, 0.1); nd1->SetPosition(updatedPos1); nd1->SetOrientation(updatedOri1); nd2->SetPosition(updatedPos2); nd2->SetOrientation(updatedOri2); myFilter->SetRepresentationObject(0,mitkToolData1); myFilter->SetRepresentationObject(1,mitkToolData2); myFilter->TransformPositionOn(0); myFilter->TransformOrientationOff(0); myFilter->TransformPositionOff(1); myFilter->TransformOrientationOn(1); myFilter->Update(); // test positions and orientations mitk::AffineTransform3D::Pointer updatedAffineTransform1 = mitkToolData1->GetGeometry()->GetIndexToWorldTransform(); mitk::AffineTransform3D::OutputVectorType updatedOffset1 = updatedAffineTransform1->GetOffset(); - MITK_TEST_CONDITION(mitk::Equal(updatedOffset1.Get_vnl_vector(),updatedPos1.Get_vnl_vector()), "Testing updated position 1"); + MITK_TEST_CONDITION(mitk::Equal(updatedOffset1.GetVnlVector(),updatedPos1.GetVnlVector()), "Testing updated position 1"); mitk::AffineTransform3D::Pointer updatedAffineTransform2 = mitkToolData2->GetGeometry()->GetIndexToWorldTransform(); mitk::AffineTransform3D::OutputVectorType updatedOffset2 = updatedAffineTransform2->GetOffset(); - MITK_TEST_CONDITION(mitk::Equal(updatedOffset2.Get_vnl_vector(),zero.Get_vnl_vector()), "Testing updated position 2"); + MITK_TEST_CONDITION(mitk::Equal(updatedOffset2.GetVnlVector(),zero.GetVnlVector()), "Testing updated position 2"); mitk::AffineTransform3D::Pointer identityTransform = mitk::AffineTransform3D::New(); identityTransform->SetIdentity(); mitk::AffineTransform3D::MatrixType identityMatrix = identityTransform->GetMatrix(); mitk::AffineTransform3D::MatrixType uM1 = updatedAffineTransform1->GetMatrix(); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(uM1,identityMatrix), "Testing updated orientation 1"); mitk::AffineTransform3D::MatrixType::InternalMatrixType uM2 = updatedAffineTransform2->GetMatrix().GetVnlMatrix(); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(uM2,updatedOri2.rotation_matrix_transpose().transpose()), "Testing updated orientation 2"); // Test that the second RepresentationObject is updated properly even when // the first RepresentationObject is invalid nd2->Modified(); myFilter->SetRepresentationObject(0, NULL); mitkToolData2->GetGeometry()->SetIdentity(); myFilter->Update(); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(mitkToolData2->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(), updatedOri2.rotation_matrix_transpose().transpose()), "Test that the second repr object is updated correctly when the first repr object is invalid"); // always end with this! MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkNavigationDataRecorderTest.cpp b/Modules/IGT/Testing/mitkNavigationDataRecorderTest.cpp index 2d13f8f2bb..ebacf6fda4 100644 --- a/Modules/IGT/Testing/mitkNavigationDataRecorderTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataRecorderTest.cpp @@ -1,339 +1,341 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include //for exceptions #include "mitkIGTException.h" #include "mitkIGTIOException.h" static void TestInstantiation() { // let's create an object of our class mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New(); MITK_TEST_CONDITION( recorder.IsNotNull(), "Testing instatiation of NavigationDataRecorder"); } static void TestRecordingWithGivenStream() { std::string tmp = ""; std::ostringstream* stream = new std::ostringstream( std::ostringstream::trunc ); stream->setf( std::ios::fixed, std::ios::floatfield ); // let's create an object of our class mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New(); MITK_TEST_CONDITION(recorder->GetInputs().size() == 0, "testing initial number of inputs"); MITK_TEST_CONDITION(recorder->GetOutputs().size() == 0, "testing initial number of outputs"); mitk::NavigationData::Pointer naviData = mitk::NavigationData::New(); recorder->AddNavigationData( naviData ); recorder->StartRecording( stream ); for ( unsigned int i=0; i<5; i++ ) { mitk::Point3D pnt; pnt[0] = i + 1; pnt[1] = i + 1/2; pnt[2] = i +1*3; naviData->SetPosition(pnt); recorder->Update(); } recorder->StopRecording(); std::string str = stream->str(); int pos = str.find( "ToolCount=" ); std::string sub = stream->str().substr(pos+11, 1); MITK_TEST_CONDITION( sub.compare("1") == 0, "check if number of inputs is correct by stringstream"); pos = str.find( "X=" ); sub = stream->str().substr(pos+3, 1); MITK_TEST_CONDITION( sub.compare("1") == 0, "check if the X coordinate is correct"); pos = str.find( "Y=" ); sub = stream->str().substr(pos+3, 1); MITK_TEST_CONDITION( sub.compare("0") == 0, "check if the Y coordinate is correct"); pos = str.find( "Z=" ); sub = stream->str().substr(pos+3, 1); MITK_TEST_CONDITION( sub.compare("3") == 0, "check if the Z coordinate is correct"); recorder->SetFileName("blablabla"); const char* string = recorder->GetFileName(); MITK_TEST_CONDITION( strcmp(string, "blablabla") == 0, "check if set- and getName-methods work"); } static void TestRecordingOnHarddiscXML() { mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New(); //create filename std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest.xml"; recorder->SetFileName(filename.c_str()); mitk::NavigationData::Pointer naviData = mitk::NavigationData::New(); recorder->AddNavigationData( naviData ); recorder->StartRecording(); for ( unsigned int i=0; i<5; i++ ) { mitk::Point3D pnt; pnt[0] = i + 1; pnt[1] = i + 1/2; pnt[2] = i +1*3; naviData->SetPosition(pnt); recorder->Update(); } recorder->StopRecording(); std::string prooffilename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml"; Poco::File myFile(prooffilename); MITK_TEST_CONDITION(myFile.exists(),"Testing XML recording on harddisc (does file exist?)."); } static void TestRecordingOnHarddiscXMLZIP() { mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New(); //create filename std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertestzip.xml"; recorder->SetFileName(filename.c_str()); recorder->SetRecordingMode(mitk::NavigationDataRecorder::ZipFile); MITK_TEST_CONDITION(recorder->GetRecordingMode()==mitk::NavigationDataRecorder::ZipFile,"Testing setter of recording mode."); } static void TestRecordingOnHarddiscCSV() { mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New(); //create filename std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest.xml"; recorder->SetFileName(filename.c_str()); recorder->SetOutputFormat(mitk::NavigationDataRecorder::csv); mitk::NavigationData::Pointer naviData = mitk::NavigationData::New(); recorder->AddNavigationData( naviData ); recorder->StartRecording(); for ( unsigned int i=0; i<5; i++ ) { mitk::Point3D pnt; pnt[0] = i + 1; pnt[1] = i + 1/2; pnt[2] = i + 1*3; naviData->SetPosition(pnt); recorder->Update(); } recorder->StopRecording(); std::string prooffilename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.csv"; Poco::File myFile(prooffilename); MITK_TEST_CONDITION(myFile.exists(),"Testing CSV recording on harddisc (does file exist?)."); } +/* static void TestLoadingRecordedXMLFile() { mitk::NavigationDataPlayer::Pointer myPlayer = mitk::NavigationDataPlayer::New(); std::string filenameXML = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml"; myPlayer->SetFileName(filenameXML.c_str()); myPlayer->StartPlaying(); //only testing first position at the moment myPlayer->Update(); mitk::NavigationData::Pointer thisData = myPlayer->GetOutput(); mitk::Point3D reference_pnt; reference_pnt[0] = 1; reference_pnt[1] = 1/2; reference_pnt[2] = 1*3; myPlayer->StopPlaying(); MITK_TEST_CONDITION((thisData->GetPosition() == reference_pnt),"Testing load data from xml file."); } +*/ static void TestRecordingInvalidData() { std::string tmp = ""; std::ostringstream* stream = new std::ostringstream( std::ostringstream::trunc ); stream->setf( std::ios::fixed, std::ios::floatfield ); // let's create an object of our class mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New(); mitk::NavigationData::Pointer naviData = mitk::NavigationData::New(); recorder->AddNavigationData( naviData ); naviData->SetDataValid(false); recorder->StartRecording( stream ); for ( unsigned int i=0; i<5; i++ ) { mitk::Point3D pnt; pnt[0] = i + 1; pnt[1] = i + 1/2; pnt[2] = i +1*3; naviData->SetPosition(pnt); recorder->Update(); } recorder->StopRecording(); bool record_success = true; std::string str = stream->str(); int pos = str.find( "ToolCount=" ); std::string sub = stream->str().substr(pos+11, 1); if (sub.compare("1") != 0) {record_success = false;} pos = str.find( "X=" ); sub = stream->str().substr(pos+3, 1); if (sub.compare("1") != 0) {record_success = false;} pos = str.find( "Y=" ); sub = stream->str().substr(pos+3, 1); if (sub.compare("0") != 0) {record_success = false;} pos = str.find( "Z=" ); sub = stream->str().substr(pos+3, 1); if (sub.compare("3") != 0) {record_success = false;} MITK_TEST_CONDITION(record_success,"Testing recording of invalid data."); } static void CleanUp() { std::string filenameXML = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml"; std::string filenameCSV = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.csv"; Poco::File myFileXML(filenameXML); Poco::File myFileCSV(filenameCSV); try { if (myFileXML.exists()) {myFileXML.remove();} } catch(std::exception e) { MITK_WARN << "Cannot delete file while cleanup: " << filenameXML; } try { if (myFileCSV.exists()) {myFileCSV.remove();} } catch(std::exception e) { MITK_WARN << "Cannot delete file while cleanup: " << filenameCSV; } } static void TestStartRecordingExceptions() { //Testing Start Recording for exceptions if recording has already started mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New(); std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest.xml"; recorder->SetFileName(filename.c_str()); //Testing double call of StartRecording(). mitk::NavigationData::Pointer naviData = mitk::NavigationData::New(); recorder->AddNavigationData( naviData ); recorder->StartRecording(); recorder->StartRecording(); recorder->StopRecording(); MITK_TEST_OUTPUT(<<"Tested double call of StartRecording(). Application should not crash."); //Testing exceptions for method StartRecording() when no file is set. mitk::NavigationDataRecorder::Pointer recorder1 = mitk::NavigationDataRecorder::New(); std::string filename1 = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest.xml"; recorder->SetFileName(""); bool exceptionThrown1 = false; mitk::NavigationData::Pointer naviData1 = mitk::NavigationData::New(); recorder1->AddNavigationData( naviData1 ); try { recorder1->StartRecording(); } catch(mitk::IGTException) { exceptionThrown1 = true; } MITK_TEST_CONDITION(exceptionThrown1,"Testing exception throwing when no file name or file path is set."); //Testing double call of StartRecording(stream) method. mitk::NavigationDataRecorder::Pointer recorder2 = mitk::NavigationDataRecorder::New(); std::string tmp = ""; std::ostringstream stream; stream.setf( std::ios::fixed, std::ios::floatfield ); recorder2->StartRecording(&stream); recorder2->StartRecording(&stream); recorder2->StopRecording(); MITK_TEST_OUTPUT(<<"Tested double call of StartRecording(stream). Application should not crash."); //Testing exceptions if the stream is not good mitk::NavigationDataRecorder::Pointer recorder3 = mitk::NavigationDataRecorder::New(); std::ofstream stream3; //making an invalid stream stream3.open(""); bool exceptionThrown3 = false; try { recorder3->StartRecording(&stream3); } catch(mitk::IGTException) { exceptionThrown3 = true; } MITK_TEST_CONDITION(exceptionThrown3,"Testing exception thrown when the stream in not good."); } /**Documentation * test for the class "NavigationDataRecorder". */ int mitkNavigationDataRecorderTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationDataRecorder"); TestInstantiation(); TestRecordingWithGivenStream(); TestRecordingOnHarddiscXML(); TestRecordingOnHarddiscXMLZIP(); TestRecordingOnHarddiscCSV(); TestRecordingInvalidData(); TestStartRecordingExceptions(); //Test fails under linux, perhaps reading permission problems, deactivated it temporary //TestLoadingRecordedXMLFile(); CleanUp(); MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkNavigationDataSourceTest.cpp b/Modules/IGT/Testing/mitkNavigationDataSourceTest.cpp index e99f1f6459..93e6edd1e9 100644 --- a/Modules/IGT/Testing/mitkNavigationDataSourceTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataSourceTest.cpp @@ -1,174 +1,174 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataSource.h" #include "mitkNavigationData.h" #include "mitkTestingMacros.h" /**Documentation * \brief test class that only adds a public New() method to NavigationDataSource, so that it can be tested * */ class MyNavigationDataSourceTest : public mitk::NavigationDataSource { public: mitkClassMacro(MyNavigationDataSourceTest, mitk::NavigationDataSource); itkNewMacro(Self); void CreateOutput() { - this->SetNumberOfOutputs(1); + this->SetNumberOfIndexedOutputs(1); this->SetNthOutput(0, this->MakeOutput(0)); }; }; /** Class that holds static test methods to structure the test. */ class mitkNavigationDataSourceTestClass { public: static void TestInstantiation() { // let's create an object of our class MyNavigationDataSourceTest::Pointer myFilter = MyNavigationDataSourceTest::New(); // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(), "Testing instantiation"); // testing create outputs MITK_TEST_CONDITION(myFilter->GetNumberOfInputs() == 0, "testing initial number of inputs"); MITK_TEST_CONDITION(myFilter->GetNumberOfOutputs() == 0, "testing initial number of outputs"); myFilter->CreateOutput(); MITK_TEST_CONDITION(myFilter->GetNumberOfOutputs() == 1, "testing SetNumberOfOutputs() and MakeOutput()"); MITK_TEST_CONDITION(dynamic_cast(myFilter->GetOutput()) != NULL, "test GetOutput() returning valid output object"); } static void TestMethodsNormalCases() { //create and initialize test objects MyNavigationDataSourceTest::Pointer myFilter = MyNavigationDataSourceTest::New(); myFilter->CreateOutput(); mitk::NavigationData::PositionType initialPos; mitk::FillVector3D(initialPos, 1.0, 2.0, 3.0); mitk::NavigationData::OrientationType initialOri(0.1, 0.2, 0.3, 0.4); mitk::ScalarType initialError(22.22); bool initialValid(true); mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->SetPosition(initialPos); nd1->SetOrientation(initialOri); nd1->SetPositionAccuracy(initialError); nd1->SetDataValid(initialValid); //test method graft MITK_TEST_OUTPUT(<< "testing Graftoutput()"); myFilter->GraftOutput(nd1); mitk::NavigationData::Pointer out = myFilter->GetOutput(); MITK_TEST_CONDITION(out.GetPointer() != nd1.GetPointer(), "testing if output is same object as source of graft"); MITK_TEST_CONDITION(mitk::Equal(out->GetPosition(), nd1->GetPosition()),"testing position equality after graft") MITK_TEST_CONDITION(mitk::Equal(out->GetOrientation(), nd1->GetOrientation()),"testing orientation equality after graft") MITK_TEST_CONDITION((out->GetCovErrorMatrix() == nd1->GetCovErrorMatrix()),"testing error matrix equality after graft") MITK_TEST_CONDITION((out->IsDataValid() == nd1->IsDataValid()),"testing data valid equality after graft") MITK_TEST_CONDITION(mitk::Equal(out->GetIGTTimeStamp(), nd1->GetIGTTimeStamp()), "testing timestamp equality after graft"); //test method GetParameters() mitk::PropertyList::ConstPointer list = myFilter->GetParameters(); MITK_TEST_CONDITION(list.IsNotNull(), "testing GetParameters()"); } static void TestMethodsInvalidCases() { //test invalid call of methods MyNavigationDataSourceTest::Pointer myFilter = MyNavigationDataSourceTest::New(); mitk::NavigationData::Pointer testOutput = myFilter->GetOutput(); MITK_TEST_CONDITION(testOutput.IsNull(), "testing GetOutput(int) before initialization"); testOutput = myFilter->GetOutput("test"); MITK_TEST_CONDITION(testOutput.IsNull(), "testing GetOutput(string) before initialization"); //test GetOutputIndex() with invalid output name myFilter->CreateOutput(); bool exceptionThrown=false; try { myFilter->GetOutputIndex("nonsense name"); } catch(std::invalid_argument e) { exceptionThrown=true; } MITK_TEST_CONDITION(exceptionThrown,"Testing method GetOutputIndex with invalid navigation data name"); //test method GraftNthOutput with invalid index exceptionThrown=false; try { mitk::NavigationData::Pointer graftObject; myFilter->GraftNthOutput(100,graftObject); } catch(itk::ExceptionObject e) { exceptionThrown=true; } MITK_TEST_CONDITION(exceptionThrown,"Testing method GraftNthOutput with invalid index"); } static void TestMicroserviceRegister() { MyNavigationDataSourceTest::Pointer myFilter = MyNavigationDataSourceTest::New(); myFilter->CreateOutput(); mitk::NavigationData::PositionType initialPos; mitk::FillVector3D(initialPos, 1.0, 2.0, 3.0); mitk::NavigationData::OrientationType initialOri(0.1, 0.2, 0.3, 0.4); mitk::ScalarType initialError(22.22); bool initialValid(true); mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->SetPosition(initialPos); nd1->SetOrientation(initialOri); nd1->SetPositionAccuracy(initialError); nd1->SetDataValid(initialValid); myFilter->RegisterAsMicroservice(); MITK_TEST_CONDITION(myFilter->GetMicroserviceID()!="","Testing if microservice was registered successfully."); } static void TestMicroserviceAvailabilityAndUnregister() { //TODO: test if Microservice is available //TODO: remove Microservice //TODO: test if Microservice is not available any more } }; /**Documentation * test for the class "NavigationDataSource". */ int mitkNavigationDataSourceTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationDataSource"); mitkNavigationDataSourceTestClass::TestInstantiation(); mitkNavigationDataSourceTestClass::TestMethodsNormalCases(); mitkNavigationDataSourceTestClass::TestMethodsInvalidCases(); mitkNavigationDataSourceTestClass::TestMicroserviceRegister(); mitkNavigationDataSourceTestClass::TestMicroserviceAvailabilityAndUnregister(); // always end with this! MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkNavigationDataTest.cpp b/Modules/IGT/Testing/mitkNavigationDataTest.cpp index 4e015eec87..0848718e19 100644 --- a/Modules/IGT/Testing/mitkNavigationDataTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataTest.cpp @@ -1,462 +1,498 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkNavigationData.h" #include "mitkVector.h" #include #include +/* static mitk::NavigationData::Pointer GetTestData() { mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType p; mitk::FillVector3D(p, 44.4, 55.5, 66.66); nd->SetPosition(p); mitk::NavigationData::OrientationType o(1.0, 2.0, 3.0, 4.0); nd->SetOrientation(o); nd->SetDataValid(true); nd->SetIGTTimeStamp(100.111); nd->SetHasPosition(false); nd->SetHasOrientation(false); mitk::NavigationData::CovarianceMatrixType m; m.Fill(17.17); m(2, 2) = 1000.01; nd->SetCovErrorMatrix(m); nd->SetName("my NavigationData"); nd->SetPositionAccuracy(100.0); nd->SetOrientationAccuracy(10.0); return nd; } +*/ +/* static void TestInstatiation() { // Test instantiation of NavigationData mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); MITK_TEST_CONDITION(nd.IsNotNull(),"Test instatiation"); } +*/ +/* static void TestGetterSetter() { mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType p; mitk::FillVector3D(p, 44.4, 55.5, 66.66); nd->SetPosition(p); MITK_TEST_CONDITION(nd->GetPosition() == p, "Set-/GetPosition()"); mitk::NavigationData::OrientationType o(1.0, 2.0, 3.0, 4.0); nd->SetOrientation(o); MITK_TEST_CONDITION(nd->GetOrientation() == o, "Set-/GetOrientation()"); nd->SetDataValid(true); MITK_TEST_CONDITION(nd->IsDataValid() == true, "Set-/IsDataValid()"); nd->SetIGTTimeStamp(100.111); MITK_TEST_CONDITION(mitk::Equal(nd->GetIGTTimeStamp(), 100.111), "Set-/GetIGTTimeStamp()"); nd->SetHasPosition(false); MITK_TEST_CONDITION(nd->GetHasPosition() == false, "Set-/GetHasPosition()"); nd->SetHasOrientation(false); MITK_TEST_CONDITION(nd->GetHasOrientation() == false, "Set-/GetHasOrientation()"); mitk::NavigationData::CovarianceMatrixType m; m.Fill(17.17); m(2, 2) = 1000.01; nd->SetCovErrorMatrix(m); MITK_TEST_CONDITION(nd->GetCovErrorMatrix() == m, "Set-/GetCovErrorMatrix()"); nd->SetName("my NavigationData"); MITK_TEST_CONDITION(std::string(nd->GetName()) == "my NavigationData", "Set-/GetName()"); nd->SetPositionAccuracy(100.0); mitk::NavigationData::CovarianceMatrixType result = nd->GetCovErrorMatrix(); MITK_TEST_CONDITION(mitk::Equal(result(0, 0), 10000.0) && mitk::Equal(result(1, 1), 10000.0) && mitk::Equal(result(2, 2), 10000.0), "SetPositionAccuracy()"); nd->SetOrientationAccuracy(10.0); mitk::NavigationData::CovarianceMatrixType result2 = nd->GetCovErrorMatrix(); MITK_TEST_CONDITION(mitk::Equal(result2(3, 3), 100.0) && mitk::Equal(result2(4, 4), 100.0) && mitk::Equal(result2(5, 5), 100.0), "SetOrientationAccuracy()"); } +*/ + +/* static void TestGraft() { //create test data mitk::NavigationData::Pointer nd = GetTestData(); mitk::NavigationData::Pointer graftedCopy = mitk::NavigationData::New(); graftedCopy->Graft(nd); bool graftIsEqual = (nd->GetPosition() == graftedCopy->GetPosition()) && (nd->GetOrientation() == graftedCopy->GetOrientation()) && (nd->IsDataValid() == graftedCopy->IsDataValid()) && mitk::Equal(nd->GetIGTTimeStamp(), graftedCopy->GetIGTTimeStamp()) && (nd->GetHasPosition() == graftedCopy->GetHasPosition()) && (nd->GetHasOrientation() == graftedCopy->GetHasOrientation()) && (nd->GetCovErrorMatrix() == graftedCopy->GetCovErrorMatrix()) && (std::string(nd->GetName()) == graftedCopy->GetName()); MITK_TEST_CONDITION(graftIsEqual, "Graft() produces equal NavigationData object"); } +*/ +/* static void TestPrintSelf() { mitk::NavigationData::Pointer nd = GetTestData(); itk::Indent myIndent = itk::Indent(); MITK_TEST_OUTPUT(<<"Testing method PrintSelf(), method output will follow:"); bool success = true; try { nd->PrintSelf(std::cout,myIndent); } catch(...) { success = false; } MITK_TEST_CONDITION(success, "Testing method PrintSelf()."); } +*/ +/* static void TestWrongInputs() { mitk::NavigationData::Pointer nd = GetTestData(); // Test CopyInformation bool success = false; try { nd->CopyInformation(NULL); } catch(itk::ExceptionObject e) { success = true; } MITK_TEST_CONDITION(success, "Testing wrong input for method CopyInformation."); // Test Graft success = false; try { nd->Graft(NULL); } catch(itk::ExceptionObject e) { success = true; } MITK_TEST_CONDITION(success, "Testing wrong input for method Graft."); } +*/ static mitk::Quaternion quaternion; static mitk::Vector3D offsetVector; static mitk::Point3D offsetPoint; static mitk::Matrix3D rotation; static mitk::Quaternion quaternion2; static mitk::Vector3D offsetVector2; static mitk::Point3D offsetPoint2; static mitk::Matrix3D rotation2; static mitk::Point3D point; -static void SetupNaviDataTests() -{ - // set rotation matrix to - /* - * 0 -1 0 - * 1 0 0 - * 0 0 1 - */ - rotation.Fill(0); - rotation[0][1] = -1; - rotation[1][0] = 1; - rotation[2][2] = 1; - - // set quaternion to quaternion equivalent - // values calculated with javascript at - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ - quaternion = mitk::Quaternion(0, 0, 0.7071067811865475, 0.7071067811865476); - - // set offset to some value. Some tests need vectors, offers points. - double offsetArray[3] = {1.0,2.0,3.123456}; - offsetVector = offsetArray; - offsetPoint = offsetArray; - - /***** Second set of data for compose tests ****/ - - // set rotation2 matrix to - /* - * 1 0 0 - * 0 0 -1 - * 0 1 0 - */ - rotation2.Fill(0); - rotation2[0][0] = 1; - rotation2[1][2] = -1; - rotation2[2][1] = 1; - - quaternion2 = mitk::Quaternion(0.7071067811865475, 0, 0, 0.7071067811865476); - mitk::ScalarType offsetArray2[3] = {1, 0, 0}; - offsetVector2 = offsetArray2; - offsetPoint2 = offsetArray2; - - /***** Create a point to be transformed *****/ - mitk::ScalarType pointArray[] = {1.0, 3.0, 5.0}; - point = pointArray; -} +//static void SetupNaviDataTests() +//{ +// // set rotation matrix to +// /* +// * 0 -1 0 +// * 1 0 0 +// * 0 0 1 +// */ +// rotation.Fill(0); +// rotation[0][1] = -1; +// rotation[1][0] = 1; +// rotation[2][2] = 1; + +// // set quaternion to quaternion equivalent +// // values calculated with javascript at +// // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ +// quaternion = mitk::Quaternion(0, 0, 0.7071067811865475, 0.7071067811865476); + +// // set offset to some value. Some tests need vectors, offers points. +// double offsetArray[3] = {1.0,2.0,3.123456}; +// offsetVector = offsetArray; +// offsetPoint = offsetArray; + +// /***** Second set of data for compose tests ****/ + +// // set rotation2 matrix to +// /* +// * 1 0 0 +// * 0 0 -1 +// * 0 1 0 +// */ +// rotation2.Fill(0); +// rotation2[0][0] = 1; +// rotation2[1][2] = -1; +// rotation2[2][1] = 1; + +// quaternion2 = mitk::Quaternion(0.7071067811865475, 0, 0, 0.7071067811865476); +// mitk::ScalarType offsetArray2[3] = {1, 0, 0}; +// offsetVector2 = offsetArray2; +// offsetPoint2 = offsetArray2; + +// /***** Create a point to be transformed *****/ +// mitk::ScalarType pointArray[] = {1.0, 3.0, 5.0}; +// point = pointArray; +//} /** * Helper method, which creates a NavigationData object using the data created in SetupNaviDataTests() */ +/* static mitk::NavigationData::Pointer CreateNavidata(mitk::Quaternion quaternion, mitk::Point3D offset) { mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(); navigationData->SetOrientation(quaternion); navigationData->SetPosition(offset); return navigationData; } +*/ +/* static mitk::AffineTransform3D::Pointer CreateAffineTransform(mitk::Matrix3D rotationMatrix, mitk::Vector3D offset) { mitk::AffineTransform3D::Pointer affineTransform3D = mitk::AffineTransform3D::New(); affineTransform3D->SetOffset(offset); affineTransform3D->SetMatrix(rotationMatrix); return affineTransform3D; } +*/ +/* static void TestInverse() { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::NavigationData::Pointer ndInverse = nd->GetInverse(); // calculate expected inverted position vector: b2 = -A2b1 // for -A2b1 we need vnl_vectors. vnl_vector_fixed b1; for (int i = 0; i < 3; ++i) { b1[i] = nd->GetPosition()[i]; } vnl_vector_fixed b2; b2 = -(ndInverse->GetOrientation().rotate(b1)); // now copy result back into our mitk::Point3D mitk::Point3D invertedPosition; for (int i = 0; i < 3; ++i) { invertedPosition[i] = b2[i]; } MITK_TEST_CONDITION(mitk::Equal(nd->GetOrientation().inverse(), ndInverse->GetOrientation()),"Testing GetInverse: orientation inverted"); MITK_TEST_CONDITION(mitk::Equal(invertedPosition, ndInverse->GetPosition()), "Testing GetInverse: position inverted"); bool otherFlagsOk = (nd->IsDataValid() == ndInverse->IsDataValid()) && mitk::Equal(nd->GetIGTTimeStamp(), ndInverse->GetIGTTimeStamp()) && (false == ndInverse->GetHasPosition()) // covariance update mechanism not yet implemented && (false == ndInverse->GetHasOrientation()) && (nd->GetCovErrorMatrix() == ndInverse->GetCovErrorMatrix()) && (std::string(nd->GetName()) == ndInverse->GetName()); MITK_TEST_CONDITION(otherFlagsOk, "Testing GetInverse: other flags are same"); } +*/ +/* static void TestDoubleInverse() { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::NavigationData::Pointer ndDoubleInverse = nd->GetInverse()->GetInverse(); MITK_TEST_CONDITION(mitk::Equal(nd->GetOrientation(), ndDoubleInverse->GetOrientation()),"Testing GetInverse double application: orientation preserved"); MITK_TEST_CONDITION(mitk::Equal(nd->GetPosition(), ndDoubleInverse->GetPosition()), "Testing GetInverse double application: position preserved"); } +*/ static void TestInverseError() { // initialize empty NavigationData (quaternion is zeroed) mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::Quaternion quaternion; quaternion.fill(0); nd->SetOrientation(quaternion); MITK_TEST_FOR_EXCEPTION(mitk::Exception&, nd->GetInverse()); } +/* static void TestTransform() { SetupNaviDataTests(); mitk::NavigationData::Pointer navigationData = CreateNavidata(quaternion, offsetPoint); point = navigationData->TransformPoint(point); mitk::ScalarType resultingPointArray[] = {-2, 3, 8.123456}; mitk::Point3D resultingPoint = resultingPointArray; MITK_TEST_CONDITION(mitk::Equal(resultingPoint, point), "Testing point transformation"); } +*/ +/* static void TestAffineConstructor() { SetupNaviDataTests(); mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(affineTransform3D); MITK_TEST_CONDITION(mitk::Equal(navigationData->GetPosition(), offsetPoint), "Testing affine constructor: offset"); MITK_TEST_CONDITION(mitk::Equal(navigationData->GetOrientation(), quaternion), "Testing affine constructor: quaternion"); MITK_TEST_CONDITION(true == navigationData->GetHasPosition(), "Testing affine constructor: hasposition == true"); MITK_TEST_CONDITION(true == navigationData->GetHasOrientation(), "Testing affine constructor: hasorientation == true"); MITK_TEST_CONDITION(true == navigationData->IsDataValid(), "Testing affine constructor: isdatavalid == true"); MITK_TEST_CONDITION(mitk::Equal(navigationData->GetIGTTimeStamp(),0.0), "Testing affine constructor: IGTTimestamp is zero"); } +*/ - +/* static void TestAffineConstructorErrorTransposedNotInverse() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[1][0] = 2; // this matrix has determinant = 1 (triangular matrix with ones in diagonal) but transposed != inverse mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); MITK_TEST_FOR_EXCEPTION(mitk::Exception&, mitk::NavigationData::New(affineTransform3D)); } +*/ +/* static void TestAffineConstructorErrorDeterminantNonEqualOne() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[0][0] = 2; // determinant for diagonal matrices is product of diagonal elements => det = 2 mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); MITK_TEST_FOR_EXCEPTION(mitk::Exception&, mitk::NavigationData::New(affineTransform3D)); } +*/ +/* static void TestAffineConstructorErrorCheckingFalse() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[0][0] = 2; // determinant for diagonal matrices is product of diagonal elements => det = 2 mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); bool exceptionSuppressed = true; try { mitk::NavigationData::New(affineTransform3D, false); } catch (mitk::Exception&) { exceptionSuppressed = false; } MITK_TEST_CONDITION(exceptionSuppressed, "Test affine constructor: exception can be suppressed.") } +*/ +/* static void TestAffineGetter() { SetupNaviDataTests(); mitk::NavigationData::Pointer navigationData = CreateNavidata(quaternion, offsetPoint); mitk::AffineTransform3D::Pointer affineTransform = navigationData->GetAffineTransform3D(); MITK_TEST_CONDITION(mitk::Equal(affineTransform->GetOffset(), offsetVector), "Testing AffineTransform3D getter: offset"); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(affineTransform->GetMatrix(), rotation), "Testing AffineTransform3D getter: rotation"); } +*/ /** * This test tests the complete chain from affineTransform -> NavigationData -> affineTransform */ +/* static void TestAffineToNaviDataToAffine() { SetupNaviDataTests(); mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); // there and back again: affineTransform -> NavigationData -> affineTransform mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(affineTransform3D); mitk::AffineTransform3D::Pointer affineTransform3D_2; affineTransform3D_2 = navigationData->GetAffineTransform3D(); MITK_TEST_CONDITION(mitk::Equal(affineTransform3D->GetOffset(), affineTransform3D_2->GetOffset()), "Testing affine -> navidata -> affine chain: offset"); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(affineTransform3D->GetMatrix(), affineTransform3D_2->GetMatrix()), "Testing affine -> navidata -> affine chain: rotation"); } +*/ +/* static void TestCompose(bool pre = false) { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::AffineTransform3D::Pointer at = CreateAffineTransform(rotation, offsetVector); // second transform for composition mitk::NavigationData::Pointer nd2 = CreateNavidata(quaternion2, offsetPoint2); mitk::AffineTransform3D::Pointer at2 = CreateAffineTransform(rotation2, offsetVector2); // save point for affinetransform mitk::Point3D point2 = point; nd->Compose(nd2, pre); point = nd->TransformPoint(point); at->Compose(at2, pre); point2 = at->TransformPoint(point2); MITK_TEST_CONDITION(mitk::Equal(point, point2), "Compose pre = " << pre << ": composition works "); bool covarianceValidityReset = !nd->GetHasOrientation() && !nd->GetHasPosition(); MITK_TEST_CONDITION(covarianceValidityReset, "Compose pre = " << pre << ": covariance validities reset because not implemented yet."); } static void TestReverseCompose() { TestCompose(true); } +*/ /** * This function is testing the Class mitk::NavigationData. For most tests we would need the MicronTracker hardware, so only a few * simple tests, which can run without the hardware are implemented yet (2009, January, 23rd). As soon as there is a working * concept to test the tracking classes which are very close to the hardware on all systems more tests are needed here. */ int mitkNavigationDataTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationData"); //TestInstatiation(); //TestGetterSetter(); //TestGraft(); //TestPrintSelf(); //TestWrongInputs(); //TestAffineConstructor(); //TestAffineConstructorErrorDeterminantNonEqualOne(); //TestAffineConstructorErrorTransposedNotInverse(); //TestAffineConstructorErrorCheckingFalse(); //TestAffineGetter(); //TestAffineToNaviDataToAffine(); //TestTransform(); //TestInverse(); //TestDoubleInverse(); TestInverseError(); //TestCompose(); //TestReverseCompose(); MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkNavigationToolStorageSerializerAndDeserializerTest.cpp b/Modules/IGT/Testing/mitkNavigationToolStorageSerializerAndDeserializerTest.cpp index 0f453eddc7..c9ae92e680 100644 --- a/Modules/IGT/Testing/mitkNavigationToolStorageSerializerAndDeserializerTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationToolStorageSerializerAndDeserializerTest.cpp @@ -1,462 +1,464 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingConfig.h" #include #include #include #include #include #include #include #include #include #include //POCO #include #include static void TestInstantiationSerializer() { // let's create objects of our classes mitk::NavigationToolStorageSerializer::Pointer testSerializer = mitk::NavigationToolStorageSerializer::New(); MITK_TEST_CONDITION_REQUIRED(testSerializer.IsNotNull(),"Testing instantiation of NavigationToolStorageSerializer"); } static void TestInstantiationDeserializer() { mitk::DataStorage::Pointer tempStorage = dynamic_cast(mitk::StandaloneDataStorage::New().GetPointer()); //needed for deserializer! mitk::NavigationToolStorageDeserializer::Pointer testDeserializer = mitk::NavigationToolStorageDeserializer::New(tempStorage); MITK_TEST_CONDITION_REQUIRED(testDeserializer.IsNotNull(),"Testing instantiation of NavigationToolStorageDeserializer") } static void TestWriteSimpleToolStorage() { //create Tool Storage mitk::NavigationToolStorage::Pointer myStorage = mitk::NavigationToolStorage::New(); //first tool mitk::NavigationTool::Pointer myTool1 = mitk::NavigationTool::New(); myTool1->SetIdentifier("001"); myStorage->AddTool(myTool1); //second tool mitk::NavigationTool::Pointer myTool2 = mitk::NavigationTool::New(); myTool2->SetIdentifier("002"); myStorage->AddTool(myTool2); //third tool mitk::NavigationTool::Pointer myTool3 = mitk::NavigationTool::New(); myTool3->SetIdentifier("003"); myStorage->AddTool(myTool3); //create Serializer mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); //create filename std::string filename = std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorage.storage"; //test serialization bool success = mySerializer->Serialize(filename,myStorage); MITK_TEST_CONDITION_REQUIRED(success,"Testing serialization of simple tool storage"); } static void TestWriteAndReadSimpleToolStorageWithToolLandmarks() { //create Tool Storage mitk::NavigationToolStorage::Pointer myStorage = mitk::NavigationToolStorage::New(); //first tool mitk::NavigationTool::Pointer myTool1 = mitk::NavigationTool::New(); myTool1->SetIdentifier("001"); mitk::PointSet::Pointer CalLandmarks1 = mitk::PointSet::New(); mitk::Point3D testPt1; mitk::FillVector3D(testPt1,1,2,3); CalLandmarks1->SetPoint(0,testPt1); mitk::PointSet::Pointer RegLandmarks1 = mitk::PointSet::New(); mitk::Point3D testPt2; mitk::FillVector3D(testPt2,4,5,6); RegLandmarks1->SetPoint(5,testPt2); myTool1->SetToolCalibrationLandmarks(CalLandmarks1); myTool1->SetToolRegistrationLandmarks(RegLandmarks1); mitk::Point3D toolTipPos; mitk::FillVector3D(toolTipPos,1.3423,2.323,4.332); mitk::Quaternion toolTipRot = mitk::Quaternion(0.1,0.2,0.3,0.4); myTool1->SetToolTipPosition(toolTipPos); myTool1->SetToolTipOrientation(toolTipRot); myStorage->AddTool(myTool1); //create Serializer mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); //create filename std::string filename = std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorageToolReg.storage"; //test serialization bool success = mySerializer->Serialize(filename,myStorage); MITK_TEST_CONDITION_REQUIRED(success,"Testing serialization of tool storage with tool registrations"); mitk::DataStorage::Pointer tempStorage = dynamic_cast(mitk::StandaloneDataStorage::New().GetPointer()); //needed for deserializer! mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(tempStorage); mitk::NavigationToolStorage::Pointer readStorage = myDeserializer->Deserialize(std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorageToolReg.storage"); MITK_TEST_CONDITION_REQUIRED(readStorage.IsNotNull(),"Testing deserialization of tool storage with tool registrations"); MITK_TEST_CONDITION_REQUIRED(readStorage->GetToolCount()==1," ..Testing number of tools in storage"); mitk::PointSet::Pointer readRegLandmarks = readStorage->GetTool(0)->GetToolRegistrationLandmarks(); mitk::PointSet::Pointer readCalLandmarks = readStorage->GetTool(0)->GetToolCalibrationLandmarks(); MITK_TEST_CONDITION_REQUIRED(((readRegLandmarks->GetPoint(5)[0] == 4)&&(readRegLandmarks->GetPoint(5)[1] == 5)&&(readRegLandmarks->GetPoint(5)[2] == 6)),"..Testing if tool registration landmarks have been stored and loaded correctly."); MITK_TEST_CONDITION_REQUIRED(((readCalLandmarks->GetPoint(0)[0] == 1)&&(readCalLandmarks->GetPoint(0)[1] == 2)&&(readCalLandmarks->GetPoint(0)[2] == 3)),"..Testing if tool calibration landmarks have been stored and loaded correctly."); mitk::Point3D readToolTipPos = readStorage->GetTool(0)->GetToolTipPosition(); mitk::Quaternion readToolTipRot = readStorage->GetTool(0)->GetToolTipOrientation(); MITK_TEST_CONDITION_REQUIRED(((float(readToolTipPos[0]) == float(1.3423))&& (float(readToolTipPos[1]) == float(2.323))&& (float(readToolTipPos[2]) == float(4.332))), "..Testing if tool tip position has been stored and loaded correctly."); MITK_TEST_CONDITION_REQUIRED(((float(readToolTipRot.x()) == float(0.1))&& (float(readToolTipRot.y()) == float(0.2))&& (float(readToolTipRot.z()) == float(0.3))&& (float(readToolTipRot.r()) == float(0.4))), "..Testing if tool tip orientation has been stored and loaded correctly."); } static void TestReadSimpleToolStorage() { mitk::DataStorage::Pointer tempStorage = dynamic_cast(mitk::StandaloneDataStorage::New().GetPointer()); //needed for deserializer! mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(tempStorage); mitk::NavigationToolStorage::Pointer readStorage = myDeserializer->Deserialize(std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorage.storage"); MITK_TEST_CONDITION_REQUIRED(readStorage.IsNotNull(),"Testing deserialization of simple tool storage"); MITK_TEST_CONDITION_REQUIRED(readStorage->GetToolCount()==3," ..Testing number of tools in storage"); //TODO: why is the order of tools changed is save/load process?? bool foundtool1 = false; bool foundtool2 = false; bool foundtool3 = false; for(int i=0; i<3; i++) { if ((readStorage->GetTool(i)->GetIdentifier()=="001")) foundtool1 = true; else if ((readStorage->GetTool(i)->GetIdentifier()=="002")) foundtool2 = true; else if ((readStorage->GetTool(i)->GetIdentifier()=="003")) foundtool3 = true; } MITK_TEST_CONDITION_REQUIRED(foundtool1&&foundtool2&&foundtool3," ..Testing if identifiers of tools where saved / loaded successfully"); } static void CleanUp() { try { std::remove((std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorage.storage").c_str()); std::remove((std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorageToolReg.storage").c_str()); std::remove((std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorage2.storage").c_str()); } catch(...) { MITK_INFO << "Warning: Error occured when deleting test file!"; } } static void TestWriteComplexToolStorage() { //create first tool mitk::Surface::Pointer testSurface; std::string toolFileName(MITK_IGT_DATA_DIR); toolFileName.append("/ClaronTool"); mitk::NavigationTool::Pointer myNavigationTool = mitk::NavigationTool::New(); myNavigationTool->SetCalibrationFile(toolFileName); mitk::DataNode::Pointer myNode = mitk::DataNode::New(); myNode->SetName("ClaronTool"); //load an stl File std::string pathToClaronTool(MITK_IGT_DATA_DIR); pathToClaronTool.append("/ClaronTool.stl"); testSurface = mitk::IOUtil::LoadSurface(pathToClaronTool); myNode->SetData(testSurface); myNavigationTool->SetDataNode(myNode); myNavigationTool->SetIdentifier("ClaronTool#1"); myNavigationTool->SetSerialNumber("0815"); myNavigationTool->SetTrackingDeviceType(mitk::ClaronMicron); myNavigationTool->SetType(mitk::NavigationTool::Fiducial); //create second tool mitk::NavigationTool::Pointer myNavigationTool2 = mitk::NavigationTool::New(); mitk::Surface::Pointer testSurface2; mitk::DataNode::Pointer myNode2 = mitk::DataNode::New(); myNode2->SetName("AuroraTool"); //load an stl File std::string pathToEMTool(MITK_IGT_DATA_DIR); pathToEMTool.append("/EMTool.stl"); testSurface2 = mitk::IOUtil::LoadSurface(pathToEMTool); myNode2->SetData(testSurface2); myNavigationTool2->SetDataNode(myNode2); myNavigationTool2->SetIdentifier("AuroraTool#1"); myNavigationTool2->SetSerialNumber("0816"); myNavigationTool2->SetTrackingDeviceType(mitk::NDIAurora); myNavigationTool2->SetType(mitk::NavigationTool::Instrument); //create navigation tool storage mitk::NavigationToolStorage::Pointer myStorage = mitk::NavigationToolStorage::New(); myStorage->AddTool(myNavigationTool); myStorage->AddTool(myNavigationTool2); //create Serializer mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); //create filename std::string filename = std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorage2.storage"; //test serialization bool success = mySerializer->Serialize(filename,myStorage); MITK_TEST_CONDITION_REQUIRED(success,"Testing serialization of complex tool storage"); } static void TestReadComplexToolStorage() { mitk::DataStorage::Pointer tempStorage = dynamic_cast(mitk::StandaloneDataStorage::New().GetPointer()); //needed for deserializer! mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(tempStorage); mitk::NavigationToolStorage::Pointer readStorage = myDeserializer->Deserialize(std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorage2.storage"); MITK_TEST_CONDITION_REQUIRED(readStorage.IsNotNull(),"Testing deserialization of complex tool storage"); MITK_TEST_CONDITION_REQUIRED(readStorage->GetToolCount()==2," ..Testing number of tools in storage"); } static void TestReadNotExistingStorage() { mitk::DataStorage::Pointer tempStorage = dynamic_cast(mitk::StandaloneDataStorage::New().GetPointer()); //needed for deserializer! mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(tempStorage); bool exceptionThrown = false; try { mitk::NavigationToolStorage::Pointer readStorage = myDeserializer->Deserialize("noStorage.tfl"); } catch (mitk::IGTException e) { exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown,"Testing if exception is thrown if a non existing storage is given for deserialization."); } static void TestReadStorageWithUnknownFiletype() { mitk::DataStorage::Pointer tempStorage = dynamic_cast(mitk::StandaloneDataStorage::New().GetPointer()); //needed for deserializer! std::string toolFileName(MITK_IGT_DATA_DIR); toolFileName.append("/ClaronTool.stl"); mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(tempStorage); bool exceptionThrown = false; try { mitk::NavigationToolStorage::Pointer readStorage = myDeserializer->Deserialize(toolFileName); } catch (mitk::IGTException e) { exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown,"Testing if exception is thrown if a wrong file type is given for deserialization."); } +/* static void TestReadZipFileWithNoToolstorage() { mitk::DataStorage::Pointer tempStorage = dynamic_cast(mitk::StandaloneDataStorage::New().GetPointer()); //needed for deserializer! std::string toolFileName(MITK_IGT_DATA_DIR); toolFileName.append("/Empty.zip"); MITK_TEST_CONDITION(toolFileName.empty() == false, "Check if tool calibration of claron tool file exists"); mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(tempStorage); bool exceptionThrown = false; try { mitk::NavigationToolStorage::Pointer readStorage = myDeserializer->Deserialize(toolFileName); } catch (mitk::IGTException e) { exceptionThrown = true; } catch (std::exception& e) { MITK_ERROR << "Unexpected exception catched: " << e.what() << " / filename: " << toolFileName; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown,"Testing if exception is thrown if a empty zip file is given for deserialization."); } +*/ static void TestWriteStorageToInvalidFile() { //create Tool Storage mitk::NavigationToolStorage::Pointer myStorage = mitk::NavigationToolStorage::New(); //first tool mitk::NavigationTool::Pointer myTool1 = mitk::NavigationTool::New(); myTool1->SetIdentifier("001"); myStorage->AddTool(myTool1); //second tool mitk::NavigationTool::Pointer myTool2 = mitk::NavigationTool::New(); myTool2->SetIdentifier("002"); myStorage->AddTool(myTool2); //third tool mitk::NavigationTool::Pointer myTool3 = mitk::NavigationTool::New(); myTool3->SetIdentifier("003"); myStorage->AddTool(myTool3); //create Serializer mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); //create filename #ifdef WIN32 std::string filename = "C:\342INVALIDFILE<>.storage"; //invalid filename for windows #else std::string filename = "/dsfdsf:$�$342INVALIDFILE.storage"; //invalid filename for linux #endif //test serialization bool exceptionThrown = false; try { mySerializer->Serialize(filename,myStorage); } catch(mitk::IGTException e) { exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown,"Testing if an exception is thrown if an invalid file is used."); } static void TestWriteEmptyToolStorage() { //create Tool Storage mitk::NavigationToolStorage::Pointer myStorage = mitk::NavigationToolStorage::New(); //create Serializer mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); std::string filename; std::string optionDirectory; std::string separator; try { //create filename separator = Poco::Path::separator(); optionDirectory = std::string( MITK_TEST_OUTPUT_DIR ); filename = std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+"TestStorage.storage"; } catch (std::exception& e) { MITK_ERROR << "File access Exception: " << e.what(); MITK_INFO << "separator: " << separator; MITK_INFO << "optionDirectory: " << optionDirectory; MITK_TEST_FAILED_MSG(<<"Could not create filename for Exceptiontest"); } //test serialization bool success = mySerializer->Serialize(filename,myStorage); MITK_TEST_CONDITION_REQUIRED(success,"Testing serialization of simple tool storage"); } //new tests for exception throwing of NavigationToolStorageSerializer static void TestSerializerForExceptions() { mitk::NavigationToolStorageSerializer::Pointer testSerializer = mitk::NavigationToolStorageSerializer::New(); mitk::NavigationToolStorage::Pointer myStorage = mitk::NavigationToolStorage::New(); //create an invalid filename std::string filename = std::string( MITK_TEST_OUTPUT_DIR )+Poco::Path::separator()+".."+Poco::Path::separator()+""; //now try to serialize an check if an exception is thrown bool ExceptionThrown = false; try { testSerializer->Serialize(filename,myStorage); } catch(mitk::IGTException) { ExceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(ExceptionThrown, "Testing serializer with invalid filename."); } //new tests for exception throwing of NavigationToolStorageDeserializer static void TestDeserializerForExceptions() { // Desearializing file with invalid name mitk::DataStorage::Pointer tempStorage = dynamic_cast(mitk::StandaloneDataStorage::New().GetPointer()); mitk::NavigationToolStorageDeserializer::Pointer testDeseralizer= mitk::NavigationToolStorageDeserializer::New(tempStorage); bool ExceptionThrown1 = false; try { mitk::NavigationToolStorage::Pointer readStorage = testDeseralizer->Deserialize("InvalidName"); } catch(mitk::IGTException) { ExceptionThrown1 = true; } MITK_TEST_CONDITION_REQUIRED(ExceptionThrown1, "Testing deserializer with invalid filename."); bool ExceptionThrown2 = false; // Deserializing of empty zip file mitk::NavigationToolStorageDeserializer::Pointer testDeseralizer2= mitk::NavigationToolStorageDeserializer::New(tempStorage); try { std::string filename(MITK_IGT_DATA_DIR); filename.append("/Empty.zip"); mitk::NavigationToolStorage::Pointer readStorage = testDeseralizer2->Deserialize(filename); } catch(mitk::IGTException) { ExceptionThrown2 = true; } MITK_TEST_CONDITION_REQUIRED(ExceptionThrown2, "Testing deserializer method with empty zip file."); } /** This function is testing the TrackingVolume class. */ int mitkNavigationToolStorageSerializerAndDeserializerTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationToolStorageSerializerAndDeserializer"); try{ TestInstantiationSerializer(); TestInstantiationDeserializer(); TestWriteSimpleToolStorage(); TestWriteAndReadSimpleToolStorageWithToolLandmarks(); TestReadSimpleToolStorage(); TestWriteComplexToolStorage(); TestReadComplexToolStorage(); TestReadNotExistingStorage(); TestReadStorageWithUnknownFiletype(); //TestReadZipFileWithNoToolstorage(); deactivated because of bug 16566 TestWriteStorageToInvalidFile(); TestWriteEmptyToolStorage(); TestSerializerForExceptions(); TestDeserializerForExceptions(); } catch (std::exception& e) { MITK_ERROR << "exception:" << e.what(); MITK_TEST_FAILED_MSG(<<"Exception occured, test failed!"); } catch (...) { MITK_ERROR << "Unknown Exception?"; MITK_TEST_FAILED_MSG(<<"Exception occured, test failed!"); } CleanUp(); MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkTrackingDeviceSourceConfiguratorTest.cpp b/Modules/IGT/Testing/mitkTrackingDeviceSourceConfiguratorTest.cpp index 2956d38128..af9b1a8be7 100644 --- a/Modules/IGT/Testing/mitkTrackingDeviceSourceConfiguratorTest.cpp +++ b/Modules/IGT/Testing/mitkTrackingDeviceSourceConfiguratorTest.cpp @@ -1,226 +1,230 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTrackingDeviceSourceConfigurator.h" #include #include #include #include #include static void TestInstantiation() { // let's create an object of our class mitk::TrackingDeviceSourceConfigurator::Pointer testInstance; mitk::NavigationToolStorage::Pointer emptyStorage = mitk::NavigationToolStorage::New(); mitk::TrackingDevice::Pointer dummyDevice = dynamic_cast(mitk::ClaronTrackingDevice::New().GetPointer()); testInstance = mitk::TrackingDeviceSourceConfigurator::New(emptyStorage,dummyDevice); MITK_TEST_CONDITION_REQUIRED(testInstance.IsNotNull(),"Testing instantiation:"); } static void TestInvalidClaronTrackingDevice() { MITK_TEST_OUTPUT(<<"Testing simple claron tracking device with 2 invalid tools"); mitk::TrackingDeviceSourceConfigurator::Pointer testInstance; mitk::NavigationToolStorage::Pointer claronStorage = mitk::NavigationToolStorage::New(); //create invalid tool 1 mitk::NavigationTool::Pointer firstTool = mitk::NavigationTool::New(); firstTool->SetTrackingDeviceType(mitk::ClaronMicron); mitk::DataNode::Pointer firstNode = mitk::DataNode::New(); firstNode->SetName("Tool1"); firstTool->SetDataNode(firstNode); claronStorage->AddTool(firstTool); //create invalid tool 2 mitk::NavigationTool::Pointer secondTool = mitk::NavigationTool::New(); secondTool->SetTrackingDeviceType(mitk::ClaronMicron); mitk::DataNode::Pointer secondNode = mitk::DataNode::New(); secondNode->SetName("Tool2"); secondTool->SetDataNode(secondNode); claronStorage->AddTool(secondTool); mitk::TrackingDevice::Pointer testDevice = dynamic_cast(mitk::ClaronTrackingDevice::New().GetPointer()); testInstance = mitk::TrackingDeviceSourceConfigurator::New(claronStorage,testDevice); mitk::TrackingDeviceSource::Pointer testSource = testInstance->CreateTrackingDeviceSource(); MITK_TEST_CONDITION_REQUIRED(testSource.IsNull(),"..testing return value"); MITK_TEST_CONDITION_REQUIRED(testInstance->GetErrorMessage().size()>1,"..testing if there is an error message"); MITK_TEST_OUTPUT(<<"Testing simple claron tracking device with another 2 invalid tools"); secondTool->SetTrackingDeviceType(mitk::NDIAurora); claronStorage = mitk::NavigationToolStorage::New(); claronStorage->AddTool(secondTool); testInstance = mitk::TrackingDeviceSourceConfigurator::New(claronStorage,testDevice); MITK_TEST_CONDITION_REQUIRED(!testInstance->IsCreateTrackingDeviceSourcePossible(),"..testing if factory class detects the invalid data"); testSource = testInstance->CreateTrackingDeviceSource(); MITK_TEST_CONDITION_REQUIRED(testSource.IsNull(),"..testing return value"); MITK_TEST_CONDITION_REQUIRED(testInstance->GetErrorMessage().size()>1,"..testing if there is an error message"); MITK_TEST_CONDITION_REQUIRED(testInstance->GetUpdatedNavigationToolStorage()->GetToolCount()==1,"..testing if navigation tool storage is still there"); MITK_TEST_OUTPUT(<<"Testing other invalid test cases"); testInstance = mitk::TrackingDeviceSourceConfigurator::New(claronStorage,NULL); MITK_TEST_CONDITION_REQUIRED(!testInstance->IsCreateTrackingDeviceSourcePossible(),"..(1) testing if factory class detects the invalid data"); testInstance = mitk::TrackingDeviceSourceConfigurator::New(NULL,testDevice); MITK_TEST_CONDITION_REQUIRED(!testInstance->IsCreateTrackingDeviceSourcePossible(),"..(2) testing if factory class detects the invalid data"); } static void TestValidClaronTrackingDevice() { MITK_TEST_OUTPUT(<<"Testing simple claron tracking device with 2 valid tools"); std::string toolFileName(MITK_IGT_DATA_DIR); toolFileName.append("/ClaronTool"); mitk::TrackingDeviceSourceConfigurator::Pointer testInstance; mitk::NavigationToolStorage::Pointer claronStorage = mitk::NavigationToolStorage::New(); //create valid tool 1 mitk::NavigationTool::Pointer firstTool = mitk::NavigationTool::New(); firstTool->SetTrackingDeviceType(mitk::ClaronMicron); mitk::DataNode::Pointer firstNode = mitk::DataNode::New(); firstNode->SetName("Tool1"); firstTool->SetDataNode(firstNode); firstTool->SetCalibrationFile(toolFileName); firstTool->SetIdentifier("Tool#1"); claronStorage->AddTool(firstTool); //create valid tool 2 mitk::NavigationTool::Pointer secondTool = mitk::NavigationTool::New(); secondTool->SetTrackingDeviceType(mitk::ClaronMicron); mitk::DataNode::Pointer secondNode = mitk::DataNode::New(); secondNode->SetName("Tool2"); secondTool->SetDataNode(secondNode); secondTool->SetCalibrationFile(toolFileName); secondTool->SetIdentifier("Tool#2"); claronStorage->AddTool(secondTool); mitk::TrackingDevice::Pointer testDevice = dynamic_cast(mitk::ClaronTrackingDevice::New().GetPointer()); testInstance = mitk::TrackingDeviceSourceConfigurator::New(claronStorage,testDevice); mitk::TrackingDeviceSource::Pointer testSource = testInstance->CreateTrackingDeviceSource(); MITK_TEST_CONDITION_REQUIRED(testSource->GetNumberOfOutputs()==2,"testing number of outputs"); MITK_TEST_CONDITION_REQUIRED(testSource->GetTrackingDevice()->GetToolCount()==2,"testing tracking device"); } +/* static void TestNDIAuroraTrackingDevice() { } +*/ +/* static void TestNDIPolarisTrackingDevice() { MITK_TEST_OUTPUT(<<"Testing simple NDI Polaris tracking device with 1 valid tool"); std::string toolFileName(MITK_IGT_DATA_DIR); toolFileName.append("/SROMFile.rom"); mitk::TrackingDeviceSourceConfigurator::Pointer testInstance; mitk::NavigationToolStorage::Pointer polarisStorage = mitk::NavigationToolStorage::New(); //create valid tool 1 mitk::NavigationTool::Pointer firstTool = mitk::NavigationTool::New(); firstTool->SetTrackingDeviceType(mitk::NDIPolaris); mitk::DataNode::Pointer firstNode = mitk::DataNode::New(); firstNode->SetName("Tool1"); firstTool->SetDataNode(firstNode); firstTool->SetCalibrationFile(toolFileName); firstTool->SetIdentifier("Tool#1"); polarisStorage->AddTool(firstTool); mitk::NDITrackingDevice::Pointer ndiDevice = mitk::NDITrackingDevice::New(); ndiDevice->SetType(mitk::NDIPolaris); mitk::TrackingDevice::Pointer testDevice = dynamic_cast(ndiDevice.GetPointer()); testInstance = mitk::TrackingDeviceSourceConfigurator::New(polarisStorage,testDevice); mitk::TrackingDeviceSource::Pointer testSource = testInstance->CreateTrackingDeviceSource(); MITK_TEST_CONDITION_REQUIRED(testSource->GetNumberOfOutputs()==1,"..testing number of outputs"); MITK_TEST_CONDITION_REQUIRED(testSource->GetTrackingDevice()->GetToolCount()==1,"..testing tracking device"); } +*/ static void TestAdditionalMethods() { MITK_TEST_OUTPUT(<<"Testing additional methods of TrackingDeviceSourceCOnfigurator"); MITK_TEST_OUTPUT(<<"..using claron tracking device for testing"); std::string toolFileName(MITK_IGT_DATA_DIR); toolFileName.append("/ClaronTool"); mitk::TrackingDeviceSourceConfigurator::Pointer testInstance; mitk::NavigationToolStorage::Pointer claronStorage = mitk::NavigationToolStorage::New(); //create valid tool 1 mitk::NavigationTool::Pointer firstTool = mitk::NavigationTool::New(); firstTool->SetTrackingDeviceType(mitk::ClaronMicron); mitk::DataNode::Pointer firstNode = mitk::DataNode::New(); firstNode->SetName("Tool1"); firstTool->SetDataNode(firstNode); firstTool->SetCalibrationFile(toolFileName); firstTool->SetIdentifier("Tool#1"); claronStorage->AddTool(firstTool); //create valid tool 2 mitk::NavigationTool::Pointer secondTool = mitk::NavigationTool::New(); secondTool->SetTrackingDeviceType(mitk::ClaronMicron); mitk::DataNode::Pointer secondNode = mitk::DataNode::New(); secondNode->SetName("Tool2"); secondTool->SetDataNode(secondNode); secondTool->SetCalibrationFile(toolFileName); secondTool->SetIdentifier("Tool#2"); claronStorage->AddTool(secondTool); mitk::TrackingDevice::Pointer testDevice = dynamic_cast(mitk::ClaronTrackingDevice::New().GetPointer()); testInstance = mitk::TrackingDeviceSourceConfigurator::New(claronStorage,testDevice); mitk::TrackingDeviceSource::Pointer testSource = testInstance->CreateTrackingDeviceSource(); //numbers must be the same in case of MicronTracker MITK_TEST_CONDITION_REQUIRED(testInstance->GetToolNumberInToolStorage(0)==0,"..testing method GetToolNumberInToolStorage()"); MITK_TEST_CONDITION_REQUIRED(testInstance->GetToolIdentifierInToolStorage(0)=="Tool#1","..testing method GetToolIdentifierInToolStorage()"); MITK_TEST_CONDITION_REQUIRED(testInstance->GetToolNumbersInToolStorage().at(0)==0,"..testing method GetToolNumbersInToolStorage()"); MITK_TEST_CONDITION_REQUIRED(testInstance->GetToolIdentifiersInToolStorage().at(0)=="Tool#1","..testing method GetToolIdentifiersInToolStorage()"); } int mitkTrackingDeviceSourceConfiguratorTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("TrackingDeviceConfigurator"); TestInstantiation(); TestInvalidClaronTrackingDevice(); TestValidClaronTrackingDevice(); TestAdditionalMethods(); MITK_TEST_END(); } diff --git a/Modules/IGT/TrackingDevices/mitkInternalTrackingTool.cpp b/Modules/IGT/TrackingDevices/mitkInternalTrackingTool.cpp index e4a0893e30..754f40176f 100644 --- a/Modules/IGT/TrackingDevices/mitkInternalTrackingTool.cpp +++ b/Modules/IGT/TrackingDevices/mitkInternalTrackingTool.cpp @@ -1,273 +1,273 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkInternalTrackingTool.h" #include typedef itk::MutexLockHolder MutexLockHolder; mitk::InternalTrackingTool::InternalTrackingTool() : TrackingTool(), m_TrackingError(0.0f), m_Enabled(true), m_DataValid(false), m_ToolTipSet(false) { m_Position[0] = 0.0f; m_Position[1] = 0.0f; m_Position[2] = 0.0f; m_Orientation[0] = 0.0f; m_Orientation[1] = 0.0f; m_Orientation[2] = 0.0f; m_Orientation[3] = 0.0f; // this should not be necessary as the tools bring their own tooltip transformation m_ToolTip[0] = 0.0f; m_ToolTip[1] = 0.0f; m_ToolTip[2] = 0.0f; m_ToolTipRotation[0] = 0.0f; m_ToolTipRotation[1] = 0.0f; m_ToolTipRotation[2] = 0.0f; m_ToolTipRotation[3] = 1.0f; } mitk::InternalTrackingTool::~InternalTrackingTool() { } void mitk::InternalTrackingTool::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Position: " << m_Position << std::endl; os << indent << "Orientation: " << m_Orientation << std::endl; os << indent << "TrackingError: " << m_TrackingError << std::endl; os << indent << "Enabled: " << m_Enabled << std::endl; os << indent << "DataValid: " << m_DataValid << std::endl; os << indent << "ToolTip: " << m_ToolTip << std::endl; os << indent << "ToolTipRotation: " << m_ToolTipRotation << std::endl; os << indent << "ToolTipSet: " << m_ToolTipSet << std::endl; } void mitk::InternalTrackingTool::SetToolName(const char* _arg) { itkDebugMacro("setting m_ToolName to " << _arg); MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex if ( _arg && (_arg == this->m_ToolName) ) { return; } if (_arg) { this->m_ToolName= _arg; } else { this->m_ToolName= ""; } this->Modified(); } void mitk::InternalTrackingTool::SetToolName( const std::string _arg ) { this->SetToolName(_arg.c_str()); } void mitk::InternalTrackingTool::GetPosition(mitk::Point3D& position) const { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex if (m_ToolTipSet) { // Compute the position of tool tip in the coordinate frame of the // tracking device: Rotate the position of the tip into the tracking // device coordinate frame then add to the position of the tracking // sensor - vnl_vector pos_vnl = m_Position.Get_vnl_vector() + m_Orientation.rotate( m_ToolTip.Get_vnl_vector() ) ; + vnl_vector pos_vnl = m_Position.GetVnlVector() + m_Orientation.rotate( m_ToolTip.GetVnlVector() ) ; position[0] = pos_vnl[0]; position[1] = pos_vnl[1]; position[2] = pos_vnl[2]; } else { position[0] = m_Position[0]; position[1] = m_Position[1]; position[2] = m_Position[2]; } this->Modified(); } void mitk::InternalTrackingTool::SetPosition(mitk::Point3D position, mitk::ScalarType eps) { itkDebugMacro("setting m_Position to " << position); if (!Equal(m_Position, position, eps)) { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex m_Position = position; this->Modified(); } } void mitk::InternalTrackingTool::GetOrientation(mitk::Quaternion& orientation) const { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex if (m_ToolTipSet) { // Compute the orientation of the tool tip in the coordinate frame of // the tracking device. // // * m_Orientation is the orientation of the sensor relative to the transmitter // * m_ToolTipRotation is the orientation of the tool tip relative to the sensor orientation = m_Orientation * m_ToolTipRotation; } else { orientation = m_Orientation; } } void mitk::InternalTrackingTool::SetToolTip(mitk::Point3D toolTipPosition, mitk::Quaternion orientation, mitk::ScalarType eps) { if ( !Equal(m_ToolTip, toolTipPosition, eps) || !Equal(m_ToolTipRotation, orientation, eps) ) { if( (toolTipPosition[0] == 0) && (toolTipPosition[1] == 0) && (toolTipPosition[2] == 0) && (orientation.x() == 0) && (orientation.y() == 0) && (orientation.z() == 0) && (orientation.r() == 1)) { m_ToolTipSet = false; } else { m_ToolTipSet = true; } m_ToolTip = toolTipPosition; m_ToolTipRotation = orientation; this->Modified(); } } void mitk::InternalTrackingTool::SetOrientation(mitk::Quaternion orientation, mitk::ScalarType eps) { itkDebugMacro("setting m_Orientation to " << orientation); if (!Equal(m_Orientation, orientation, eps)) { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex m_Orientation = orientation; this->Modified(); } } void mitk::InternalTrackingTool::SetTrackingError(float error) { itkDebugMacro("setting m_TrackingError to " << error); MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex if (error == m_TrackingError) { return; } m_TrackingError = error; this->Modified(); } float mitk::InternalTrackingTool::GetTrackingError() const { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex float r = m_TrackingError; return r; } bool mitk::InternalTrackingTool::Enable() { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex if (m_Enabled == false) { this->m_Enabled = true; this->Modified(); } return true; } bool mitk::InternalTrackingTool::Disable() { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex if (m_Enabled == true) { this->m_Enabled = false; this->Modified(); } return true; } bool mitk::InternalTrackingTool::IsEnabled() const { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex return m_Enabled; } bool mitk::InternalTrackingTool::IsTooltipSet() const { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex return m_ToolTipSet; } bool mitk::InternalTrackingTool::IsDataValid() const { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex return m_DataValid; } void mitk::InternalTrackingTool::SetDataValid(bool _arg) { itkDebugMacro("setting m_DataValid to " << _arg); if (this->m_DataValid != _arg) { MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex this->m_DataValid = _arg; this->Modified(); } } void mitk::InternalTrackingTool::SetErrorMessage(const char* _arg) { itkDebugMacro("setting m_ErrorMessage to " << _arg); MutexLockHolder lock(*m_MyMutex); // lock and unlock the mutex if ((_arg == NULL) || (_arg == this->m_ErrorMessage)) return; if (_arg != NULL) this->m_ErrorMessage = _arg; else this->m_ErrorMessage = ""; this->Modified(); } diff --git a/Modules/IGT/TrackingDevices/mitkNDIProtocol.cpp b/Modules/IGT/TrackingDevices/mitkNDIProtocol.cpp index 88e4fddaa9..fbd4e3bc3b 100644 --- a/Modules/IGT/TrackingDevices/mitkNDIProtocol.cpp +++ b/Modules/IGT/TrackingDevices/mitkNDIProtocol.cpp @@ -1,1883 +1,1883 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNDIProtocol.h" #include "mitkNDITrackingDevice.h" #include #include #include #include #include mitk::NDIProtocol::NDIProtocol() : itk::Object(), m_TrackingDevice(NULL), m_UseCRC(true) { } mitk::NDIProtocol::~NDIProtocol() { } mitk::NDIErrorCode mitk::NDIProtocol::COMM(mitk::SerialCommunication::BaudRate baudRate , mitk::SerialCommunication::DataBits dataBits, mitk::SerialCommunication::Parity parity, mitk::SerialCommunication::StopBits stopBits, mitk::SerialCommunication::HardwareHandshake hardwareHandshake) { /* Build parameter string */ std::string param; switch (baudRate) { case mitk::SerialCommunication::BaudRate14400: param += "1"; break; case mitk::SerialCommunication::BaudRate19200: param += "2"; break; case mitk::SerialCommunication::BaudRate38400: param += "3"; break; case mitk::SerialCommunication::BaudRate57600: param += "4"; break; case mitk::SerialCommunication::BaudRate115200: param += "5"; break; case mitk::SerialCommunication::BaudRate9600: default: // assume 9600 Baud as default param += "0"; break; } switch (dataBits) { case mitk::SerialCommunication::DataBits7: param += "1"; break; case mitk::SerialCommunication::DataBits8: default: // set 8 data bits as default param += "0"; break; } switch (parity) { case mitk::SerialCommunication::Odd: param += "1"; break; case mitk::SerialCommunication::Even: param += "2"; break; case mitk::SerialCommunication::None: default: // set no parity as default param += "0"; break; } switch (stopBits) { case mitk::SerialCommunication::StopBits2: param += "1"; break; case mitk::SerialCommunication::StopBits1: default: // set 1 stop bit as default param += "0"; break; } switch (hardwareHandshake) { case mitk::SerialCommunication::HardwareHandshakeOn: param += "1"; break; case mitk::SerialCommunication::HardwareHandshakeOff: default: // set no hardware handshake as default param += "0"; break; } return GenericCommand("COMM", ¶m); } mitk::NDIErrorCode mitk::NDIProtocol::INIT() { return GenericCommand("INIT"); } mitk::NDIErrorCode mitk::NDIProtocol::DSTART() { return GenericCommand("DSTART"); } mitk::NDIErrorCode mitk::NDIProtocol::DSTOP() { return GenericCommand("DSTOP"); } mitk::NDIErrorCode mitk::NDIProtocol::IRINIT() { return GenericCommand("IRINIT"); } mitk::NDIErrorCode mitk::NDIProtocol::IRCHK(bool* IRdetected) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "IRCHK:0001"; // command string format 1: with crc else fullcommand = "IRCHK 0001"; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } /* wait for the trackingsystem to process the command */ itksys::SystemTools::Delay(100); /* read and parse the reply from tracking device */ // the reply for IRCHK can be either Infrared Source Information or ERROR## // because we use the simple reply format, the answer will be only one char: // "0" - no IR detected // "1" - IR detected std::string reply; char b; m_TrackingDevice->ReceiveByte(&b);// read the first byte reply = b; if ((b == '0') || (b == '1')) // normal answer { /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code { if ( b == '0') *IRdetected = false; else *IRdetected = true; returnValue = NDIOKAY; } else // return error in CRC { returnValue = NDICRCERROR; *IRdetected = false; // IRdetected is only valid if return code of this function is NDIOKAY } } else if (b =='E') // expect ERROR## { std::string errorstring; m_TrackingDevice->Receive(&errorstring, 4); // read the remaining 4 characters of ERROR reply += errorstring; static const std::string error("ERROR"); if (error.compare(0, 5, reply) == 0) // check for "ERROR" { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code /* perform CRC checking */ reply += errorcode; // build complete reply string std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else returnValue = NDICRCERROR; // return error in CRC } } else // something else, that we do not expect returnValue = NDIUNEXPECTEDREPLY; /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PHSR(PHSRQueryType queryType, std::string* portHandles) { NDIErrorCode returnValue = NDIUNKNOWNERROR; if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string command; char stringQueryType[3]; sprintf(stringQueryType, "%02X", queryType);// convert numerical queryType to string in hexadecimal format if (m_UseCRC == true) command = std::string("PHSR:") + std::string(stringQueryType); else //if (m_UseCRC != true) command = std::string("PHSR ") + std::string(stringQueryType); // command string format 2: without crc returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } itksys::SystemTools::Delay(100); std::string reply; m_TrackingDevice->Receive(&reply, 2); // read first 2 characters of reply ("Number of Handles" as a 2 digit hexadecimal number) static const std::string error("ERROR"); if (error.compare(0, 2, reply) == 0) // check for "ERROR" (compare for "ER" because we can not be sure that the reply is more than 2 characters (in case of 0 port handles returned) { std::string ror; m_TrackingDevice->Receive(&ror, 3); // read rest of ERROR (=> "ROR") reply += ror; // build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // No error, expect number of handles as a 2 character hexadecimal value { unsigned int numberOfHandles = 0; // convert the hexadecimal string representation to a numerical using a stringstream std::stringstream s; s << reply; s >> numberOfHandles; if (numberOfHandles > 16) // there can not be more than 16 handles ToDo: exact maximum number depend on tracking device and firmware revision. these data could be read with VER and used here { returnValue = NDIUNKNOWNERROR; } else { std::string handleInformation; portHandles->clear(); for (unsigned int i = 0; i < numberOfHandles; i++) // read 5 characters for each handle and extract port handle { m_TrackingDevice->Receive(&handleInformation, 5); *portHandles += handleInformation.substr(0, 2); // Append the port handle to the portHandles string reply += handleInformation; // build complete reply string for crc checking } /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } } /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PHRQ(std::string* portHandle) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking device if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string command; if (m_UseCRC == true) command = "PHRQ:*********1****"; // command string format 1: with crc else command = "PHRQ *********1****"; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } itksys::SystemTools::Delay(100); // give the tracking device some time to process the command std::string reply; m_TrackingDevice->Receive(&reply, 2); // read first 2 characters of reply ("Number of Handles" as a 2 digit hexadecimal number) static const std::string error("ERROR"); if (error.compare(0, 2, reply) == 0) // check for "ERROR" (compare for "ER" because we can not be sure that the reply is more than 2 characters (in case of 0 port handles returned) { std::string ror; m_TrackingDevice->Receive(&ror, 3); // read rest of ERROR (=> "ROR") reply += ror; // build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // No error, expect port handle as a 2 character hexadecimal value { *portHandle = reply; // assign the port handle to the return string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay returnValue = NDIOKAY; else // else return error in CRC returnValue = NDICRCERROR; } /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PVWR(std::string* portHandle, const unsigned char* sromData, unsigned int sromDataLength) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; if (sromDataLength > 1024) return SROMFILETOOLARGE; if (sromDataLength == 0) return SROMFILETOOSMALL; /* build send commands */ std::string basecommand; if (m_UseCRC == true) basecommand = "PVWR:"; // command string format 1: with crc else basecommand = "PVWR "; // command string format 2: without crc std::string hexSROMData; hexSROMData.reserve(2 * sromDataLength); char hexcharacter[20]; // 7 bytes should be enough (in send loop) for (unsigned int i = 0; i < sromDataLength; i++) { sprintf(hexcharacter, "%02X", sromData[i]); // convert srom byte to string in hexadecimal format //hexSROMData += "12"; hexSROMData += hexcharacter; // append hex string to srom data in hex format } /* data must be written in chunks of 64 byte (128 hex characters). To ensure 64 byte chunks the last chunk must be padded with 00 */ unsigned int zerosToPad = 128 - (hexSROMData.size() % 128); // hexSROMData must be a multiple of 128 if (zerosToPad > 0) hexSROMData.append(zerosToPad, '0'); /* now we have all the data, send it in 128 character chunks */ std::string fullcommand; for (unsigned int j = 0; j < hexSROMData.size(); j += 128) { sprintf(hexcharacter, "%s%04X", portHandle->c_str(), j/2); // build the first two parameters: PortHandle and SROM device adress (not in hex characters, but in bytes) fullcommand = basecommand + hexcharacter + hexSROMData.substr(j, 128); // build complete command string returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); // send command itksys::SystemTools::Delay(50); // Wait for trackingsystem to process the data if (returnValue != NDIOKAY) // check for send error break; returnValue = this->ParseOkayError(); // parse answer if (returnValue != NDIOKAY) // check for error returned from tracking device break; } /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PINIT(std::string* portHandle) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = std::string("PINIT:") + *portHandle; // command string format 1: with crc else fullcommand = std::string("PINIT ") + *portHandle; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } /* wait for the trackingsystem to process the command */ itksys::SystemTools::Delay(100); std::string reply; m_TrackingDevice->Receive(&reply, 4); // read first 4 characters of reply /* Parse reply from tracking device */ static const std::string okay("OKAYA896"); // OKAY is static, so we can perform a static crc check static const std::string error("ERROR"); static const std::string warning("WARNING7423"); // WARNING has a static crc too if (okay.compare(0, 4, reply) == 0) // check for "OKAY": compare first 4 characters from okay with reply { // OKAY was found, now check the CRC16 too m_TrackingDevice->Receive(&reply, 4); // read 4 hexadecimal characters for CRC16 if (okay.compare(4, 4, reply, 0, 4) == 0) // first 4 from new reply should match last 4 from okay returnValue = NDIOKAY; else returnValue = NDICRCERROR; } else if (warning.compare(0, 4, reply) == 0) // check for "WARNING" { // WARN was found, now check remaining characters and CRC16 m_TrackingDevice->Receive(&reply, 4); // read 4 hexadecimal characters for CRC16 if (warning.compare(4, 7, reply, 0, 7) == 0) // first 7 from new reply should match last 7 from okay returnValue = NDIWARNING; else returnValue = NDICRCERROR; } else if (error.compare(0, 4, reply) == 0) // check for "ERRO" { char b; // The ERROR reply is not static, so we can not use a static crc check. m_TrackingDevice->ReceiveByte(&b); // read next character ("R" from ERROR) reply += b; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // else it is something else, that we do not expect returnValue = NDIUNEXPECTEDREPLY; //read cr carriage return char b; m_TrackingDevice->ReceiveByte(&b); /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PENA(std::string* portHandle, TrackingPriority prio) { std::string param; if (portHandle != NULL) param = *portHandle + (char) prio; else param = ""; return this->GenericCommand("PENA", ¶m); } mitk::NDIErrorCode mitk::NDIProtocol::PHINF(std::string portHandle, std::string* portInfo) { std::string command; if (m_UseCRC) command = "PHINF:" + portHandle; else command = "PHINF " + portHandle; mitk::NDIErrorCode returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue==NDIOKAY) { m_TrackingDevice->ClearReceiveBuffer(); m_TrackingDevice->Receive(portInfo, 33); m_TrackingDevice->ClearReceiveBuffer(); } else m_TrackingDevice->ClearReceiveBuffer(); return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PDIS(std::string* portHandle) { return this->GenericCommand("PDIS", portHandle); } mitk::NDIErrorCode mitk::NDIProtocol::PHF(std::string* portHandle) { return this->GenericCommand("PHF", portHandle); } mitk::NDIErrorCode mitk::NDIProtocol::IRATE(IlluminationActivationRate rate) { std::string param; switch (rate) { case Hz60: param = "2"; break; case Hz30: param = "1"; break; case Hz20: default: param = "0"; break; } return this->GenericCommand("IRATE", ¶m); } mitk::NDIErrorCode mitk::NDIProtocol::BEEP(unsigned char count) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; std::string p; if ((count >= 1) && (count <= 9)) p = (count + '0'); // convert the number count to a character representation else return NDICOMMANDPARAMETEROUTOFRANGE; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "BEEP:" + p; // command string format 1: with crc else fullcommand = "BEEP " + p; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } /* wait for the trackingsystem to process the command */ itksys::SystemTools::Delay(100); std::string reply; char b; m_TrackingDevice->ReceiveByte(&b); // read the first byte reply = b; if ((b == '0') || (b == '1')) // normal answer { /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } else if (b =='E') // expect ERROR## { std::string errorstring; m_TrackingDevice->Receive(&errorstring, 4); // read the remaining 4 characters of ERROR reply += errorstring; static const std::string error("ERROR"); if (error.compare(0, 5, reply) == 0) // check for "ERROR" { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code /* perform CRC checking */ reply += errorcode; // build complete reply string std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else returnValue = NDICRCERROR; // return error in CRC } } else // something else, that we do not expect returnValue = NDIUNEXPECTEDREPLY; /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::TSTART(bool resetFrameCounter) { std::string param = "80"; if (resetFrameCounter == true) return this->GenericCommand("TSTART", ¶m); else return this->GenericCommand("TSTART"); } mitk::NDIErrorCode mitk::NDIProtocol::TSTOP() { return this->GenericCommand("TSTOP"); } mitk::NDIErrorCode mitk::NDIProtocol::PSOUT(std::string portHandle, std::string state) { std::string param = portHandle + state; return this->GenericCommand("PSOUT", ¶m); } mitk::NDIErrorCode mitk::NDIProtocol::TX(bool trackIndividualMarkers, MarkerPointContainerType* markerPositions) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking device if(trackIndividualMarkers) markerPositions->clear(); if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string fullcommand; if (trackIndividualMarkers) { if (m_UseCRC == true) fullcommand = "TX:1001"; // command string format 1: with crc else fullcommand = "TX 1001"; // command string format 2: without crc } else { if (m_UseCRC == true) fullcommand = "TX:"; // command string format 1: with crc else fullcommand = "TX "; // command string format 2: without crc } returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } /* read number of handles returned */ std::string reply; std::string s; m_TrackingDevice->Receive(&reply, 2); // read first 2 characters of reply (error or number of handles returned) //printf("%d",reply); static const std::string error("ERROR"); if (error.compare(0, 2, reply) == 0) { m_TrackingDevice->Receive(&s, 3); // read next characters ("ROR" from ERROR) reply += s; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code { returnValue = this->GetErrorCode(&errorcode); } else // return error in CRC { returnValue = NDICRCERROR; } } else // transformation data is returned { /* parse number of handles from first 2 characters */ std::stringstream converter; unsigned int numberOfHandles = 0; converter << std::hex << reply; // insert reply into stringstream converter >> numberOfHandles; // extract number of handles as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse transformation data for each handle */ for (unsigned int i = 0; i < numberOfHandles; i++) // for each handle { /* Read port handle */ m_TrackingDevice->Receive(&s, 2); // read port handle reply += s; // build complete command string NDIPassiveTool::Pointer tool = m_TrackingDevice->GetInternalTool(s); // get tool object for that handle if (tool.IsNull()) { returnValue = UNKNOWNHANDLERETURNED; break; // if we do not know the handle, we can not assume anything about the remaining data, so we better abort (we could read up to the next LF) } /* Parse reply from tracking device */ static const std::string missing("MISSING"); static const std::string disabled("DISABLED"); static const std::string unoccupied("UNOCCUPIED"); m_TrackingDevice->Receive(&s, 6); // read next 6 characters: either an error message or part of the transformation data reply += s; // build complete command string if (missing.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'missing'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 18); // after 'missin', 1 character for 'g', 8 characters for port status, 8 characters for frame number and one for line feed are send reply += s; // build complete command string } else if (disabled.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'disabled'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 3); // read last characters of disabled plus 8 characters for port status, 8 characters for frame number and one for line feed reply += s; // build complete command string } else if (unoccupied.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'unoccupied'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 21); // read remaining characters of UNOCCUPIED reply += s; // build complete command string } else // transformation data { /* define local copies */ signed int number = 0; float localPos[3] = {0.0, 0.0, 0.0}; float localQuat[4] = {0.0, 0.0, 0.0, 0.0}; float localError = 0.0; unsigned long localPortStatus = 0; unsigned int localFrameNumber = 0; /* read and parse the four 6 character quaternion values */ //std::cout << "s = " << s << std::endl; converter << std::dec << s; // insert string with first number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); //std::cout << "number = " << number << std::endl; localQuat[0] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right for (unsigned int i = 1; i < 4; i++)// read the next 3 numbers { m_TrackingDevice->Receive(&s, 6); // read the next number reply += s; // build complete command string converter << std::dec << s; // insert string with first number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localQuat[i] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right } /* read and parse the three 7 character translation values */ for (unsigned int i = 0; i < 3; i++) { m_TrackingDevice->Receive(&s, 7); // read the next position vector number reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localPos[i] = number / 100.0; // the value is send with an implied decimal point with 2 digits to the right } /* read and parse 6 character error value */ m_TrackingDevice->Receive(&s, 6); // read the error value reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract the number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localError = number / 10000.0; // the error value is send with an implied decimal point with 4 digits to the right /* read and parse 8 character port status */ m_TrackingDevice->Receive(&s, 8); // read the port status value reply += s; // build complete command string converter << std::hex << s; // insert string into stringstream converter >> localPortStatus; // extract the number as unsigned long converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse 8 character frame number as hexadecimal */ m_TrackingDevice->Receive(&s, 8); // read the frame number value reply += s; // build complete command string converter << std::hex << s; // insert string with hex value encoded number into stringstream converter >> localFrameNumber; // extract the number as unsigned long converter.clear(); // converter must be cleared to be reused converter.str(""); /* copy local values to the tool */ mitk::Quaternion orientation(localQuat[1], localQuat[2], localQuat[3], localQuat[0]); //If the rotation mode is vnlTransposed we have to transpose the quaternion if (m_TrackingDevice->GetRotationMode() == mitk::NDITrackingDevice::RotationTransposed) { orientation[0] *= -1; //qx orientation[1] *= -1; //qy orientation[2] *= -1; //qz //qr is not inverted } tool->SetOrientation(orientation); mitk::Point3D position; position[0] = localPos[0]; position[1] = localPos[1]; position[2] = localPos[2]; tool->SetPosition(position); tool->SetTrackingError(localError); tool->SetErrorMessage(""); tool->SetDataValid(true); m_TrackingDevice->Receive(&s, 1); // read the line feed character, that terminates each handle data reply += s; // build complete command string } } // for //Read Reply Option 1000 data if(trackIndividualMarkers) { /* parse number of markers from first 2 characters */ m_TrackingDevice->Receive(&s, 2); reply += s; unsigned int numberOfMarkers = 0; converter << std::hex << s; // insert reply into stringstream converter >> numberOfMarkers; // extract number of markers as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); unsigned int oovReplySize = (unsigned int)ceil((double)numberOfMarkers/4.0); unsigned int nbMarkersInVolume = 0; char c; // parse oov data to find out how many marker positions were recorded for (unsigned int i = 0; i < oovReplySize; i++) { m_TrackingDevice->ReceiveByte(&c); reply += c; nbMarkersInVolume += ByteToNbBitsOn(c); } nbMarkersInVolume = numberOfMarkers-nbMarkersInVolume; /* read and parse position data for each marker */ for (unsigned int i = 0; i < nbMarkersInVolume; i++) { /* define local copies */ signed int number = 0; MarkerPointType markerPosition; /* read and parse the three 7 character translation values */ for (unsigned int i = 0; i < 3; i++) { m_TrackingDevice->Receive(&s, 7); // read the next position vector number reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); markerPosition[i] = number / 100.0; // the value is send with an implied decimal point with 2 digits to the right } markerPositions->push_back(markerPosition); } // end for all markers } //END read Reply Option 1000 data /* Read System Status */ m_TrackingDevice->Receive(&s, 4); // read system status reply += s; // build complete command string /* now the reply string is complete, perform crc checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay { returnValue = NDIOKAY; } else // return error in CRC { returnValue = NDICRCERROR; /* Invalidate all tools because the received data contained an error */ m_TrackingDevice->InvalidateAll(); if(trackIndividualMarkers) markerPositions->clear(); } } // else /* cleanup and return */ m_TrackingDevice->Receive(&s, 1); // read the last linde feed (because the tracking system device is sometimes to slow to send it before we clear the buffer. In this case, the LF would remain in the receive buffer and be read as the first character of the next command m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::TX1000(MarkerPointContainerType* markerPositions) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem markerPositions->clear(); if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "TX:1001"; // command string format 1: with crc else fullcommand = "TX 1001"; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); /* read number of handles returned */ std::string reply; std::string s; m_TrackingDevice->Receive(&reply, 2); // read first 2 characters of reply (error or number of handles returned) static const std::string error("ERROR"); if (error.compare(0, 2, reply) == 0) { m_TrackingDevice->Receive(&s, 3); // read next characters ("ROR" from ERROR) reply += s; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code { returnValue = this->GetErrorCode(&errorcode); } else // return error in CRC { returnValue = NDICRCERROR; } } else // transformation data is returned { /* parse number of handles from first 2 characters */ std::stringstream converter; unsigned int numberOfHandles = 0; converter << std::hex << reply; // insert reply into stringstream converter >> numberOfHandles; // extract number of handles as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse transformation data for each handle */ for (unsigned int i = 0; i < numberOfHandles; i++) // for each handle { /* Read port handle */ m_TrackingDevice->Receive(&s, 2); // read port handle reply += s; // build complete command string NDIPassiveTool::Pointer tool = m_TrackingDevice->GetInternalTool(s); // get tool object for that handle if (tool.IsNull()) { returnValue = UNKNOWNHANDLERETURNED; break; // if we do not know the handle, we can not assume anything about the remaining data, so we better abort (we could read up to the next LF) } /* Parse reply from tracking device */ static const std::string missing("MISSING"); static const std::string disabled("DISABLED"); static const std::string unoccupied("UNOCCUPIED"); m_TrackingDevice->Receive(&s, 6); // read next 6 characters: either an error message or part of the transformation data reply += s; // build complete command string if (missing.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'missing'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 18); // after 'missin', 1 character for 'g', 8 characters for port status, 8 characters for frame number and one for line feed are send reply += s; // build complete command string } else if (disabled.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'disabled'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 19); // read last characters of disabled plus 8 characters for port status, 8 characters for frame number and one for line feed reply += s; // build complete command string } else if (unoccupied.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'unoccupied'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 21); // read remaining characters of UNOCCUPIED reply += s; // build complete command string } else // transformation data { /* define local copies */ signed int number = 0; float localPos[3] = {0.0, 0.0, 0.0}; float localQuat[4] = {0.0, 0.0, 0.0, 0.0}; float localError = 0.0; unsigned long localPortStatus = 0; unsigned int localFrameNumber = 0; /* read and parse the four 6 character quaternion values */ //std::cout << "s = " << s << std::endl; converter << std::dec << s; // insert string with first number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); //std::cout << "number = " << number << std::endl; localQuat[0] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right for (unsigned int i = 1; i < 4; i++)// read the next 3 numbers { m_TrackingDevice->Receive(&s, 6); // read the next number reply += s; // build complete command string converter << std::dec << s; // insert string with first number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localQuat[i] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right } /* read and parse the three 7 character translation values */ for (unsigned int i = 0; i < 3; i++) { m_TrackingDevice->Receive(&s, 7); // read the next position vector number reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localPos[i] = number / 100.0; // the value is send with an implied decimal point with 2 digits to the right } /* read and parse 6 character error value */ m_TrackingDevice->Receive(&s, 6); // read the error value reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract the number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localError = number / 10000.0; // the error value is send with an implied decimal point with 4 digits to the right /* read and parse 8 character port status */ m_TrackingDevice->Receive(&s, 8); // read the port status value reply += s; // build complete command string converter << std::hex << s; // insert string into stringstream converter >> localPortStatus; // extract the number as unsigned long converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse 8 character frame number as hexadecimal */ m_TrackingDevice->Receive(&s, 8); // read the frame number value reply += s; // build complete command string converter << std::hex << s; // insert string with hex value encoded number into stringstream converter >> localFrameNumber; // extract the number as unsigned long converter.clear(); // converter must be cleared to be reused converter.str(""); /* copy local values to the tool */ mitk::Quaternion orientation(localQuat[1], localQuat[2], localQuat[3], localQuat[0]); tool->SetOrientation(orientation); mitk::Point3D position; position[0] = localPos[0]; position[1] = localPos[1]; position[2] = localPos[2]; tool->SetPosition(position); tool->SetTrackingError(localError); tool->SetErrorMessage(""); tool->SetDataValid(true); m_TrackingDevice->Receive(&s, 1); // read the line feed character, that terminates each handle data reply += s; // build complete command string } } //Read Reply Option 1000 data /* parse number of markers from first 2 characters */ m_TrackingDevice->Receive(&s, 2); reply += s; unsigned int numberOfMarkers = 0; converter << std::hex << s; // insert reply into stringstream converter >> numberOfMarkers; // extract number of markers as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); unsigned int oovReplySize = (unsigned int)ceil((double)numberOfMarkers/4.0); unsigned int nbMarkersInVolume = 0; char c; // parse oov data to find out how many marker positions were recorded for (unsigned int i = 0; i < oovReplySize; i++) { m_TrackingDevice->ReceiveByte(&c); reply += c; nbMarkersInVolume += ByteToNbBitsOn(c); } nbMarkersInVolume = numberOfMarkers-nbMarkersInVolume; /* read and parse position data for each marker */ for (unsigned int i = 0; i < nbMarkersInVolume; i++) { /* define local copies */ signed int number = 0; MarkerPointType markerPosition; /* read and parse the three 7 character translation values */ for (unsigned int i = 0; i < 3; i++) { m_TrackingDevice->Receive(&s, 7); // read the next position vector number reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); markerPosition[i] = number / 100.0; // the value is send with an implied decimal point with 2 digits to the right } markerPositions->push_back(markerPosition); } // end for all markers //m_TrackingDevice->Receive(&s, 1); // read the line feed character, that terminates each handle data //reply += s; // build complete command string // //END read Reply Option 1000 data m_TrackingDevice->Receive(&s, 4); // read system status reply += s; // build complete command string /* now the reply string is complete, perform crc checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay { returnValue = NDIOKAY; } else // return error in CRC { returnValue = NDICRCERROR; /* Invalidate all tools because the received data contained an error */ markerPositions->clear(); m_TrackingDevice->InvalidateAll(); } } // else /* cleanup and return */ m_TrackingDevice->Receive(&s, 1); // read the last linde feed (because the tracking system device is sometimes to slow to send it before we clear the buffer. In this case, the LF would remain in the receive buffer and be read as the first character of the next command m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::BX() { std::cout << "BX() not implemented yet, using TX() instead." << std::endl; return this->TX(); } mitk::NDIErrorCode mitk::NDIProtocol::VER(mitk::TrackingDeviceType& t) { if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking system /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "VER:4"; // command string format 1: with crc else fullcommand = "VER 4"; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } /* read number of handles returned */ std::string reply; m_TrackingDevice->Receive(&reply, 5); // read first 5 characters of reply (error beginning of version information) static const std::string error("ERROR"); if (error.compare(0, 6, reply) == 0) // ERROR case { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // no error, valid reply { std::string s; m_TrackingDevice->ReceiveLine(&s); // read until first LF character reply += s; std::string upperCaseReply; upperCaseReply.resize(reply.size()); std::transform (reply.begin(), reply.end(), upperCaseReply.begin(), toupper); // convert reply to uppercase to ease finding if (upperCaseReply.find("POLARIS") != std::string::npos) t = mitk::NDIPolaris; else if (upperCaseReply.find("AURORA") != std::string::npos) t = mitk::NDIAurora; else t = mitk::TrackingSystemNotSpecified; // check for "VICRA", "SPECTRA", "ACCEDO" /* do not check for remaining reply, do not check for CRC, just delete remaining reply */ itksys::SystemTools::Delay(500); // wait until reply should be finished m_TrackingDevice->ClearReceiveBuffer(); returnValue = NDIOKAY; } return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::POS3D(MarkerPointContainerType* markerPositions) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) { return TRACKINGDEVICENOTSET; } if (markerPositions == NULL) { std::cout << "ERROR: markerPositions==NULL" << std::endl; return NDIUNKNOWNERROR; } markerPositions->clear(); // empty point container /* try to obtain a porthandle */ if (m_TrackingDevice->GetToolCount() == 0) { std::cout << "ERROR: no tools present" << std::endl; return NDIUNKNOWNERROR; } const TrackingTool* t = m_TrackingDevice->GetTool(static_cast(0)); const NDIPassiveTool* t2 = dynamic_cast(t); if (t2 == NULL) { std::cout << "ERROR: no tool present" << std::endl; return NDIUNKNOWNERROR; } std::string portHandle = t2->GetPortHandle(); if (portHandle.size() == 0) { std::cout << "ERROR: no port handle" << std::endl; return NDIUNKNOWNERROR; } /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "3D:" + portHandle + "5"; // command string format 1: with crc else fullcommand = "3D " + portHandle + "5"; // command string format 2: without crc m_TrackingDevice->ClearReceiveBuffer(); returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); /* read number of markers returned */ std::string reply; std::string s; mitk::NDIErrorCode receivevalue = m_TrackingDevice->Receive(&reply, 3); // read first 3 characters of reply (error or number of markers returned) if(receivevalue != NDIOKAY) { std::cout << "ERROR: receive_value != NDIOKAY" << std::endl; return receivevalue; } static const std::string error("ERROR"); if (error.compare(0, 3, reply) == 0) { m_TrackingDevice->Receive(&s, 2); // read next characters ("OR" from ERROR) reply += s; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code { returnValue = this->GetErrorCode(&errorcode); } else // return error in CRC { returnValue = NDICRCERROR; } } else // transformation data is returned { signed int number = 0; //float localPos[3] = {0.0, 0.0, 0.0}; MarkerPointType p; - float lineSeparation = 0.0; + //float lineSeparation = 0.0; /* parse number of markers from first 3 characters */ std::stringstream converter; unsigned int numberOfMarkers = 0; converter << std::dec << reply; // insert reply into stringstream converter >> numberOfMarkers; // extract number of handles as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse 3D data for each marker */ for (unsigned int markerID = 0; markerID < numberOfMarkers; markerID++) // for each marker { m_TrackingDevice->Receive(&s, 1); // read line feed reply += s; // build complete command string /* read and parse the three 9 character translation values */ for (unsigned int i = 0; i < 3; i++) { receivevalue = m_TrackingDevice->Receive(&s, 9); // read the next position vector number if(receivevalue != NDIOKAY) { markerPositions->clear(); std::cout << "ERROR: receive_value != NDIOKAY" << std::endl; return receivevalue; } reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract the number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); p[i] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right } /* read and parse 4 character line separation value */ receivevalue = m_TrackingDevice->Receive(&s, 4); // read the line separation value if(receivevalue != NDIOKAY) { markerPositions->clear(); std::cout << "ERROR: receive_value != NDIOKAY" << std::endl; return receivevalue; } reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract the number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); - lineSeparation = number / 100.0; // the line separation value is send with an implied decimal point with 2 digits to the right + //lineSeparation = number / 100.0; // the line separation value is send with an implied decimal point with 2 digits to the right /* read and parse 1 character out of volume value */ receivevalue = m_TrackingDevice->Receive(&s, 1); // read the port status value if(receivevalue != NDIOKAY) { markerPositions->clear(); std::cout << std::endl << std::endl << std::endl << "ERROR: POS3D != NDIOKAY" << std::endl; return receivevalue; } reply += s; // build complete command string /* store the marker positions in the point container */ markerPositions->push_back(p); } //std::cout << "INFO: Found " << markerPositions->size() << " markers." << std::endl; /* now the reply string is complete, perform crc checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay { returnValue = NDIOKAY; } else // return error in CRC { returnValue = NDICRCERROR; std::cout << "ERROR: receive_value != NDIOKAY" << std::endl; /* delete all marker positions because the received data contained an error */ markerPositions->clear(); } } // else /* cleanup and return */ m_TrackingDevice->Receive(&s, 1); // read the last linde feed (because the tracking system device is sometimes to slow to send it before we clear the buffer. In this case, the LF would remain in the receive buffer and be read as the first character of the next command m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::GenericCommand(const std::string command, const std::string* parameter) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; std::string p; if (parameter != NULL) p = *parameter; else p = ""; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = command + ":" + p; // command string format 1: with crc else fullcommand = command + " " + p; // command string format 2: without crc m_TrackingDevice->ClearReceiveBuffer(); // This is a workaround for a linux specific issue: // after sending the TSTART command and expecting an "okay" there are some unexpected bytes left in the buffer. // this issue is explained in bug 11825 returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } /* wait for the trackingsystem to process the command */ itksys::SystemTools::Delay(100); /* read and parse the reply from tracking device */ // the reply for a generic command can be OKAY or ERROR## // so we can use the generic parse method for these replies this->ParseOkayError(); return returnValue; } unsigned int mitk::NDIProtocol::ByteToNbBitsOn(char& c) const { if(c == '0') return 0; else if (c == '1' || c == '2' || c == '4' || c == '8') return 1; else if (c == '3' || c == '5' || c == '9' || c == '6' || c == 'A' || c == 'C') return 2; else if (c == '7' || c == 'B' || c == 'D' || c == 'E') return 3; else if (c == 'F') return 4; else return 0; } mitk::NDIErrorCode mitk::NDIProtocol::ParseOkayError() { NDIErrorCode returnValue = NDIUNKNOWNERROR; /* read reply from tracking device */ // the reply is expected to be OKAY or ERROR## // define reply strings std::string reply; m_TrackingDevice->Receive(&reply, 4); // read first 4 characters of reply /* Parse reply from tracking device */ static const std::string okay("OKAYA896"); // OKAY is static, so we can perform a static crc check static const std::string error("ERROR"); if (okay.compare(0, 4, reply) == 0) // check for "OKAY": compare first 4 characters from okay with reply { // OKAY was found, now check the CRC16 too m_TrackingDevice->Receive(&reply, 4); // read 4 hexadecimal characters for CRC16 if (okay.compare(4, 4, reply, 0, 4) == 0) // first 4 from new reply should match last 4 from okay returnValue = NDIOKAY; else returnValue = NDICRCERROR; } else if (error.compare(0, 4, reply) == 0) // check for "ERRO" { char b; // The ERROR reply is not static, so we can not use a static crc check. m_TrackingDevice->ReceiveByte(&b); // read next character ("R" from ERROR) reply += b; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // something else, that we do not expect returnValue = NDIUNEXPECTEDREPLY; /* cleanup and return */ char b; m_TrackingDevice->ReceiveByte(&b); // read CR character m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::GetErrorCode(const std::string* input) { if (input->compare("01") == 0) return NDIINVALIDCOMMAND; else if (input->compare("02") == 0) return NDICOMMANDTOOLONG; else if (input->compare("03") == 0) return NDICOMMANDTOOSHORT; else if (input->compare("04") == 0) return NDICRCDOESNOTMATCH; else if (input->compare("05") == 0) return NDITIMEOUT; else if (input->compare("06") == 0) return NDIUNABLETOSETNEWCOMMPARAMETERS; else if (input->compare("07") == 0) return NDIINCORRECTNUMBEROFPARAMETERS; else if (input->compare("08") == 0) return NDIINVALIDPORTHANDLE; else if (input->compare("09") == 0) return NDIINVALIDTRACKINGPRIORITY; else if (input->compare("0A") == 0) return NDIINVALIDLED; else if (input->compare("0B") == 0) return NDIINVALIDLEDSTATE; else if (input->compare("0C") == 0) return NDICOMMANDINVALIDINCURRENTMODE; else if (input->compare("0D") == 0) return NDINOTOOLFORPORT; else if (input->compare("0E") == 0) return NDIPORTNOTINITIALIZED; // ... else if (input->compare("10") == 0) return NDISYSTEMNOTINITIALIZED; else if (input->compare("11") == 0) return NDIUNABLETOSTOPTRACKING; else if (input->compare("12") == 0) return NDIUNABLETOSTARTTRACKING; else if (input->compare("13") == 0) return NDIINITIALIZATIONFAILED; else if (input->compare("14") == 0) return NDIINVALIDVOLUMEPARAMETERS; else if (input->compare("16") == 0) return NDICANTSTARTDIAGNOSTICMODE; else if (input->compare("1B") == 0) return NDICANTINITIRDIAGNOSTICS; else if (input->compare("1F") == 0) return NDIFAILURETOWRITESROM; else if (input->compare("22") == 0) return NDIENABLEDTOOLSNOTSUPPORTED; else if (input->compare("23") == 0) return NDICOMMANDPARAMETEROUTOFRANGE; else if (input->compare("2A") == 0) return NDINOMEMORYAVAILABLE; else if (input->compare("2B") == 0) return NDIPORTHANDLENOTALLOCATED; else if (input->compare("2C") == 0) return NDIPORTHASBECOMEUNOCCUPIED; else if (input->compare("2D") == 0) return NDIOUTOFHANDLES; else if (input->compare("2E") == 0) return NDIINCOMPATIBLEFIRMWAREVERSIONS; else if (input->compare("2F") == 0) return NDIINVALIDPORTDESCRIPTION; else if (input->compare("32") == 0) return NDIINVALIDOPERATIONFORDEVICE; // ... else return NDIUNKNOWNERROR; } mitk::NDIErrorCode mitk::NDIProtocol::APIREV(std::string* revision) { if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking system /* send command */ std::string command; if (m_UseCRC) command = "APIREV:"; else command = "APIREV "; returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } //wait for tracking system to compute the output //itksys::SystemTools::Delay(100); /* read number of handles returned */ std::string reply; m_TrackingDevice->Receive(&reply, 5); //look for ERROR // read first 5 characters of reply (error beginning of version information) static const std::string error("ERROR"); if (error.compare(0, 6, reply) == 0) // ERROR case { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // no error, valid reply: expect something like: D.001.00450D4 (.. { std::string s; m_TrackingDevice->Receive(&s, 4); // read further reply += s; /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } *revision = reply; m_TrackingDevice->ClearReceiveBuffer(); return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::SFLIST(std::string* info) { if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking system /* send command */ std::string command; if (m_UseCRC) command = "SFLIST:03"; else command = "SFLIST 03"; returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } /* read number of handles returned */ std::string reply; m_TrackingDevice->Receive(&reply, 5); //look for "ERROR" static const std::string error("ERROR"); if (error.compare(0,6,reply) == 0) // ERROR case { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // no error, valid reply: expect numbers of devices in hex, and then info of each featured tracking volume { /* parse number of volumes from first character in hex */ std::stringstream converter; unsigned int numberOfVolumes = 0; converter << std::hex << reply[0]; // insert reply into stringstream converter >> numberOfVolumes; // extract number of handles as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); //reply currently contains the first 5 elements if (numberOfVolumes>0) { //for each featured volume for (unsigned int i = 0; iReceive(&s, 69);// 69 characters to get all dimensions plus two characters at the end: one reserved and one for metal resistance. reply += s; currentVolume += s; } else { //read to the end of the line from the last volume //(needed here, because if only one volume is supported, //then there is no lineending before CRC checksum std::string l; m_TrackingDevice->ReceiveLine(&l); reply += l; std::string s; m_TrackingDevice->Receive(&s, 73); //need total of 73 bytes for a volume reply += s; currentVolume += s; } //analyze volume here if (currentVolume.compare(0,1,mitk::DeviceDataPolarisOldModel.HardwareCode)==0) MITK_INFO<<"Standard volume supported \n"; else if (currentVolume.compare(0,3,mitk::DeviceDataPolarisSpectra.HardwareCode)==0) MITK_INFO<<"Spectra pyramid volume supported \n"; else if (currentVolume.compare(0,3,mitk::DeviceDataSpectraExtendedPyramid.HardwareCode)==0) MITK_INFO<<"Spectra extended pyramid volume supported \n"; else if (currentVolume.compare(0,1,mitk::DeviceDataPolarisVicra.HardwareCode)==0) MITK_INFO<<"Vicra volume supported \n"; else if (currentVolume.compare(0,1,mitk::DeviceDataAuroraPlanarCube.HardwareCode)==0) MITK_INFO<<"Cube volume supported \n"; else if (currentVolume.compare(0,1,mitk::DeviceDataAuroraPlanarDome.HardwareCode)==0) MITK_INFO<<"Dome volume supported \n"; else MITK_WARN<<"Message not understood!\n"; } } /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits /* CRC check is commented out at the moment, because there is a bug (see bug 16285 for more information) if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; */ returnValue = NDIOKAY; } *info = reply; m_TrackingDevice->ClearReceiveBuffer(); return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::VSEL(mitk::TrackingDeviceData deviceData) { if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking system //get information about the order of volumes from tracking device. Then choose the number needed for VSEL by the output and parameter "device" unsigned int numberOfVolumes; mitk::NDITrackingDevice::NDITrackingVolumeContainerType volumes; mitk::NDITrackingDevice::TrackingVolumeDimensionType volumesDimensions; if (!m_TrackingDevice->GetSupportedVolumes(&numberOfVolumes, &volumes, &volumesDimensions)) return returnValue; //interested in volumes(!) if (volumes.empty()) return returnValue; //with the order within volumes we can define our needed parameter for VSEL //find the index where volumes[n] == device unsigned int index = 1; //the index for VSEL starts at 1 mitk::NDITrackingDevice::NDITrackingVolumeContainerType::iterator it = volumes.begin(); while (it != volumes.end()) { if ((*it) == deviceData.Model) { MITK_INFO << deviceData.Model << " selected."; break; } it++, index++; } if (it == volumes.end() || index > numberOfVolumes) //not found / volume not supported return NDIINVALIDOPERATIONFORDEVICE; //index now contains the information on which position the desired volume is situated /* send command */ std::string command; if (m_UseCRC) command = "VSEL:"; else command = "VSEL "; //add index to command std::stringstream s; s << index; command += s.str(); returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } /* read number of handles returned */ std::string reply; m_TrackingDevice->Receive(&reply, 4); //look for "ERROR" or "OKAY" static const std::string error("ERRO"); if (error.compare(reply) == 0) // ERROR case { std::string s; m_TrackingDevice->Receive(&s, 1); //get the last "R" in "ERROR" reply += s; std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else { /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } m_TrackingDevice->ClearReceiveBuffer(); return returnValue; } diff --git a/Modules/IGT/files.cmake b/Modules/IGT/files.cmake index 57360ee6aa..7b6b8edf18 100644 --- a/Modules/IGT/files.cmake +++ b/Modules/IGT/files.cmake @@ -1,74 +1,75 @@ set(CPP_FILES Algorithms/mitkNavigationDataDisplacementFilter.cpp Algorithms/mitkNavigationDataEvaluationFilter.cpp Algorithms/mitkNavigationDataLandmarkTransformFilter.cpp Algorithms/mitkNavigationDataReferenceTransformFilter.cpp Algorithms/mitkNavigationDataToMessageFilter.cpp Algorithms/mitkNavigationDataToNavigationDataFilter.cpp Algorithms/mitkNavigationDataToPointSetFilter.cpp Algorithms/mitkNavigationDataTransformFilter.cpp Common/mitkIGTTimeStamp.cpp Common/mitkSerialCommunication.cpp + Common/mitkTrackingTypes.cpp DataManagement/mitkNavigationData.cpp DataManagement/mitkNavigationDataSource.cpp DataManagement/mitkNavigationTool.cpp DataManagement/mitkNavigationToolStorage.cpp DataManagement/mitkTrackingDeviceSourceConfigurator.cpp DataManagement/mitkTrackingDeviceSource.cpp ExceptionHandling/mitkIGTException.cpp ExceptionHandling/mitkIGTHardwareException.cpp ExceptionHandling/mitkIGTIOException.cpp IO/mitkNavigationDataPlayer.cpp IO/mitkNavigationDataPlayerBase.cpp IO/mitkNavigationDataRecorder.cpp IO/mitkNavigationDataSequentialPlayer.cpp IO/mitkNavigationToolReader.cpp IO/mitkNavigationToolStorageSerializer.cpp IO/mitkNavigationToolStorageDeserializer.cpp IO/mitkNavigationToolWriter.cpp Rendering/mitkCameraVisualization.cpp Rendering/mitkNavigationDataObjectVisualizationFilter.cpp TrackingDevices/mitkClaronTool.cpp TrackingDevices/mitkClaronTrackingDevice.cpp TrackingDevices/mitkInternalTrackingTool.cpp TrackingDevices/mitkNDIPassiveTool.cpp TrackingDevices/mitkNDIProtocol.cpp TrackingDevices/mitkNDITrackingDevice.cpp TrackingDevices/mitkTrackingDevice.cpp TrackingDevices/mitkTrackingTool.cpp TrackingDevices/mitkTrackingVolumeGenerator.cpp TrackingDevices/mitkVirtualTrackingDevice.cpp TrackingDevices/mitkVirtualTrackingTool.cpp ) set(RESOURCE_FILES ClaronMicron.stl IntuitiveDaVinci.stl NDIAurora.stl NDIAurora_Dome.stl NDIAuroraCompactFG_Dome.stl NDIAuroraPlanarFG_Dome.stl NDIAuroraTabletopFG_Dome.stl NDIAuroraTabletopFG_Prototype_Dome.stl NDIPolarisOldModel.stl NDIPolarisSpectra.stl NDIPolarisSpectraExtendedPyramid.stl NDIPolarisVicra.stl ) if(MITK_USE_MICRON_TRACKER) set(CPP_FILES ${CPP_FILES} TrackingDevices/mitkClaronInterface.cpp) else() set(CPP_FILES ${CPP_FILES} TrackingDevices/mitkClaronInterfaceStub.cpp) endif(MITK_USE_MICRON_TRACKER) if(MITK_USE_MICROBIRD_TRACKER) set(CPP_FILES ${CPP_FILES} TrackingDevices/mitkMicroBirdTrackingDevice.cpp) endif(MITK_USE_MICROBIRD_TRACKER) diff --git a/Modules/IGTBase/CMakeLists.txt b/Modules/IGTBase/CMakeLists.txt index 82475bf38b..e22a0f364c 100644 --- a/Modules/IGTBase/CMakeLists.txt +++ b/Modules/IGTBase/CMakeLists.txt @@ -1,3 +1,4 @@ MITK_CREATE_MODULE(MitkIGTBase DEPENDS Mitk + WARNINGS_AS_ERRORS ) diff --git a/Modules/ImageExtraction/CMakeLists.txt b/Modules/ImageExtraction/CMakeLists.txt index c35b7c0bc3..110757a2b4 100644 --- a/Modules/ImageExtraction/CMakeLists.txt +++ b/Modules/ImageExtraction/CMakeLists.txt @@ -1,9 +1,10 @@ MITK_CREATE_MODULE( ImageExtraction - DEPENDS MitkAlgorithmsExt + DEPENDS MitkAlgorithmsExt + WARNINGS_AS_ERRORS ) if(BUILD_TESTING) add_subdirectory(Testing) endif(BUILD_TESTING) diff --git a/Modules/ImageExtraction/mitkExtractDirectedPlaneImageFilterNew.cpp b/Modules/ImageExtraction/mitkExtractDirectedPlaneImageFilterNew.cpp index 41512e6df1..3c92d1308b 100644 --- a/Modules/ImageExtraction/mitkExtractDirectedPlaneImageFilterNew.cpp +++ b/Modules/ImageExtraction/mitkExtractDirectedPlaneImageFilterNew.cpp @@ -1,297 +1,297 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkExtractDirectedPlaneImageFilterNew.h" #include "mitkImageCast.h" #include "mitkImageTimeSelector.h" #include "itkImageRegionIterator.h" #include mitk::ExtractDirectedPlaneImageFilterNew::ExtractDirectedPlaneImageFilterNew() :m_CurrentWorldGeometry2D(NULL), m_ActualInputTimestep(-1) { MITK_WARN << "Class ExtractDirectedPlaneImageFilterNew is deprecated! Use ExtractSliceFilter instead."; } mitk::ExtractDirectedPlaneImageFilterNew::~ExtractDirectedPlaneImageFilterNew() { } void mitk::ExtractDirectedPlaneImageFilterNew::GenerateData(){ mitk::Image::ConstPointer inputImage = ImageToImageFilter::GetInput(0); if ( !inputImage ) { MITK_ERROR << "mitk::ExtractDirectedPlaneImageFilterNew: No input available. Please set the input!" << std::endl; itkExceptionMacro("mitk::ExtractDirectedPlaneImageFilterNew: No input available. Please set the input!"); return; } m_ImageGeometry = inputImage->GetGeometry(); //If no timestep is set, the lowest given will be selected const mitk::TimeGeometry* inputTimeGeometry = this->GetInput()->GetTimeGeometry(); if ( m_ActualInputTimestep == -1) { ScalarType time = m_CurrentWorldGeometry2D->GetTimeBounds()[0]; if ( time > ScalarTypeNumericTraits::NonpositiveMin() ) { m_ActualInputTimestep = inputTimeGeometry->TimePointToTimeStep( time ); } } if ( inputImage->GetDimension() > 4 || inputImage->GetDimension() < 2) { MITK_ERROR << "mitk::ExtractDirectedPlaneImageFilterNew:GenerateData works only with 3D and 3D+t images, sorry." << std::endl; itkExceptionMacro("mitk::ExtractDirectedPlaneImageFilterNew works only with 3D and 3D+t images, sorry."); return; } else if ( inputImage->GetDimension() == 4 ) { mitk::ImageTimeSelector::Pointer timeselector = mitk::ImageTimeSelector::New(); timeselector->SetInput( inputImage ); timeselector->SetTimeNr( m_ActualInputTimestep ); timeselector->UpdateLargestPossibleRegion(); inputImage = timeselector->GetOutput(); } else if ( inputImage->GetDimension() == 2) { mitk::Image::Pointer resultImage = ImageToImageFilter::GetOutput(); resultImage = const_cast( inputImage.GetPointer() ); ImageToImageFilter::SetNthOutput( 0, resultImage); return; } if ( !m_CurrentWorldGeometry2D ) { MITK_ERROR<< "mitk::ExtractDirectedPlaneImageFilterNew::GenerateData has no CurrentWorldGeometry2D set" << std::endl; return; } AccessFixedDimensionByItk( inputImage, ItkSliceExtraction, 3 ); }//Generate Data void mitk::ExtractDirectedPlaneImageFilterNew::GenerateOutputInformation () { Superclass::GenerateOutputInformation(); } /* * The desired slice is extracted by filling the image`s corresponding pixel values in an empty 2 dimensional itk::Image * Therefor the itk image`s extent in pixel (in each direction) is doubled and its spacing (also in each direction) is divided by two * (similar to the shannon theorem). */ template void mitk::ExtractDirectedPlaneImageFilterNew::ItkSliceExtraction (itk::Image* inputImage) { typedef itk::Image InputImageType; typedef itk::Image SliceImageType; typedef itk::ImageRegionConstIterator< SliceImageType > SliceIterator; //Creating an itk::Image that represents the sampled slice typename SliceImageType::Pointer resultSlice = SliceImageType::New(); typename SliceImageType::IndexType start; start[0] = 0; start[1] = 0; Point3D origin = m_CurrentWorldGeometry2D->GetOrigin(); Vector3D right = m_CurrentWorldGeometry2D->GetAxisVector(0); Vector3D bottom = m_CurrentWorldGeometry2D->GetAxisVector(1); //Calculation the sample-spacing, i.e the half of the smallest spacing existing in the original image Vector3D newPixelSpacing = m_ImageGeometry->GetSpacing(); float minSpacing = newPixelSpacing[0]; for (unsigned int i = 1; i < newPixelSpacing.Size(); i++) { if (newPixelSpacing[i] < minSpacing ) { minSpacing = newPixelSpacing[i]; } } newPixelSpacing[0] = 0.5*minSpacing; newPixelSpacing[1] = 0.5*minSpacing; newPixelSpacing[2] = 0.5*minSpacing; float pixelSpacing[2]; pixelSpacing[0] = newPixelSpacing[0]; pixelSpacing[1] = newPixelSpacing[1]; //Calculating the size of the sampled slice typename SliceImageType::SizeType size; Vector2D extentInMM; extentInMM[0] = m_CurrentWorldGeometry2D->GetExtentInMM(0); extentInMM[1] = m_CurrentWorldGeometry2D->GetExtentInMM(1); //The maximum extent is the lenght of the diagonal of the considered plane double maxExtent = sqrt(extentInMM[0]*extentInMM[0]+extentInMM[1]*extentInMM[1]); unsigned int xTranlation = (maxExtent-extentInMM[0]); unsigned int yTranlation = (maxExtent-extentInMM[1]); size[0] = (maxExtent+xTranlation)/newPixelSpacing[0]; size[1] = (maxExtent+yTranlation)/newPixelSpacing[1]; //Creating an ImageRegion Object typename SliceImageType::RegionType region; region.SetSize( size ); region.SetIndex( start ); //Defining the image`s extent and origin by passing the region to it and allocating memory for it resultSlice->SetRegions( region ); resultSlice->SetSpacing( pixelSpacing ); resultSlice->Allocate(); /* * Here we create an new geometry so that the transformations are calculated correctly (our resulting slice has a different bounding box and spacing) * The original current worldgeometry must be cloned because we have to keep the directions of the axis vector which represents the rotation */ right.Normalize(); bottom.Normalize(); //Here we translate the origin to adapt the new geometry to the previous calculated extent origin[0] -= xTranlation*right[0]+yTranlation*bottom[0]; origin[1] -= xTranlation*right[1]+yTranlation*bottom[1]; origin[2] -= xTranlation*right[2]+yTranlation*bottom[2]; //Putting it together for the new geometry mitk::Geometry3D::Pointer newSliceGeometryTest = dynamic_cast(m_CurrentWorldGeometry2D->Clone().GetPointer()); newSliceGeometryTest->ChangeImageGeometryConsideringOriginOffset(true); //Workaround because of BUG (#6505) newSliceGeometryTest->GetIndexToWorldTransform()->SetMatrix(m_CurrentWorldGeometry2D->GetIndexToWorldTransform()->GetMatrix()); //Workaround end newSliceGeometryTest->SetOrigin(origin); - ScalarType bounds[6]={0, size[0], 0, size[1], 0, 1}; + ScalarType bounds[6]={0, static_cast(size[0]), 0, static_cast(size[1]), 0, 1}; newSliceGeometryTest->SetBounds(bounds); newSliceGeometryTest->SetSpacing(newPixelSpacing); newSliceGeometryTest->Modified(); //Workaround because of BUG (#6505) itk::MatrixOffsetTransformBase::MatrixType tempTransform = newSliceGeometryTest->GetIndexToWorldTransform()->GetMatrix(); //Workaround end /* * Now we iterate over the recently created slice. * For each slice - pixel we check whether there is an according * pixel in the input - image which can be set in the slice. * In this way a slice is sampled out of the input - image regrading to the given PlaneGeometry */ Point3D currentSliceIndexPointIn2D; Point3D currentImageWorldPointIn3D; typename InputImageType::IndexType inputIndex; SliceIterator sliceIterator ( resultSlice, resultSlice->GetLargestPossibleRegion() ); sliceIterator.GoToBegin(); while ( !sliceIterator.IsAtEnd() ) { /* * Here we add 0.5 to to assure that the indices are correctly transformed. * (Because of the 0.5er Bug) */ currentSliceIndexPointIn2D[0] = sliceIterator.GetIndex()[0]+0.5; currentSliceIndexPointIn2D[1] = sliceIterator.GetIndex()[1]+0.5; currentSliceIndexPointIn2D[2] = 0; newSliceGeometryTest->IndexToWorld( currentSliceIndexPointIn2D, currentImageWorldPointIn3D ); m_ImageGeometry->WorldToIndex( currentImageWorldPointIn3D, inputIndex); if ( m_ImageGeometry->IsIndexInside( inputIndex )) { resultSlice->SetPixel( sliceIterator.GetIndex(), inputImage->GetPixel(inputIndex) ); } else { resultSlice->SetPixel( sliceIterator.GetIndex(), 0); } ++sliceIterator; } Image::Pointer resultImage = ImageToImageFilter::GetOutput(); GrabItkImageMemory(resultSlice, resultImage, NULL, false); resultImage->SetClonedGeometry(newSliceGeometryTest); //Workaround because of BUG (#6505) resultImage->GetGeometry()->GetIndexToWorldTransform()->SetMatrix(tempTransform); //Workaround end } ///**TEST** May ba a little bit more efficient but doesn`t already work/ //right.Normalize(); //bottom.Normalize(); //Point3D currentImagePointIn3D = origin /*+ bottom*newPixelSpacing*/; //unsigned int columns ( 0 ); /**ENDE**/ /****TEST***/ //SliceImageType::IndexType index = sliceIterator.GetIndex(); //if ( columns == (extentInPixel[0]) ) //{ //If we are at the end of a row, then we have to go to the beginning of the next row //currentImagePointIn3D = origin; //currentImagePointIn3D += newPixelSpacing[1]*bottom*index[1]; //columns = 0; //m_ImageGeometry->WorldToIndex(currentImagePointIn3D, inputIndex); //} //else //{ //// //if ( columns != 0 ) //{ //currentImagePointIn3D += newPixelSpacing[0]*right; //} //m_ImageGeometry->WorldToIndex(currentImagePointIn3D, inputIndex); //} //if ( m_ImageGeometry->IsIndexInside( inputIndex )) //{ //resultSlice->SetPixel( sliceIterator.GetIndex(), inputImage->GetPixel(inputIndex) ); //} //else if (currentImagePointIn3D == origin) //{ //Point3D temp; //temp[0] = bottom[0]*newPixelSpacing[0]*0.5; //temp[1] = bottom[1]*newPixelSpacing[1]*0.5; //temp[2] = bottom[2]*newPixelSpacing[2]*0.5; //origin[0] += temp[0]; //origin[1] += temp[1]; //origin[2] += temp[2]; //currentImagePointIn3D = origin; //m_ImageGeometry->WorldToIndex(currentImagePointIn3D, inputIndex); //if ( m_ImageGeometry->IsIndexInside( inputIndex )) //{ //resultSlice->SetPixel( sliceIterator.GetIndex(), inputImage->GetPixel(inputIndex) ); //} //} /****TEST ENDE****/ diff --git a/Modules/ImageStatistics/CMakeLists.txt b/Modules/ImageStatistics/CMakeLists.txt index 4ed6da03a3..bbc12f2033 100644 --- a/Modules/ImageStatistics/CMakeLists.txt +++ b/Modules/ImageStatistics/CMakeLists.txt @@ -1,9 +1,10 @@ MITK_CREATE_MODULE( ImageStatistics - DEPENDS Mitk ImageExtraction PlanarFigure + DEPENDS Mitk ImageExtraction PlanarFigure + WARNINGS_AS_ERRORS ) if(BUILD_TESTING) add_subdirectory(Testing) endif(BUILD_TESTING) diff --git a/Modules/IpPicSupportIO/Internal/mitkIpPicGet.c b/Modules/IpPicSupportIO/Internal/mitkIpPicGet.c index db1e1b7b28..9839f1346c 100755 --- a/Modules/IpPicSupportIO/Internal/mitkIpPicGet.c +++ b/Modules/IpPicSupportIO/Internal/mitkIpPicGet.c @@ -1,646 +1,638 @@ /***************************************************************************** Copyright (c) 1993-2000, Div. Medical and Biological Informatics, Deutsches Krebsforschungszentrum, Heidelberg, Germany All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - All advertising materials mentioning features or use of this software must display the following acknowledgement: "This product includes software developed by the Div. Medical and Biological Informatics, Deutsches Krebsforschungszentrum, Heidelberg, Germany." - Neither the name of the Deutsches Krebsforschungszentrum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE DIVISION MEDICAL AND BIOLOGICAL INFORMATICS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DIVISION MEDICAL AND BIOLOGICAL INFORMATICS, THE DEUTSCHES KREBSFORSCHUNGSZENTRUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Send comments and/or bug reports to: mbi-software@dkfz-heidelberg.de *****************************************************************************/ /* * $RCSfile$ *-------------------------------------------------------------------- * DESCRIPTION * reads a PicFile from disk * * $Log$ * Revision 1.11 2006/09/18 13:55:50 nolden * FIX: removed define USE_ITKZLIB, crashes on windows * * Revision 1.10 2006/09/18 12:57:40 nolden * CHG: added USE_ITKZLIB define * * Revision 1.9 2006/09/15 17:29:57 nolden * CHG: simplified ipPic include for non-plugin builds * * Revision 1.8 2006/01/10 16:53:09 hasselberg * FIX: ANSI C conformance (required for MSVC7.0) * * Revision 1.7 2005/12/21 08:28:42 max * FIX: renamed ipSize_t to size_t, since ipSize_t is only available in the 64Bit branch op ipPic. * * Revision 1.6 2005/12/20 12:56:35 max * ENH: Added possibility to read beyond 2GB limit. * * Revision 1.5 2005/10/19 11:19:43 ivo * ENH: Chili ipPic compatibility * * Revision 1.4 2005/10/13 11:21:12 ivo * FIX: linker warning (unused var) * * Revision 1.3 2005/10/13 08:35:47 ivo * FIX: warnings * * Revision 1.2 2005/10/13 07:52:55 max * fixed warnings Algorithms/mitkImageFilters/mitkImageToSurfaceFilter.h Algorithms/mitkImageFilters/mitkManualSegmentationToSurfaceFilter.h Algorithms/mitkImageIO/mitkIpPicGet.c * * Revision 1.1 2005/10/12 19:08:51 ivo * ADD: substitute for mitkIpPicGet: original always deletes data pointer and re-allocs it using malloc, which is not compatible with mitk::ImageDataItem. * * Revision 1.16 2004/01/16 22:11:59 andre * big endian bug fix * * Revision 1.15 2002/11/13 17:53:00 ivo * new ipPic added. * * Revision 1.13 2002/02/27 09:02:56 andre * zlib changes * * Revision 1.12 2002/02/27 08:54:43 andre * zlib changes * * Revision 1.11 2000/05/04 12:52:37 ivo * inserted BSD style license * * Revision 1.10 2000/02/16 14:29:20 andre * *** empty log message *** * * Revision 1.9 1999/11/28 18:22:42 andre * *** empty log message *** * * Revision 1.8 1999/11/28 16:29:43 andre * *** empty log message *** * * Revision 1.7 1999/11/27 20:03:48 andre * *** empty log message *** * * Revision 1.6 1999/11/27 19:29:43 andre * *** empty log message *** * * Revision 1.5 1998/09/04 17:45:54 andre * *** empty log message *** * * Revision 1.4 1998/05/06 14:13:15 andre * added info->pixel_start_in_file * * Revision 1.3 1997/10/20 13:35:39 andre * *** empty log message *** * * Revision 1.2 1997/09/15 13:21:13 andre * switched to new what string format * * Revision 1.1.1.1 1997/09/06 19:09:59 andre * initial import * * Revision 0.1 1993/04/02 16:18:39 andre * now works on PC, SUN and DECstation * * Revision 0.0 1993/03/26 12:56:26 andre * Initial revision, NO error checking * * *-------------------------------------------------------------------- * COPYRIGHT (c) 1993 by DKFZ (Dept. MBI) Heidelberg, FRG */ #ifdef CHILIPLUGIN #include mitkIpPicDescriptor * MITKipPicGetTags( char *infile_name, mitkIpPicDescriptor *pic ) { return mitkIpPicGetTags(infile_name, pic); } _mitkIpPicTagsElement_t * _MITKipPicReadTags( _mitkIpPicTagsElement_t *head, mitkIpUInt4_t bytes_to_read, FILE *stream, char encryption_type ) { return _mitkIpPicReadTags(head, bytes_to_read, stream, encryption_type); } //mitkIpPicDescriptor * _MITKipPicOldGet( FILE *infile, mitkIpPicDescriptor *pic ) //{ // return _mitkIpPicOldGet(infile, pic); //} mitkIpPicDescriptor * MITKipPicGet( char *infile_name, mitkIpPicDescriptor *pic ) { if(pic != NULL) { mitkIpPicDescriptor * tmpPic; size_t sizePic, sizeTmpPic; tmpPic = mitkIpPicGet(infile_name, NULL); sizePic = _mitkIpPicSize(pic); sizeTmpPic = _mitkIpPicSize(tmpPic); if(sizePic != sizeTmpPic) { fprintf( stderr, "Critical: MITKipPicGet was given a pic with wrong size\n" ); return tmpPic; } memcpy(pic->data, tmpPic->data, sizePic); pic->info->tags_head = tmpPic->info->tags_head; tmpPic->info->tags_head = NULL; mitkIpPicFree(tmpPic); return pic; } else return mitkIpPicGet(infile_name, pic); } #else #include "mitkIpPic.h" #ifdef DOS #include "mitkIpPicOP.h" #else #include "mitkIpPicOldP.h" #endif char * MITKstrdup (const char * string) { char *memory; if (string==NULL) return NULL; if ( ( memory = (char*)malloc(strlen(string) + 1) ) ) return strcpy(memory,string); return NULL; } _mitkIpPicTagsElement_t * _MITKipPicReadTags( _mitkIpPicTagsElement_t *head, mitkIpUInt4_t bytes_to_read, FILE *stream, char encryption_type ); mitkIpPicDescriptor * _MITKipPicOldGet( FILE *infile, mitkIpPicDescriptor *pic ) { _mitkIpPicOldHeader old_pic; size_t elements; size_t size = 0; size_t number_of_elements; size_t bytes_per_element; size_t number_of_bytes; size_t block_size; size_t number_of_blocks; size_t remaining_bytes; size_t bytes_read; size_t block_nr; - size_t ignored; + //size_t ignored; mitkIpUInt1_t* data; if( pic == NULL ) pic = mitkIpPicNew(); else { size= _mitkIpPicSize(pic); if(pic->data == NULL) size = 0; } /* read infile */ - ignored = mitkIpFReadLE( &(old_pic.dummy1), sizeof(mitkIpUInt4_t), 4, infile ); + mitkIpFReadLE( &(old_pic.dummy1), sizeof(mitkIpUInt4_t), 4, infile ); if( old_pic.conv <= 0 || old_pic.conv > 6 ) { old_pic.conv = 3; old_pic.rank = 2; } - ignored = mitkIpFReadLE( &(old_pic.n1), sizeof(mitkIpUInt4_t), old_pic.rank, infile ); + mitkIpFReadLE( &(old_pic.n1), sizeof(mitkIpUInt4_t), old_pic.rank, infile ); if( old_pic.rank == 3 && old_pic.n3 == 1 ) old_pic.rank = 2; - ignored = mitkIpFReadLE( &(old_pic.type), sizeof(mitkIpUInt4_t), 3, infile ); + mitkIpFReadLE( &(old_pic.type), sizeof(mitkIpUInt4_t), 3, infile ); if( old_pic.ntxt ) { fseek( infile, old_pic.ltxt, SEEK_CUR ); } elements = old_pic.n1 * old_pic.n2; if( old_pic.rank == 3 ) elements *= old_pic.n3; if((size == 0) || (size != _mitkIpPicSize(pic))) { if( pic->data != NULL ) { free( pic->data ); pic->data = NULL; } pic->data = malloc( _mitkIpPicSize(pic) ); } /* * data is read in blocks of size 'block_size' to prevent from * errors due to large file sizes (>=2GB) */ number_of_elements = elements; bytes_per_element = old_pic.type; number_of_bytes = number_of_elements * bytes_per_element; block_size = 1024*1024; /* Use 1 MB blocks. Make sure that block size is smaller than 2^31 */ number_of_blocks = number_of_bytes / block_size; remaining_bytes = number_of_bytes % block_size; bytes_read = 0; block_nr = 0; data = (mitkIpUInt1_t*) pic->data; for ( block_nr = 0 ; block_nr < number_of_blocks ; ++block_nr ) bytes_read += mitkIpPicFReadLE( data + ( block_nr * block_size ), 1, (unsigned int) block_size, infile ); bytes_read += mitkIpPicFReadLE( data + ( number_of_blocks * block_size ), 1, (unsigned int) remaining_bytes, infile ); if ( bytes_read != number_of_bytes ) fprintf( stderr, "Error while reading (ferror indicates %u), only %lu bytes were read! Eof indicator is %u.\n", ferror(infile), (long unsigned int)bytes_read, feof(infile) ); /* convert to the new pic3 format */ if( old_pic.type == 1 ) pic->type = mitkIpPicUInt; else pic->type = (mitkIpPicType_t)old_pic.conv; pic->bpe = old_pic.type*8; pic->dim = old_pic.rank; pic->n[0] = old_pic.n1; pic->n[1] = old_pic.n2; pic->n[2] = old_pic.n3; pic->n[3] = old_pic.n4; pic->n[4] = old_pic.n5; pic->n[5] = old_pic.n6; pic->n[6] = old_pic.n7; pic->n[7] = old_pic.n8; return( pic ); } mitkIpUInt4_t _MITKipPicTSVElements( mitkIpPicTSV_t *tsv ) { mitkIpUInt4_t i; mitkIpUInt4_t elements; if( tsv->dim == 0 ) return( 0 ); elements = tsv->n[0]; for( i = 1; i < tsv->dim; i++ ) elements *= tsv->n[i]; return( elements ); } _mitkIpPicTagsElement_t * _MITKipPicReadTags( _mitkIpPicTagsElement_t *head, mitkIpUInt4_t bytes_to_read, FILE *stream, char encryption_type ) { while( bytes_to_read > 0 ) { mitkIpPicTSV_t *tsv; mitkIpPicTag_t tag_name; mitkIpUInt4_t len; - size_t ignored; - /*printf( "bytes_to_read: %i\n", bytes_to_read ); */ tsv = malloc( sizeof(mitkIpPicTSV_t) ); - ignored = mitkIpPicFRead( &tag_name, 1, sizeof(mitkIpPicTag_t), stream ); + mitkIpPicFRead( &tag_name, 1, sizeof(mitkIpPicTag_t), stream ); strncpy( tsv->tag, tag_name, _mitkIpPicTAGLEN ); tsv->tag[_mitkIpPicTAGLEN] = '\0'; - ignored = mitkIpPicFReadLE( &len, sizeof(mitkIpUInt4_t), 1, stream ); + mitkIpPicFReadLE( &len, sizeof(mitkIpUInt4_t), 1, stream ); - ignored = mitkIpPicFReadLE( &(tsv->type), sizeof(mitkIpUInt4_t), 1, stream ); - ignored = mitkIpPicFReadLE( &(tsv->bpe), sizeof(mitkIpUInt4_t), 1, stream ); - ignored = mitkIpPicFReadLE( &(tsv->dim), sizeof(mitkIpUInt4_t), 1, stream ); + mitkIpPicFReadLE( &(tsv->type), sizeof(mitkIpUInt4_t), 1, stream ); + mitkIpPicFReadLE( &(tsv->bpe), sizeof(mitkIpUInt4_t), 1, stream ); + mitkIpPicFReadLE( &(tsv->dim), sizeof(mitkIpUInt4_t), 1, stream ); - ignored = mitkIpPicFReadLE( &(tsv->n), sizeof(mitkIpUInt4_t), tsv->dim, stream ); + mitkIpPicFReadLE( &(tsv->n), sizeof(mitkIpUInt4_t), tsv->dim, stream ); if( tsv->type == mitkIpPicTSV ) { tsv->value = NULL; tsv->value = _mitkIpPicReadTags( tsv->value, len - 3 * sizeof(mitkIpUInt4_t) - tsv->dim * sizeof(mitkIpUInt4_t), stream, encryption_type ); } else { mitkIpUInt4_t elements; elements = _MITKipPicTSVElements( tsv ); if( tsv->type == mitkIpPicASCII || tsv->type == mitkIpPicNonUniform ) tsv->bpe = 8; assert( elements * tsv->bpe / 8 == len - 3 * sizeof(mitkIpUInt4_t) - tsv->dim * sizeof(mitkIpUInt4_t) ); if( tsv->type == mitkIpPicASCII ) tsv->value = malloc( elements+1 * tsv->bpe / 8 ); else tsv->value = malloc( elements * tsv->bpe / 8 ); - ignored = mitkIpPicFReadLE( tsv->value, tsv->bpe / 8, elements, stream ); + mitkIpPicFReadLE( tsv->value, tsv->bpe / 8, elements, stream ); if( tsv->type == mitkIpPicASCII ) ((char *)(tsv->value))[elements] = '\0'; if( encryption_type == 'e' && ( tsv->type == mitkIpPicASCII || tsv->type == mitkIpPicNonUniform ) ) { if( tsv->type == mitkIpPicNonUniform ) { sprintf( tsv->tag, "*** ENCRYPTED ***" ); tsv->tag[_mitkIpPicTAGLEN] = '\0'; } free( tsv->value ); tsv->value = MITKstrdup( "*** ENCRYPTED ***" ); tsv->n[0] = (mitkIpUInt4_t)strlen(tsv->value); tsv->type = mitkIpPicASCII; tsv->dim = 1; } } head = _mitkIpPicInsertTag( head, tsv ); bytes_to_read -= 32 /* name */ + sizeof(mitkIpUInt4_t) /* len */ + len; /* type + bpe + dim + n[] + data */ } return( head ); } mitkIpPicDescriptor * MITKipPicGetTags( char *infile_name, mitkIpPicDescriptor *pic ) { mitkIpPicFile_t infile; mitkIpPicTag_t tag_name; mitkIpUInt4_t dummy; mitkIpUInt4_t len; mitkIpUInt4_t dim; mitkIpUInt4_t n[_mitkIpPicNDIM]; mitkIpUInt4_t to_read; - size_t ignored; - infile = _mitkIpPicOpenPicFileIn( infile_name ); if( infile == NULL ) { /*ipPrintErr( "mitkIpPicGetTags: sorry, error opening infile\n" );*/ return( NULL ); } if( pic != NULL ) pic->info->write_protect = mitkIpFalse; /* read infile */ - ignored = mitkIpPicFRead( &(tag_name[0]), 1, 4, infile ); + mitkIpPicFRead( &(tag_name[0]), 1, 4, infile ); if( strncmp( mitkIpPicVERSION, tag_name, 4 ) != 0 ) { if( infile != stdin ) mitkIpPicFClose( infile ); return( pic ); } if( pic == NULL ) pic = mitkIpPicNew(); - ignored = mitkIpPicFRead( &(tag_name[4]), 1, sizeof(mitkIpPicTag_t)-4, infile ); + mitkIpPicFRead( &(tag_name[4]), 1, sizeof(mitkIpPicTag_t)-4, infile ); /*strncpy( pic->info->version, tag_name, _mitkIpPicTAGLEN );*/ - ignored = mitkIpPicFReadLE( &len, sizeof(mitkIpUInt4_t), 1, infile ); + mitkIpPicFReadLE( &len, sizeof(mitkIpUInt4_t), 1, infile ); - ignored = mitkIpPicFReadLE( &dummy, sizeof(mitkIpUInt4_t), 1, infile ); - ignored = mitkIpPicFReadLE( &dummy, sizeof(mitkIpUInt4_t), 1, infile ); - ignored = mitkIpPicFReadLE( &dim, sizeof(mitkIpUInt4_t), 1, infile ); + mitkIpPicFReadLE( &dummy, sizeof(mitkIpUInt4_t), 1, infile ); + mitkIpPicFReadLE( &dummy, sizeof(mitkIpUInt4_t), 1, infile ); + mitkIpPicFReadLE( &dim, sizeof(mitkIpUInt4_t), 1, infile ); - ignored = mitkIpPicFReadLE( n, sizeof(mitkIpUInt4_t), dim, infile ); + mitkIpPicFReadLE( n, sizeof(mitkIpUInt4_t), dim, infile ); to_read = len - 3 * sizeof(mitkIpUInt4_t) - dim * sizeof(mitkIpUInt4_t); pic->info->tags_head = _MITKipPicReadTags( pic->info->tags_head, to_read, infile, mitkIpPicEncryptionType(pic) ); pic->info->pixel_start_in_file = mitkIpPicFTell( infile ); if( infile != stdin ) mitkIpPicFClose( infile ); return( pic ); } mitkIpPicDescriptor * MITKipPicGet( char *infile_name, mitkIpPicDescriptor *pic ) { mitkIpPicFile_t infile; mitkIpPicTag_t tag_name; mitkIpUInt4_t len; mitkIpUInt4_t to_read; size_t size; size_t number_of_elements; size_t bytes_per_element; size_t number_of_bytes; size_t block_size; size_t number_of_blocks; size_t remaining_bytes; size_t bytes_read; size_t block_nr; mitkIpUInt1_t* data; - size_t ignored; - infile = _mitkIpPicOpenPicFileIn( infile_name ); if( !infile ) { /*ipPrintErr( "mitkIpPicGet: sorry, error opening infile\n" );*/ return( NULL ); } /* read infile */ - ignored = mitkIpPicFRead( tag_name, 1, 4, infile ); + mitkIpPicFRead( tag_name, 1, 4, infile ); if( strncmp( "\037\213", tag_name, 2 ) == 0 ) { fprintf( stderr, "mitkIpPicGetHeader: sorry, can't read compressed file\n" ); return( NULL ); } else if( strncmp( mitkIpPicVERSION, tag_name, 4 ) != 0 ) { #ifndef CHILIPLUGIN if( pic == NULL ) pic = _MITKipPicOldGet( infile, NULL ); else _MITKipPicOldGet( infile, pic ); if( infile != stdin ) mitkIpPicFClose( infile ); #else return NULL; #endif return( pic ); } size = 0; if( pic == NULL ) pic = mitkIpPicNew(); else { size= _mitkIpPicSize(pic); if(pic->data == NULL) size = 0; } if( pic->info != NULL ) { _mitkIpPicFreeTags( pic->info->tags_head ); pic->info->tags_head = NULL; } - ignored = mitkIpPicFRead( &(tag_name[4]), 1, sizeof(mitkIpPicTag_t)-4, infile ); + mitkIpPicFRead( &(tag_name[4]), 1, sizeof(mitkIpPicTag_t)-4, infile ); strncpy( pic->info->version, tag_name, _mitkIpPicTAGLEN ); - ignored = mitkIpPicFReadLE( &len, sizeof(mitkIpUInt4_t), 1, infile ); - - ignored = mitkIpPicFReadLE( &(pic->type), sizeof(mitkIpUInt4_t), 1, infile ); - ignored = mitkIpPicFReadLE( &(pic->bpe), sizeof(mitkIpUInt4_t), 1, infile ); - ignored = mitkIpPicFReadLE( &(pic->dim), sizeof(mitkIpUInt4_t), 1, infile ); + mitkIpPicFReadLE( &len, sizeof(mitkIpUInt4_t), 1, infile ); - ignored = mitkIpPicFReadLE( &(pic->n), sizeof(mitkIpUInt4_t), pic->dim, infile ); + mitkIpPicFReadLE( &(pic->type), sizeof(mitkIpUInt4_t), 1, infile ); + mitkIpPicFReadLE( &(pic->bpe), sizeof(mitkIpUInt4_t), 1, infile ); + mitkIpPicFReadLE( &(pic->dim), sizeof(mitkIpUInt4_t), 1, infile ); - (void *)ignored; + mitkIpPicFReadLE( &(pic->n), sizeof(mitkIpUInt4_t), pic->dim, infile ); to_read = len - 3 * sizeof(mitkIpUInt4_t) - pic->dim * sizeof(mitkIpUInt4_t); #if 0 mitkIpPicFSeek( infile, to_read, SEEK_CUR ); #else pic->info->tags_head = _MITKipPicReadTags( pic->info->tags_head, to_read, infile, mitkIpPicEncryptionType(pic) ); #endif pic->info->write_protect = mitkIpFalse; if((size == 0) || (size != _mitkIpPicSize(pic))) { if( pic->data != NULL ) { free( pic->data ); pic->data = NULL; } #ifdef WIN if ((pic->hdata = GlobalAlloc( GMEM_MOVEABLE, _mitkIpPicSize(pic) )) != 0) pic->data = GlobalLock( pic->hdata ); #else pic->data = malloc( _mitkIpPicSize(pic) ); #endif } pic->info->pixel_start_in_file = mitkIpPicFTell( infile ); /* * data is read in blocks of size 'block_size' to prevent from * errors due to large file sizes (>=2GB) */ number_of_elements = _mitkIpPicElements(pic); bytes_per_element = pic->bpe / 8; number_of_bytes = number_of_elements * bytes_per_element; block_size = 1024*1024; /* Use 1 MB blocks. Make sure that block size is smaller than 2^31 */ number_of_blocks = number_of_bytes / block_size; remaining_bytes = number_of_bytes % block_size; bytes_read = 0; block_nr = 0; /*printf( "mitkIpPicGet: number of blocks to read is %ul.\n", number_of_blocks ); */ data = (mitkIpUInt1_t*) pic->data; if( pic->type == mitkIpPicNonUniform ) { for ( block_nr = 0 ; block_nr < number_of_blocks ; ++block_nr ) bytes_read += mitkIpPicFRead( data + ( block_nr * block_size ), 1, (unsigned int) block_size, infile ); bytes_read += mitkIpPicFRead( data + ( number_of_blocks * block_size ), 1, (unsigned int) remaining_bytes, infile ); } else { for ( block_nr = 0 ; block_nr < number_of_blocks ; ++block_nr ) bytes_read += mitkIpPicFReadLE( data + ( block_nr * block_size ), 1, (unsigned int) block_size, infile ); bytes_read += mitkIpPicFReadLE( data + ( number_of_blocks * block_size ), 1, (unsigned int) remaining_bytes, infile ); } if ( bytes_read != number_of_bytes ) { fprintf( stderr, "Error while reading, only %lu bytes were read! Eof indicator is %u.\n", (long unsigned int)bytes_read, mitkIpPicFEOF(infile) ); #ifndef USE_ZLIB fprintf( stderr, "(ferror indicates %u).\n", ferror(infile)); #endif } if( infile != stdin ) mitkIpPicFClose( infile ); #ifdef WIN GlobalUnlock( pic->hdata ); #endif return( pic ); } #endif // CHILIPLUGIN diff --git a/Modules/Overlays/CMakeLists.txt b/Modules/Overlays/CMakeLists.txt index a3f96543e5..2855d35fd4 100644 --- a/Modules/Overlays/CMakeLists.txt +++ b/Modules/Overlays/CMakeLists.txt @@ -1,4 +1,5 @@ MITK_CREATE_MODULE( Overlays DEPENDS Qmitk QT4_MODULES QtGui + WARNINGS_AS_ERRORS ) diff --git a/Modules/PlanarFigure/Algorithms/mitkImageToPlanarFigureFilter.h b/Modules/PlanarFigure/Algorithms/mitkImageToPlanarFigureFilter.h index 5d69071133..f7006ce3b5 100644 --- a/Modules/PlanarFigure/Algorithms/mitkImageToPlanarFigureFilter.h +++ b/Modules/PlanarFigure/Algorithms/mitkImageToPlanarFigureFilter.h @@ -1,80 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef IMAGETOPLANARFIGUREFILTER_H_HEADER_INCLUDED_C1E5E869 #define IMAGETOPLANARFIGUREFILTER_H_HEADER_INCLUDED_C1E5E869 #include "mitkCommon.h" #include "mitkPlanarFigureSource.h" #include "mitkImage.h" namespace mitk { //##Documentation //## @brief Superclass of all classes having one or more Images as input and //## generating PlanarFigures as output //## @ingroup PlanarFigure class PlanarFigure_EXPORT ImageToPlanarFigureFilter : public PlanarFigureSource { public: mitkClassMacro(ImageToPlanarFigureFilter,PlanarFigureSource); //itkNewMacro(Self); /** Some convenient typedefs. */ typedef mitk::Image InputImageType; typedef InputImageType::Pointer InputImagePointer; typedef InputImageType::ConstPointer InputImageConstPointer; typedef SlicedData::RegionType InputImageRegionType; /** Set/Get the image input of this process object. */ + using Superclass::SetInput; virtual void SetInput( const InputImageType *image); virtual void SetInput( unsigned int, const InputImageType * image); const InputImageType * GetInput(void); const InputImageType * GetInput(unsigned int idx); protected: ImageToPlanarFigureFilter(); ~ImageToPlanarFigureFilter(); virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; /** What is the input requested region that is required to produce the * output requested region? The base assumption for image processing * filters is that the input requested region can be set to match the * output requested region. If a filter requires more input (for instance * a filter that uses neighborhoods needs more input than output to avoid * introducing artificial boundary conditions) or less input (for instance * a magnify filter) will have to override this method. In doing so, it * should call its superclass' implementation as its first step. Note that * this imaging filters operate differently than the classes to this * point in the class hierachy. Up till now, the base assumption has been * that the largest possible region will be requested of the input. * * \sa ProcessObject::GenerateInputRequestedRegion(), * ImageSource::GenerateInputRequestedRegion() */ virtual void GenerateInputRequestedRegion(); private: void operator=(const Self&); //purposely not implemented }; } // namespace mitk #endif /* IMAGETOPLANARFIGUREFILTER_H_HEADER_INCLUDED_C1E5E869 */ diff --git a/Modules/PlanarFigure/Algorithms/mitkPlanarFigureToPlanarFigureFilter.h b/Modules/PlanarFigure/Algorithms/mitkPlanarFigureToPlanarFigureFilter.h index dc22b2f300..ebdd834b42 100644 --- a/Modules/PlanarFigure/Algorithms/mitkPlanarFigureToPlanarFigureFilter.h +++ b/Modules/PlanarFigure/Algorithms/mitkPlanarFigureToPlanarFigureFilter.h @@ -1,61 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKPlanarFigureToPlanarFigureFilter_H_HEADER_INCLUDED #define MITKPlanarFigureToPlanarFigureFilter_H_HEADER_INCLUDED #include "mitkPlanarFigure.h" #include "PlanarFigureExports.h" #include "mitkCommon.h" #include "mitkPlanarFigureSource.h" namespace mitk { /** * @brief Base class for all filters which have an object of type * mitk::PlanarFigure as input and output * * Base class for all filters which have an object of type mitk::PlanarFigure * as input and output. * @ingroup PlanarFigure_EXPORT */ class PlanarFigure_EXPORT PlanarFigureToPlanarFigureFilter : public mitk::PlanarFigureSource { public: mitkClassMacro( PlanarFigureToPlanarFigureFilter, PlanarFigureSource ); itkNewMacro( Self ); typedef PlanarFigure InputType; typedef InputType::Pointer InputTypePointer; typedef itk::DataObject::Pointer DataObjectPointer; + using Superclass::SetInput; + virtual void SetInput( const InputType* figure ); virtual void SetInput( unsigned int idx, const InputType* figure ); virtual const InputType* GetInput(); virtual const InputType* GetInput( unsigned int idx ); virtual void CreateOutputsForAllInputs(); protected: PlanarFigureToPlanarFigureFilter(); virtual ~PlanarFigureToPlanarFigureFilter(); }; } // namespace mitk #endif diff --git a/Modules/PlanarFigure/CMakeLists.txt b/Modules/PlanarFigure/CMakeLists.txt index cc9d50b89e..5705da3f74 100644 --- a/Modules/PlanarFigure/CMakeLists.txt +++ b/Modules/PlanarFigure/CMakeLists.txt @@ -1,8 +1,9 @@ MITK_CREATE_MODULE( PlanarFigure INCLUDE_DIRS Algorithms DataManagement Interactions IO Rendering DEPENDS Mitk SceneSerializationBase + WARNINGS_AS_ERRORS ) IF( BUILD_TESTING ) add_subdirectory(Testing) ENDIF() diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp index cc828c0761..ca8fe70fc5 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp @@ -1,735 +1,730 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarFigure.h" #include "mitkGeometry2D.h" #include "mitkProperties.h" #include #include "algorithm" mitk::PlanarFigure::PlanarFigure() : m_SelectedControlPoint( -1 ), m_PreviewControlPointVisible( false ), m_FigurePlaced( false ), m_Geometry2D( NULL ), m_PolyLineUpToDate(false), m_HelperLinesUpToDate(false), m_FeaturesUpToDate(false), m_FeaturesMTime( 0 ) { m_HelperPolyLinesToBePainted = BoolContainerType::New(); m_DisplaySize.first = 0.0; m_DisplaySize.second = 0; this->SetProperty( "closed", mitk::BoolProperty::New( false ) ); // Currently only single-time-step geometries are supported this->InitializeTimeGeometry( 1 ); } mitk::PlanarFigure::~PlanarFigure() { } mitk::PlanarFigure::PlanarFigure(const Self& other) : BaseData(other), m_ControlPoints(other.m_ControlPoints), m_NumberOfControlPoints(other.m_NumberOfControlPoints), m_SelectedControlPoint(other.m_SelectedControlPoint), m_PolyLines(other.m_PolyLines), m_HelperPolyLines(other.m_HelperPolyLines), m_HelperPolyLinesToBePainted(other.m_HelperPolyLinesToBePainted->Clone()), m_PreviewControlPoint(other.m_PreviewControlPoint), m_PreviewControlPointVisible(other.m_PreviewControlPointVisible), m_FigurePlaced(other.m_FigurePlaced), m_Geometry2D(other.m_Geometry2D), // do not clone since SetGeometry2D() doesn't clone either m_PolyLineUpToDate(other.m_PolyLineUpToDate), m_HelperLinesUpToDate(other.m_HelperLinesUpToDate), m_FeaturesUpToDate(other.m_FeaturesUpToDate), m_Features(other.m_Features), m_FeaturesMTime(other.m_FeaturesMTime), m_DisplaySize(other.m_DisplaySize) { } void mitk::PlanarFigure::SetGeometry2D( mitk::Geometry2D *geometry ) { this->SetGeometry( geometry ); m_Geometry2D = dynamic_cast(GetGeometry(0));//geometry; } const mitk::Geometry2D *mitk::PlanarFigure::GetGeometry2D() const { return m_Geometry2D; } bool mitk::PlanarFigure::IsClosed() const { mitk::BoolProperty* closed = dynamic_cast< mitk::BoolProperty* >( this->GetProperty( "closed" ).GetPointer() ); if ( closed != NULL ) { return closed->GetValue(); } return false; } void mitk::PlanarFigure::PlaceFigure( const mitk::Point2D& point ) { for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( i, point ) ); } m_FigurePlaced = true; m_SelectedControlPoint = 1; } bool mitk::PlanarFigure::AddControlPoint( const mitk::Point2D& point, int position ) { // if we already have the maximum number of control points, do nothing if ( m_NumberOfControlPoints < this->GetMaximumNumberOfControlPoints() ) { // if position has not been defined or position would be the last control point, just append the new one // we also append a new point if we click onto the line between the first two control-points if the second control-point is selected // -> special case for PlanarCross if ( position == -1 || position > (int)m_NumberOfControlPoints-1 || (position == 1 && m_SelectedControlPoint == 2) ) { if ( m_ControlPoints.size() > this->GetMaximumNumberOfControlPoints()-1 ) { // get rid of deprecated control points in the list. This is necessary // as ::ResetNumberOfControlPoints() only sets the member, does not resize the list! m_ControlPoints.resize( this->GetNumberOfControlPoints() ); } m_ControlPoints.push_back( this->ApplyControlPointConstraints( m_NumberOfControlPoints, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } else { // insert the point at the given position and set it as selected point ControlPointListType::iterator iter = m_ControlPoints.begin() + position; m_ControlPoints.insert( iter, this->ApplyControlPointConstraints( position, point ) ); for( unsigned int i = 0; i < m_ControlPoints.size(); ++i ) { if( point == m_ControlPoints.at(i) ) { m_SelectedControlPoint = i; } } } // polylines & helperpolylines need to be repainted m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; // one control point more ++m_NumberOfControlPoints; return true; } else { return false; } } bool mitk::PlanarFigure::SetControlPoint( unsigned int index, const Point2D& point, bool createIfDoesNotExist ) { bool controlPointSetCorrectly = false; if (createIfDoesNotExist) { if ( m_NumberOfControlPoints <= index ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( index, point ) ); m_NumberOfControlPoints++; } else { m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point ); } controlPointSetCorrectly = true; } else if ( index < m_NumberOfControlPoints ) { m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point ); controlPointSetCorrectly = true; } else { return false; } if ( controlPointSetCorrectly ) { m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; } return controlPointSetCorrectly; } bool mitk::PlanarFigure::SetCurrentControlPoint( const Point2D& point ) { if ( (m_SelectedControlPoint < 0) || (m_SelectedControlPoint >= (int)m_NumberOfControlPoints) ) { return false; } return this->SetControlPoint(m_SelectedControlPoint, point, false); } unsigned int mitk::PlanarFigure::GetNumberOfControlPoints() const { return m_NumberOfControlPoints; } bool mitk::PlanarFigure::SelectControlPoint( unsigned int index ) { if ( index < this->GetNumberOfControlPoints() ) { m_SelectedControlPoint = index; return true; } else { return false; } } bool mitk::PlanarFigure::DeselectControlPoint() { bool wasSelected = ( m_SelectedControlPoint != -1); m_SelectedControlPoint = -1; return wasSelected; } void mitk::PlanarFigure::SetPreviewControlPoint( const Point2D& point ) { m_PreviewControlPoint = point; m_PreviewControlPointVisible = true; } void mitk::PlanarFigure::ResetPreviewContolPoint() { m_PreviewControlPointVisible = false; } mitk::Point2D mitk::PlanarFigure::GetPreviewControlPoint() { return m_PreviewControlPoint; } bool mitk::PlanarFigure::IsPreviewControlPointVisible() { return m_PreviewControlPointVisible; } mitk::Point2D mitk::PlanarFigure::GetControlPoint( unsigned int index ) const { if ( index < m_NumberOfControlPoints ) { return m_ControlPoints.at( index ); } itkExceptionMacro( << "GetControlPoint(): Invalid index!" ); } mitk::Point3D mitk::PlanarFigure::GetWorldControlPoint( unsigned int index ) const { Point3D point3D; if ( (m_Geometry2D != NULL) && (index < m_NumberOfControlPoints) ) { m_Geometry2D->Map( m_ControlPoints.at( index ), point3D ); return point3D; } itkExceptionMacro( << "GetWorldControlPoint(): Invalid index!" ); } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) { mitk::PlanarFigure::PolyLineType polyLine; if ( index > m_PolyLines.size() || !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } return m_PolyLines.at( index );; } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) const { return m_PolyLines.at( index ); } void mitk::PlanarFigure::ClearPolyLines() { for ( std::vector::size_type i=0; iGenerateHelperPolyLine(mmPerDisplayUnit, displayHeight); m_HelperLinesUpToDate = true; // store these parameters to be able to check next time if somebody zoomed in or out m_DisplaySize.first = mmPerDisplayUnit; m_DisplaySize.second = displayHeight; } helperPolyLine = m_HelperPolyLines.at(index); } return helperPolyLine; } void mitk::PlanarFigure::ClearHelperPolyLines() { for ( std::vector::size_type i=0; iGeneratePolyLine(); } this->EvaluateFeaturesInternal(); m_FeaturesUpToDate = true; } } void mitk::PlanarFigure::UpdateOutputInformation() { // Bounds are NOT calculated here, since the Geometry2D defines a fixed // frame (= bounds) for the planar figure. Superclass::UpdateOutputInformation(); this->GetTimeGeometry()->Update(); } void mitk::PlanarFigure::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PlanarFigure::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PlanarFigure::VerifyRequestedRegion() { return true; } void mitk::PlanarFigure::SetRequestedRegion(const itk::DataObject * /*data*/ ) { } void mitk::PlanarFigure::ResetNumberOfControlPoints( int numberOfControlPoints ) { // DO NOT resize the list here, will cause crash!! m_NumberOfControlPoints = numberOfControlPoints; } mitk::Point2D mitk::PlanarFigure::ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point ) { if ( m_Geometry2D == NULL ) { return point; } Point2D indexPoint; m_Geometry2D->WorldToIndex( point, indexPoint ); BoundingBox::BoundsArrayType bounds = m_Geometry2D->GetBounds(); if ( indexPoint[0] < bounds[0] ) { indexPoint[0] = bounds[0]; } if ( indexPoint[0] > bounds[1] ) { indexPoint[0] = bounds[1]; } if ( indexPoint[1] < bounds[2] ) { indexPoint[1] = bounds[2]; } if ( indexPoint[1] > bounds[3] ) { indexPoint[1] = bounds[3]; } Point2D constrainedPoint; m_Geometry2D->IndexToWorld( indexPoint, constrainedPoint ); return constrainedPoint; } unsigned int mitk::PlanarFigure::AddFeature( const char *featureName, const char *unitName ) { unsigned int index = m_Features.size(); Feature newFeature( featureName, unitName ); m_Features.push_back( newFeature ); return index; } void mitk::PlanarFigure::SetFeatureName( unsigned int index, const char *featureName ) { if ( index < m_Features.size() ) { m_Features[index].Name = featureName; } } void mitk::PlanarFigure::SetFeatureUnit( unsigned int index, const char *unitName ) { if ( index < m_Features.size() ) { m_Features[index].Unit = unitName; } } void mitk::PlanarFigure::SetQuantity( unsigned int index, double quantity ) { if ( index < m_Features.size() ) { m_Features[index].Quantity = quantity; } } void mitk::PlanarFigure::ActivateFeature( unsigned int index ) { if ( index < m_Features.size() ) { m_Features[index].Active = true; } } void mitk::PlanarFigure::DeactivateFeature( unsigned int index ) { if ( index < m_Features.size() ) { m_Features[index].Active = false; } } -void mitk::PlanarFigure::InitializeTimeSlicedGeometry( unsigned int timeSteps ) -{ - InitializeTimeGeometry(timeSteps); -} - void mitk::PlanarFigure::InitializeTimeGeometry( unsigned int timeSteps ) { mitk::Geometry2D::Pointer geometry2D = mitk::Geometry2D::New(); geometry2D->Initialize(); if ( timeSteps > 1 ) { mitk::ScalarType timeBounds[] = {0.0, 1.0}; geometry2D->SetTimeBounds( timeBounds ); } // The geometry is propagated automatically to all time steps, // if EvenlyTimed is true... ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(geometry2D, timeSteps); SetTimeGeometry(timeGeometry); } void mitk::PlanarFigure::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << this->GetNameOfClass() << ":\n"; if (this->IsClosed()) os << indent << "This figure is closed\n"; else os << indent << "This figure is not closed\n"; os << indent << "Minimum number of control points: " << this->GetMinimumNumberOfControlPoints() << std::endl; os << indent << "Maximum number of control points: " << this->GetMaximumNumberOfControlPoints() << std::endl; os << indent << "Current number of control points: " << this->GetNumberOfControlPoints() << std::endl; os << indent << "Control points:" << std::endl; for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { //os << indent.GetNextIndent() << i << ": " << m_ControlPoints->ElementAt( i ) << std::endl; os << indent.GetNextIndent() << i << ": " << m_ControlPoints.at( i ) << std::endl; } os << indent << "Geometry:\n"; this->GetGeometry2D()->Print(os, indent.GetNextIndent()); } unsigned short mitk::PlanarFigure::GetPolyLinesSize() { if ( !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } return m_PolyLines.size(); } unsigned short mitk::PlanarFigure::GetHelperPolyLinesSize() { return m_HelperPolyLines.size(); } bool mitk::PlanarFigure::IsHelperToBePainted(unsigned int index) { return m_HelperPolyLinesToBePainted->GetElement( index ); } bool mitk::PlanarFigure::ResetOnPointSelect() { return false; } void mitk::PlanarFigure::RemoveControlPoint( unsigned int index ) { if ( index > m_ControlPoints.size() ) return; if ( (m_ControlPoints.size() -1) < this->GetMinimumNumberOfControlPoints() ) return; ControlPointListType::iterator iter; iter = m_ControlPoints.begin() + index; m_ControlPoints.erase( iter ); m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; --m_NumberOfControlPoints; } void mitk::PlanarFigure::RemoveLastControlPoint() { RemoveControlPoint( m_ControlPoints.size()-1 ); } void mitk::PlanarFigure::DeepCopy(Self::Pointer oldFigure) { //DeepCopy only same types of planar figures //Notice to get typeid polymorph you have to use the *operator if(typeid(*oldFigure) != typeid(*this)) { itkExceptionMacro( << "DeepCopy(): Inconsistent type of source (" << typeid(*oldFigure).name() << ") and destination figure (" << typeid(*this).name() << ")!" ); return; } m_ControlPoints.clear(); this->ClearPolyLines(); this->ClearHelperPolyLines(); // clone base data members SetPropertyList(oldFigure->GetPropertyList()->Clone()); /// deep copy members m_FigurePlaced = oldFigure->m_FigurePlaced; m_SelectedControlPoint = oldFigure->m_SelectedControlPoint; m_FeaturesMTime = oldFigure->m_FeaturesMTime; m_Features = oldFigure->m_Features; m_NumberOfControlPoints = oldFigure->m_NumberOfControlPoints; //copy geometry 2D of planar figure Geometry2D::Pointer affineGeometry = oldFigure->m_Geometry2D->Clone(); SetGeometry2D(affineGeometry.GetPointer()); for(unsigned long index=0; index < oldFigure->GetNumberOfControlPoints(); index++) { m_ControlPoints.push_back( oldFigure->GetControlPoint( index )); } //After setting the control points we can generate the polylines this->GeneratePolyLine(); } void mitk::PlanarFigure::SetNumberOfPolyLines( unsigned int numberOfPolyLines ) { m_PolyLines.resize(numberOfPolyLines); } void mitk::PlanarFigure::SetNumberOfHelperPolyLines( unsigned int numberOfHerlperPolyLines ) { m_HelperPolyLines.resize(numberOfHerlperPolyLines); } void mitk::PlanarFigure::AppendPointToPolyLine( unsigned int index, PolyLineElement element ) { if ( index < m_PolyLines.size() ) { m_PolyLines.at( index ).push_back( element ); m_PolyLineUpToDate = false; } else { MITK_ERROR << "Tried to add point to PolyLine " << index+1 << ", although only " << m_PolyLines.size() << " exists"; } } void mitk::PlanarFigure::AppendPointToHelperPolyLine( unsigned int index, PolyLineElement element ) { if ( index < m_HelperPolyLines.size() ) { m_HelperPolyLines.at( index ).push_back( element ); m_HelperLinesUpToDate = false; } else { MITK_ERROR << "Tried to add point to HelperPolyLine " << index+1 << ", although only " << m_HelperPolyLines.size() << " exists"; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h index 56ac65e45a..060eb1b900 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h @@ -1,425 +1,418 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_FIGURE_H_ #define _MITK_PLANAR_FIGURE_H_ #include "PlanarFigureExports.h" #include "mitkBaseData.h" #include "mitkCommon.h" #include namespace mitk { class Geometry2D; /** * \brief Base-class for geometric planar (2D) figures, such as * lines, circles, rectangles, polygons, etc. * * \warning Currently does not support time-resolved data handling * * Behavior and appearance of PlanarFigures are controlled by various properties; for a detailed * list of appearance properties see mitk::PlanarFigureMapper2D * * The following properties control general PlanarFigure behavior: * *
    *
  • "selected": true if the planar figure is selected *
  • "planarfigure.ishovering": true if the mouse "hovers" over the planar figure *
  • "planarfigure.iseditable": true if the planar figure can be edited (otherwise, * it can only be picked/selected, but its control points cannot be edited); default is true *
  • "planarfigure.isextendable": true if new control points can be inserted into the list of control points; * default is false *
* * * TODO: Implement local 2D transform (including center of rotation...) * */ class PlanarFigure_EXPORT PlanarFigure : public BaseData { public: mitkClassMacro( PlanarFigure, BaseData ) itkCloneMacro( Self ) struct PolyLineElement { PolyLineElement( Point2D point, int index ) : Point( point ), Index( index ) { }; Point2D Point; int Index; }; typedef itk::VectorContainer< unsigned long, bool> BoolContainerType; typedef std::deque< Point2D > ControlPointListType; typedef std::list< PolyLineElement > PolyLineType; /** \brief Sets the 2D geometry on which this figure will be placed. * * In most cases, this is a Geometry already owned by another object, e.g. * describing the slice of the image on which measurements will be * performed. */ virtual void SetGeometry2D( mitk::Geometry2D *geometry ); /** \brief Returns (previously set) 2D geometry of this figure. */ virtual const Geometry2D *GetGeometry2D() const; /** \brief True if the planar figure is closed. * * Default is false. The "closed" boolean property must be set in sub-classes. */ virtual bool IsClosed() const; /** \brief True if the planar figure has been placed (and can be * displayed/interacted with). */ virtual bool IsPlaced() const { return m_FigurePlaced; }; /** \brief Place figure at the given point (in 2D index coordinates) onto * the given 2D geometry. * * By default, the first two control points of the figure are set to the * passed point. Further points can be set via AddControlPoint(), if the * current number of control points is below the maximum number of control * points. * * Can be re-implemented in sub-classes as needed. */ virtual void PlaceFigure( const Point2D& point ); /** * \brief Adds / inserts new control-points * * This method adds a new control-point with the coordinates defined by point at the given index. * If 'index' == -1 or index is greater than the number of control-points the new point is appended * to the back of the list of control points. * If a control-point already exists for 'index', an additional point is inserted at that position. * It is not possible to add more points if the maximum number of control-points (GetMaximumNumberOfControlPoints()) * has been reached. */ virtual bool AddControlPoint( const Point2D& point, int index = -1 ); virtual bool SetControlPoint( unsigned int index, const Point2D& point, bool createIfDoesNotExist = false); virtual bool SetCurrentControlPoint( const Point2D& point ); /** \brief Returns the current number of 2D control points defining this figure. */ unsigned int GetNumberOfControlPoints() const; /** \brief Returns the minimum number of control points needed to represent * this figure. * * Must be implemented in sub-classes. */ virtual unsigned int GetMinimumNumberOfControlPoints() const = 0; /** \brief Returns the maximum number of control points allowed for * this figure (e.g. 3 for triangles). * * Must be implemented in sub-classes. */ virtual unsigned int GetMaximumNumberOfControlPoints() const = 0; /** \brief Selects currently active control points. */ virtual bool SelectControlPoint( unsigned int index ); /** \brief Deselect control point; no control point active. */ virtual bool DeselectControlPoint(); /** \brief Return currently selected control point. */ virtual int GetSelectedControlPoint() const { return m_SelectedControlPoint; } /** \brief Returns specified control point in 2D world coordinates. */ Point2D GetControlPoint( unsigned int index ) const; /** \brief Returns specified control point in world coordinates. */ Point3D GetWorldControlPoint( unsigned int index ) const; /** \brief Returns the polyline representing the planar figure * (for rendering, measurements, etc.). */ const PolyLineType GetPolyLine(unsigned int index); /** \brief Returns the polyline representing the planar figure * (for rendering, measurments, etc.). */ const PolyLineType GetPolyLine(unsigned int index) const; /** \brief Returns the polyline that should be drawn the same size at every scale * (for text, angles, etc.). */ const PolyLineType GetHelperPolyLine( unsigned int index, double mmPerDisplayUnit, unsigned int displayHeight ); /** \brief Sets the position of the PreviewControlPoint. Automatically sets it visible.*/ void SetPreviewControlPoint( const Point2D& point ); /** \brief Marks the PreviewControlPoint as invisible.*/ void ResetPreviewContolPoint(); /** \brief Returns whether or not the PreviewControlPoint is visible.*/ bool IsPreviewControlPointVisible(); /** \brief Returns the coordinates of the PreviewControlPoint. */ Point2D GetPreviewControlPoint(); /** \brief Returns the number of features available for this PlanarFigure * (such as, radius, area, ...). */ virtual unsigned int GetNumberOfFeatures() const; /** \brief Returns the name (identifier) of the specified features. */ const char *GetFeatureName( unsigned int index ) const; /** \brief Returns the physical unit of the specified features. */ const char *GetFeatureUnit( unsigned int index ) const; /** Returns quantity of the specified feature (e.g., length, radius, * area, ... ) */ double GetQuantity( unsigned int index ) const; /** \brief Returns true if the feature with the specified index exists and * is active (an inactive feature may e.g. be the area of a non-closed * polygon. */ bool IsFeatureActive( unsigned int index ) const; /** \brief Returns true if the feature with the specified index exists and is set visible */ bool IsFeatureVisible( unsigned int index ) const; /** \brief Defines if the feature with the specified index will be shown as an * overlay in the RenderWindow */ void SetFeatureVisible( unsigned int index, bool visible ); /** \brief Calculates quantities of all features of this planar figure. */ virtual void EvaluateFeatures(); /** \brief Intherited from parent */ virtual void UpdateOutputInformation(); /** \brief Intherited from parent */ virtual void SetRequestedRegionToLargestPossibleRegion(); /** \brief Intherited from parent */ virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); /** \brief Intherited from parent */ virtual bool VerifyRequestedRegion(); /** \brief Intherited from parent */ virtual void SetRequestedRegion( const itk::DataObject *data); /** \brief Returns the current number of polylines */ virtual unsigned short GetPolyLinesSize(); /** \brief Returns the current number of helperpolylines */ virtual unsigned short GetHelperPolyLinesSize(); /** \brief Returns whether a helper polyline should be painted or not */ virtual bool IsHelperToBePainted(unsigned int index); /** \brief Returns true if the planar figure is reset to "add points" mode * when a point is selected. * * Default return value is false. Subclasses can overwrite this method and * execute any reset / initialization statements required. */ virtual bool ResetOnPointSelect(); /** \brief removes the point with the given index from the list of controlpoints. */ virtual void RemoveControlPoint( unsigned int index ); /** \brief Removes last control point */ virtual void RemoveLastControlPoint(); /** \brief Copies contents and state of a figre provided as parameter to the current object. * * Requires a matching type of both figures. * * \note Deprecated, use Clone() instead. */ DEPRECATED(void DeepCopy(Self::Pointer oldFigure)); /** \brief Allow sub-classes to apply constraints on control points. * * Sub-classes can define spatial constraints to certain control points by * overwriting this method and returning a constrained point. By default, * the points are constrained by the image bounds. */ virtual Point2D ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point ); protected: PlanarFigure(); virtual ~PlanarFigure(); PlanarFigure(const Self& other); /** \brief Set the initial number of control points of the planar figure */ void ResetNumberOfControlPoints( int numberOfControlPoints ); /** Adds feature (e.g., circumference, radius, angle, ...) to feature vector * of a planar figure object and returns integer ID for the feature element. * Should be called in sub-class constructors. */ virtual unsigned int AddFeature( const char *featureName, const char *unitName ); /** Sets the name of the specified feature. INTERNAL METHOD. */ void SetFeatureName( unsigned int index, const char *featureName ); /** Sets the physical unit of the specified feature. INTERNAL METHOD. */ void SetFeatureUnit( unsigned int index, const char *unitName ); /** Sets quantity of the specified feature. INTERNAL METHOD. */ void SetQuantity( unsigned int index, double quantity ); /** Sets the specified feature as active. INTERAL METHOD. */ void ActivateFeature( unsigned int index ); /** Sets the specified feature as active. INTERAL METHOD. */ void DeactivateFeature( unsigned int index ); /** \brief Generates the poly-line representation of the planar figure. * Must be implemented in sub-classes. */ virtual void GeneratePolyLine() = 0; /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom. * Must be implemented in sub-classes. */ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight) = 0; /** \brief Calculates quantities of all features of this planar figure. * Must be implemented in sub-classes. */ virtual void EvaluateFeaturesInternal() = 0; - /** \brief Initializes the TimeGeometry describing the (time-resolved) - * geometry of this figure. Note that each time step holds one Geometry2D. - * - * \deprecatedSince{2013_09} Please use InitializeTimeGeometry instead: For additional information see http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 - */ - DEPRECATED(virtual void InitializeTimeSlicedGeometry( unsigned int timeSteps = 1 )); - /** \brief Initializes the TimeGeometry describing the (time-resolved) * geometry of this figure. Note that each time step holds one Geometry2D. */ virtual void InitializeTimeGeometry( unsigned int timeSteps = 1 ); /** \brief defines the number of PolyLines that will be available */ void SetNumberOfPolyLines( unsigned int numberOfPolyLines ); /** \brief Append a point to the PolyLine # index */ void AppendPointToPolyLine( unsigned int index, PolyLineElement element ); /** \brief clears the list of PolyLines. Call before re-calculating a new Polyline. */ void ClearPolyLines(); /** \brief defines the number of HelperPolyLines that will be available */ void SetNumberOfHelperPolyLines( unsigned int numberOfHelperPolyLines ); /** \brief Append a point to the HelperPolyLine # index */ void AppendPointToHelperPolyLine( unsigned int index, PolyLineElement element ); /** \brief clears the list of HelperPolyLines. Call before re-calculating a new HelperPolyline. */ void ClearHelperPolyLines(); virtual void PrintSelf( std::ostream& os, itk::Indent indent ) const; ControlPointListType m_ControlPoints; unsigned int m_NumberOfControlPoints; // Currently selected control point; -1 means no point selected int m_SelectedControlPoint; std::vector m_PolyLines; std::vector m_HelperPolyLines; BoolContainerType::Pointer m_HelperPolyLinesToBePainted; // this point is used to store the coordiantes an additional 'ControlPoint' that is rendered // when the mouse cursor is above the figure (and not a control-point) and when the // property 'planarfigure.isextendable' is set to true Point2D m_PreviewControlPoint; bool m_PreviewControlPointVisible; bool m_FigurePlaced; private: // not implemented to prevent PlanarFigure::New() calls which would create an itk::Object. static Pointer New(); struct Feature { Feature( const char *name, const char *unit ) : Name( name ), Unit( unit ), Quantity( 0.0 ), Active( true ), Visible( true ) { } std::string Name; std::string Unit; double Quantity; bool Active; bool Visible; }; virtual itk::LightObject::Pointer InternalClone() const = 0; Geometry2D *m_Geometry2D; bool m_PolyLineUpToDate; bool m_HelperLinesUpToDate; bool m_FeaturesUpToDate; // Vector of features available for this geometric figure typedef std::vector< Feature > FeatureVectorType; FeatureVectorType m_Features; unsigned long m_FeaturesMTime; // this pair is used to store the mmInDisplayUnits (m_DisplaySize.first) and the displayHeight (m_DisplaySize.second) // that the helperPolyLines have been calculated for. // It's used to determine whether or not GetHelperPolyLine() needs to recalculate the HelperPolyLines. std::pair m_DisplaySize; }; } // namespace mitk #endif //_MITK_PLANAR_FIGURE_H_ diff --git a/Modules/PlanarFigure/IO/mitkPlanarFigureWriter.h b/Modules/PlanarFigure/IO/mitkPlanarFigureWriter.h index 36611a760a..1c7e40a9b8 100644 --- a/Modules/PlanarFigure/IO/mitkPlanarFigureWriter.h +++ b/Modules/PlanarFigure/IO/mitkPlanarFigureWriter.h @@ -1,203 +1,205 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PlanarFigure_WRITER__H_ #define _MITK_PlanarFigure_WRITER__H_ #include #include "PlanarFigureExports.h" #include #include class TiXmlElement; namespace mitk { /** * @brief XML-based writer for mitk::PlanarFigures * * XML-based writer for mitk::PlanarFigures. * @ingroup Process */ class PlanarFigure_EXPORT PlanarFigureWriter : public mitk::FileWriterWithInformation { public: mitkClassMacro( PlanarFigureWriter, mitk::FileWriter ); mitkWriterMacro; itkNewMacro( Self ); typedef mitk::PlanarFigure InputType; typedef InputType::Pointer InputTypePointer; /** * Sets the filename of the file to write. * @param FileName the name of the file to write. */ itkSetStringMacro( FileName ); /** * @returns the name of the file to be written to disk. */ itkGetStringMacro( FileName ); /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePrefix ); /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePrefix ); /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePattern ); /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePattern ); + using Superclass::SetInput; + /** * Sets the 0'th input object for the filter. * @param input the first input for the filter. */ void SetInput( InputType* input ); /** * Sets the n'th input object for the filter. If num is * larger than GetNumberOfInputs() the number of inputs is * resized appropriately. * @param input the n'th input for the filter. */ void SetInput( const unsigned int& num, InputType* input); /** * @returns the 0'th input object of the filter. */ PlanarFigure* GetInput(); /** * @param num the index of the desired output object. * @returns the n'th input object of the filter. */ PlanarFigure* GetInput( const unsigned int& num ); /** * @brief Return the possible file extensions for the data type associated with the writer */ virtual std::vector GetPossibleFileExtensions(); /** * @brief Return the extension to be added to the filename. */ virtual std::string GetFileExtension(); /** * @brief Check if the Writer can write the Content of the */ virtual bool CanWriteDataType( DataNode* ); /** * @brief Return the MimeType of the saved File. */ virtual std::string GetWritenMIMEType(); /** * @brief Set the DataTreenode as Input. Important: The Writer always have a SetInput-Function. */ virtual void SetInput( DataNode* ); /** * @returns whether the last write attempt was successful or not. */ itkGetConstMacro(Success, bool); virtual const char * GetDefaultFilename() { return "PlanarFigure.pf"; } virtual const char * GetFileDialogPattern() { return "Planar Figure Files (*.pf)"; } virtual const char * GetDefaultExtension() { return ".pf"; } virtual bool CanWriteBaseDataType(BaseData::Pointer data) { return dynamic_cast( data.GetPointer() ); } virtual void DoWrite(BaseData::Pointer data) { if (CanWriteBaseDataType(data)) { this->SetInput(dynamic_cast(data.GetPointer())); this->Update(); } } /** @brief CAUTION: It's up to the user to call this function to release the memory buffer after use in case the file writer has written to its memory array. See mitkFileWriter base class. */ virtual void ReleaseMemory(); protected: /** * Constructor. */ PlanarFigureWriter(); /** * Virtual destructor. */ virtual ~PlanarFigureWriter(); /** * Writes the a .pf file in xml format that contains all input planar figures */ virtual void GenerateData(); /** * Resizes the number of inputs of the writer. * The inputs are initialized by empty PlanarFigures * @param num the new number of inputs */ virtual void ResizeInputs( const unsigned int& num ); /**Documentation * \brief creates a TinyXML element that contains x, y, and z values * * \param[in] name the name of the XML element * \param[in] v the vector or point that contains the x, y and z values * \return returns a TiXmlElement named name and three attributes x, y and z. */ TiXmlElement* CreateXMLVectorElement(const char* name, itk::FixedArray v); std::string m_FileName; std::string m_FilePrefix; std::string m_FilePattern; std::string m_Extension; std::string m_MimeType; bool m_Success; }; } #endif diff --git a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp index 5751bf4c28..7d07b8aefa 100644 --- a/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp +++ b/Modules/PlanarFigure/Interactions/mitkPlanarFigureInteractor.cpp @@ -1,959 +1,947 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define PLANARFIGUREINTERACTOR_DBG MITK_DEBUG("PlanarFigureInteractor") << __LINE__ << ": " #include "mitkPlanarFigureInteractor.h" #include "mitkPlanarFigure.h" #include "mitkPlanarPolygon.h" #include "mitkInteractionPositionEvent.h" #include "mitkInternalEvent.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" //how precise must the user pick the point //default value mitk::PlanarFigureInteractor::PlanarFigureInteractor() : DataInteractor() , m_Precision( 6.5 ) , m_MinimumPointDistance( 25.0 ) , m_IsHovering( false ) , m_LastPointWasValid( false ) { } mitk::PlanarFigureInteractor::~PlanarFigureInteractor() { } void mitk::PlanarFigureInteractor::ConnectActionsAndFunctions() { CONNECT_CONDITION("figure_is_on_current_slice", CheckFigureOnRenderingGeometry); CONNECT_CONDITION("figure_is_placed", CheckFigurePlaced); CONNECT_CONDITION("minimal_figure_is_finished", CheckMinimalFigureFinished); CONNECT_CONDITION("hovering_above_figure", CheckFigureHovering); CONNECT_CONDITION("hovering_above_point", CheckControlPointHovering); CONNECT_CONDITION("figure_is_selected", CheckSelection); CONNECT_CONDITION("point_is_valid", CheckPointValidity); CONNECT_CONDITION("figure_is_finished", CheckFigureFinished); CONNECT_CONDITION("reset_on_point_select_needed", CheckResetOnPointSelect); CONNECT_CONDITION("points_can_be_added_or_removed", CheckFigureIsExtendable); CONNECT_FUNCTION( "finalize_figure", FinalizeFigure); CONNECT_FUNCTION( "hide_preview_point", HidePreviewPoint ) CONNECT_FUNCTION( "hide_control_points", HideControlPoints ) CONNECT_FUNCTION( "set_preview_point_position", SetPreviewPointPosition ) CONNECT_FUNCTION( "move_current_point", MoveCurrentPoint); CONNECT_FUNCTION( "deselect_point", DeselectPoint); CONNECT_FUNCTION( "add_new_point", AddPoint); CONNECT_FUNCTION( "add_initial_point", AddInitialPoint); CONNECT_FUNCTION( "remove_selected_point", RemoveSelectedPoint); CONNECT_FUNCTION( "request_context_menu", RequestContextMenu); CONNECT_FUNCTION( "select_figure", SelectFigure ); CONNECT_FUNCTION( "select_point", SelectPoint ); CONNECT_FUNCTION( "end_interaction", EndInteraction ); CONNECT_FUNCTION( "start_hovering", StartHovering ) CONNECT_FUNCTION( "end_hovering", EndHovering ); } -bool mitk::PlanarFigureInteractor::CheckFigurePlaced( const InteractionEvent* interactionEvent ) +bool mitk::PlanarFigureInteractor::CheckFigurePlaced( const InteractionEvent* /*interactionEvent*/ ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); bool isFigureFinished = false; planarFigure->GetPropertyList()->GetBoolProperty( "initiallyplaced", isFigureFinished ); return planarFigure->IsPlaced() && isFigureFinished; } bool mitk::PlanarFigureInteractor::MoveCurrentPoint(StateMachineAction*, InteractionEvent* interactionEvent) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; bool isEditable = true; GetDataNode()->GetBoolProperty( "planarfigure.iseditable", isEditable ); mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::Geometry2D *planarFigureGeometry = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); // Extract point in 2D world coordinates (relative to Geometry2D of // PlanarFigure) Point2D point2D; if ( !this->TransformPositionEventToPoint2D( positionEvent, planarFigureGeometry, point2D ) || !isEditable ) { return false; } // check if the control points shall be hidden during interaction bool hidecontrolpointsduringinteraction = false; GetDataNode()->GetBoolProperty( "planarfigure.hidecontrolpointsduringinteraction", hidecontrolpointsduringinteraction ); // hide the control points if necessary //interactionEvent->GetSender()->GetDataStorage()->BlockNodeModifiedEvents( true ); GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", !hidecontrolpointsduringinteraction ); //interactionEvent->GetSender()->GetDataStorage()->BlockNodeModifiedEvents( false ); // Move current control point to this point planarFigure->SetCurrentControlPoint( point2D ); // Re-evaluate features planarFigure->EvaluateFeatures(); // Update rendered scene interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::PlanarFigureInteractor::FinalizeFigure( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); planarFigure->Modified(); planarFigure->DeselectControlPoint(); planarFigure->RemoveLastControlPoint(); planarFigure->SetProperty( "initiallyplaced", mitk::BoolProperty::New( true ) ); GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true ); GetDataNode()->Modified(); planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() ); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return false; } bool mitk::PlanarFigureInteractor::EndInteraction( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true ); planarFigure->Modified(); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return false; } bool mitk::PlanarFigureInteractor::EndHovering( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); planarFigure->ResetPreviewContolPoint(); // Invoke end-hover event once the mouse is exiting the figure area m_IsHovering = false; planarFigure->InvokeEvent( EndHoverPlanarFigureEvent() ); // Set bool property to indicate that planar figure is no longer in "hovering" mode GetDataNode()->SetBoolProperty( "planarfigure.ishovering", false ); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return false; } -bool mitk::PlanarFigureInteractor::CheckMinimalFigureFinished( const InteractionEvent* interactionEvent ) +bool mitk::PlanarFigureInteractor::CheckMinimalFigureFinished( const InteractionEvent* /*interactionEvent*/ ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); return ( planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMinimumNumberOfControlPoints() ); } -bool mitk::PlanarFigureInteractor::CheckFigureFinished( const InteractionEvent* interactionEvent ) +bool mitk::PlanarFigureInteractor::CheckFigureFinished( const InteractionEvent* /*interactionEvent*/ ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); return ( planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMaximumNumberOfControlPoints() ); } -bool mitk::PlanarFigureInteractor::CheckFigureIsExtendable( const InteractionEvent* interactionEvent ) +bool mitk::PlanarFigureInteractor::CheckFigureIsExtendable( const InteractionEvent* /*interactionEvent*/ ) { bool isExtendable = false; GetDataNode()->GetBoolProperty("planarfigure.isextendable", isExtendable); return isExtendable; } -bool mitk::PlanarFigureInteractor::DeselectPoint(StateMachineAction*, InteractionEvent* interactionEvent) +bool mitk::PlanarFigureInteractor::DeselectPoint(StateMachineAction*, InteractionEvent* /*interactionEvent*/) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); bool wasSelected = planarFigure->DeselectControlPoint(); if ( wasSelected ) { // Issue event so that listeners may update themselves planarFigure->Modified(); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true ); // GetDataNode()->SetBoolProperty( "planarfigure.ishovering", false ); GetDataNode()->Modified(); } return true; } bool mitk::PlanarFigureInteractor::AddPoint(StateMachineAction*, InteractionEvent* interactionEvent) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; bool selected = false; bool isEditable = true; GetDataNode()->GetBoolProperty("selected", selected); GetDataNode()->GetBoolProperty( "planarfigure.iseditable", isEditable ); if ( !selected || !isEditable ) { return false; } mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::Geometry2D *planarFigureGeometry = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); // If the planarFigure already has reached the maximum number if ( planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMaximumNumberOfControlPoints() ) { return false; } // Extract point in 2D world coordinates (relative to Geometry2D of // PlanarFigure) Point2D point2D, projectedPoint; if ( !this->TransformPositionEventToPoint2D( positionEvent, planarFigureGeometry, point2D ) ) { return false; } // TODO: check segment of polyline we clicked in int nextIndex = -1; // We only need to check which position to insert the control point // when interacting with a PlanarPolygon. For all other types // new control points will always be appended /* * Added check for "initiallyplaced" due to bug 13097: * * There are two possible cases in which a point can be inserted into a PlanarPolygon: * * 1. The figure is currently drawn -> the point will be appended at the end of the figure * 2. A point is inserted at a userdefined position after the initial placement of the figure is finished * * In the second case we need to determine the proper insertion index. In the first case the index always has * to be -1 so that the point is appended to the end. * * These changes are neccessary because of a mac os x specific issue: If a users draws a PlanarPolygon then the * next point to be added moves according to the mouse position. If then the user left clicks in order to add * a point one would assume the last move position is identical to the left click position. This is actually the * case for windows and linux but somehow NOT for mac. Because of the insertion logic of a new point in the * PlanarFigure then for mac the wrong current selected point is determined. * * With this check here this problem can be avoided. However a redesign of the insertion logic should be considered */ bool isFigureFinished = false; planarFigure->GetPropertyList()->GetBoolProperty( "initiallyplaced", isFigureFinished ); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); if ( dynamic_cast( planarFigure ) && isFigureFinished) { nextIndex = this->IsPositionOverFigure( positionEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer->GetDisplayGeometry(), projectedPoint ); } // Add point as new control point renderer->GetDisplayGeometry()->DisplayToWorld( projectedPoint, projectedPoint ); if ( planarFigure->IsPreviewControlPointVisible() ) { point2D = planarFigure->GetPreviewControlPoint(); } planarFigure->AddControlPoint( point2D, nextIndex ); if ( planarFigure->IsPreviewControlPointVisible() ) { planarFigure->SelectControlPoint( nextIndex ); planarFigure->ResetPreviewContolPoint(); } // Re-evaluate features planarFigure->EvaluateFeatures(); //this->LogPrintPlanarFigureQuantities( planarFigure ); // Update rendered scene renderer->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::PlanarFigureInteractor::AddInitialPoint(StateMachineAction*, InteractionEvent* interactionEvent) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); mitk::Geometry2D *planarFigureGeometry = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); // Invoke event to notify listeners that placement of this PF starts now planarFigure->InvokeEvent( StartPlacementPlanarFigureEvent() ); // Use Geometry2D of the renderer clicked on for this PlanarFigure mitk::PlaneGeometry *planeGeometry = const_cast< mitk::PlaneGeometry * >( dynamic_cast< const mitk::PlaneGeometry * >( renderer->GetSliceNavigationController()->GetCurrentPlaneGeometry() ) ); if ( planeGeometry != NULL ) { planarFigureGeometry = planeGeometry; planarFigure->SetGeometry2D( planeGeometry ); } else { return false; } // Extract point in 2D world coordinates (relative to Geometry2D of // PlanarFigure) Point2D point2D; if ( !this->TransformPositionEventToPoint2D( positionEvent, planarFigureGeometry, point2D ) ) { return false; } // Place PlanarFigure at this point planarFigure->PlaceFigure( point2D ); // Re-evaluate features planarFigure->EvaluateFeatures(); //this->LogPrintPlanarFigureQuantities( planarFigure ); // Set a bool property indicating that the figure has been placed in // the current RenderWindow. This is required so that the same render // window can be re-aligned to the Geometry2D of the PlanarFigure later // on in an application. GetDataNode()->SetBoolProperty( "PlanarFigureInitializedWindow", true, renderer ); // Update rendered scene renderer->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::PlanarFigureInteractor::StartHovering( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); - mitk::Geometry2D *planarFigureGeometry = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); - const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); if ( !m_IsHovering ) { // Invoke hover event once when the mouse is entering the figure area m_IsHovering = true; planarFigure->InvokeEvent( StartHoverPlanarFigureEvent() ); // Set bool property to indicate that planar figure is currently in "hovering" mode GetDataNode()->SetBoolProperty( "planarfigure.ishovering", true ); renderer->GetRenderingManager()->RequestUpdateAll(); } return true; } bool mitk::PlanarFigureInteractor::SetPreviewPointPosition( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); - mitk::Geometry2D *planarFigureGeometry = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); - const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); planarFigure->DeselectControlPoint(); mitk::Point2D pointProjectedOntoLine; - int previousControlPoint = mitk::PlanarFigureInteractor::IsPositionOverFigure( - positionEvent, - planarFigure, - planarFigureGeometry, - projectionPlane, - renderer->GetDisplayGeometry(), - pointProjectedOntoLine - ); bool selected(false); bool isExtendable(false); bool isEditable(true); GetDataNode()->GetBoolProperty("selected", selected); GetDataNode()->GetBoolProperty("planarfigure.isextendable", isExtendable); GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable ); if ( selected && isExtendable && isEditable ) { renderer->GetDisplayGeometry()->DisplayToWorld( pointProjectedOntoLine, pointProjectedOntoLine ); planarFigure->SetPreviewControlPoint( pointProjectedOntoLine ); } renderer->GetRenderingManager()->RequestUpdateAll(); return true; } -bool mitk::PlanarFigureInteractor::HideControlPoints( StateMachineAction*, InteractionEvent* interactionEvent ) +bool mitk::PlanarFigureInteractor::HideControlPoints( StateMachineAction*, InteractionEvent* /*interactionEvent*/ ) { GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", false ); return true; } bool mitk::PlanarFigureInteractor::HidePreviewPoint( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); planarFigure->ResetPreviewContolPoint(); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); renderer->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::PlanarFigureInteractor::CheckFigureHovering( const InteractionEvent* interactionEvent ) { const mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); mitk::Geometry2D *planarFigureGeometry = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); mitk::Point2D pointProjectedOntoLine; int previousControlPoint = this->IsPositionOverFigure( positionEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer->GetDisplayGeometry(), pointProjectedOntoLine ); bool isHovering = (previousControlPoint != -1); if ( isHovering ) { return true; } else { return false; } return false; } bool mitk::PlanarFigureInteractor::CheckControlPointHovering( const InteractionEvent* interactionEvent ) { const mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); mitk::Geometry2D *planarFigureGeometry = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); int pointIndex = -1; pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker( positionEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer->GetDisplayGeometry() ); if ( pointIndex >= 0 ) { return true; } else { return false; } } -bool mitk::PlanarFigureInteractor::CheckSelection( const InteractionEvent* interactionEvent ) +bool mitk::PlanarFigureInteractor::CheckSelection( const InteractionEvent* /*interactionEvent*/ ) { bool selected = false; GetDataNode()->GetBoolProperty("selected", selected); return selected; } -bool mitk::PlanarFigureInteractor::SelectFigure( StateMachineAction*, InteractionEvent* interactionEvent ) +bool mitk::PlanarFigureInteractor::SelectFigure( StateMachineAction*, InteractionEvent* /*interactionEvent*/ ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); planarFigure->InvokeEvent( SelectPlanarFigureEvent() ); return false; } bool mitk::PlanarFigureInteractor::SelectPoint( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); mitk::Geometry2D *planarFigureGeometry = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); int pointIndex = -1; pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker( positionEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer->GetDisplayGeometry() ); if ( pointIndex >= 0 ) { // If mouse is above control point, mark it as selected planarFigure->SelectControlPoint( pointIndex ); } else { planarFigure->DeselectControlPoint(); } return false; } bool mitk::PlanarFigureInteractor::CheckPointValidity( const InteractionEvent* interactionEvent ) { // Check if the distance of the current point to the previously set point in display coordinates // is sufficient (if a previous point exists) // Extract display position const mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if ( positionEvent == NULL ) return false; mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); m_LastPointWasValid = IsMousePositionAcceptableAsNewControlPoint( positionEvent, planarFigure ); return m_LastPointWasValid; } bool mitk::PlanarFigureInteractor::RemoveSelectedPoint(StateMachineAction*, InteractionEvent* interactionEvent) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); int selectedControlPoint = planarFigure->GetSelectedControlPoint(); planarFigure->RemoveControlPoint( selectedControlPoint ); // Re-evaluate features planarFigure->EvaluateFeatures(); planarFigure->Modified(); GetDataNode()->SetBoolProperty( "planarfigure.drawcontrolpoints", true ); planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() ); renderer->GetRenderingManager()->RequestUpdateAll(); HandleEvent( mitk::InternalEvent::New( renderer, this, "Dummy-Event" ), GetDataNode() ); return true; } -bool mitk::PlanarFigureInteractor::RequestContextMenu(StateMachineAction*, InteractionEvent* interactionEvent) +bool mitk::PlanarFigureInteractor::RequestContextMenu(StateMachineAction*, InteractionEvent* /*interactionEvent*/) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); bool selected = false; GetDataNode()->GetBoolProperty("selected", selected); // no need to invoke this if the figure is already selected if ( !selected ) { planarFigure->InvokeEvent( SelectPlanarFigureEvent() ); } planarFigure->InvokeEvent( ContextMenuPlanarFigureEvent() ); return true; } -bool mitk::PlanarFigureInteractor::CheckResetOnPointSelect( const InteractionEvent* interactionEvent ) +bool mitk::PlanarFigureInteractor::CheckResetOnPointSelect( const InteractionEvent* /*interactionEvent*/ ) { mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); // Invoke tmpEvent to notify listeners that interaction with this PF starts now planarFigure->InvokeEvent( StartInteractionPlanarFigureEvent() ); // Reset the PlanarFigure if required return planarFigure->ResetOnPointSelect(); } bool mitk::PlanarFigureInteractor::CheckFigureOnRenderingGeometry( const InteractionEvent* interactionEvent ) { const mitk::InteractionPositionEvent* posEvent = dynamic_cast(interactionEvent); if ( posEvent == NULL ) return false; mitk::Point3D worldPoint3D = posEvent->GetPositionInWorld(); mitk::PlanarFigure *planarFigure = dynamic_cast( GetDataNode()->GetData() ); mitk::Geometry2D *planarFigureGeometry2D = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); double planeThickness = planarFigureGeometry2D->GetExtentInMM( 2 ); if ( planarFigureGeometry2D->Distance( worldPoint3D ) > planeThickness ) { // don't react, when interaction is too far away return false; } return true; } void mitk::PlanarFigureInteractor::SetPrecision( mitk::ScalarType precision ) { m_Precision = precision; } void mitk::PlanarFigureInteractor::SetMinimumPointDistance( ScalarType minimumDistance ) { m_MinimumPointDistance = minimumDistance; } bool mitk::PlanarFigureInteractor::TransformPositionEventToPoint2D( const InteractionPositionEvent *positionEvent, const Geometry2D *planarFigureGeometry, Point2D &point2D ) { mitk::Point3D worldPoint3D = positionEvent->GetPositionInWorld(); // TODO: proper handling of distance tolerance if ( planarFigureGeometry->Distance( worldPoint3D ) > 0.1 ) { return false; } // Project point onto plane of this PlanarFigure planarFigureGeometry->Map( worldPoint3D, point2D ); return true; } bool mitk::PlanarFigureInteractor::TransformObjectToDisplay( const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ) const { mitk::Point3D point3D; // Map circle point from local 2D geometry into 3D world space objectGeometry->Map( point2D, point3D ); // TODO: proper handling of distance tolerance if ( displayGeometry->Distance( point3D ) < 0.1 ) { // Project 3D world point onto display geometry rendererGeometry->Map( point3D, displayPoint ); displayGeometry->WorldToDisplay( displayPoint, displayPoint ); return true; } return false; } bool mitk::PlanarFigureInteractor::IsPointNearLine( const mitk::Point2D& point, const mitk::Point2D& startPoint, const mitk::Point2D& endPoint, mitk::Point2D& projectedPoint ) const { mitk::Vector2D n1 = endPoint - startPoint; n1.Normalize(); // Determine dot products between line vector and startpoint-point / endpoint-point vectors double l1 = n1 * (point - startPoint); double l2 = -n1 * (point - endPoint); // Determine projection of specified point onto line defined by start / end point mitk::Point2D crossPoint = startPoint + n1 * l1; projectedPoint = crossPoint; // Point is inside encompassing rectangle IF // - its distance to its projected point is small enough // - it is not further outside of the line than the defined tolerance if (((crossPoint.SquaredEuclideanDistanceTo(point) < 20.0) && (l1 > 0.0) && (l2 > 0.0)) || endPoint.SquaredEuclideanDistanceTo(point) < 20.0 || startPoint.SquaredEuclideanDistanceTo(point) < 20.0) { return true; } return false; } int mitk::PlanarFigureInteractor::IsPositionOverFigure( const InteractionPositionEvent *positionEvent, PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, const DisplayGeometry *displayGeometry, Point2D& pointProjectedOntoLine ) const { mitk::Point2D displayPosition = positionEvent->GetPointerPositionOnScreen(); // Iterate over all polylines of planar figure, and check if // any one is close to the current display position typedef mitk::PlanarFigure::PolyLineType VertexContainerType; Point2D polyLinePoint; Point2D firstPolyLinePoint; Point2D previousPolyLinePoint; for ( unsigned short loop=0; loopGetPolyLinesSize(); ++loop ) { const VertexContainerType polyLine = planarFigure->GetPolyLine( loop ); bool firstPoint( true ); for ( VertexContainerType::const_iterator it = polyLine.begin(); it != polyLine.end(); ++it ) { // Get plane coordinates of this point of polyline (if possible) if ( !this->TransformObjectToDisplay( it->Point, polyLinePoint, planarFigureGeometry, rendererGeometry, displayGeometry ) ) { break; // Poly line invalid (not on current 2D plane) --> skip it } if ( firstPoint ) { firstPolyLinePoint = polyLinePoint; firstPoint = false; } else if ( this->IsPointNearLine( displayPosition, previousPolyLinePoint, polyLinePoint, pointProjectedOntoLine ) ) { // Point is close enough to line segment --> Return index of the segment return it->Index; } previousPolyLinePoint = polyLinePoint; } // For closed figures, also check last line segment if ( planarFigure->IsClosed() && this->IsPointNearLine( displayPosition, polyLinePoint, firstPolyLinePoint, pointProjectedOntoLine ) ) { return 0; // Return index of first control point } } return -1; } int mitk::PlanarFigureInteractor::IsPositionInsideMarker( const InteractionPositionEvent* positionEvent, const PlanarFigure *planarFigure, const Geometry2D *planarFigureGeometry, const Geometry2D *rendererGeometry, const DisplayGeometry *displayGeometry ) const { mitk::Point2D displayPosition = positionEvent->GetPointerPositionOnScreen(); // Iterate over all control points of planar figure, and check if // any one is close to the current display position mitk::Point2D displayControlPoint; int numberOfControlPoints = planarFigure->GetNumberOfControlPoints(); for ( int i=0; iTransformObjectToDisplay( planarFigure->GetControlPoint(i), displayControlPoint, planarFigureGeometry, rendererGeometry, displayGeometry ) ) { // TODO: variable size of markers if ( displayPosition.SquaredEuclideanDistanceTo( displayControlPoint ) < 20.0 ) { return i; } } } return -1; } void mitk::PlanarFigureInteractor::LogPrintPlanarFigureQuantities( const PlanarFigure *planarFigure ) { MITK_INFO << "PlanarFigure: " << planarFigure->GetNameOfClass(); for ( unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i ) { MITK_INFO << "* " << planarFigure->GetFeatureName( i ) << ": " << planarFigure->GetQuantity( i ) << " " << planarFigure->GetFeatureUnit( i ); } } bool mitk::PlanarFigureInteractor::IsMousePositionAcceptableAsNewControlPoint( const mitk::InteractionPositionEvent* positionEvent, const PlanarFigure* planarFigure ) { assert(positionEvent && planarFigure); BaseRenderer* renderer = positionEvent->GetSender(); assert(renderer); // Get the timestep to support 3D+t int timeStep( renderer->GetTimeStep( planarFigure ) ); bool tooClose(false); const Geometry2D *renderingPlane = renderer->GetCurrentWorldGeometry2D(); mitk::Geometry2D *planarFigureGeometry = dynamic_cast< mitk::Geometry2D * >( planarFigure->GetGeometry( timeStep ) ); Point2D point2D, correctedPoint; // Get the point2D from the positionEvent if ( !this->TransformPositionEventToPoint2D( positionEvent, planarFigureGeometry, point2D ) ) { return false; } // apply the controlPoint constraints of the planarFigure to get the // coordinates that would actually be used. correctedPoint = const_cast( planarFigure )->ApplyControlPointConstraints( 0, point2D ); // map the 2D coordinates of the new point to world-coordinates // and transform those to display-coordinates mitk::Point3D newPoint3D; planarFigureGeometry->Map( correctedPoint, newPoint3D ); mitk::Point2D newDisplayPosition; renderingPlane->Map( newPoint3D, newDisplayPosition ); renderer->GetDisplayGeometry()->WorldToDisplay( newDisplayPosition, newDisplayPosition ); for( int i=0; i < (int)planarFigure->GetNumberOfControlPoints(); i++ ) { if ( i != planarFigure->GetSelectedControlPoint() ) { // Try to convert previous point to current display coordinates mitk::Point3D previousPoint3D; // map the 2D coordinates of the control-point to world-coordinates planarFigureGeometry->Map( planarFigure->GetControlPoint( i ), previousPoint3D ); if ( renderer->GetDisplayGeometry()->Distance( previousPoint3D ) < 0.1 ) // ugly, but assert makes this work { mitk::Point2D previousDisplayPosition; // transform the world-coordinates into display-coordinates renderingPlane->Map( previousPoint3D, previousDisplayPosition ); renderer->GetDisplayGeometry()->WorldToDisplay( previousDisplayPosition, previousDisplayPosition ); //Calculate the distance. We use display-coordinates here to make // the check independent of the zoom-level of the rendering scene. double a = newDisplayPosition[0] - previousDisplayPosition[0]; double b = newDisplayPosition[1] - previousDisplayPosition[1]; // If point is to close, do not set a new point tooClose = (a * a + b * b < m_MinimumPointDistance ); } if ( tooClose ) return false; // abort loop early } } return !tooClose; // default } void mitk::PlanarFigureInteractor::ConfigurationChanged() { mitk::PropertyList::Pointer properties = GetAttributes(); std::string precision = ""; if (properties->GetStringProperty("precision", precision)) { m_Precision = atof(precision.c_str()); } else { m_Precision = (ScalarType) 6.5; } std::string minPointDistance = ""; if (properties->GetStringProperty("minPointDistance", minPointDistance)) { m_MinimumPointDistance = atof(minPointDistance.c_str()); } else { m_MinimumPointDistance = (ScalarType) 25.0; } } diff --git a/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.cpp b/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.cpp index 9cd1184a43..3b0b809638 100644 --- a/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.cpp +++ b/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.cpp @@ -1,896 +1,897 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarFigureMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkGL.h" #include "mitkVtkPropRenderer.h" #define _USE_MATH_DEFINES #include // offset which moves the planarfigures on top of the other content // the crosshair is rendered into the z = 1 layer. static const float PLANAR_OFFSET = 0.5f; mitk::PlanarFigureMapper2D::PlanarFigureMapper2D() + : m_NodeModified(true) + , m_NodeModifiedObserverTag(0) + , m_NodeModifiedObserverAdded(false) { - m_NodeModifiedObserverTag = -1; - m_NodeModified = true; this->InitializeDefaultPlanarFigureProperties(); } mitk::PlanarFigureMapper2D::~PlanarFigureMapper2D() { - if ( m_NodeModifiedObserverTag != -1 - && GetDataNode() != NULL ) + if ( m_NodeModifiedObserverAdded && GetDataNode() != NULL ) { GetDataNode()->RemoveObserver( m_NodeModifiedObserverTag ); } } void mitk::PlanarFigureMapper2D::Paint( mitk::BaseRenderer *renderer ) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; // Get PlanarFigure from input mitk::PlanarFigure *planarFigure = const_cast< mitk::PlanarFigure * >( static_cast< const mitk::PlanarFigure * >( GetDataNode()->GetData() ) ); // Check if PlanarFigure has already been placed; otherwise, do nothing if ( !planarFigure->IsPlaced() ) { return; } // Get 2D geometry frame of PlanarFigure mitk::Geometry2D *planarFigureGeometry2D = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); if ( planarFigureGeometry2D == NULL ) { MITK_ERROR << "PlanarFigure does not have valid Geometry2D!"; return; } // Get current world 2D geometry from renderer const mitk::Geometry2D *rendererGeometry2D = renderer->GetCurrentWorldGeometry2D(); // If the PlanarFigure geometry is a plane geometry, check if current // world plane is parallel to and within the planar figure geometry bounds // (otherwise, display nothing) mitk::PlaneGeometry *planarFigurePlaneGeometry = dynamic_cast< PlaneGeometry * >( planarFigureGeometry2D ); const mitk::PlaneGeometry *rendererPlaneGeometry = dynamic_cast< const PlaneGeometry * >( rendererGeometry2D ); if ( (planarFigurePlaneGeometry != NULL) && (rendererPlaneGeometry != NULL) ) { double planeThickness = planarFigurePlaneGeometry->GetExtentInMM( 2 ); if ( !planarFigurePlaneGeometry->IsParallel( rendererPlaneGeometry ) || !(planarFigurePlaneGeometry->DistanceFromPlane( rendererPlaneGeometry ) < planeThickness / 3.0) ) { // Planes are not parallel or renderer plane is not within PlanarFigure // geometry bounds --> exit return; } } else { // Plane is not valid (curved reformations are not possible yet) return; } // Get display geometry mitk::DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry(); assert( displayGeometry != NULL ); // Apply visual appearance properties from the PropertyList ApplyColorAndOpacityProperties( renderer ); // Enable line antialiasing glEnable( GL_LINE_SMOOTH ); glHint( GL_LINE_SMOOTH_HINT, GL_NICEST ); glEnable(GL_DEPTH_TEST); // Get properties from node (if present) const mitk::DataNode* node=this->GetDataNode(); this->InitializePlanarFigurePropertiesFromDataNode( node ); PlanarFigureDisplayMode lineDisplayMode = PF_DEFAULT; if ( m_IsSelected ) { lineDisplayMode = PF_SELECTED; } else if ( m_IsHovering ) { lineDisplayMode = PF_HOVER; } mitk::Point2D anchorPoint; anchorPoint[0] = 0; anchorPoint[1] = 1; // render the actual lines of the PlanarFigure RenderLines(lineDisplayMode, planarFigure, anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry); // position-offset of the annotations, is set in RenderAnnotations() and // used in RenderQuantities() double annotationOffset = 0.0; //Get Global Opacity float globalOpacity = 1.0; node->GetFloatProperty("opacity", globalOpacity); // draw name near the anchor point (point located on the right) std::string name = node->GetName(); if ( m_DrawName && !name.empty() ) { RenderAnnotations(renderer, name, anchorPoint, globalOpacity, lineDisplayMode, annotationOffset); } // draw feature quantities (if requested) next to the anchor point, // but under the name (that is where 'annotationOffset' is used) if ( m_DrawQuantities ) { RenderQuantities(planarFigure, renderer, anchorPoint, annotationOffset, globalOpacity, lineDisplayMode); } if ( m_DrawControlPoints ) { // draw the control-points RenderControlPoints(planarFigure, lineDisplayMode, planarFigureGeometry2D, rendererGeometry2D, displayGeometry); } glLineWidth( 1.0f ); } void mitk::PlanarFigureMapper2D::PaintPolyLine( mitk::PlanarFigure::PolyLineType vertices, bool closed, Point2D& anchorPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry) { mitk::Point2D rightMostPoint; rightMostPoint.Fill( itk::NumericTraits::min() ); // transform all vertices into Point2Ds in display-Coordinates and store them in vector std::vector pointlist; for ( PlanarFigure::PolyLineType::iterator iter = vertices.begin(); iter!=vertices.end(); iter++ ) { // Draw this 2D point as OpenGL vertex mitk::Point2D displayPoint; this->TransformObjectToDisplay( iter->Point, displayPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); pointlist.push_back(displayPoint); if ( displayPoint[0] > rightMostPoint[0] ) rightMostPoint = displayPoint; } // now paint all the points in one run std::vector::iterator pointIter; if ( closed ) { glBegin( GL_LINE_LOOP ); } else { glBegin( GL_LINE_STRIP ); } for ( pointIter = pointlist.begin(); pointIter!=pointlist.end(); pointIter++ ) { glVertex3f( (*pointIter)[0], (*pointIter)[1], PLANAR_OFFSET ); } glEnd(); anchorPoint = rightMostPoint; } void mitk::PlanarFigureMapper2D::DrawMainLines( mitk::PlanarFigure* figure, Point2D& anchorPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry) { unsigned short numberOfPolyLines = figure->GetPolyLinesSize(); for ( unsigned short loop=0; loopGetPolyLine(loop); this->PaintPolyLine( polyline, figure->IsClosed(), anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } } void mitk::PlanarFigureMapper2D::DrawHelperLines( mitk::PlanarFigure* figure, Point2D& anchorPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry) { unsigned short numberOfHelperPolyLines = figure->GetHelperPolyLinesSize(); // Draw helper objects for ( unsigned int loop=0; loopGetHelperPolyLine(loop, displayGeometry->GetScaleFactorMMPerDisplayUnit(), displayGeometry->GetDisplayHeight() ); // Check if the current helper objects is to be painted if ( !figure->IsHelperToBePainted( loop ) ) { continue; } // ... and once normally above the shadow. this->PaintPolyLine( helperPolyLine, false, anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } } void mitk::PlanarFigureMapper2D::TransformObjectToDisplay( const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ) { mitk::Point3D point3D; // Map circle point from local 2D geometry into 3D world space objectGeometry->Map( point2D, point3D ); // Project 3D world point onto display geometry rendererGeometry->Map( point3D, displayPoint ); displayGeometry->WorldToDisplay( displayPoint, displayPoint ); } void mitk::PlanarFigureMapper2D::DrawMarker( const mitk::Point2D &point, float* lineColor, float lineOpacity, float* markerColor, float markerOpacity, float lineWidth, PlanarFigureControlPointStyleProperty::Shape shape, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ) { mitk::Point2D displayPoint; if ( markerOpacity == 0 && lineOpacity == 0 ) return; this->TransformObjectToDisplay( point, displayPoint, objectGeometry, rendererGeometry, displayGeometry ); glColor4f( markerColor[0], markerColor[1], markerColor[2], markerOpacity ); glLineWidth( lineWidth ); switch ( shape ) { case PlanarFigureControlPointStyleProperty::Square: default: { // Paint filled square // Disable line antialiasing (does not look nice for squares) glDisable( GL_LINE_SMOOTH ); if ( markerOpacity > 0 ) { glRectf( displayPoint[0] - 4, displayPoint[1] - 4, displayPoint[0] + 4, displayPoint[1] + 4 ); } // Paint outline glColor4f( lineColor[0], lineColor[1], lineColor[2], lineOpacity ); glBegin( GL_LINE_LOOP ); glVertex3f( displayPoint[0] - 4, displayPoint[1] - 4, PLANAR_OFFSET ); glVertex3f( displayPoint[0] - 4, displayPoint[1] + 4, PLANAR_OFFSET ); glVertex3f( displayPoint[0] + 4, displayPoint[1] + 4, PLANAR_OFFSET ); glVertex3f( displayPoint[0] + 4, displayPoint[1] - 4, PLANAR_OFFSET ); glEnd(); break; } case PlanarFigureControlPointStyleProperty::Circle: { float radius = 4.0; if ( markerOpacity > 0 ) { // Paint filled circle glBegin( GL_POLYGON ); for ( int angle = 0; angle < 8; ++angle ) { float angleRad = angle * (float) 3.14159 / 4.0; float x = displayPoint[0] + radius * (float)cos( angleRad ); float y = displayPoint[1] + radius * (float)sin( angleRad ); glVertex3f(x, y, PLANAR_OFFSET); } glEnd(); } // Paint outline glColor4f( lineColor[0], lineColor[1], lineColor[2], lineOpacity ); glBegin( GL_LINE_LOOP ); for ( int angle = 0; angle < 8; ++angle ) { float angleRad = angle * (float) 3.14159 / 4.0; float x = displayPoint[0] + radius * (float)cos( angleRad ); float y = displayPoint[1] + radius * (float)sin( angleRad ); glVertex3f(x, y, PLANAR_OFFSET); } glEnd(); break; } } // end switch } void mitk::PlanarFigureMapper2D::InitializeDefaultPlanarFigureProperties() { m_IsSelected = false; m_IsHovering = false; m_DrawOutline = false; m_DrawQuantities = false; m_DrawShadow = false; m_DrawControlPoints = false; m_DrawName = true; m_DrawDashed = true; m_ShadowWidthFactor = 1.2; m_LineWidth = 1.0; m_OutlineWidth = 4.0; m_HelperlineWidth = 2.0; m_ControlPointShape = PlanarFigureControlPointStyleProperty::Square; this->SetColorProperty( m_LineColor, PF_DEFAULT, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_LineOpacity, PF_DEFAULT, 1.0 ); this->SetColorProperty( m_OutlineColor, PF_DEFAULT, 0.0, 0.0, 1.0 ); this->SetFloatProperty( m_OutlineOpacity, PF_DEFAULT, 1.0 ); this->SetColorProperty( m_HelperlineColor, PF_DEFAULT, 0.4, 0.8, 0.2 ); this->SetFloatProperty( m_HelperlineOpacity, PF_DEFAULT, 0.4 ); this->SetColorProperty( m_MarkerlineColor, PF_DEFAULT, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_MarkerlineOpacity, PF_DEFAULT, 1.0 ); this->SetColorProperty( m_MarkerColor, PF_DEFAULT, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_MarkerOpacity, PF_DEFAULT, 0.0 ); this->SetColorProperty( m_LineColor, PF_HOVER, 1.0, 0.7, 0.0 ); this->SetFloatProperty( m_LineOpacity, PF_HOVER, 1.0 ); this->SetColorProperty( m_OutlineColor, PF_HOVER, 0.0, 0.0, 1.0 ); this->SetFloatProperty( m_OutlineOpacity, PF_HOVER, 1.0 ); this->SetColorProperty( m_HelperlineColor, PF_HOVER, 0.4, 0.8, 0.2 ); this->SetFloatProperty( m_HelperlineOpacity, PF_HOVER, 0.4 ); this->SetColorProperty( m_MarkerlineColor, PF_HOVER, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_MarkerlineOpacity, PF_HOVER, 1.0 ); this->SetColorProperty( m_MarkerColor, PF_HOVER, 1.0, 0.6, 0.0 ); this->SetFloatProperty( m_MarkerOpacity, PF_HOVER, 0.2 ); this->SetColorProperty( m_LineColor, PF_SELECTED, 1.0, 0.0, 0.0 ); this->SetFloatProperty( m_LineOpacity, PF_SELECTED, 1.0 ); this->SetColorProperty( m_OutlineColor, PF_SELECTED, 0.0, 0.0, 1.0 ); this->SetFloatProperty( m_OutlineOpacity, PF_SELECTED, 1.0 ); this->SetColorProperty( m_HelperlineColor, PF_SELECTED, 0.4, 0.8, 0.2 ); this->SetFloatProperty( m_HelperlineOpacity, PF_SELECTED, 0.4 ); this->SetColorProperty( m_MarkerlineColor, PF_SELECTED, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_MarkerlineOpacity, PF_SELECTED, 1.0 ); this->SetColorProperty( m_MarkerColor, PF_SELECTED, 1.0, 0.6, 0.0 ); this->SetFloatProperty( m_MarkerOpacity, PF_SELECTED, 1.0 ); } void mitk::PlanarFigureMapper2D::InitializePlanarFigurePropertiesFromDataNode( const mitk::DataNode* node ) { if ( node == NULL ) { return; } - // if we have not added an observer for ModifiedEvents on teh DataNode, + // if we have not added an observer for ModifiedEvents on the DataNode, // we add one now. - if ( m_NodeModifiedObserverTag == -1 ) + if ( !m_NodeModifiedObserverAdded ) { itk::SimpleMemberCommand::Pointer nodeModifiedCommand = itk::SimpleMemberCommand::New(); nodeModifiedCommand->SetCallbackFunction(this, &mitk::PlanarFigureMapper2D::OnNodeModified); m_NodeModifiedObserverTag = node->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand); + m_NodeModifiedObserverAdded = true; } // If the DataNode has not been modified since the last execution of // this method, we do not run it now. if ( !m_NodeModified ) return; // Mark the current properties as unmodified m_NodeModified = false; //Get Global Opacity float globalOpacity = 1.0; node->GetFloatProperty("opacity", globalOpacity); node->GetBoolProperty( "selected", m_IsSelected ); node->GetBoolProperty( "planarfigure.ishovering", m_IsHovering ); node->GetBoolProperty( "planarfigure.drawoutline", m_DrawOutline ); node->GetBoolProperty( "planarfigure.drawshadow", m_DrawShadow ); node->GetBoolProperty( "planarfigure.drawquantities", m_DrawQuantities ); node->GetBoolProperty( "planarfigure.drawcontrolpoints", m_DrawControlPoints ); node->GetBoolProperty( "planarfigure.drawname", m_DrawName ); node->GetBoolProperty( "planarfigure.drawdashed", m_DrawDashed ); node->GetFloatProperty( "planarfigure.line.width", m_LineWidth ); node->GetFloatProperty( "planarfigure.shadow.widthmodifier", m_ShadowWidthFactor ); node->GetFloatProperty( "planarfigure.outline.width", m_OutlineWidth ); node->GetFloatProperty( "planarfigure.helperline.width", m_HelperlineWidth ); PlanarFigureControlPointStyleProperty::Pointer styleProperty = dynamic_cast< PlanarFigureControlPointStyleProperty* >( node->GetProperty( "planarfigure.controlpointshape" ) ); if ( styleProperty.IsNotNull() ) { m_ControlPointShape = styleProperty->GetShape(); } //Set default color and opacity //If property "planarfigure.default.*.color" exists, then use that color. Otherwise global "color" property is used. if( !node->GetColor( m_LineColor[PF_DEFAULT], NULL, "planarfigure.default.line.color")) { node->GetColor( m_LineColor[PF_DEFAULT], NULL, "color" ); } node->GetFloatProperty( "planarfigure.default.line.opacity", m_LineOpacity[PF_DEFAULT] ); if( !node->GetColor( m_OutlineColor[PF_DEFAULT], NULL, "planarfigure.default.outline.color")) { node->GetColor( m_OutlineColor[PF_DEFAULT], NULL, "color" ); } node->GetFloatProperty( "planarfigure.default.outline.opacity", m_OutlineOpacity[PF_DEFAULT] ); if( !node->GetColor( m_HelperlineColor[PF_DEFAULT], NULL, "planarfigure.default.helperline.color")) { node->GetColor( m_HelperlineColor[PF_DEFAULT], NULL, "color" ); } node->GetFloatProperty( "planarfigure.default.helperline.opacity", m_HelperlineOpacity[PF_DEFAULT] ); node->GetColor( m_MarkerlineColor[PF_DEFAULT], NULL, "planarfigure.default.markerline.color" ); node->GetFloatProperty( "planarfigure.default.markerline.opacity", m_MarkerlineOpacity[PF_DEFAULT] ); node->GetColor( m_MarkerColor[PF_DEFAULT], NULL, "planarfigure.default.marker.color" ); node->GetFloatProperty( "planarfigure.default.marker.opacity", m_MarkerOpacity[PF_DEFAULT] ); //Set hover color and opacity node->GetColor( m_LineColor[PF_HOVER], NULL, "planarfigure.hover.line.color" ); node->GetFloatProperty( "planarfigure.hover.line.opacity", m_LineOpacity[PF_HOVER] ); node->GetColor( m_OutlineColor[PF_HOVER], NULL, "planarfigure.hover.outline.color" ); node->GetFloatProperty( "planarfigure.hover.outline.opacity", m_OutlineOpacity[PF_HOVER] ); node->GetColor( m_HelperlineColor[PF_HOVER], NULL, "planarfigure.hover.helperline.color" ); node->GetFloatProperty( "planarfigure.hover.helperline.opacity", m_HelperlineOpacity[PF_HOVER] ); node->GetColor( m_MarkerlineColor[PF_HOVER], NULL, "planarfigure.hover.markerline.color" ); node->GetFloatProperty( "planarfigure.hover.markerline.opacity", m_MarkerlineOpacity[PF_HOVER] ); node->GetColor( m_MarkerColor[PF_HOVER], NULL, "planarfigure.hover.marker.color" ); node->GetFloatProperty( "planarfigure.hover.marker.opacity", m_MarkerOpacity[PF_HOVER] ); //Set selected color and opacity node->GetColor( m_LineColor[PF_SELECTED], NULL, "planarfigure.selected.line.color" ); node->GetFloatProperty( "planarfigure.selected.line.opacity", m_LineOpacity[PF_SELECTED] ); node->GetColor( m_OutlineColor[PF_SELECTED], NULL, "planarfigure.selected.outline.color" ); node->GetFloatProperty( "planarfigure.selected.outline.opacity", m_OutlineOpacity[PF_SELECTED] ); node->GetColor( m_HelperlineColor[PF_SELECTED], NULL, "planarfigure.selected.helperline.color" ); node->GetFloatProperty( "planarfigure.selected.helperline.opacity", m_HelperlineOpacity[PF_SELECTED] ); node->GetColor( m_MarkerlineColor[PF_SELECTED], NULL, "planarfigure.selected.markerline.color" ); node->GetFloatProperty( "planarfigure.selected.markerline.opacity", m_MarkerlineOpacity[PF_SELECTED] ); node->GetColor( m_MarkerColor[PF_SELECTED], NULL, "planarfigure.selected.marker.color" ); node->GetFloatProperty( "planarfigure.selected.marker.opacity", m_MarkerOpacity[PF_SELECTED] ); //adapt opacity values to global "opacity" property for( unsigned int i = 0; i < PF_COUNT; ++i ) { m_LineOpacity[i] *= globalOpacity; m_OutlineOpacity[i] *= globalOpacity; m_HelperlineOpacity[i] *= globalOpacity; m_MarkerlineOpacity[i] *= globalOpacity; m_MarkerOpacity[i] *= globalOpacity; } } void mitk::PlanarFigureMapper2D::OnNodeModified() { m_NodeModified = true; } void mitk::PlanarFigureMapper2D::SetDefaultProperties( mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite ) { node->AddProperty( "visible", mitk::BoolProperty::New(true), renderer, overwrite ); //node->SetProperty("planarfigure.iseditable",mitk::BoolProperty::New(true)); node->AddProperty("planarfigure.isextendable",mitk::BoolProperty::New(false)); //node->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawoutline", mitk::BoolProperty::New(false) ); //node->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawcontrolpoints", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawname", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawdashed", mitk::BoolProperty::New(false) ); node->AddProperty("planarfigure.line.width", mitk::FloatProperty::New(2.0) ); node->AddProperty("planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0) ); node->AddProperty("planarfigure.outline.width", mitk::FloatProperty::New(2.0) ); node->AddProperty("planarfigure.helperline.width", mitk::FloatProperty::New(2.0) ); node->AddProperty( "planarfigure.default.line.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.default.outline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.default.helperline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); node->AddProperty( "planarfigure.default.markerline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); node->AddProperty( "planarfigure.default.marker.opacity",mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.line.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.outline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.markerline.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.marker.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.marker.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.selected.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.line.opacity",mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.outline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty( "planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.helperline.opacity",mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.marker.opacity",mitk::FloatProperty::New(1.0)); } void mitk::PlanarFigureMapper2D::RenderControlPoints( mitk::PlanarFigure * planarFigure, PlanarFigureDisplayMode lineDisplayMode, mitk::Geometry2D * planarFigureGeometry2D, const mitk::Geometry2D * rendererGeometry2D, mitk::DisplayGeometry * displayGeometry ) { bool isEditable = true; m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable ); PlanarFigureDisplayMode pointDisplayMode = PF_DEFAULT; unsigned int selectedControlPointsIdx = (unsigned int) planarFigure->GetSelectedControlPoint(); unsigned int numberOfControlPoints = planarFigure->GetNumberOfControlPoints(); // Draw markers at control points (selected control point will be colored) for ( unsigned int i = 0; i < numberOfControlPoints ; ++i ) { // Only if planar figure is marked as editable: display markers (control points) in a // different style if mouse is over them or they are selected if ( isEditable ) { if ( i == selectedControlPointsIdx ) { pointDisplayMode = PF_SELECTED; } else if ( m_IsHovering && isEditable ) { pointDisplayMode = PF_HOVER; } } if ( m_MarkerOpacity[pointDisplayMode] == 0 && m_MarkerlineOpacity[pointDisplayMode] == 0 ) { continue; } if ( m_DrawOutline ) { // draw outlines for markers as well // linewidth for the contour is only half, as full width looks // much too thick! this->DrawMarker( planarFigure->GetControlPoint( i ), m_OutlineColor[lineDisplayMode], m_MarkerlineOpacity[pointDisplayMode], m_OutlineColor[lineDisplayMode], m_MarkerOpacity[pointDisplayMode], m_OutlineWidth/2, m_ControlPointShape, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } this->DrawMarker( planarFigure->GetControlPoint( i ), m_MarkerlineColor[pointDisplayMode], m_MarkerlineOpacity[pointDisplayMode], m_MarkerColor[pointDisplayMode], m_MarkerOpacity[pointDisplayMode], m_LineWidth, m_ControlPointShape, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } if ( planarFigure->IsPreviewControlPointVisible() ) { this->DrawMarker( planarFigure->GetPreviewControlPoint(), m_MarkerlineColor[PF_HOVER], m_MarkerlineOpacity[PF_HOVER], m_MarkerColor[PF_HOVER], m_MarkerOpacity[PF_HOVER], m_LineWidth, m_ControlPointShape, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } } void mitk::PlanarFigureMapper2D::RenderAnnotations( mitk::BaseRenderer * renderer, std::string name, mitk::Point2D anchorPoint, float globalOpacity, PlanarFigureDisplayMode lineDisplayMode, double &annotationOffset ) { mitk::VtkPropRenderer* openGLrenderer = dynamic_cast( renderer ); if ( openGLrenderer ) { openGLrenderer->WriteSimpleText( name, anchorPoint[0] + 6.0, anchorPoint[1] + 4.0, 0, 0, 0, globalOpacity ); //this is a shadow openGLrenderer->WriteSimpleText( name, anchorPoint[0] + 5.0, anchorPoint[1] + 5.0, m_LineColor[lineDisplayMode][0], m_LineColor[lineDisplayMode][1], m_LineColor[lineDisplayMode][2], globalOpacity ); // If drawing is successful, add approximate height to annotation offset annotationOffset -= 15.0; } } void mitk::PlanarFigureMapper2D::RenderQuantities( mitk::PlanarFigure * planarFigure, mitk::BaseRenderer * renderer, mitk::Point2D anchorPoint, double &annotationOffset, float globalOpacity, PlanarFigureDisplayMode lineDisplayMode ) { std::stringstream quantityString; quantityString.setf( ios::fixed, ios::floatfield ); quantityString.precision( 1 ); bool firstActiveFeature = true; for ( unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i ) { if( planarFigure->IsFeatureActive(i) && planarFigure->IsFeatureVisible( i ) ) { if ( ! firstActiveFeature ) { quantityString << " x "; } quantityString << planarFigure->GetQuantity( i ) << " "; quantityString << planarFigure->GetFeatureUnit( i ); firstActiveFeature = false; } } mitk::VtkPropRenderer* openGLrenderer = dynamic_cast( renderer ); if ( openGLrenderer ) { openGLrenderer->WriteSimpleText( quantityString.str().c_str(), anchorPoint[0] + 6.0, anchorPoint[1] + 4.0 + annotationOffset, 0, 0, 0, globalOpacity ); //this is a shadow openGLrenderer->WriteSimpleText( quantityString.str().c_str(), anchorPoint[0] + 5.0, anchorPoint[1] + 5.0 + annotationOffset, m_LineColor[lineDisplayMode][0], m_LineColor[lineDisplayMode][1], m_LineColor[lineDisplayMode][2], globalOpacity ); // If drawing is successful, add approximate height to annotation offset annotationOffset -= 15.0; } } void mitk::PlanarFigureMapper2D::RenderLines( PlanarFigureDisplayMode lineDisplayMode, mitk::PlanarFigure * planarFigure, mitk::Point2D &anchorPoint, mitk::Geometry2D * planarFigureGeometry2D, const mitk::Geometry2D * rendererGeometry2D, mitk::DisplayGeometry * displayGeometry ) { if ( m_DrawDashed ) { glLineStipple(1, 0x00FF); glEnable(GL_LINE_STIPPLE); } // If we want to draw an outline, we do it here if ( m_DrawOutline ) { float* color = m_OutlineColor[lineDisplayMode]; float opacity = m_OutlineOpacity[lineDisplayMode]; // convert to a float array that also contains opacity, faster GL float* colorVector = new float[4]; colorVector[0] = color[0]; colorVector[1] = color[1]; colorVector[2] = color[2]; colorVector[3] = opacity; // set the color and opacity here as it is common for all outlines glColor4fv( colorVector ); glLineWidth(m_OutlineWidth); // Draw the outline for all polylines if requested this->DrawMainLines( planarFigure, anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); // Draw the outline for all helper objects if requested this->DrawHelperLines( planarFigure, anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); // cleanup delete[] colorVector; } // If we want to draw a shadow, we do it here if ( m_DrawShadow ) { // determine the shadow opacity float opacity = m_OutlineOpacity[lineDisplayMode]; float shadowOpacity = 0.0f; if( opacity > 0.2f ) shadowOpacity = opacity - 0.2f; // convert to a float array that also contains opacity, faster GL float* shadow = new float[4]; shadow[0] = 0; shadow[1] = 0; shadow[2] = 0; shadow[3] = shadowOpacity; // set the color and opacity here as it is common for all shadows glColor4fv( shadow ); glLineWidth( m_OutlineWidth * m_ShadowWidthFactor ); // Draw the outline for all polylines if requested this->DrawMainLines( planarFigure, anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); // Draw the outline for all helper objects if requested this->DrawHelperLines( planarFigure, anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); // cleanup delete[] shadow; } // set this in brackets to avoid duplicate variables in the same scope { float* color = m_LineColor[lineDisplayMode]; float opacity = m_LineOpacity[lineDisplayMode]; // convert to a float array that also contains opacity, faster GL float* colorVector = new float[4]; colorVector[0] = color[0]; colorVector[1] = color[1]; colorVector[2] = color[2]; colorVector[3] = opacity; // set the color and opacity here as it is common for all mainlines glColor4fv( colorVector ); glLineWidth( m_LineWidth ); // Draw the main line for all polylines this->DrawMainLines( planarFigure, anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); float* helperColor = m_HelperlineColor[lineDisplayMode]; float helperOpacity = m_HelperlineOpacity[lineDisplayMode]; // convert to a float array that also contains opacity, faster GL float* helperColorVector = new float[4]; helperColorVector[0] = helperColor[0]; helperColorVector[1] = helperColor[1]; helperColorVector[2] = helperColor[2]; helperColorVector[3] = helperOpacity; // we only set the color for the helperlines as the linewidth is unchanged glColor4fv( helperColorVector ); // Draw helper objects this->DrawHelperLines( planarFigure, anchorPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); // cleanup delete[] colorVector; delete[] helperColorVector; } if ( m_DrawDashed ) { glDisable(GL_LINE_STIPPLE); } } diff --git a/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.h b/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.h index 69305b7e6f..233f4d92a6 100644 --- a/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.h +++ b/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.h @@ -1,304 +1,307 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITK_PLANAR_FIGURE_MAPPER_2D_H_ #define MITK_PLANAR_FIGURE_MAPPER_2D_H_ #include "mitkCommon.h" #include "PlanarFigureExports.h" #include "mitkGLMapper.h" #include "mitkPlanarFigure.h" #include "mitkPlanarFigureControlPointStyleProperty.h" namespace mitk { class BaseRenderer; class Contour; /** * \brief OpenGL-based mapper to render display sub-class instances of mitk::PlanarFigure * * The appearance of planar figures can be configured through properties. If no properties are specified, * default values will be used. There are four elements a planar figure consists of: * *
    *
  1. "line": the main line segments of the planar figure (note: text is drawn in the same style) *
  2. "helperline": additional line segments of planar figures, such as arrow tips, arches of angles, etc. *
  3. "outline": background which is drawn behind the lines and helperlines of the planar figure (optional) *
  4. "marker": the markers (control points) of a planar figure *
  5. "markerline": the lines by which markers (control points) are surrounded *
* * In the following, all appearance-related planar figure properties are listed: * *
    *
  1. General properties for the planar figure *
      *
    • "planarfigure.drawoutline": if true, the "outline" lines is drawn *
    • "planarfigure.drawquantities": if true, the quantities (text) associated with the planar figure is drawn *
    • "planarfigure.drawname": if true, the name specified by the dataNode is drawn *
    • "planarfigure.drawshadow": if true, a black shadow is drawn around the planar figure *
    • "planarfigure.controlpointshape": style of the control points (enum) *
    *
  2. Line widths of planar figure elements *
      *
    • "planarfigure.line.width": width of "line" segments (float value, in mm) *
    • "planarfigure.shadow.widthmodifier": the width of the shadow is defined by width of the "line" * this modifier *
    • "planarfigure.outline.width": width of "outline" segments (float value, in mm) *
    • "planarfigure.helperline.width": width of "helperline" segments (float value, in mm) *
    *
  3. Color/opacity of planar figure elements in normal mode (unselected) *
      *
    • "planarfigure.default.line.color" *
    • "planarfigure.default.line.opacity" *
    • "planarfigure.default.outline.color" *
    • "planarfigure.default.outline.opacity" *
    • "planarfigure.default.helperline.color" *
    • "planarfigure.default.helperline.opacity" *
    • "planarfigure.default.markerline.color" *
    • "planarfigure.default.markerline.opacity" *
    • "planarfigure.default.marker.color" *
    • "planarfigure.default.marker.opacity" *
    *
  4. Color/opacity of planar figure elements in hover mode (mouse-over) *
      *
    • "planarfigure.hover.line.color" *
    • "planarfigure.hover.line.opacity" *
    • "planarfigure.hover.outline.color" *
    • "planarfigure.hover.outline.opacity" *
    • "planarfigure.hover.helperline.color" *
    • "planarfigure.hover.helperline.opacity" *
    • "planarfigure.hover.markerline.color" *
    • "planarfigure.hover.markerline.opacity" *
    • "planarfigure.hover.marker.color" *
    • "planarfigure.hover.marker.opacity" *
    *
  5. Color/opacity of planar figure elements in selected mode *
      *
    • "planarfigure.selected.line.color" *
    • "planarfigure.selected.line.opacity" *
    • "planarfigure.selected.outline.color" *
    • "planarfigure.selected.outline.opacity" *
    • "planarfigure.selected.helperline.color" *
    • "planarfigure.selected.helperline.opacity" *
    • "planarfigure.selected.markerline.color;" *
    • "planarfigure.selected.markerline.opacity" *
    • "planarfigure.selected.marker.color" *
    • "planarfigure.selected.marker.opacity" *
    *
* * \ingroup Mapper */ class PlanarFigure_EXPORT PlanarFigureMapper2D : public GLMapper { public: mitkClassMacro(PlanarFigureMapper2D, GLMapper); itkNewMacro(Self); /** * reimplemented from Baseclass */ virtual void Paint(BaseRenderer * renderer); static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); protected: enum PlanarFigureDisplayMode { PF_DEFAULT = 0, PF_HOVER = 1, PF_SELECTED = 2, PF_COUNT = 3 //helper variable }; PlanarFigureMapper2D(); virtual ~PlanarFigureMapper2D(); /** * \brief Renders all the lines defined by the PlanarFigure. * * This method renders all the lines that are defined by the PlanarFigure. * That includes the mainlines and helperlines as well as their shadows * and the outlines. * * This method already takes responsibility for the setting of the relevant * openGL attributes to reduce unnecessary setting of these attributes. * (e.g. no need to set color twice if it's the same) */ void RenderLines( PlanarFigureDisplayMode lineDisplayMode, mitk::PlanarFigure * planarFigure, mitk::Point2D &anchorPoint, mitk::Geometry2D * planarFigureGeometry2D, const mitk::Geometry2D * rendererGeometry2D, mitk::DisplayGeometry * displayGeometry ); /** * \brief Renders the quantities of the figure below the text annotations. */ void RenderQuantities( mitk::PlanarFigure * planarFigure, mitk::BaseRenderer * renderer, mitk::Point2D anchorPoint, double &annotationOffset, float globalOpacity, PlanarFigureDisplayMode lineDisplayMode ); /** * \brief Renders the text annotations. */ void RenderAnnotations( mitk::BaseRenderer * renderer, std::string name, mitk::Point2D anchorPoint, float globalOpacity, PlanarFigureDisplayMode lineDisplayMode, double &annotationOffset ); /** * \brief Renders the control-points. */ void RenderControlPoints( mitk::PlanarFigure * planarFigure, PlanarFigureDisplayMode lineDisplayMode, mitk::Geometry2D * planarFigureGeometry2D, const mitk::Geometry2D * rendererGeometry2D, mitk::DisplayGeometry * displayGeometry ); void TransformObjectToDisplay( const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ); void DrawMarker( const mitk::Point2D &point, float* lineColor, float lineOpacity, float* markerColor, float markerOpacity, float lineWidth, PlanarFigureControlPointStyleProperty::Shape shape, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ); /** * \brief Actually paints the polyline defined by the figure. */ void PaintPolyLine( mitk::PlanarFigure::PolyLineType vertices, bool closed, Point2D& anchorPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry); /** * \brief Internally used by RenderLines() to draw the mainlines using * PaintPolyLine(). */ void DrawMainLines( mitk::PlanarFigure* figure, Point2D& anchorPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry) ; /** * \brief Internally used by RenderLines() to draw the helperlines using * PaintPolyLine(). */ void DrawHelperLines( mitk::PlanarFigure* figure, Point2D& anchorPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry) ; void InitializeDefaultPlanarFigureProperties(); void InitializePlanarFigurePropertiesFromDataNode( const mitk::DataNode* node ); void SetColorProperty( float property[3][3], PlanarFigureDisplayMode mode, float red, float green, float blue ) { property[mode][0] = red; property[mode][1] = green; property[mode][2] = blue; } void SetFloatProperty( float* property, PlanarFigureDisplayMode mode, float value ) { property[mode] = value; } /** * \brief Callback that sets m_NodeModified to true. * * This method set the bool flag m_NodeModified to true. It's a callback * that is executed when a itk::ModifiedEvet is invoked on our * DataNode. */ void OnNodeModified(); private: bool m_IsSelected; bool m_IsHovering; bool m_DrawOutline; bool m_DrawQuantities; bool m_DrawShadow; bool m_DrawControlPoints; bool m_DrawName; bool m_DrawDashed; // the width of the shadow is defined as 'm_LineWidth * m_ShadowWidthFactor' float m_LineWidth; float m_ShadowWidthFactor; float m_OutlineWidth; float m_HelperlineWidth; float m_PointWidth; PlanarFigureControlPointStyleProperty::Shape m_ControlPointShape; float m_LineColor[3][3]; float m_LineOpacity[3]; float m_OutlineColor[3][3]; float m_OutlineOpacity[3]; float m_HelperlineColor[3][3]; float m_HelperlineOpacity[3]; float m_MarkerlineColor[3][3]; float m_MarkerlineOpacity[3]; float m_MarkerColor[3][3]; float m_MarkerOpacity[3]; // Bool flag that represents whether or not the DataNode has been modified. bool m_NodeModified; // Observer-tag for listening to itk::ModifiedEvents on the DataNode unsigned long m_NodeModifiedObserverTag; + + // Bool flag that indicates if a node modified observer was added + bool m_NodeModifiedObserverAdded; }; } // namespace mitk #endif /* MITK_PLANAR_FIGURE_MAPPER_2D_H_ */ diff --git a/Modules/PlanarFigure/Testing/mitkPlanarFigureIOTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarFigureIOTest.cpp index 69bbaae013..b868d3f8d5 100644 --- a/Modules/PlanarFigure/Testing/mitkPlanarFigureIOTest.cpp +++ b/Modules/PlanarFigure/Testing/mitkPlanarFigureIOTest.cpp @@ -1,620 +1,587 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkPlanarAngle.h" #include "mitkPlanarCircle.h" #include "mitkPlanarCross.h" #include "mitkPlanarFourPointAngle.h" #include "mitkPlanarLine.h" #include "mitkPlanarPolygon.h" #include "mitkPlanarSubdivisionPolygon.h" #include "mitkPlanarRectangle.h" #include "mitkPlanarFigureWriter.h" #include "mitkPlanarFigureReader.h" #include "mitkPlaneGeometry.h" #include static mitk::PlanarFigure::Pointer Clone(mitk::PlanarFigure::Pointer original) { return original->Clone(); } /** \brief Helper class for testing PlanarFigure reader and writer classes. */ class PlanarFigureIOTestClass { public: typedef std::list< mitk::PlanarFigure::Pointer > PlanarFigureList; typedef std::vector< mitk::PlanarFigureWriter::Pointer > PlanarFigureToMemoryWriterList; static PlanarFigureList CreatePlanarFigures() { PlanarFigureList planarFigures; // Create PlaneGeometry on which to place the PlanarFigures mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane( 100.0, 100.0 ); // Create a few sample points for PlanarFigure placement mitk::Point2D p0; p0[0] = 20.0; p0[1] = 20.0; mitk::Point2D p1; p1[0] = 80.0; p1[1] = 80.0; mitk::Point2D p2; p2[0] = 90.0; p2[1] = 10.0; mitk::Point2D p3; p3[0] = 10.0; p3[1] = 90.0; // Create PlanarAngle mitk::PlanarAngle::Pointer planarAngle = mitk::PlanarAngle::New(); planarAngle->SetGeometry2D( planeGeometry ); planarAngle->PlaceFigure( p0 ); planarAngle->SetCurrentControlPoint( p1 ); planarAngle->AddControlPoint( p2 ); planarFigures.push_back( planarAngle.GetPointer() ); // Create PlanarCircle mitk::PlanarCircle::Pointer planarCircle = mitk::PlanarCircle::New(); planarCircle->SetGeometry2D( planeGeometry ); planarCircle->PlaceFigure( p0 ); planarCircle->SetCurrentControlPoint( p1 ); planarFigures.push_back( planarCircle.GetPointer() ); // Create PlanarCross mitk::PlanarCross::Pointer planarCross = mitk::PlanarCross::New(); planarCross->SetSingleLineMode( false ); planarCross->SetGeometry2D( planeGeometry ); planarCross->PlaceFigure( p0 ); planarCross->SetCurrentControlPoint( p1 ); planarCross->AddControlPoint( p2 ); planarCross->AddControlPoint( p3 ); planarFigures.push_back( planarCross.GetPointer() ); // Create PlanarFourPointAngle mitk::PlanarFourPointAngle::Pointer planarFourPointAngle = mitk::PlanarFourPointAngle::New(); planarFourPointAngle->SetGeometry2D( planeGeometry ); planarFourPointAngle->PlaceFigure( p0 ); planarFourPointAngle->SetCurrentControlPoint( p1 ); planarFourPointAngle->AddControlPoint( p2 ); planarFourPointAngle->AddControlPoint( p3 ); planarFigures.push_back( planarFourPointAngle.GetPointer() ); // Create PlanarLine mitk::PlanarLine::Pointer planarLine = mitk::PlanarLine::New(); planarLine->SetGeometry2D( planeGeometry ); planarLine->PlaceFigure( p0 ); planarLine->SetCurrentControlPoint( p1 ); planarFigures.push_back( planarLine.GetPointer() ); // Create PlanarPolygon mitk::PlanarPolygon::Pointer planarPolygon = mitk::PlanarPolygon::New(); planarPolygon->SetClosed( false ); planarPolygon->SetGeometry2D( planeGeometry ); planarPolygon->PlaceFigure( p0 ); planarPolygon->SetCurrentControlPoint( p1 ); planarPolygon->AddControlPoint( p2 ); planarPolygon->AddControlPoint( p3 ); planarFigures.push_back( planarPolygon.GetPointer() ); // Create PlanarSubdivisionPolygon mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon = mitk::PlanarSubdivisionPolygon::New(); planarSubdivisionPolygon->SetClosed( false ); planarSubdivisionPolygon->SetGeometry2D( planeGeometry ); planarSubdivisionPolygon->PlaceFigure( p0 ); planarSubdivisionPolygon->SetCurrentControlPoint( p1 ); planarSubdivisionPolygon->AddControlPoint( p2 ); planarSubdivisionPolygon->AddControlPoint( p3 ); planarFigures.push_back( planarSubdivisionPolygon.GetPointer() ); // Create PlanarRectangle mitk::PlanarRectangle::Pointer planarRectangle = mitk::PlanarRectangle::New(); planarRectangle->SetGeometry2D( planeGeometry ); planarRectangle->PlaceFigure( p0 ); planarRectangle->SetCurrentControlPoint( p1 ); planarFigures.push_back( planarRectangle.GetPointer() ); //create preciseGeometry which is using float coordinates mitk::PlaneGeometry::Pointer preciseGeometry = mitk::PlaneGeometry::New(); mitk::Vector3D right; right[0] = 0.0; right[1] = 1.23456; right[2] = 0.0; mitk::Vector3D down; down[0] = 1.23456; down[1] = 0.0; down[2] = 0.0; mitk::Vector3D spacing; spacing[0] = 0.0123456; spacing[1] = 0.0123456; spacing[2] = 1.123456; preciseGeometry->InitializeStandardPlane( right, down, &spacing ); //convert points into the precise coordinates mitk::Point2D p0precise; p0precise[0] = p0[0] * spacing[0]; p0precise[1] = p0[1] * spacing[1]; mitk::Point2D p1precise; p1precise[0] = p1[0] * spacing[0]; p1precise[1] = p1[1] * spacing[1]; mitk::Point2D p2precise; p2precise[0] = p2[0] * spacing[0]; p2precise[1] = p2[1] * spacing[1]; mitk::Point2D p3precise; p3precise[0] = p3[0] * spacing[0]; p3precise[1] = p3[1] * spacing[1]; //Now all PlanarFigures are create using the precise Geometry // Create PlanarCross mitk::PlanarCross::Pointer nochncross = mitk::PlanarCross::New(); nochncross->SetSingleLineMode( false ); nochncross->SetGeometry2D( preciseGeometry ); nochncross->PlaceFigure( p0precise ); nochncross->SetCurrentControlPoint( p1precise ); nochncross->AddControlPoint( p2precise ); nochncross->AddControlPoint( p3precise ); planarFigures.push_back( nochncross.GetPointer() ); // Create PlanarAngle mitk::PlanarAngle::Pointer planarAnglePrecise = mitk::PlanarAngle::New(); planarAnglePrecise->SetGeometry2D( preciseGeometry ); planarAnglePrecise->PlaceFigure( p0precise ); planarAnglePrecise->SetCurrentControlPoint( p1precise ); planarAnglePrecise->AddControlPoint( p2precise ); planarFigures.push_back( planarAnglePrecise.GetPointer() ); // Create PlanarCircle mitk::PlanarCircle::Pointer planarCirclePrecise = mitk::PlanarCircle::New(); planarCirclePrecise->SetGeometry2D( preciseGeometry ); planarCirclePrecise->PlaceFigure( p0precise ); planarCirclePrecise->SetCurrentControlPoint( p1precise ); planarFigures.push_back( planarCirclePrecise.GetPointer() ); // Create PlanarFourPointAngle mitk::PlanarFourPointAngle::Pointer planarFourPointAnglePrecise = mitk::PlanarFourPointAngle::New(); planarFourPointAnglePrecise->SetGeometry2D( preciseGeometry ); planarFourPointAnglePrecise->PlaceFigure( p0precise ); planarFourPointAnglePrecise->SetCurrentControlPoint( p1precise ); planarFourPointAnglePrecise->AddControlPoint( p2precise ); planarFourPointAnglePrecise->AddControlPoint( p3precise ); planarFigures.push_back( planarFourPointAnglePrecise.GetPointer() ); // Create PlanarLine mitk::PlanarLine::Pointer planarLinePrecise = mitk::PlanarLine::New(); planarLinePrecise->SetGeometry2D( preciseGeometry ); planarLinePrecise->PlaceFigure( p0precise ); planarLinePrecise->SetCurrentControlPoint( p1precise ); planarFigures.push_back( planarLinePrecise.GetPointer() ); // Create PlanarPolygon mitk::PlanarPolygon::Pointer planarPolygonPrecise = mitk::PlanarPolygon::New(); planarPolygonPrecise->SetClosed( false ); planarPolygonPrecise->SetGeometry2D( preciseGeometry ); planarPolygonPrecise->PlaceFigure( p0precise ); planarPolygonPrecise->SetCurrentControlPoint( p1precise ); planarPolygonPrecise->AddControlPoint( p2precise ); planarPolygonPrecise->AddControlPoint( p3precise ); planarFigures.push_back( planarPolygonPrecise.GetPointer() ); // Create PlanarSubdivisionPolygon mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygonPrecise = mitk::PlanarSubdivisionPolygon::New(); planarSubdivisionPolygonPrecise->SetClosed( false ); planarSubdivisionPolygonPrecise->SetGeometry2D( preciseGeometry ); planarSubdivisionPolygonPrecise->PlaceFigure( p0precise ); planarSubdivisionPolygonPrecise->SetCurrentControlPoint( p1precise ); planarSubdivisionPolygonPrecise->AddControlPoint( p2precise ); planarSubdivisionPolygonPrecise->AddControlPoint( p3precise ); planarFigures.push_back( planarSubdivisionPolygonPrecise.GetPointer() ); // Create PlanarRectangle mitk::PlanarRectangle::Pointer planarRectanglePrecise = mitk::PlanarRectangle::New(); planarRectanglePrecise->SetGeometry2D( preciseGeometry ); planarRectanglePrecise->PlaceFigure( p0precise ); planarRectanglePrecise->SetCurrentControlPoint( p1precise ); planarFigures.push_back( planarRectanglePrecise.GetPointer() ); return planarFigures; } static PlanarFigureList CreateDeepCopiedPlanarFigures(PlanarFigureList original) { PlanarFigureList copiedPlanarFigures; PlanarFigureList::iterator it1; for ( it1 = original.begin(); it1 != original.end(); ++it1 ) { - mitk::PlanarFigure::Pointer copiedFigure; - if(strcmp((*it1)->GetNameOfClass(), "PlanarAngle") == 0) - { - copiedFigure = mitk::PlanarAngle::New(); - } - if(strcmp((*it1)->GetNameOfClass(), "PlanarCircle") == 0) - { - copiedFigure = mitk::PlanarCircle::New(); - } - if(strcmp((*it1)->GetNameOfClass(), "PlanarLine") == 0) - { - copiedFigure = mitk::PlanarLine::New(); - } - if(strcmp((*it1)->GetNameOfClass(), "PlanarPolygon") == 0) - { - copiedFigure = mitk::PlanarPolygon::New(); - } - if(strcmp((*it1)->GetNameOfClass(), "PlanarSubdivisionPolygon") == 0) - { - copiedFigure = mitk::PlanarSubdivisionPolygon::New(); - } - if(strcmp((*it1)->GetNameOfClass(), "PlanarCross") == 0) - { - copiedFigure = mitk::PlanarCross::New(); - } - if(strcmp((*it1)->GetNameOfClass(), "PlanarRectangle") == 0) - { - copiedFigure = mitk::PlanarRectangle::New(); - } - if(strcmp((*it1)->GetNameOfClass(), "PlanarFourPointAngle") == 0) - { - copiedFigure = mitk::PlanarFourPointAngle::New(); - } + mitk::PlanarFigure::Pointer copiedFigure = (*it1)->Clone(); - copiedFigure->DeepCopy((*it1)); - copiedPlanarFigures.push_back(copiedFigure.GetPointer()); + copiedPlanarFigures.push_back(copiedFigure); } return copiedPlanarFigures; } static PlanarFigureList CreateClonedPlanarFigures(PlanarFigureList original) { PlanarFigureList clonedPlanarFigures; clonedPlanarFigures.resize(original.size()); std::transform(original.begin(), original.end(), clonedPlanarFigures.begin(), Clone); return clonedPlanarFigures; } static void VerifyPlanarFigures( PlanarFigureList &planarFigures1, PlanarFigureList &planarFigures2 ) { PlanarFigureList::iterator it1, it2; int i = 0; for ( it1 = planarFigures1.begin(); it1 != planarFigures1.end(); ++it1 ) { bool planarFigureFound = false; int j = 0; for ( it2 = planarFigures2.begin(); it2 != planarFigures2.end(); ++it2 ) { // Compare PlanarFigures (returns false if different types) if ( ComparePlanarFigures( *it1, *it2 ) ) { planarFigureFound = true; } ++j; } // Test if (at least) on PlanarFigure of the first type was found in the second list MITK_TEST_CONDITION_REQUIRED( planarFigureFound, "Testing if " << (*it1)->GetNameOfClass() << " has a counterpart " << i ); ++i; } } static bool ComparePlanarFigures( mitk::PlanarFigure* figure1, mitk::PlanarFigure* figure2 ) { // Test if PlanarFigures are of same type; otherwise return if ( strcmp( figure1->GetNameOfClass(), figure2->GetNameOfClass() ) != 0 ) { return false; } if( strcmp( figure1->GetNameOfClass(), "PlanarCross" ) == 0 ) { std::cout << "Planar Cross Found" << std::endl; } // Test for equal number of control points if(figure1->GetNumberOfControlPoints() != figure2->GetNumberOfControlPoints()) { return false; } // Test if all control points are equal for ( unsigned int i = 0; i < figure1->GetNumberOfControlPoints(); ++i ) { mitk::Point2D point1 = figure1->GetControlPoint( i ); mitk::Point2D point2 = figure2->GetControlPoint( i ); if(point1.EuclideanDistanceTo( point2 ) >= mitk::eps) { return false; } } // Test for equal number of properties typedef mitk::PropertyList::PropertyMap PropertyMap; const PropertyMap* properties1 = figure1->GetPropertyList()->GetMap(); const PropertyMap* properties2 = figure2->GetPropertyList()->GetMap(); if(properties1->size() != properties2->size()) { return false; } MITK_INFO << "List 1:"; for (PropertyMap::const_iterator i1 = properties1->begin(); i1 != properties1->end(); ++i1) { std::cout << i1->first << std::endl; } MITK_INFO << "List 2:"; for (PropertyMap::const_iterator i2 = properties2->begin(); i2 != properties2->end(); ++i2) { std::cout << i2->first << std::endl; } MITK_INFO << "-------"; // Test if all properties are equal if(!std::equal( properties1->begin(), properties1->end(), properties2->begin(), PropertyMapEntryCompare() )) { return false; } // Test if Geometry is equal const mitk::PlaneGeometry* planeGeometry1 = dynamic_cast(figure1->GetGeometry2D()); const mitk::PlaneGeometry* planeGeometry2 = dynamic_cast(figure2->GetGeometry2D()); // Test Geometry transform parameters typedef mitk::Geometry3D::TransformType TransformType; const TransformType* affineGeometry1 = planeGeometry1->GetIndexToWorldTransform(); const TransformType::ParametersType& parameters1 = affineGeometry1->GetParameters(); const TransformType::ParametersType& parameters2 = planeGeometry2->GetIndexToWorldTransform()->GetParameters(); for ( unsigned int i = 0; i < affineGeometry1->GetNumberOfParameters(); ++i ) { if ( fabs(parameters1.GetElement( i ) - parameters2.GetElement( i )) >= mitk::eps ) { return false; } } // Test Geometry bounds typedef mitk::Geometry3D::BoundsArrayType BoundsArrayType; const BoundsArrayType& bounds1 = planeGeometry1->GetBounds(); const BoundsArrayType& bounds2 = planeGeometry2->GetBounds(); for ( unsigned int i = 0; i < 6; ++i ) { if ( fabs(bounds1.GetElement( i ) - bounds2.GetElement( i )) >= mitk::eps ) { return false; }; } // Test Geometry spacing and origin mitk::Vector3D spacing1 = planeGeometry1->GetSpacing(); mitk::Vector3D spacing2 = planeGeometry2->GetSpacing(); if((spacing1 - spacing2).GetNorm() >= mitk::eps) { return false; } mitk::Point3D origin1 = planeGeometry1->GetOrigin(); mitk::Point3D origin2 = planeGeometry2->GetOrigin(); if(origin1.EuclideanDistanceTo( origin2 ) >= mitk::eps) { return false; } return true; } static void SerializePlanarFigures( PlanarFigureList &planarFigures, std::string& fileName ) { //std::string sceneFileName = Poco::Path::temp() + /*Poco::Path::separator() +*/ "scene.zip"; std::cout << "File name: " << fileName << std::endl; mitk::PlanarFigureWriter::Pointer writer = mitk::PlanarFigureWriter::New(); writer->SetFileName( fileName.c_str() ); unsigned int i; PlanarFigureList::iterator it; for ( it = planarFigures.begin(), i = 0; it != planarFigures.end(); ++it, ++i ) { writer->SetInput( i, *it ); } writer->Update(); MITK_TEST_CONDITION_REQUIRED( writer->GetSuccess(), "Testing if writing was successful"); } static PlanarFigureList DeserializePlanarFigures( std::string& fileName) { // Read in the planar figures mitk::PlanarFigureReader::Pointer reader = mitk::PlanarFigureReader::New(); reader->SetFileName( fileName.c_str() ); reader->Update(); MITK_TEST_CONDITION_REQUIRED( reader->GetSuccess(), "Testing if reading was successful"); // Store them in the list and return it PlanarFigureList planarFigures; for ( unsigned int i = 0; i < reader->GetNumberOfOutputs(); ++i ) { mitk::PlanarFigure* figure = reader->GetOutput( i ); planarFigures.push_back( figure ); } return planarFigures; } static PlanarFigureToMemoryWriterList SerializePlanarFiguresToMemoryBuffers( PlanarFigureList &planarFigures ) { PlanarFigureToMemoryWriterList pfMemoryWriters; unsigned int i; PlanarFigureList::iterator it; bool success = true; for ( it = planarFigures.begin(), i = 0; it != planarFigures.end(); ++it, ++i ) { mitk::PlanarFigureWriter::Pointer writer = mitk::PlanarFigureWriter::New(); writer->SetWriteToMemory( true ); writer->SetInput( *it ); writer->Update(); pfMemoryWriters.push_back(writer); if(!writer->GetSuccess()) success = false; } MITK_TEST_CONDITION_REQUIRED(success, "Testing if writing to memory buffers was successful"); return pfMemoryWriters; } static PlanarFigureList DeserializePlanarFiguresFromMemoryBuffers( PlanarFigureToMemoryWriterList pfMemoryWriters) { // Store them in the list and return it PlanarFigureList planarFigures; bool success = true; for ( unsigned int i = 0; i < pfMemoryWriters.size(); ++i ) { // Read in the planar figures mitk::PlanarFigureReader::Pointer reader = mitk::PlanarFigureReader::New(); reader->SetReadFromMemory( true ); reader->SetMemoryBuffer(pfMemoryWriters[i]->GetMemoryPointer(), pfMemoryWriters[i]->GetMemorySize()); reader->Update(); mitk::PlanarFigure* figure = reader->GetOutput( 0 ); planarFigures.push_back( figure ); if(!reader->GetSuccess()) success = false; } MITK_TEST_CONDITION_REQUIRED(success, "Testing if reading was successful"); return planarFigures; } private: class PropertyMapEntryCompare { public: bool operator()( const mitk::PropertyList::PropertyMap::value_type &entry1, const mitk::PropertyList::PropertyMap::value_type &entry2 ) { MITK_INFO << "Comparing " << entry1.first << "(" << entry1.second->GetValueAsString() << ") and " << entry2.first << "(" << entry2.second->GetValueAsString() << ")"; // Compare property objects contained in the map entries (see mitk::PropertyList) return *(entry1.second) == *(entry2.second); } }; }; // end test helper class /** \brief Test for PlanarFigure reader and writer classes. * * The test works as follows: * * First, a number of PlanarFigure objects of different types are created and placed with * various control points. These objects are the serialized to file, read again from file, and * the retrieved objects are compared with their control points, properties, and geometry * information to the original PlanarFigure objects. */ int mitkPlanarFigureIOTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("PlanarFigureIO"); // Create a number of PlanarFigure objects PlanarFigureIOTestClass::PlanarFigureList originalPlanarFigures = PlanarFigureIOTestClass::CreatePlanarFigures(); // Create a number of "deep-copied" planar figures to test the DeepCopy function (deprecated) PlanarFigureIOTestClass::PlanarFigureList copiedPlanarFigures = PlanarFigureIOTestClass::CreateDeepCopiedPlanarFigures(originalPlanarFigures); PlanarFigureIOTestClass::VerifyPlanarFigures(originalPlanarFigures, copiedPlanarFigures ); // Create a number of cloned planar figures to test the Clone function PlanarFigureIOTestClass::PlanarFigureList clonedPlanarFigures = PlanarFigureIOTestClass::CreateClonedPlanarFigures(originalPlanarFigures); PlanarFigureIOTestClass::VerifyPlanarFigures(originalPlanarFigures, clonedPlanarFigures ); // Write PlanarFigure objects into temp file // tmpname static unsigned long count = 0; unsigned long n = count++; std::ostringstream name; for (int i = 0; i < 6; ++i) { name << char('a' + (n % 26)); n /= 26; } std::string myname; myname.append(name.str()); std::string fileName = itksys::SystemTools::GetCurrentWorkingDirectory() + myname + ".pf"; PlanarFigureIOTestClass::SerializePlanarFigures( originalPlanarFigures, fileName ); // Write PlanarFigure objects to memory buffers PlanarFigureIOTestClass::PlanarFigureToMemoryWriterList writersWithMemoryBuffers = PlanarFigureIOTestClass::SerializePlanarFiguresToMemoryBuffers( originalPlanarFigures ); // Read PlanarFigure objects from temp file PlanarFigureIOTestClass::PlanarFigureList retrievedPlanarFigures = PlanarFigureIOTestClass::DeserializePlanarFigures( fileName ); // Read PlanarFigure objects from memory buffers PlanarFigureIOTestClass::PlanarFigureList retrievedPlanarFiguresFromMemory = PlanarFigureIOTestClass::DeserializePlanarFiguresFromMemoryBuffers( writersWithMemoryBuffers ); PlanarFigureIOTestClass::PlanarFigureToMemoryWriterList::iterator it = writersWithMemoryBuffers.begin(); while(it != writersWithMemoryBuffers.end()) { (*it)->ReleaseMemory(); ++it; } // Test if original and retrieved PlanarFigure objects are the same PlanarFigureIOTestClass::VerifyPlanarFigures( originalPlanarFigures, retrievedPlanarFigures ); // Test if original and memory retrieved PlanarFigure objects are the same PlanarFigureIOTestClass::VerifyPlanarFigures( originalPlanarFigures, retrievedPlanarFiguresFromMemory ); //empty the originalPlanarFigures originalPlanarFigures.empty(); // Test if deep-copied and retrieved PlanarFigure objects are the same PlanarFigureIOTestClass::VerifyPlanarFigures( copiedPlanarFigures, retrievedPlanarFigures ); MITK_TEST_END() } diff --git a/Modules/PlanarFigure/Testing/mitkViewportRenderingTest.cpp b/Modules/PlanarFigure/Testing/mitkViewportRenderingTest.cpp index 0e28ec8c89..4cee18f1b1 100644 --- a/Modules/PlanarFigure/Testing/mitkViewportRenderingTest.cpp +++ b/Modules/PlanarFigure/Testing/mitkViewportRenderingTest.cpp @@ -1,152 +1,152 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include "mitkNodePredicateDataType.h" #include "mitkLevelWindowProperty.h" #include "mitkColorProperty.h" #include "mitkLevelWindowProperty.h" #include "mitkPlanarFigure.h" #include "mitkSurface.h" // ITK #include // VTK #include // stdlib #include int mitkViewportRenderingTest(int argc, char* argv[]) { // 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("mitkViewportRenderingTest") // enough parameters? if ( argc < 2 ) { MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) exit( EXIT_FAILURE ); } double renderWindowWidth = atof(argv[1]); double renderWindowHeight = atof(argv[2]); double left = atof(argv[3]); double bottom = atof(argv[4]); double right = atof(argv[5]); double top = atof(argv[6]); std::string referenceFilename = argv[8+6]; argv += 6; // DO NOT attempt to read these as files, this just makes no sense argc -= 6; // DO NOT attempt to read these as files, this just makes no sense MITK_INFO << "Testing viewport "<GetSubset( mitk::TNodePredicateDataType::New()); for (ObjectsSet::const_iterator iterFigures = figures->begin(); iterFigures != figures->end(); ++iterFigures) { (*iterFigures)->SetProperty("planarfigure.default.line.color", mitk::ColorProperty::New( 1.0, 0.0, 0.0 ) ); // red (*iterFigures)->SetProperty("planarfigure.drawcontrolpoints", mitk::BoolProperty::New( false ) ); (*iterFigures)->SetProperty("planarfigure.drawname", mitk::BoolProperty::New( false ) ); (*iterFigures)->SetProperty("planarfigure.drawquantities", mitk::BoolProperty::New( true ) ); } ObjectsSet::ConstPointer surfaces = renderingHelper.GetDataStorage()->GetSubset( mitk::TNodePredicateDataType::New()); for (ObjectsSet::const_iterator iterSurfaces = surfaces->begin(); iterSurfaces != surfaces->end(); ++iterSurfaces) { (*iterSurfaces)->SetProperty("color", mitk::ColorProperty::New( 0.0, 1.0, 0.0 ) ); // green } ObjectsSet::ConstPointer images = renderingHelper.GetDataStorage()->GetSubset( mitk::TNodePredicateDataType::New()); for (ObjectsSet::const_iterator iterImages = images->begin(); iterImages != images->end(); ++iterImages) { (*iterImages)->SetProperty("levelwindow", mitk::LevelWindowProperty::New( mitk::LevelWindow(128.0, 256.0) ) ); // green int imageWidth = dynamic_cast((*iterImages)->GetData())->GetDimension(0); int imageHeight = dynamic_cast((*iterImages)->GetData())->GetDimension(1); MITK_INFO << "Image dimension "<InitializeViews( renderingHelper.GetDataStorage()->ComputeBoundingGeometry3D( images ) ); double vLeft = left / renderWindowWidth; double vBottom = bottom / renderWindowHeight; double vRight = right / renderWindowWidth; double vTop = top / renderWindowHeight; // THIS HERE IS THE ACTUAL TEST PART, all the rest is setup and decoration renderingHelper.GetVtkRenderer()->SetViewport( vLeft, vBottom, vRight, vTop ); renderingHelper.SetAutomaticallyCloseRenderWindow(true); // set to false for testing the test itself renderingHelper.Render(); //use this to generate a reference screenshot or save the file: bool generateReferenceScreenshot = false; if(generateReferenceScreenshot) { std::string tmpFilename = referenceFilename; std::string::size_type slashpos = referenceFilename.find_last_of('/'); tmpFilename = referenceFilename.substr(slashpos+1); tmpFilename = std::string("/tmp/") + tmpFilename; renderingHelper.SaveAsPNG( tmpFilename ); MITK_INFO << "*********************************"; MITK_INFO << "SAVE TO " << tmpFilename; MITK_INFO << "*********************************"; } //### Usage of vtkRegressionTestImage: //vtkRegressionTestImage( vtkRenderWindow ) //Set a vtkRenderWindow containing the desired scene. //vtkRegressionTestImage automatically searches in argc and argv[] //for a path a valid image with -V. If the test failed with the //first image (foo.png) check if there are images of the form //foo_N.png (where N=1,2,3...) and compare against them. int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); //retVal meanings: (see VTK/Rendering/vtkTesting.h) //0 = test failed //1 = test passed //2 = test not run //3 = something with vtkInteraction MITK_TEST_CONDITION( retVal == 1, "VTK rendering result matches expectation" ); MITK_TEST_END(); } diff --git a/Modules/PlanarFigureSegmentation/CMakeLists.txt b/Modules/PlanarFigureSegmentation/CMakeLists.txt index 397eed5a3c..b0cfb78e1b 100644 --- a/Modules/PlanarFigureSegmentation/CMakeLists.txt +++ b/Modules/PlanarFigureSegmentation/CMakeLists.txt @@ -1,4 +1,5 @@ MITK_CREATE_MODULE( PlanarFigureSegmentation - DEPENDS SurfaceInterpolation PlanarFigure + DEPENDS SurfaceInterpolation PlanarFigure + WARNINGS_AS_ERRORS ) diff --git a/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.cpp b/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.cpp index 02588ff49f..c08ba01651 100644 --- a/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.cpp +++ b/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.cpp @@ -1,307 +1,308 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarFigureSegmentationController.h" #include "mitkSurfaceToImageFilter.h" #include #include #include #include #include #include #include "mitkImageWriter.h" #include "mitkSurfaceVtkWriter.h" #include "mitkImageToSurfaceFilter.h" #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" mitk::PlanarFigureSegmentationController::PlanarFigureSegmentationController() : itk::Object() , m_ReduceFilter( NULL ) , m_NormalsFilter( NULL ) , m_DistanceImageCreator( NULL ) , m_ReferenceImage( NULL ) , m_SegmentationAsImage( NULL ) { InitializeFilters(); } mitk::PlanarFigureSegmentationController::~PlanarFigureSegmentationController() { } void mitk::PlanarFigureSegmentationController::SetReferenceImage( mitk::Image::Pointer referenceImage ) { m_ReferenceImage = referenceImage; } void mitk::PlanarFigureSegmentationController::AddPlanarFigure( mitk::PlanarFigure::Pointer planarFigure ) { if ( planarFigure.IsNull() ) return; bool newFigure = true; - int indexOfFigure = -1; - for( int i=0; iCreateSurfaceFromPlanarFigure( planarFigure ); m_SurfaceList.push_back( figureAsSurface ); - indexOfFigure = m_PlanarFigureList.size() -1 ; + if (!m_PlanarFigureList.empty()) + { + indexOfFigure = m_PlanarFigureList.size() -1 ; + } } else { figureAsSurface = this->CreateSurfaceFromPlanarFigure( planarFigure ); m_SurfaceList.at(indexOfFigure) = figureAsSurface; } m_ReduceFilter->SetInput( indexOfFigure, figureAsSurface ); m_NormalsFilter->SetInput( indexOfFigure, m_ReduceFilter->GetOutput( indexOfFigure ) ); m_DistanceImageCreator->SetInput( indexOfFigure, m_NormalsFilter->GetOutput( indexOfFigure ) ); } void mitk::PlanarFigureSegmentationController::RemovePlanarFigure( mitk::PlanarFigure::Pointer planarFigure ) { if ( planarFigure.IsNull() ) return; bool figureFound = false; - int indexOfFigure = -1; - for( int i=0; iRemoveInputs( m_NormalsFilter->GetOutput( indexOfFigure ) ); // m_NormalsFilter->RemoveInput( m_ReduceFilter->GetOutput( indexOfFigure ) ); // m_ReduceFilter->RemoveInput( const_cast(m_ReduceFilter->GetInput(indexOfFigure)) ); } else { // this is not very nice! If the figure that has been removed is NOT the last // one in the list we have to create new filters and add all remaining // inputs again. // // Has to be done as the filters do not work when removing an input // other than the last one. // create new filters InitializeFilters(); // and add all existing surfaces SurfaceListType::iterator surfaceIter = m_SurfaceList.begin(); for ( surfaceIter = m_SurfaceList.begin(); surfaceIter!=m_SurfaceList.end(); surfaceIter++ ) { m_ReduceFilter->SetInput( indexOfFigure, (*surfaceIter) ); m_NormalsFilter->SetInput( indexOfFigure, m_ReduceFilter->GetOutput( indexOfFigure ) ); m_DistanceImageCreator->SetInput( indexOfFigure, m_NormalsFilter->GetOutput( indexOfFigure ) ); } } PlanarFigureListType::iterator whereIter = m_PlanarFigureList.begin(); whereIter += indexOfFigure; m_PlanarFigureList.erase( whereIter ); SurfaceListType::iterator surfaceIter = m_SurfaceList.begin(); surfaceIter += indexOfFigure; m_SurfaceList.erase( surfaceIter ); } template void mitk::PlanarFigureSegmentationController::GetImageBase(itk::Image* input, itk::ImageBase<3>::Pointer& result) { result = input; } mitk::Image::Pointer mitk::PlanarFigureSegmentationController::GetInterpolationResult() { m_SegmentationAsImage = NULL; if ( m_PlanarFigureList.size() == 0 ) { m_SegmentationAsImage = mitk::Image::New(); - m_SegmentationAsImage->Initialize(mitk::MakeScalarPixelType() , *m_ReferenceImage->GetTimeSlicedGeometry()); + m_SegmentationAsImage->Initialize(mitk::MakeScalarPixelType() , *m_ReferenceImage->GetTimeGeometry()); return m_SegmentationAsImage; } itk::ImageBase<3>::Pointer itkImage; AccessFixedDimensionByItk_1( m_ReferenceImage.GetPointer(), GetImageBase, 3, itkImage ); m_DistanceImageCreator->SetReferenceImage( itkImage.GetPointer() ); m_ReduceFilter->Update(); m_NormalsFilter->Update(); m_DistanceImageCreator->Update(); mitk::Image::Pointer distanceImage = m_DistanceImageCreator->GetOutput(); // Cleanup the pipeline distanceImage->DisconnectPipeline(); m_DistanceImageCreator = NULL; m_NormalsFilter = NULL; m_ReduceFilter = NULL; itkImage = NULL; // If this bool flag is true, the distanceImage will be written to the // filesystem as nrrd-image and as surface-representation. bool debugOutput(false); if ( debugOutput ) { mitk::ImageWriter::Pointer imageWriter = mitk::ImageWriter::New(); imageWriter->SetInput( distanceImage ); imageWriter->SetExtension( ".nrrd" ); imageWriter->SetFileName( "v:/DistanceImage" ); imageWriter->Update(); } mitk::ImageToSurfaceFilter::Pointer imageToSurfaceFilter = mitk::ImageToSurfaceFilter::New(); imageToSurfaceFilter->SetInput( distanceImage ); imageToSurfaceFilter->SetThreshold( 0 ); imageToSurfaceFilter->Update(); mitk::Surface::Pointer segmentationAsSurface = imageToSurfaceFilter->GetOutput(); // Cleanup the pipeline segmentationAsSurface->DisconnectPipeline(); imageToSurfaceFilter = NULL; if ( debugOutput ) { mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); surfaceWriter->SetInput( segmentationAsSurface ); surfaceWriter->SetExtension( ".vtk" ); surfaceWriter->SetFileName( "v:/DistanceImageAsSurface.vtk" ); surfaceWriter->Update(); } mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->SetInput( segmentationAsSurface ); surfaceToImageFilter->SetImage( m_ReferenceImage ); surfaceToImageFilter->SetMakeOutputBinary(true); surfaceToImageFilter->Update(); m_SegmentationAsImage = surfaceToImageFilter->GetOutput(); // Cleanup the pipeline m_SegmentationAsImage->DisconnectPipeline(); return m_SegmentationAsImage; } mitk::Surface::Pointer mitk::PlanarFigureSegmentationController::CreateSurfaceFromPlanarFigure( mitk::PlanarFigure::Pointer figure ) { if ( figure.IsNull() ) { MITK_ERROR << "Given PlanarFigure is NULL. Please provide valid PlanarFigure."; return NULL; } mitk::Surface::Pointer newSurface = mitk::Surface::New(); vtkSmartPointer points = vtkSmartPointer::New(); vtkSmartPointer polygon = vtkSmartPointer::New(); vtkSmartPointer cells = vtkSmartPointer::New(); vtkSmartPointer polyData = vtkSmartPointer::New(); const mitk::Geometry2D* figureGeometry = figure->GetGeometry2D(); // Get the polyline mitk::PlanarFigure::PolyLineType planarPolyLine = figure->GetPolyLine(0); mitk::PlanarFigure::PolyLineType::iterator iter; // iterate over the polyline, ... int pointCounter = 0; for( iter = planarPolyLine.begin(); iter != planarPolyLine.end(); iter++ ) { // ... determine the world-coordinates mitk::Point2D polyLinePoint = iter->Point; mitk::Point3D pointInWorldCoordiantes; figureGeometry->Map( polyLinePoint, pointInWorldCoordiantes ); // and add them as new points to the vtkPoints points->InsertNextPoint( pointInWorldCoordiantes[0], pointInWorldCoordiantes[1], pointInWorldCoordiantes[2] ); ++pointCounter; } // create a polygon with the points of the polyline polygon->GetPointIds()->SetNumberOfIds( pointCounter ); - for(unsigned int i = 0; i < pointCounter; i++) + for(int i = 0; i < pointCounter; i++) { polygon->GetPointIds()->SetId(i,i); } // initialize the vtkCellArray and vtkPolyData cells->InsertNextCell(polygon); polyData->SetPoints(points); polyData->SetPolys( cells ); // set the polydata to the surface newSurface->SetVtkPolyData( polyData ); return newSurface; } mitk::PlanarFigureSegmentationController::PlanarFigureListType mitk::PlanarFigureSegmentationController::GetAllPlanarFigures() { return m_PlanarFigureList; } void mitk::PlanarFigureSegmentationController::InitializeFilters() { m_ReduceFilter = mitk::ReduceContourSetFilter::New(); m_ReduceFilter->SetReductionType(ReduceContourSetFilter::NTH_POINT); m_ReduceFilter->SetStepSize( 10 ); m_NormalsFilter = mitk::ComputeContourSetNormalsFilter::New(); m_DistanceImageCreator = mitk::CreateDistanceImageFromSurfaceFilter::New(); } - - diff --git a/Modules/Qt4Qt5TestModule/CMakeLists.txt b/Modules/Qt4Qt5TestModule/CMakeLists.txt index 4c4869a3e6..b3f53bdb73 100644 --- a/Modules/Qt4Qt5TestModule/CMakeLists.txt +++ b/Modules/Qt4Qt5TestModule/CMakeLists.txt @@ -1,7 +1,8 @@ MITK_CREATE_MODULE(Qt4Qt5TestModule QT4_MODULES QtCore # we want something in the Qt 4 case QT5_MODULES Qt5Core # we want something else in the Qt 5 case SUBPROJECTS MITK-CoreUI + WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/Qt4Qt5TestModule/Testing/QWonderStringTest.cpp b/Modules/Qt4Qt5TestModule/Testing/QWonderStringTest.cpp index cb41e4e5bd..95cae9bc4b 100644 --- a/Modules/Qt4Qt5TestModule/Testing/QWonderStringTest.cpp +++ b/Modules/Qt4Qt5TestModule/Testing/QWonderStringTest.cpp @@ -1,38 +1,38 @@ #include "mitkTestingMacros.h" #include #include "QWonderString.h" /** Just SOME kind of testing, nothing meaningful. This test is just company to the Qt4Qt5TestModule, which is mean to demostrate how to implement a module for both Qt4 and Qt5 */ -int QWonderStringTest(int argc, char* argv[]) +int QWonderStringTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_CONDITION( !QWonderString::penguinUID().isEmpty(), "Penguin registry working" ) QWonderString s; QSignalSpy happyCounter( &s, SIGNAL(happy())); QSignalSpy sadCounter( &s, SIGNAL(sad())); MITK_TEST_CONDITION( happyCounter.count() == 0 && sadCounter.count() == 0, "No feelings in the beginning" ) s.setText("Happy feet"); MITK_TEST_CONDITION( happyCounter.count() == 1, "Penguins are happy" ) s.setText("Talk too much"); MITK_TEST_CONDITION( sadCounter.count() == 1, "Penguin ears bleed" ) s.setText("Fishy fish"); MITK_TEST_CONDITION( happyCounter.count() == 2, "Penguins sleepy" ) s.setText("Knok knok"); MITK_TEST_CONDITION( sadCounter.count() == 2, "Penguins irritated" ) return EXIT_SUCCESS; } diff --git a/Modules/SceneSerialization/CMakeLists.txt b/Modules/SceneSerialization/CMakeLists.txt index 1dc727725d..255ad8a39c 100644 --- a/Modules/SceneSerialization/CMakeLists.txt +++ b/Modules/SceneSerialization/CMakeLists.txt @@ -1,7 +1,8 @@ MITK_CREATE_MODULE( SceneSerialization INCLUDE_DIRS BaseDataSerializer BasePropertySerializer BasePropertyDeserializer DEPENDS SceneSerializationBase PACKAGE_DEPENDS Poco + WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/SceneSerialization/mitkSceneReaderV1.cpp b/Modules/SceneSerialization/mitkSceneReaderV1.cpp index af539f7591..18ad2a1f7f 100644 --- a/Modules/SceneSerialization/mitkSceneReaderV1.cpp +++ b/Modules/SceneSerialization/mitkSceneReaderV1.cpp @@ -1,392 +1,391 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSceneReaderV1.h" #include "mitkSerializerMacros.h" #include "mitkDataNodeFactory.h" #include "mitkBaseRenderer.h" #include "mitkPropertyListDeserializer.h" #include "mitkProgressBar.h" #include "Poco/Path.h" #include MITK_REGISTER_SERIALIZER(SceneReaderV1) bool mitk::SceneReaderV1::LoadScene( TiXmlDocument& document, const std::string& workingDirectory, DataStorage* storage ) { assert(storage); bool error(false); // TODO prepare to detect errors (such as cycles) from wrongly written or edited xml files //Get number of elements to initialze progress bar // 1. if there is a element, // - construct a name for the appropriate serializer // - try to instantiate this serializer via itk object factory // - if serializer could be created, use it to read the file into a BaseData object // - if successful, call the new node's SetData(..) // create a node for the tag "data" and test if node was created typedef std::vector DataNodeVector; DataNodeVector DataNodes; unsigned int listSize = 0; for( TiXmlElement* element = document.FirstChildElement("node"); element != NULL; element = element->NextSiblingElement("node") ) { ++listSize; DataNodes.push_back( LoadBaseDataFromDataTag( element->FirstChildElement("data"), workingDirectory, error ) ); } OrderedLayers orderedLayers; this->GetLayerOrder(document, workingDirectory, DataNodes, orderedLayers); ProgressBar::GetInstance()->AddStepsToDo( listSize ); // iterate all nodes // first level nodes should be elements DataNodeVector::iterator nit = DataNodes.begin(); for( TiXmlElement* element = document.FirstChildElement("node"); element != NULL || nit != DataNodes.end(); element = element->NextSiblingElement("node"), ++nit ) { mitk::DataNode::Pointer node = *nit; // in case dataXmlElement is valid test whether it containts the "properties" child tag // and process further if and only if yes TiXmlElement *dataXmlElement = element->FirstChildElement("data"); if( dataXmlElement && dataXmlElement->FirstChildElement("properties") ) { TiXmlElement *baseDataElement = dataXmlElement->FirstChildElement("properties"); if ( node->GetData() ) { DecorateBaseDataWithProperties( node->GetData(), baseDataElement, workingDirectory); } else { MITK_WARN << "BaseData properties stored in scene file, but BaseData can't be read" << std::endl; } } // 2. check child nodes const char* uida = element->Attribute("UID"); std::string uid(""); if (uida) { uid = uida; m_NodeForID[uid] = node.GetPointer(); m_IDForNode[ node.GetPointer() ] = uid; } else { MITK_ERROR << "No UID found for current node. Node will have no parents."; error = true; } // 3. if there are nodes, // - instantiate the appropriate PropertyListDeSerializer // - use them to construct PropertyList objects // - add these properties to the node (if necessary, use renderwindow name) bool success = DecorateNodeWithProperties(node, element, workingDirectory); if (!success) { MITK_ERROR << "Could not load properties for node."; error = true; } // remember node for later adding to DataStorage //node->GetIntProperty("layer", layer); int layer; OrderedLayers::iterator it = orderedLayers.find(uid); layer = (*it).second; m_OrderedNodePairs.insert( std::make_pair( layer, std::make_pair( node, std::list() ) ) ); // 4. if there are elements, remember parent objects for( TiXmlElement* source = element->FirstChildElement("source"); source != NULL; source = source->NextSiblingElement("source") ) { const char* sourceUID = source->Attribute("UID"); if (sourceUID) { m_OrderedNodePairs[layer].second.push_back( std::string(sourceUID) ); } } ProgressBar::GetInstance()->Progress(); } // end for all // remove all unknown parent UIDs for (LayerPropertyMapType::iterator nodesIter = m_OrderedNodePairs.begin(); nodesIter != m_OrderedNodePairs.end(); ++nodesIter) { for (std::list::iterator parentsIter = nodesIter->second.second.begin(); parentsIter != nodesIter->second.second.end();) { if (m_NodeForID.find( *parentsIter ) == m_NodeForID.end()) { parentsIter = nodesIter->second.second.erase( parentsIter ); MITK_WARN << "Found a DataNode with unknown parents. Will add it to DataStorage without any parent objects."; error = true; } else { ++parentsIter; } } } // repeat // for all created nodes unsigned int lastMapSize(0); while ( lastMapSize != m_OrderedNodePairs.size()) // this is to prevent infinite loops; each iteration must at least add one node to DataStorage { lastMapSize = m_OrderedNodePairs.size(); for (LayerPropertyMapType::iterator nodesIter = m_OrderedNodePairs.begin(); nodesIter != m_OrderedNodePairs.end(); ++nodesIter) { bool addNow(true); // if any parent node is not yet in DataStorage, skip node for now and check later for (std::list::iterator parentsIter = nodesIter->second.second.begin(); parentsIter != nodesIter->second.second.end(); ++parentsIter) { if ( !storage->Exists( m_NodeForID[ *parentsIter ] ) ) { addNow = false; break; } } if (addNow) { DataStorage::SetOfObjects::Pointer parents = DataStorage::SetOfObjects::New(); for (std::list::iterator parentsIter = nodesIter->second.second.begin(); parentsIter != nodesIter->second.second.end(); ++parentsIter) { parents->push_back( m_NodeForID[ *parentsIter ] ); } // if all parents are found in datastorage (or are unknown), add node to DataStorage storage->Add( nodesIter->second.first, parents ); // remove this node from m_OrderedNodePairs m_OrderedNodePairs.erase( nodesIter ); // break this for loop because iterators are probably invalid break; } } } // All nodes that are still in m_OrderedNodePairs at this point are not part of a proper directed graph structure. We'll add such nodes without any parent information. for (LayerPropertyMapType::iterator nodesIter = m_OrderedNodePairs.begin(); nodesIter != m_OrderedNodePairs.end(); ++nodesIter) { storage->Add( nodesIter->second.first ); MITK_WARN << "Encountered node that is not part of a directed graph structure. Will be added to DataStorage without parents."; error = true; } return !error; } void mitk::SceneReaderV1::GetLayerOrder(TiXmlDocument& document, const std::string& workingDirectory, std::vector DataNodes, OrderedLayers& order) { typedef std::vector DataNodeVector; DataNodeVector::iterator nit = DataNodes.begin(); for( TiXmlElement* element = document.FirstChildElement("node"); element != NULL || nit != DataNodes.end(); element = element->NextSiblingElement("node"), ++nit ) { - bool error(false); DataNode::Pointer node = *nit; DecorateNodeWithProperties(node, element, workingDirectory); int layer; node->GetIntProperty("layer", layer); std::string uid = element->Attribute("UID"); this->m_UnorderedLayers.insert( std::make_pair( layer, uid ) ); } int lastLayer = itk::NumericTraits::min(); UnorderedLayers::iterator it; for (it = m_UnorderedLayers.begin(); it != m_UnorderedLayers.end(); it++) { int currentLayer = (*it).first; if (currentLayer == lastLayer) { ++currentLayer; } order.insert( std::make_pair( (*it).second, currentLayer ) ); lastLayer = currentLayer; } } mitk::DataNode::Pointer mitk::SceneReaderV1::LoadBaseDataFromDataTag( TiXmlElement* dataElement, const std::string& workingDirectory, bool& error ) { DataNode::Pointer node; if (dataElement) { const char* filename( dataElement->Attribute("file") ); if ( filename ) { DataNodeFactory::Pointer factory = DataNodeFactory::New(); factory->SetFileName( workingDirectory + Poco::Path::separator() + filename ); try { factory->Update(); node = factory->GetOutput(); } catch (std::exception& e) { MITK_ERROR << "Error during attempt to read '" << filename << "'. Exception says: " << e.what(); error = true; } if (node.IsNull()) { MITK_ERROR << "Error during attempt to read '" << filename << "'. Factory returned NULL object."; error = true; } } } // in case there was no element we create a new empty node (for appending a propertylist later) if (node.IsNull()) { node = DataNode::New(); } return node; } bool mitk::SceneReaderV1::DecorateNodeWithProperties(DataNode* node, TiXmlElement* nodeElement, const std::string& workingDirectory) { assert(node); assert(nodeElement); bool error(false); for( TiXmlElement* properties = nodeElement->FirstChildElement("properties"); properties != NULL; properties = properties->NextSiblingElement("properties") ) { const char* propertiesfilea( properties->Attribute("file") ); std::string propertiesfile( propertiesfilea ? propertiesfilea : "" ); const char* renderwindowa( properties->Attribute("renderwindow") ); std::string renderwindow( renderwindowa ? renderwindowa : "" ); BaseRenderer* renderer = BaseRenderer::GetByName( renderwindow ); if (renderer || renderwindow.empty()) { PropertyList::Pointer propertyList = node->GetPropertyList(renderer); // DataNode implementation always returns a propertylist // clear all properties from node that might be set by DataNodeFactory during loading propertyList->Clear(); // use deserializer to construct new properties PropertyListDeserializer::Pointer deserializer = PropertyListDeserializer::New(); deserializer->SetFilename(workingDirectory + Poco::Path::separator() + propertiesfile); bool success = deserializer->Deserialize(); error |= !success; PropertyList::Pointer readProperties = deserializer->GetOutput(); if (readProperties.IsNotNull()) { //'use color' is deprecated since 2013.03 release. It was replaced by //'Image Rendering.Mode' in bug #12056. This code is for legacy support //of old scene files containing the property 'use color'. The code should //be removed in one of the upcomng releases. if(readProperties->GetProperty("Image Rendering.Mode") == NULL ) { mitk::BaseProperty* useColorProperty = readProperties->GetProperty("use color"); if(mitk::BoolProperty* boolProp = dynamic_cast(useColorProperty)) { bool useColor = boolProp->GetValue(); readProperties->DeleteProperty("use color"); mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); if(useColor) renderingMode->SetValue( mitk::RenderingModeProperty::LEVELWINDOW_COLOR ); else renderingMode->SetValue( mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR ); readProperties->SetProperty("Image Rendering.Mode", renderingMode); MITK_WARN << "The property 'use color' has been found in a scene file and was replaced by 'Image Rendering.Mode'. 'use color' is deprecated since 2013.03 release."; } } propertyList->ConcatenatePropertyList( readProperties, true ); // true = replace } else { MITK_ERROR << "Property list reader did not return a property list. This is an implementation error. Please tell your developer."; error = true; } } else { MITK_ERROR << "Found properties for renderer " << renderwindow << " but there is no such renderer in current application. Ignoring those properties"; error = true; } } return !error; } bool mitk::SceneReaderV1::DecorateBaseDataWithProperties(BaseData::Pointer data, TiXmlElement *baseDataNodeElem, const std::string &workingDir) { // check given variables, initialize error variable assert(baseDataNodeElem); bool error(false); // get the file name stored in the tag const char* baseDataPropertyFile( baseDataNodeElem->Attribute("file") ); // check if the filename was found if(baseDataPropertyFile) { //PropertyList::Pointer dataPropList = data->GetPropertyList(); PropertyListDeserializer::Pointer propertyDeserializer = PropertyListDeserializer::New(); // initialize the property reader propertyDeserializer->SetFilename(workingDir + Poco::Path::separator() + baseDataPropertyFile); bool ioSuccess = propertyDeserializer->Deserialize(); error = !ioSuccess; // get the output PropertyList::Pointer inProperties = propertyDeserializer->GetOutput(); // store the read-in properties to the given node or throw error otherwise if( inProperties.IsNotNull() ) { data->SetPropertyList( inProperties ); } else { MITK_ERROR << "The property deserializer did not return a (valid) property list."; error = true; } } else { MITK_ERROR << "Function DecorateBaseDataWithProperties(...) called with false TiXmlElement. \n \t ->Given element does not contain a 'file' attribute. \n"; error = true; } return !error; } diff --git a/Modules/SceneSerializationBase/CMakeLists.txt b/Modules/SceneSerializationBase/CMakeLists.txt index 5c51524447..aadb9508cb 100644 --- a/Modules/SceneSerializationBase/CMakeLists.txt +++ b/Modules/SceneSerializationBase/CMakeLists.txt @@ -1,6 +1,7 @@ MITK_CREATE_MODULE( SceneSerializationBase INCLUDE_DIRS BaseDataSerializer BasePropertySerializer DEPENDS Mitk + WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/SurfaceInterpolation/CMakeLists.txt b/Modules/SurfaceInterpolation/CMakeLists.txt index 981ad60a47..adba80da23 100644 --- a/Modules/SurfaceInterpolation/CMakeLists.txt +++ b/Modules/SurfaceInterpolation/CMakeLists.txt @@ -1,3 +1,4 @@ MITK_CREATE_MODULE( SurfaceInterpolation - DEPENDS Mitk ImageExtraction -) \ No newline at end of file + DEPENDS Mitk ImageExtraction + WARNINGS_AS_ERRORS +) diff --git a/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.cpp b/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.cpp index d02136b536..3e1abcb0a6 100644 --- a/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.cpp +++ b/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.cpp @@ -1,676 +1,676 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCreateDistanceImageFromSurfaceFilter.h" mitk::CreateDistanceImageFromSurfaceFilter::CreateDistanceImageFromSurfaceFilter() { 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() { //First of all we have to build the equation-system from the existing contour-edge-points this->CreateSolutionMatrixAndFunctionValues(); //Then we solve the equation-system via QR - decomposition. The interpolation weights are obtained in that way vnl_qr solver (m_SolutionMatrix); m_Weights = solver.solve(m_FunctionValues); //Setting progressbar if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(2); //The last step is to create the distance map with the interpolated distance function this->CreateDistanceImage(); m_Centers.clear(); m_FunctionValues.clear(); m_Normals.clear(); m_Weights.clear(); m_SolutionMatrix.clear(); //Setting progressbar if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(3); } void mitk::CreateDistanceImageFromSurfaceFilter::CreateSolutionMatrixAndFunctionValues() { 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 Surface* currentSurface; vtkSmartPointer polyData; vtkSmartPointer currentCellNormals; vtkSmartPointer existingPolys; vtkSmartPointer existingPoints; double p[3]; PointType currentPoint; PointType normal; for (unsigned int i = 0; i < numberOfInputs; i++) { currentSurface = const_cast( 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 (NULL); vtkIdType cellSize (0); for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { for ( unsigned int 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 //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.set_size(numberOfCenters*3); m_FunctionValues.fill(0); //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]; currentPoint[1] = currentPoint[1] - normal[1]; currentPoint[2] = currentPoint[2] - normal[2]; m_Centers.push_back(currentPoint); m_FunctionValues.put(numberOfCenters+i, -1); } //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]; currentPoint[1] = currentPoint[1] + normal[1]; currentPoint[2] = currentPoint[2] + normal[2]; m_Centers.push_back(currentPoint); m_FunctionValues.put(numberOfCenters*2+i, 1); } //Now we have created all centers and all function values. Next step is to create the solution matrix numberOfCenters = m_Centers.size(); m_SolutionMatrix.set_size(numberOfCenters, numberOfCenters); m_Weights.set_size(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::CreateDistanceImage() { DistanceImageType::Pointer distanceImg = DistanceImageType::New(); // 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] = (int) ( (std::max( std::abs(maxPointInIndexCoordinates[dim] - minPointInIndexCoordinates[dim]), (DistanceImageType::IndexType::IndexValueType) 1 ) + 1.0) // (max-index - min-index)+1 because the pixels between index 3 and 5 cover 2+1=3 pixels (pixel 3,4, and 5) * m_ReferenceImage->GetSpacing()[dim] ) + 1; // (int) ((...) + 1) -> we round up to the next BIGGER int value } /* * Now create an empty distance image. The create image will always have the same sizeOfRegion, 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 = ( 500000 / extentX*extentY*extentZ )^(1/3) */ double basis = (extentMM[0]*extentMM[1]*extentMM[2]) / m_DistanceImageVolume; double exponent = 1.0/3.0; double distImgSpacing = pow(basis, exponent); int tempSpacing = (distImgSpacing+0.05)*10; m_DistanceImageSpacing = (double)tempSpacing/10.0; // 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 + 4; sizeOfRegion[1] = numberOfYPixel + 4; sizeOfRegion[2] = numberOfZPixel + 4; // 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 distanceImg->SetOrigin( originAsWorld ); distanceImg->SetDirection( m_ReferenceImage->GetDirection() ); distanceImg->SetRegions( lpRegion ); distanceImg->SetSpacing( m_DistanceImageSpacing ); distanceImg->Allocate(); //First of all the image is initialized with the value 10 for each pixel distanceImg->FillBuffer(10); // Now we move the origin of the distanceImage 2 index-Coordinates // in all directions DistanceImageType::IndexType originAsIndex; distanceImg->TransformPhysicalPointToIndex( originAsWorld, originAsIndex ); originAsIndex[0] -= 2; originAsIndex[1] -= 2; originAsIndex[2] -= 2; distanceImg->TransformIndexToPhysicalPoint( originAsIndex, originAsWorld ); distanceImg->SetOrigin( originAsWorld ); /* * 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. */ 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; distanceImg->TransformPhysicalPointToIndex( currentPointAsPoint, currentIndex ); assert( lpRegion.IsInside(currentIndex) ); // we are quite certain this should hold narrowbandPoints.push(currentIndex); distanceImg->SetPixel(currentIndex, distance); NeighborhoodImageIterator::RadiusType radius; radius.Fill(1); NeighborhoodImageIterator nIt(radius, distanceImg, distanceImg->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) == 10) { currentIndex = nIt.GetIndex(*relativeNb); // Transform the currently checked point from index-coordinates to // world-coordinates distanceImg->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 ( abs(distance) <= m_DistanceImageSpacing ) { nIt.SetPixel(*relativeNb, distance); narrowbandPoints.push(currentIndex); } } relativeNb++; } } // Fist we set the border slices of the image to value 1000 so that we can perform a // region growing afterwards starting from the middle of the image DistanceImageType::SizeType reqSize; reqSize[0] = distanceImg->GetLargestPossibleRegion().GetSize()[0]; reqSize[1] = distanceImg->GetLargestPossibleRegion().GetSize()[1]; reqSize[2] = 1; DistanceImageType::IndexType reqStart; reqStart[0] = 0; reqStart[1] = 0; reqStart[2] = 0; DistanceImageType::RegionType reqRegion; reqRegion.SetSize(reqSize); reqRegion.SetIndex(reqStart); this->FillImageRegion(reqRegion, 1000, distanceImg); reqStart[0] = 0; reqStart[1] = 0; reqStart[2] = distanceImg->GetLargestPossibleRegion().GetSize()[2]-1; reqRegion.SetIndex(reqStart); this->FillImageRegion(reqRegion, 1000, distanceImg); reqSize[0] = 1; reqSize[1] = distanceImg->GetLargestPossibleRegion().GetSize()[1]; reqSize[2] = distanceImg->GetLargestPossibleRegion().GetSize()[2];; reqStart[0] = 0; reqStart[1] = 0; reqStart[2] = 0; reqRegion.SetSize(reqSize); reqRegion.SetIndex(reqStart); this->FillImageRegion(reqRegion, 1000, distanceImg); reqStart[0] = distanceImg->GetLargestPossibleRegion().GetSize()[0]-1; reqStart[1] = 0; reqStart[2] = 0; reqRegion.SetIndex(reqStart); this->FillImageRegion(reqRegion, 1000, distanceImg); reqSize[0] = distanceImg->GetLargestPossibleRegion().GetSize()[0]; reqSize[1] = 1; reqSize[2] = distanceImg->GetLargestPossibleRegion().GetSize()[2];; reqStart[0] = 0; reqStart[1] = 0; reqStart[2] = 0; reqRegion.SetSize(reqSize); reqRegion.SetIndex(reqStart); this->FillImageRegion(reqRegion, 1000, distanceImg); reqStart[0] = 0; reqStart[1] = distanceImg->GetLargestPossibleRegion().GetSize()[1]-1; reqStart[2] = 0; reqRegion.SetIndex(reqStart); this->FillImageRegion(reqRegion, 1000, distanceImg); // Now we make some kind of region growing from the middle of the image to set all // inner pixels to -10. In this way we assure to extract a valid surface NeighborhoodImageIterator nIt2(radius, distanceImg, distanceImg->GetLargestPossibleRegion()); currentIndex[0] = distanceImg->GetLargestPossibleRegion().GetSize()[0]*0.5; currentIndex[1] = distanceImg->GetLargestPossibleRegion().GetSize()[1]*0.5; currentIndex[2] = distanceImg->GetLargestPossibleRegion().GetSize()[2]*0.5; narrowbandPoints.push(currentIndex); distanceImg->SetPixel(currentIndex, -10); while ( !narrowbandPoints.empty() ) { nIt2.SetLocation(narrowbandPoints.front()); narrowbandPoints.pop(); for (int i = 0; i < 6; i++) { - if( nIt2.GetPixel(relativeNbIdx[i]) == 10 || nIt2.GetPixel(relativeNbIdx[i]) < 0 && nIt2.GetPixel(relativeNbIdx[i]) != -10) + if( nIt2.GetPixel(relativeNbIdx[i]) == 10 || (nIt2.GetPixel(relativeNbIdx[i]) < 0 && nIt2.GetPixel(relativeNbIdx[i]) != -10)) { currentIndex = nIt2.GetIndex(relativeNbIdx[i]); nIt2.SetPixel(relativeNbIdx[i], -10); narrowbandPoints.push(currentIndex); } } } Image::Pointer resultImage = this->GetOutput(); // Cast the created distance-Image from itk::Image to the mitk::Image // that is our output. CastToMitkImage(distanceImg, resultImage); } void mitk::CreateDistanceImageFromSurfaceFilter::FillImageRegion(DistanceImageType::RegionType reqRegion, DistanceImageType::PixelType pixelValue, DistanceImageType::Pointer image) { image->SetRequestedRegion(reqRegion); ImageIterator it (image, image->GetRequestedRegion()); while (!it.IsAtEnd()) { it.Set(pixelValue); ++it; } } double mitk::CreateDistanceImageFromSurfaceFilter::CalculateDistanceValue(PointType p) { double distanceValue (0); PointType p1; PointType p2; double norm; CenterList::iterator centerIter; InterpolationWeights::iterator weightsIter; for ( centerIter=m_Centers.begin(), weightsIter=m_Weights.begin(); centerIter!=m_Centers.end(), weightsIter!=m_Weights.end(); centerIter++, weightsIter++ ) { p1 = *centerIter; p2 = p-p1; norm = p2.two_norm(); distanceValue = distanceValue + norm* (*weightsIter); } return distanceValue; } void mitk::CreateDistanceImageFromSurfaceFilter::GenerateOutputInformation() { } void mitk::CreateDistanceImageFromSurfaceFilter::PrintEquationSystem() { std::ofstream esfile; esfile.open("C:/Users/fetzer/Desktop/equationSystem/es.txt"); esfile<<"Nummber of rows: "<SetInput( 0, const_cast( 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 NULL; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::Surface* mitk::CreateDistanceImageFromSurfaceFilter::GetInput( unsigned int idx) { if (this->GetNumberOfIndexedInputs() < 1) return NULL; 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 DistanceImageType::IndexType tmpIndex; m_ReferenceImage->TransformPhysicalPointToIndex( tmpPoint, tmpIndex ); // initialize the variables with this first point int xmin = tmpIndex[0]; int ymin = tmpIndex[1]; int zmin = tmpIndex[2]; int xmax = tmpIndex[0]; int ymax = tmpIndex[1]; int zmax = tmpIndex[2]; // iterate over the rest of the points CenterList::iterator 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->TransformPhysicalPointToIndex( 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/mitkCreateDistanceImageFromSurfaceFilter.h b/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.h index fffb7fc097..9e5f5a4d01 100644 --- a/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.h +++ b/Modules/SurfaceInterpolation/mitkCreateDistanceImageFromSurfaceFilter.h @@ -1,194 +1,196 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkCreateDistanceImageFromSurfaceFilter_h_Included #define mitkCreateDistanceImageFromSurfaceFilter_h_Included #include "SurfaceInterpolationExports.h" #include "mitkImageSource.h" #include "mitkSurface.h" #include "mitkProgressBar.h" #include "vtkSmartPointer.h" #include "vtkDoubleArray.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkPolyData.h" #include "vnl/vnl_matrix.h" #include "vnl/vnl_vector.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/algo/vnl_qr.h" #include "itkImageBase.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkNeighborhoodIterator.h" #include namespace mitk { /** \brief This filter interpolates the 3D surface for a segmented area. The basis for the interpolation are the edge-points of contours that are drawn into an image. The interpolation itself is performed via Radial Basis Function Interpolation. ATTENTION: This filter needs beside the edge points of the delineated contours additionally the normals for each edge point. \sa mitkSurfaceInterpolationController Based on the contour edge points and their normal this filter calculates a distance function with the following properties: - Putting a point into the distance function that lies inside the considered surface gives a negativ scalar value - Putting a point into the distance function that lies outside the considered surface gives a positive scalar value - Putting a point into the distance function that lies exactly on the considered surface gives the value zero With this interpolated distance function a distance image will be created. The desired surface can then be extract e.g. with the marching cubes algorithm. (Within the distance image the surface goes exactly where the pixelvalues are zero) Note that the obtained distance image has always an isotropig spacing. The size (in this case volume) of the image can be adjusted by calling SetDistanceImageVolume(unsigned int volume) which specifies the number ob pixels enclosed by the image. \ingroup Process $Author: fetzer$ */ class SurfaceInterpolation_EXPORT CreateDistanceImageFromSurfaceFilter : public ImageSource { public: typedef vnl_vector_fixed PointType; typedef itk::Image DistanceImageType; typedef DistanceImageType::IndexType IndexType; typedef itk::ImageRegionIteratorWithIndex ImageIterator; typedef itk::NeighborhoodIterator NeighborhoodImageIterator; typedef std::vector< PointType > NormalList; typedef std::vector< PointType > CenterList; typedef vnl_matrix SolutionMatrix; typedef vnl_vector FunctionValues; typedef vnl_vector InterpolationWeights; typedef std::vector SurfaceList; mitkClassMacro(CreateDistanceImageFromSurfaceFilter,ImageSource); itkNewMacro(Self); + using Superclass::SetInput; + //Methods copied from mitkSurfaceToSurfaceFilter virtual void SetInput( const mitk::Surface* surface ); virtual void SetInput( unsigned int idx, const mitk::Surface* surface ); virtual const mitk::Surface* GetInput(); virtual const mitk::Surface* GetInput( unsigned int idx ); virtual void RemoveInputs(mitk::Surface* input); /** \brief Set the size of the output distance image. The size is specified by the image's volume (i.e. in this case how many pixels are enclosed by the image) If non is set, the volume will be 500000 pixels. */ itkSetMacro(DistanceImageVolume, unsigned int); void PrintEquationSystem(); //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); /** \brief Set the stepsize which the progress bar should proceed \a Parameter The stepsize for progressing */ void SetProgressStepSize(unsigned int stepSize); void SetReferenceImage( itk::ImageBase<3>::Pointer referenceImage ); protected: CreateDistanceImageFromSurfaceFilter(); virtual ~CreateDistanceImageFromSurfaceFilter(); virtual void GenerateData(); virtual void GenerateOutputInformation(); private: void CreateSolutionMatrixAndFunctionValues(); double CalculateDistanceValue(PointType p); void CreateDistanceImage (); /** * \brief This method fills the given variables with the minimum and * maximum coordinates that contain all input-points in index- and * world-coordinates. * * This method iterates over all input-points and transforms them from * world-coordinates to index-coordinates using the transform of the * reference-Image. * Next, the minimal and maximal index-coordinates are determined that * span an area that contains all given input-points. * These index-coordinates are then transformed back to world-coordinates. * * These minimal and maximal points are then set to the given variables. */ void DetermineBounds( DistanceImageType::PointType &minPointInWorldCoordinates, DistanceImageType::PointType &maxPointInWorldCoordinates, DistanceImageType::IndexType &minPointInIndexCoordinates, DistanceImageType::IndexType &maxPointInIndexCoordinates ); void FillImageRegion(DistanceImageType::RegionType reqRegion, DistanceImageType::PixelType pixelValue, DistanceImageType::Pointer image); //Datastructures for the interpolation CenterList m_Centers; NormalList m_Normals; FunctionValues m_FunctionValues; InterpolationWeights m_Weights; SolutionMatrix m_SolutionMatrix; double m_DistanceImageSpacing; itk::ImageBase<3>::Pointer m_ReferenceImage; unsigned int m_DistanceImageVolume; bool m_UseProgressBar; unsigned int m_ProgressStepSize; }; }//namespace #endif diff --git a/mitkConfig.h.in b/mitkConfig.h.in index bbc2d1cd88..d47d25ae6b 100644 --- a/mitkConfig.h.in +++ b/mitkConfig.h.in @@ -1,43 +1,38 @@ /* mitkConfig.h this file is generated. Do not change! */ #ifndef MITKCONFIG_H #define MITKCONFIG_H #define MITK_ROOT "${PROJECT_SOURCE_DIR}/" #cmakedefine MITK_BUILD_SHARED_CORE #cmakedefine USE_ITKZLIB #cmakedefine MITK_CHILI_PLUGIN #cmakedefine MITK_USE_TD_MOUSE -#cmakedefine MITK_HAS_UNORDERED_MAP_H -#cmakedefine MITK_HAS_UNORDERED_SET_H -#cmakedefine MITK_HAS_HASH_STRING -#cmakedefine MITK_HAS_HASH_SIZE_T - #define MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES @MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES@ #define MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES @MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES@ #define MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES @MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES@ #define MITK_ACCESSBYITK_PIXEL_TYPES @MITK_ACCESSBYITK_PIXEL_TYPES@ #define MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES_SEQ @MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES_SEQ@ #define MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES_SEQ @MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES_SEQ@ #define MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES_SEQ @MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES_SEQ@ #define MITK_ACCESSBYITK_PIXEL_TYPES_SEQ @MITK_ACCESSBYITK_PIXEL_TYPES_SEQ@ #define MITK_ACCESSBYITK_DIMENSIONS @MITK_ACCESSBYITK_DIMENSIONS@ #define MITK_ACCESSBYITK_DIMENSIONS_SEQ @MITK_ACCESSBYITK_DIMENSIONS_SEQ@ #define MITK_ACCESSBYITK_INTEGRAL_TYPES_DIMN_SEQ(dim) @MITK_ACCESSBYITK_INTEGRAL_TYPES_DIMN_SEQ@ #define MITK_ACCESSBYITK_FLOATING_TYPES_DIMN_SEQ(dim) @MITK_ACCESSBYITK_FLOATING_TYPES_DIMN_SEQ@ #define MITK_ACCESSBYITK_COMPOSITE_TYPES_DIMN_SEQ(dim) @MITK_ACCESSBYITK_COMPOSITE_TYPES_DIMN_SEQ@ #define MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dim) @MITK_ACCESSBYITK_TYPES_DIMN_SEQ@ #define MITK_CHILI_PLUGIN_SDK_IPPIC_H "@MITK_CHILI_PLUGIN_SDK_IPPIC_H@" #define MITK_CHILI_PLUGIN_SDK_IPTYPES_H "@MITK_CHILI_PLUGIN_SDK_IPTYPES_H@" #define MITK_DOXYGEN_OUTPUT_DIR "@MITK_DOXYGEN_OUTPUT_DIR@" #define MITK_HELPPAGES_OUTPUT_DIR "@MITK_HELPPAGES_OUTPUT_DIR@" #endif // MITKCONFIG_H