diff --git a/CMake/PackageDepends/MITK_OpenIGTLink_Config.cmake b/CMake/PackageDepends/MITK_OpenIGTLink_Config.cmake new file mode 100644 index 0000000000..3aafcb0b1d --- /dev/null +++ b/CMake/PackageDepends/MITK_OpenIGTLink_Config.cmake @@ -0,0 +1,7 @@ + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +list(APPEND ALL_LIBRARIES ${OpenIGTLink_LIBRARIES}) +#list(APPEND ALL_INCLUDE_DIRECTORIES ${OpenIGTLink_INCLUDE_DIRS}) diff --git a/CMake/mitkFunctionGetLibrarySearchPaths.cmake b/CMake/mitkFunctionGetLibrarySearchPaths.cmake index 8ca66499b5..9a0a5dcd0d 100644 --- a/CMake/mitkFunctionGetLibrarySearchPaths.cmake +++ b/CMake/mitkFunctionGetLibrarySearchPaths.cmake @@ -1,174 +1,180 @@ function(mitkFunctionGetLibrarySearchPaths search_path intermediate_dir) set(_dir_candidates ${MITK_VTK_LIBRARY_DIRS} ${MITK_ITK_LIBRARY_DIRS} "${MITK_BINARY_DIR}/bin" "${MITK_BINARY_DIR}/bin/plugins") # Determine the Qt4/5 library installation prefix set(_qmake_location ) if(MITK_USE_Qt4) set(_qmake_location ${QT_QMAKE_EXECUTABLE}) elseif(MITK_USE_Qt5 AND TARGET ${Qt5Core_QMAKE_EXECUTABLE}) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) endif() if(_qmake_location) if(NOT _qt_install_libs) if(WIN32) execute_process(COMMAND ${_qmake_location} -query QT_INSTALL_BINS OUTPUT_VARIABLE _qt_install_libs OUTPUT_STRIP_TRAILING_WHITESPACE) else() execute_process(COMMAND ${_qmake_location} -query QT_INSTALL_LIBS OUTPUT_VARIABLE _qt_install_libs OUTPUT_STRIP_TRAILING_WHITESPACE) endif() file(TO_CMAKE_PATH "${_qt_install_libs}" _qt_install_libs) set(_qt_install_libs ${_qt_install_libs} CACHE INTERNAL "Qt library installation prefix" FORCE) endif() if(_qt_install_libs) list(APPEND _dir_candidates ${_qt_install_libs}) endif() elseif(MITK_USE_QT) message(WARNING "The qmake executable could not be found.") endif() get_property(_additional_paths GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) if(_additional_paths) list(APPEND _dir_candidates ${_additional_paths}) endif() if(VTK_DIR) find_package(VTK QUIET) if(VTK_RUNTIME_LIBRARY_DIRS) list(APPEND _dir_candidates ${VTK_RUNTIME_LIBRARY_DIRS}) endif() endif() # The code below is sub-optimal. It makes assumptions about # the structure of the build directories, pointed to by # the *_DIR variables. Instead, we should rely on package # specific "LIBRARY_DIRS" variables, if they exist. if(WIN32) if(DCMTK_DIR) list(APPEND _dir_candidates "${DCMTK_DIR}/bin") endif() if(OpenCV_DIR) list(APPEND _dir_candidates "${OpenCV_DIR}/bin") endif() + if(OpenIGTLink_DIR) + list(APPEND _dir_candidates "${OpenIGTLink_DIR}/bin") + endif() if(SOFA_DIR) list(APPEND _dir_candidates "${SOFA_DIR}/bin") endif() if(Python_DIR) list(APPEND _dir_candidates "${Python_DIR}/bin") endif() if(SimpleITK_DIR) list(APPEND _dir_candidates "${SimpleITK_DIR}/bin") endif() list(APPEND _dir_candidates "${ITK_DIR}/bin") else() if(DCMTK_DIR) list(APPEND _dir_candidates "${DCMTK_DIR}/lib") endif() if(OpenCV_DIR) list(APPEND _dir_candidates "${OpenCV_DIR}/lib") endif() + if(OpenIGTLink_DIR) + list(APPEND _dir_candidates "${OpenIGTLink_DIR}/lib") + endif() if(SOFA_DIR) list(APPEND _dir_candidates "${SOFA_DIR}/lib") endif() if(Python_DIR) list(APPEND _dir_candidates "${Python_DIR}/lib") endif() if(SimpleITK_DIR) list(APPEND _dir_candidates "${SimpleITK_DIR}/lib") endif() list(APPEND _dir_candidates "${ITK_DIR}/lib") endif() if(MITK_USE_Python AND CTK_PYTHONQT_INSTALL_DIR) list(APPEND _dir_candidates "${CTK_PYTHONQT_INSTALL_DIR}/bin") endif() if(MITK_USE_Boost AND MITK_USE_Boost_LIBRARIES AND NOT MITK_USE_SYSTEM_Boost) list(APPEND _dir_candidates "${Boost_LIBRARY_DIR}") endif() if(ACVD_DIR) list(APPEND _dir_candidates "${ACVD_DIR}/bin") endif() if(ANN_DIR) list(APPEND _dir_candidates "${ANN_DIR}") endif() if(CppUnit_DIR) list(APPEND _dir_candidates "${CppUnit_DIR}") endif() if(GLUT_DIR) list(APPEND _dir_candidates "${GLUT_DIR}") endif() if(GDCM_DIR) list(APPEND _dir_candidates "${GDCM_DIR}/bin") endif() if(GLEW_DIR) list(APPEND _dir_candidates "${GLEW_DIR}") endif() if(tinyxml_DIR) list(APPEND _dir_candidates "${tinyxml_DIR}") endif() if(Poco_DIR) list(APPEND _dir_candidates "${Poco_DIR}/lib") endif() if(Qwt_DIR) list(APPEND _dir_candidates "${Qwt_DIR}") endif() if(MITK_USE_TOF_PMDO3 OR MITK_USE_TOF_PMDCAMCUBE OR MITK_USE_TOF_PMDCAMBOARD) list(APPEND _dir_candidates "${MITK_PMD_SDK_DIR}/plugins" "${MITK_PMD_SDK_DIR}/bin") endif() if(MITK_USE_CTK) list(APPEND _dir_candidates "${CTK_LIBRARY_DIRS}") foreach(_ctk_library ${CTK_LIBRARIES}) if(${_ctk_library}_LIBRARY_DIRS) list(APPEND _dir_candidates "${${_ctk_library}_LIBRARY_DIRS}") endif() endforeach() endif() if(MITK_USE_BLUEBERRY) if(DEFINED CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY) if(IS_ABSOLUTE "${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") list(APPEND _dir_candidates "${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") else() list(APPEND _dir_candidates "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") endif() endif() endif() if(MITK_LIBRARY_DIRS) list(APPEND _dir_candidates ${MITK_LIBRARY_DIRS}) endif() list(REMOVE_DUPLICATES _dir_candidates) set(_search_dirs ) foreach(_dir ${_dir_candidates}) if(EXISTS "${_dir}/${intermediate_dir}") list(APPEND _search_dirs "${_dir}/${intermediate_dir}") else() list(APPEND _search_dirs "${_dir}") endif() endforeach() # Special handling for "internal" search dirs. The intermediate directory # might not have been created yet, so we can't check for its existence. # Hence we just add it for Windows without checking. set(_internal_search_dirs "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/plugins") if(WIN32) foreach(_dir ${_internal_search_dirs}) set(_search_dirs "${_dir}/${intermediate_dir}" ${_search_dirs}) endforeach() else() set(_search_dirs ${_internal_search_dirs} ${_search_dirs}) endif() list(REMOVE_DUPLICATES _search_dirs) set(${search_path} ${_search_dirs} PARENT_SCOPE) endfunction() diff --git a/CMakeExternals/OpenIGTLink.cmake b/CMakeExternals/OpenIGTLink.cmake new file mode 100644 index 0000000000..a725d091c0 --- /dev/null +++ b/CMakeExternals/OpenIGTLink.cmake @@ -0,0 +1,60 @@ +#----------------------------------------------------------------------------- +# OpenIGTLink +#----------------------------------------------------------------------------- + +if(MITK_USE_OpenIGTLink) + + # Sanity checks + if(DEFINED OpenIGTLink_DIR AND NOT EXISTS ${OpenIGTLink_DIR}) + message(FATAL_ERROR "OpenIGTLink_DIR variable is defined but corresponds to non-existing directory") + endif() + + set(proj OpenIGTLink) + + set(OPENIGTLINK_DEPENDS ${proj}) + + if(NOT DEFINED OpenIGTLink_DIR) + + set(additional_cmake_args ) + if(MINGW) + set(additional_cmake_args + -DCMAKE_USE_WIN32_THREADS:BOOL=ON + -DCMAKE_USE_PTHREADS:BOOL=OFF) + endif() + + #list(APPEND additional_cmake_args + # -DUSE_WRAP_ITK:BOOL=OFF + # ) + + # set(ITK_PATCH_COMMAND ${CMAKE_COMMAND} -DTEMPLATE_FILE:FILEPATH=${MITK_SOURCE_DIR}/CMakeExternals/EmptyFileForPatching.dummy -P ${MITK_SOURCE_DIR}/CMakeExternals/PatchITK-4.5.1.cmake) + + ExternalProject_Add(${proj} + SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src + BINARY_DIR ${proj}-build + PREFIX ${proj}-cmake + URL /projects/OpenIGTLink-54df50de62511f8fd07a7ce5b308f1202b30933a.tar.gz + URL_MD5 b9fd8351b059f4ec615f2dfd74ab2458 + INSTALL_COMMAND "" + #PATCH_COMMAND ${ITK_PATCH_COMMAND} + CMAKE_GENERATOR ${gen} + CMAKE_ARGS + ${ep_common_args} + ${additional_cmake_args} + -DBUILD_TESTING:BOOL=OFF + -DBUILD_EXAMPLES:BOOL=OFF + -DOpenIGTLink_PROTOCOL_VERSION_2:BOOL=ON + -DCMAKE_CXX_FLAGS:STRING=${ep_common_cxx_flags} + -DCMAKE_C_FLAGS:STRING=${ep_common_c_flags} + #-DITK_USE_SYSTEM_GDCM:BOOL=ON + #-DGDCM_DIR:PATH=${GDCM_DIR} + DEPENDS ${proj_DEPENDENCIES} + ) + + set(OpenIGTLink_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}-build) + + else() + + mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") + + endif() +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b95dab46a..e8a78b7ae1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1108 +1,1109 @@ set(DESIRED_QT_VERSION 4 CACHE STRING "Pick a version of Qt to use: 4 or 5") if(DESIRED_QT_VERSION MATCHES "4") cmake_minimum_required(VERSION 2.8.9) else() cmake_minimum_required(VERSION 2.8.12) 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. CMP0028 # NEW: Double colon in target name means ALIAS or IMPORTED target. CMP0043 # NEW: Ignore COMPILE_DEFINITIONS_ properties. ) 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) include(mitkFunctionEnableBuildConfiguration) include(mitkFunctionWhitelists) include(FeatureSummary) 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) macro(env_option name doc value) set(_value $ENV{${name}}) if("${_value}" STREQUAL "") set(_value ${value}) endif() option(${name} "${doc}" ${_value}) endmacro() # ----------------------------------------- # Qt version related variables env_option(MITK_USE_QT "Use Nokia's Qt library" ON) set(MITK_DESIRED_QT_VERSION ${DESIRED_QT_VERSION}) 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.7) find_package(Qt4 ${MITK_QT4_MINIMUM_VERSION} REQUIRED) set(MITK_USE_Qt4 TRUE) set(MITK_USE_Qt5 FALSE) endif() if(DESIRED_QT_VERSION MATCHES 5) set(MITK_QT5_MINIMUM_VERSION 5.0.0) set(MITK_USE_Qt4 FALSE) set(MITK_USE_Qt5 TRUE) set(QT5_INSTALL_PREFIX "" CACHE PATH "The install location of Qt5") set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT5_INSTALL_PREFIX}) find_package(Qt5Core ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5Concurrent ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5OpenGL ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5PrintSupport ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5Sql ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5Svg ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5WebKit ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5WebKitWidgets ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5Widgets ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5Xml ${MITK_QT5_MINIMUM_VERSION} REQUIRED) endif() else() set(MITK_USE_Qt4 FALSE) set(MITK_USE_Qt5 FALSE) endif() # ----------------------------------------- # MITK_USE_* build variables env_option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) set(MITK_BUILD_TUTORIAL OFF CACHE INTERNAL "Deprecated! Use MITK_BUILD_EXAMPLES instead!") env_option(MITK_BUILD_EXAMPLES "Build the MITK Examples" ${MITK_BUILD_TUTORIAL}) env_option(MITK_USE_ACVD "Use Approximated Centroidal Voronoi Diagrams" OFF) env_option(MITK_USE_ANN "Use Approximate Nearest Neighbor Library" ON) env_option(MITK_USE_CppUnit "Use CppUnit for unit tests" ON) if(BUILD_TESTING AND NOT MITK_USE_CppUnit) message("> Forcing MITK_USE_CppUnit to ON because BUILD_TESTING=ON") set(MITK_USE_CppUnit ON CACHE BOOL "Use CppUnit for unit tests" FORCE) endif() env_option(MITK_USE_Eigen "Use the Eigen library" ON) env_option(MITK_USE_GLEW "Use the GLEW library" ON) env_option(MITK_USE_Boost "Use the Boost C++ library" OFF) env_option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) env_option(MITK_USE_CTK "Use CTK in MITK" ON) env_option(MITK_USE_DCMTK "EXPERIMENTAL, superbuild only: Use DCMTK in MITK" ${MITK_USE_CTK}) env_option(MITK_USE_OpenCV "Use Intel's OpenCV library" OFF) env_option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) env_option(MITK_USE_Poco "Use the Poco library" ON) env_option(MITK_USE_SOFA "Use Simulation Open Framework Architecture" OFF) env_option(MITK_USE_Python "Use Python wrapping in MITK" OFF) env_option(MITK_USE_SimpleITK "Use the SimpleITK library" OFF) +env_option(MITK_USE_OpenIGTLink "Use the OpenIGTLink library" OFF) set(MITK_USE_CableSwig ${MITK_USE_Python}) option(MITK_ENABLE_PIC_READER "Enable support for reading the DKFZ pic file format." ON) set(_buildConfigs "Custom") file(GLOB _buildConfigFiles CMake/BuildConfigurations/*.cmake) foreach(_buildConfigFile ${_buildConfigFiles}) get_filename_component(_buildConfigFile ${_buildConfigFile} NAME_WE) list(APPEND _buildConfigs ${_buildConfigFile}) endforeach() set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations") set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs}) mitkFunctionEnableBuildConfiguration() mitkFunctionCreateWhitelistPaths(MITK) mitkFunctionFindWhitelists(MITK) mark_as_advanced(MITK_BUILD_ALL_APPS MITK_USE_CppUnit MITK_USE_GLEW MITK_USE_CTK MITK_USE_DCMTK MITK_ENABLE_PIC_READER MITK_BUILD_CONFIGURATION ) if(MITK_USE_Python) if(APPLE) message(WARNING "Python wrapping is unsuported on mac OSX!") set(MITK_USE_Python OFF CACHE BOOL "Use Python wrapping in MITK" FORCE) else() option(MITK_USE_SYSTEM_PYTHON "Use the system python runtime" OFF) # SimpleITK is required when python is enabled set(MITK_USE_SimpleITK ON CACHE BOOL "Use the SimpleITK library" FORCE) if(MITK_USE_SYSTEM_PYTHON) FIND_PACKAGE(PythonLibs REQUIRED) FIND_PACKAGE(PythonInterp REQUIRED) else() FIND_PACKAGE(PythonLibs) FIND_PACKAGE(PythonInterp) endif() endif() 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) 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 AND NOT MITK_USE_DCMTK) message("> Forcing MITK_USE_DCMTK to ON because of MITK_USE_CTK") set(MITK_USE_DCMTK ON CACHE BOOL "Use DCMTK in MITK" FORCE) 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/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() # Simulation plugin requires boost chrono library list(FIND MITK_USE_Boost_LIBRARIES chrono _result) if(_result LESS 0) message("Adding 'chrono' to MITK_USE_Boost_LIBRARIES.") list(APPEND MITK_USE_Boost_LIBRARIES chrono) endif() set(MITK_USE_Boost_LIBRARIES ${MITK_USE_Boost_LIBRARIES} CACHE STRING "" FORCE) # Allow setting external SOFA plugins directory and SOFA plugins set(MITK_USE_SOFA_PLUGINS_DIR ${MITK_USE_SOFA_PLUGINS_DIR} CACHE PATH "External SOFA plugins directory" FORCE) set(MITK_USE_SOFA_PLUGINS ${MITK_USE_SOFA_PLUGINS} CACHE PATH "List of semicolon-separated plugin names" 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_VECTOR_PIXEL_TYPES) string(REPLACE "," ";" _integral_types ${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES}) string(REPLACE "," ";" _floating_types ${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES}) foreach(_scalar_type ${_integral_types} ${_floating_types}) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}itk::VariableLengthVector<${_scalar_type}>,") endforeach() string(LENGTH "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" _length) math(EXPR _length "${_length} - 1") string(SUBSTRING "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" 0 ${_length} MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES ${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES} CACHE STRING "List of vector pixel types used in AccessByItk and InstantiateAccessFunction macros for itk::VectorImage types" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) 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") # Print configuration summary message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL) return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(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(mitkFunctionCheckModuleDependencies) include(mitkFunctionCreateModule) include(mitkMacroCreateExecutable) include(mitkMacroCheckModule) include(mitkMacroCreateModuleTests) include(mitkFunctionAddCustomModuleTest) include(mitkMacroUseModule) include(mitkMacroMultiplexPicType) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) #----------------------------------------------------------------------------- # 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} Mitk${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 ) if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -D_WIN32_WINNT=0x0501 -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN -DNOMINMAX") mitkFunctionCheckCompilerFlags("/wd4005" MITK_CXX_FLAGS) # warning C4005: macro redefinition mitkFunctionCheckCompilerFlags("/wd4231" MITK_CXX_FLAGS) # warning C4231: nonstandard extension used : 'extern' before template explicit instantiation # the following line should be removed after fixing bug 17637 mitkFunctionCheckCompilerFlags("/wd4316" MITK_CXX_FLAGS) # warning C4316: object alignment on heap 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() if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) endif() if(CMAKE_COMPILER_IS_GNUCXX) 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}) #----------------------------------------------------------------------------- # 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") if(TARGET CoreApp) get_target_property(_is_macosx_bundle CoreApp MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp.app/Contents/MacOS/CoreApp") endif() endif() set(BLUEBERRY_TEST_APP_ID "org.mitk.qt.coreapplication") endif() include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") mitkFunctionWhitelistPlugins(MITK MITK_EXT_PLUGINS) 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}) string(FIND ${mitk_app} "MITK_BUILD_APP_" _index) string(SUBSTRING ${mitk_app} ${_index} -1 _var) if(${_var}) list(APPEND mitk_apps_fullpath "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${mitk_app}") endif() endforeach() if (mitk_plugins_fullpath) ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) endif() set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() # 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() #----------------------------------------------------------------------------- # 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) write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${MITK_VERSION_STRING} COMPATIBILITY AnyNewerVersion) # 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() #----------------------------------------------------------------------------- # Print configuration summary #----------------------------------------------------------------------------- message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL ) diff --git a/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp b/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp new file mode 100644 index 0000000000..881bc4ba04 --- /dev/null +++ b/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp @@ -0,0 +1,454 @@ +/*=================================================================== + +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 "mitkIGTLMessageToNavigationDataFilter.h" +#include "igtlTrackingDataMessage.h" +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlTransformMessage.h" +#include "mitkQuaternion.h" +#include + + +mitk::IGTLMessageToNavigationDataFilter::IGTLMessageToNavigationDataFilter() +: mitk::NavigationDataSource() +{ + mitk::NavigationData::Pointer output = mitk::NavigationData::New(); + this->SetNumberOfRequiredOutputs(1); + this->SetNthOutput(0, output.GetPointer()); +} + + +mitk::IGTLMessageToNavigationDataFilter::~IGTLMessageToNavigationDataFilter() +{ +} + + +void mitk::IGTLMessageToNavigationDataFilter::SetInput( const IGTLMessage* msg ) +{ + this->SetInput(0, msg); +} + + +void mitk::IGTLMessageToNavigationDataFilter::SetInput( unsigned int idx, const IGTLMessage* msg ) +{ + if ( msg == NULL ) // if an input is set to NULL, remove it + { + this->RemoveInput(idx); + } + else + { + // ProcessObject is not const-correct so a const_cast is required here + this->ProcessObject::SetNthInput(idx, const_cast(msg)); + } + this->CreateOutputsForAllInputs(); +} + + +const mitk::IGTLMessage* +mitk::IGTLMessageToNavigationDataFilter::GetInput( void ) const +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + + return static_cast(this->ProcessObject::GetInput(0)); +} + + +const mitk::IGTLMessage* +mitk::IGTLMessageToNavigationDataFilter::GetInput( unsigned int idx ) const +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + + return static_cast(this->ProcessObject::GetInput(idx)); +} + + +const mitk::IGTLMessage* +mitk::IGTLMessageToNavigationDataFilter::GetInput(std::string messageName) const +{ + const DataObjectPointerArray& inputs = const_cast(this)->GetInputs(); + for (DataObjectPointerArray::const_iterator it = inputs.begin(); + it != inputs.end(); ++it) + { + if (std::string(messageName) == + (static_cast(it->GetPointer()))->GetName()) + { + return static_cast(it->GetPointer()); + } + } + return NULL; +} + + +itk::ProcessObject::DataObjectPointerArraySizeType +mitk::IGTLMessageToNavigationDataFilter::GetInputIndex( std::string messageName ) +{ + DataObjectPointerArray outputs = this->GetInputs(); + for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i) + { + if (messageName == + (static_cast(outputs.at(i).GetPointer()))->GetName()) + { + return i; + } + } + throw std::invalid_argument("output name does not exist"); +} + +void mitk::IGTLMessageToNavigationDataFilter::ConnectTo( + mitk::IGTLMessageSource* UpstreamFilter) +{ + for (DataObjectPointerArraySizeType i = 0; + i < UpstreamFilter->GetNumberOfOutputs(); i++) + { + this->SetInput(i, UpstreamFilter->GetOutput(i)); + } +} + +void mitk::IGTLMessageToNavigationDataFilter::SetNumberOfExpectedOutputs( + unsigned int numOutputs) +{ + this->SetNumberOfIndexedOutputs(numOutputs); + this->CreateOutputsForAllInputs(); +} + + +void mitk::IGTLMessageToNavigationDataFilter::CreateOutputsForAllInputs() +{ + // create outputs for all inputs +// this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); + bool isModified = false; + 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); + isModified = true; + } + } + + if(isModified) + this->Modified(); +} + +void mitk::IGTLMessageToNavigationDataFilter::GenerateTransformData() +{ + const mitk::IGTLMessage* input = this->GetInput(0); + assert(input); + + //cast the input message into the proper type + igtl::TransformMessage* tMsg = + (igtl::TransformMessage*)(input->GetMessage().GetPointer()); + + //check if cast was successful + if ( !tMsg ) + { + mitkThrow() << "Cast from igtl::MessageBase to igtl::TransformMessage " + << "failed! Please check the message."; + } + + /* update outputs with tracking data from tools */ + for (unsigned int i = 0; i < this->GetNumberOfOutputs() ; ++i) + { + mitk::NavigationData* output = this->GetOutput(i); + assert(output); + + if (input->IsDataValid() == false) + { + output->SetDataValid(false); + continue; + } + + //debug output + tMsg->Print(std::cout); + + //get the transformation matrix and convert it into an affinetransformation + igtl::Matrix4x4 transformation_; + tMsg->GetMatrix(transformation_); + mitk::AffineTransform3D::Pointer affineTransformation = + mitk::AffineTransform3D::New(); + mitk::Matrix3D transformation; + mitk::Vector3D offset; + for ( unsigned int r = 0; r < 3; r++ ) + { + for ( unsigned int c = 0; c < 3; c++ ) + { + transformation.GetVnlMatrix().set( r , c , transformation_[r][c] ); + } + offset.SetElement(r, transformation_[r][3]); + } + //convert the igtl matrix here and set it in the affine transformation + affineTransformation->SetMatrix(transformation); + affineTransformation->SetOffset(offset); + + //create a new navigation data here, there is a neat constructor for + //affine transformations that sets the orientation, position according to + //the affine transformation. The other values are initialized with standard + //values + mitk::NavigationData::Pointer nd = + mitk::NavigationData::New(affineTransformation, true); + //set the time stamp + nd->SetIGTTimeStamp(input->GetTimeStamp()); + //set the name +// nd->SetName(td->GetName()); + + output->Graft(nd); + + nd->Print(std::cout); + } +} + +void mitk::IGTLMessageToNavigationDataFilter::GenerateTrackingDataData() +{ + const mitk::IGTLMessage* input = this->GetInput(0); + assert(input); + + //cast the input message into the proper type + igtl::TrackingDataMessage* tdMsg = + (igtl::TrackingDataMessage*)(input->GetMessage().GetPointer()); + + //check if cast was successful + if ( !tdMsg ) + { + mitkThrow() << "Cast from igtl::MessageBase to igtl::TrackingDataMessage " + << "failed! Please check the message."; + } + + //get the number of tracking data elements + unsigned int numTrackingDataElements = + tdMsg->GetNumberOfTrackingDataElements(); + + if ( !numTrackingDataElements ) + { + MITK_ERROR("IGTLMsgToNavDataFilter") << "There are no tracking data " + "elements in this message"; + } + + /* update outputs with tracking data from tools */ + for (unsigned int i = 0; i < this->GetNumberOfOutputs() ; ++i) + { + mitk::NavigationData* output = this->GetOutput(i); + assert(output); + + //invalidate the output + output->SetDataValid(false); + + //check if the current index, all outputs that have no corresponding input + //tracking element stay invalidated, the others are validated according to + //the tracking element + if ( input->IsDataValid() == false || i >= numTrackingDataElements ) + { + continue; + } + output->SetDataValid(true); + + //get the tracking data element which holds all the data + igtl::TrackingDataElement::Pointer td; + tdMsg->GetTrackingDataElement(i, td); + + //get the transformation matrix and convert it into an affinetransformation + igtl::Matrix4x4 transformation_; + td->GetMatrix(transformation_); + mitk::AffineTransform3D::Pointer affineTransformation = + mitk::AffineTransform3D::New(); + mitk::Matrix3D transformation; + mitk::Vector3D offset; + for ( unsigned int r = 0; r < 3; r++ ) + { + for ( unsigned int c = 0; c < 3; c++ ) + { + transformation.GetVnlMatrix().set( r , c , transformation_[r][c] ); + } + offset.SetElement(r, transformation_[r][3]); + } + //convert the igtl matrix here and set it in the affine transformation + affineTransformation->SetMatrix(transformation); + affineTransformation->SetOffset(offset); + + mitk::NavigationData::Pointer nd; + + //check the rotation matrix + vnl_matrix_fixed rotationMatrix = + affineTransformation->GetMatrix().GetVnlMatrix(); + vnl_matrix_fixed rotationMatrixTransposed = + rotationMatrix.transpose(); + // a quadratic matrix is a rotation matrix exactly when determinant is 1 + // and transposed is inverse + if (!Equal(1.0, vnl_det(rotationMatrix), 0.1) + || !((rotationMatrix*rotationMatrixTransposed).is_identity(0.1))) + { + MITK_ERROR("IGTLMsgToNavDataFilter") << "tried to initialize NavData " + << "with non-rotation matrix :" << rotationMatrix << " (Does your " + "AffineTransform3D object include spacing? This is not " + "supported by NavigationData objects!)"; + nd = mitk::NavigationData::New(); + } + else + { + //create a new navigation data here, there is a neat constructor for + //affine transformations that sets the orientation, position according to + //the affine transformation. The other values are initialized with standard + //values + nd = mitk::NavigationData::New(affineTransformation, true); + } + //set the time stamp + nd->SetIGTTimeStamp(input->GetTimeStamp()); + //set the name + nd->SetName(td->GetName()); + output->Graft(nd); + } +} + +void +mitk::IGTLMessageToNavigationDataFilter::GenerateQuaternionTrackingDataData() +{ + const mitk::IGTLMessage* input = this->GetInput(0); + assert(input); + + //cast the input message into the proper type + igtl::QuaternionTrackingDataMessage* tdMsg = + (igtl::QuaternionTrackingDataMessage*)(input->GetMessage().GetPointer()); + + //check if cast was successful + if ( !tdMsg ) + { + mitkThrow() << "Cast from igtl::MessageBase to igtl::TrackingDataMessage " + << "failed! Please check the message."; + } + + //get the number of tracking data elements + unsigned int numTrackingDataElements = + tdMsg->GetNumberOfQuaternionTrackingDataElements(); + + if ( !numTrackingDataElements ) + { + MITK_ERROR("IGTLMsgToNavDataFilter") << "There are no tracking data " + "elements in this message"; + } + + /* update outputs with tracking data from tools */ + for (unsigned int i = 0; i < this->GetNumberOfOutputs() ; ++i) + { + mitk::NavigationData* output = this->GetOutput(i); + assert(output); + + //invalidate the output + output->SetDataValid(false); + + //check if the current index, all outputs that have no corresponding input + //tracking element stay invalidated, the others are validated according to + //the tracking element + if ( input->IsDataValid() == false || i >= numTrackingDataElements ) + { + continue; + } + output->SetDataValid(true); + + + //get the tracking data element which holds all the data + igtl::QuaternionTrackingDataElement::Pointer td; + tdMsg->GetQuaternionTrackingDataElement(i, td); + + //get the quaternion and set it + float quaternion_[4]; //igtl quat type + td->GetQuaternion(quaternion_); + mitk::Quaternion quaternion; + quaternion.put(0, quaternion_[0]); + quaternion.put(1, quaternion_[1]); + quaternion.put(2, quaternion_[2]); + output->SetOrientation(quaternion); + output->SetHasOrientation(true); + + //get the position and set it + float position_[3]; //igtl position type + td->GetPosition(position_); + mitk::NavigationData::PositionType position; //mitk position type + position.SetElement(0, position_[0]); + position.SetElement(1, position_[1]); + position.SetElement(2, position_[2]); + output->SetPosition(position); + output->SetHasPosition(true); + //set the time stamp + output->SetIGTTimeStamp(input->GetTimeStamp()); + //set the name + output->SetName(td->GetName()); + + //there is no explicit covarience matrix + output->SetCovErrorMatrix(mitk::NavigationData::CovarianceMatrixType()); + } +} + +void mitk::IGTLMessageToNavigationDataFilter::GenerateData() +{ + //get the IGTLMessage from the previous filter + const mitk::IGTLMessage* input = this->GetInput(0); + assert(input); + + //check if the message is valid, if it is not valid we do not generate new + //outputs + if ( !input->IsDataValid() ) + { + MITK_DEBUG("IGTLMessageToNavigationDataFilter") << "Input data is invalid."; + return; + } + + //get the message type + const char* msgType = input->GetIGTLMessageType(); + + //check if the IGTL message has the proper type + if( strcmp(msgType, "TRANSFORM") == 0 ) + { + this->GenerateTransformData(); + } + else if( strcmp(msgType, "TDATA") == 0 ) + { + this->GenerateTrackingDataData(); + } + else if( strcmp(msgType, "QTDATA") == 0 ) + { + this->GenerateQuaternionTrackingDataData(); + } + else + { + //the message has another type + //ignore + MITK_INFO("IGTLMessageToNavigationDataFilter") << "The input has a unknown " + << "message type: " + << msgType; + } +} + + +void mitk::IGTLMessageToNavigationDataFilter::GenerateOutputInformation() +{ +// Superclass::GenerateOutputInformation(); + +// mitk::NavigationData* output = this->GetOutput(0); +// assert(output); +// const mitk::IGTLMessage* input = this->GetInput(0); +// assert(input); + + itkDebugMacro(<<"GenerateOutputInformation()"); + +// output->Initialize(input->GetPixelType(), input->GetDimension(), input->GetDimensions()); + +// // initialize geometry +// output->SetPropertyList(input->GetPropertyList()->Clone()); +// mitk::TimeGeometry::Pointer clonGeometry = input->GetTimeGeometry()->Clone(); +// output->SetTimeGeometry(clonGeometry.GetPointer()); +} diff --git a/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.h b/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.h new file mode 100644 index 0000000000..d9345174fb --- /dev/null +++ b/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.h @@ -0,0 +1,142 @@ +/*=================================================================== + +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 MITKOPENIGTLINKMESSAGETONAVIGATIONDATAFILTER_H_HEADER_INCLUDED_ +#define MITKOPENIGTLINKMESSAGETONAVIGATIONDATAFILTER_H_HEADER_INCLUDED_ + +#include +#include "mitkIGTLMessage.h" +#include "mitkIGTLMessageSource.h" +#include "MitkIGTExports.h" + +namespace mitk +{ + + /**Documentation + * \brief IGTLinkMessageToNavigationDataFilter is a filter that receives + * OpenIGTLink messages as input and produce NavigationDatas as output + * + * IGTLinkMessageToNavigationDataFilter is a filter that receives + * OpenIGTLink messages as input and produce NavigationDatas as output. + * If the OpenIGTLink message is not of the proper type the filter will not + * do anything. + * + * \ingroup IGT + */ + class MitkIGT_EXPORT + IGTLMessageToNavigationDataFilter : public NavigationDataSource + { + public: + mitkClassMacro(IGTLMessageToNavigationDataFilter, NavigationDataSource); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + 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 IGTLMessage* msg); + + /** + * \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 IGTLMessage* msg); + + /** Set an input */ +// virtual void SetInput(const DataObjectIdentifierType & key, DataObject *input); + + /** + * \brief Get the input of this filter + */ + const IGTLMessage* GetInput(void) const; + + /** + * \brief Get the input with id idx of this filter + */ + const IGTLMessage* GetInput(unsigned int idx) const; + + /** + * \brief Get the input with name messageName of this filter + */ + const IGTLMessage* GetInput(std::string messageName) const; + + /** + *\brief return the index of the input with name messageName, + * throw std::invalid_argument exception if that name was not found + * + */ + DataObjectPointerArraySizeType GetInputIndex(std::string messageName); + + /** + *\brief Connects the input of this filter to the outputs of the given + * IGTLMessageSource + * + * This method does not support smartpointer. use FilterX.GetPointer() to + * retrieve a dumbpointer. + */ + virtual void ConnectTo(mitk::IGTLMessageSource * UpstreamFilter); + + /** + *\brief Sets the number of expected outputs. + * + * Normally, this is done automatically by the filter concept. However, in our + * case we can not know, for example, how many tracking elements are stored + * in the incoming igtl message. Therefore, we have to set the number here to + * the expected value. + */ + void SetNumberOfExpectedOutputs(unsigned int numOutputs); + + protected: + IGTLMessageToNavigationDataFilter(); + virtual ~IGTLMessageToNavigationDataFilter(); + + virtual void GenerateData(); + void GenerateTransformData(); + void GenerateTrackingDataData(); + void GenerateQuaternionTrackingDataData(); + + /** + * \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(); + + /** + * \brief Defines how the input will be copied into the output + */ + virtual void GenerateOutputInformation(); + }; +} // namespace mitk +#endif /* MITKOPENIGTLMESSAGETONAVIGATIONDATAFILTER_H_HEADER_INCLUDED_ */ diff --git a/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.cpp b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.cpp new file mode 100644 index 0000000000..70341f0fff --- /dev/null +++ b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.cpp @@ -0,0 +1,344 @@ +/*=================================================================== + +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 "mitkNavigationDataToIGTLMessageFilter.h" + +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlTrackingDataMessage.h" +#include "igtlTransformMessage.h" +#include "igtlPositionMessage.h" + +#include +#include + +mitk::NavigationDataToIGTLMessageFilter::NavigationDataToIGTLMessageFilter() +{ + mitk::IGTLMessage::Pointer output = mitk::IGTLMessage::New(); + this->SetNumberOfRequiredOutputs(1); + this->SetNthOutput(0, output.GetPointer()); + + this->SetNumberOfRequiredInputs(1); + +// m_OperationMode = Mode3D; + m_CurrentTimeStep = 0; +// m_RingBufferSize = 50; //the default ring buffer size +// m_NumberForMean = 100; +} + +mitk::NavigationDataToIGTLMessageFilter::~NavigationDataToIGTLMessageFilter() +{ +} + +void mitk::NavigationDataToIGTLMessageFilter::GenerateData() +{ + switch (m_OperationMode) + { + case ModeSendQTDataMsg: + this->GenerateDataModeSendQTDataMsg(); + break; + case ModeSendTDataMsg: + this->GenerateDataModeSendTDataMsg(); + break; + case ModeSendQTransMsg: + this->GenerateDataModeSendQTransMsg(); + break; + case ModeSendTransMsg: + this->GenerateDataModeSendTransMsg(); + break; + default: + break; + } +} + + +void mitk::NavigationDataToIGTLMessageFilter::SetInput(const NavigationData* nd) +{ + // Process object is not const-correct so the const_cast is required here + this->ProcessObject::SetNthInput(0, const_cast(nd)); + this->CreateOutputsForAllInputs(); +} + + +void mitk::NavigationDataToIGTLMessageFilter::SetInput(unsigned int idx, const NavigationData* nd) +{ + // Process object is not const-correct so the const_cast is required here + this->ProcessObject::SetNthInput(idx, const_cast(nd)); + this->CreateOutputsForAllInputs(); +} + + +const mitk::NavigationData* mitk::NavigationDataToIGTLMessageFilter::GetInput( void ) +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + return static_cast(this->ProcessObject::GetInput(0)); +} + + +const mitk::NavigationData* mitk::NavigationDataToIGTLMessageFilter::GetInput( unsigned int idx ) +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + return static_cast(this->ProcessObject::GetInput(idx)); +} + + +void mitk::NavigationDataToIGTLMessageFilter::CreateOutputsForAllInputs() +{ + switch (m_OperationMode) + { + case ModeSendQTDataMsg: + // create one message output for all navigation data inputs + this->SetNumberOfIndexedOutputs(1); + // set the type for this filter + this->SetType("QTDATA"); + break; + case ModeSendTDataMsg: + // create one message output for all navigation data inputs + this->SetNumberOfIndexedOutputs(1); + // set the type for this filter + this->SetType("TDATA"); + break; + case ModeSendQTransMsg: + // create one message output for all navigation data input together + this->SetNumberOfIndexedOutputs(1); + // set the type for this filter + this->SetType("POSITION"); + break; + case ModeSendTransMsg: + // create one message output for all navigation data input together + this->SetNumberOfIndexedOutputs(1); + // set the type for this filter + this->SetType("TRANS"); + break; + default: + break; + } + + for (unsigned int idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx) + { + if (this->GetOutput(idx) == NULL) + { + DataObjectPointer newOutput = this->MakeOutput(idx); + this->SetNthOutput(idx, newOutput); + } + this->Modified(); + } +} + + +void ConvertAffineTransformationIntoIGTLMatrix(mitk::AffineTransform3D* trans, + igtl::Matrix4x4 igtlTransform) +{ + const mitk::AffineTransform3D::MatrixType& matrix = trans->GetMatrix(); + mitk::Vector3D position = trans->GetOffset(); + //copy the data into a matrix type that igtl understands + for ( unsigned int r = 0; r < 3; r++ ) + { + for ( unsigned int c = 0; c < 3; c++ ) + { + igtlTransform[r][c] = matrix(r,c); + } + igtlTransform[r][3] = position[r]; + } + for ( unsigned int c = 0; c < 3; c++ ) + { + igtlTransform[3][c] = 0.0; + } + igtlTransform[3][3] = 1.0; +} + +void mitk::NavigationDataToIGTLMessageFilter::GenerateDataModeSendQTransMsg() +{ + // for each output message + for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs() ; ++i) + { + mitk::IGTLMessage* output = this->GetOutput(i); + assert(output); + const mitk::NavigationData* input = this->GetInput(i); + assert(input); + // do not add navigation data to message if input is invalid + if (input->IsDataValid() == false) + continue; + + //get the navigation data components + mitk::NavigationData::PositionType pos = input->GetPosition(); + mitk::NavigationData::OrientationType ori = input->GetOrientation(); + + //insert this information into the message + igtl::PositionMessage::Pointer posMsg = igtl::PositionMessage::New(); + posMsg->SetPosition(pos[0], pos[1], pos[2]); + posMsg->SetQuaternion(ori[0], ori[1], ori[2], ori[3]); + posMsg->SetTimeStamp((unsigned int)input->GetIGTTimeStamp(), 0); + posMsg->SetDeviceName(input->GetName()); + posMsg->Pack(); + + //add the igtl message to the mitk::IGTLMessage + output->SetMessage(posMsg.GetPointer()); + } +} + +void mitk::NavigationDataToIGTLMessageFilter::GenerateDataModeSendTransMsg() +{ + // for each output message + for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs() ; ++i) + { + mitk::IGTLMessage* output = this->GetOutput(i); + assert(output); + const mitk::NavigationData* input = this->GetInput(i); + assert(input); + // do not add navigation data to message if input is invalid + if (input->IsDataValid() == false) + continue; + + //get the navigation data components + mitk::AffineTransform3D::Pointer transform = input->GetAffineTransform3D(); + mitk::NavigationData::PositionType position = transform->GetOffset(); + + //convert the transform into a igtl type + igtl::Matrix4x4 igtlTransform; + ConvertAffineTransformationIntoIGTLMatrix(transform, igtlTransform); + + //insert this information into the message + igtl::TransformMessage::Pointer transMsg = igtl::TransformMessage::New(); + transMsg->SetMatrix(igtlTransform); + transMsg->SetPosition(position[0], position[1], position[2]); + transMsg->SetTimeStamp((unsigned int)input->GetIGTTimeStamp(), 0); + transMsg->SetDeviceName(input->GetName()); + transMsg->Pack(); + + //add the igtl message to the mitk::IGTLMessage + output->SetMessage(transMsg.GetPointer()); + } +} + +void mitk::NavigationDataToIGTLMessageFilter::GenerateDataModeSendQTDataMsg() +{ + mitk::IGTLMessage* output = this->GetOutput(); + assert(output); + + //create a output igtl message + igtl::QuaternionTrackingDataMessage::Pointer qtdMsg = + igtl::QuaternionTrackingDataMessage::New(); + + mitk::NavigationData::PositionType pos; + mitk::NavigationData::OrientationType ori; + + for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++) + { + const mitk::NavigationData* nd = GetInput(index); + assert(nd); + + //get the navigation data components + pos = nd->GetPosition(); + ori = nd->GetOrientation(); + + //insert the information into the tracking element + igtl::QuaternionTrackingDataElement::Pointer tde = + igtl::QuaternionTrackingDataElement::New(); + tde->SetPosition(pos[0], pos[1], pos[2]); + tde->SetQuaternion(ori[0], ori[1], ori[2], ori[3]); + tde->SetName(nd->GetName()); + + //insert this element into the tracking data message + qtdMsg->AddQuaternionTrackingDataElement(tde); + + //copy the time stamp + //todo find a better way to do that + qtdMsg->SetTimeStamp((unsigned int)nd->GetIGTTimeStamp(), 0); + } + qtdMsg->Pack(); + + //add the igtl message to the mitk::IGTLMessage + output->SetMessage(qtdMsg.GetPointer()); +} + +void mitk::NavigationDataToIGTLMessageFilter::GenerateDataModeSendTDataMsg() +{ + bool isValidData = true; + mitk::IGTLMessage* output = this->GetOutput(); + assert(output); + + //create a output igtl message + igtl::TrackingDataMessage::Pointer tdMsg = igtl::TrackingDataMessage::New(); + + mitk::AffineTransform3D::Pointer transform; + Vector3D position; + igtl::Matrix4x4 igtlTransform; + vnl_matrix_fixed rotationMatrix; + vnl_matrix_fixed rotationMatrixTransposed; + + for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++) + { + const mitk::NavigationData* nd = GetInput(index); + assert(nd); + + //create a new tracking element + igtl::TrackingDataElement::Pointer tde = igtl::TrackingDataElement::New(); + + //get the navigation data components + transform = nd->GetAffineTransform3D(); + position = transform->GetOffset(); + + //check the rotation matrix + rotationMatrix = transform->GetMatrix().GetVnlMatrix(); + rotationMatrixTransposed = rotationMatrix.transpose(); + // a quadratic matrix is a rotation matrix exactly when determinant is 1 + // and transposed is inverse + if (!Equal(1.0, vnl_det(rotationMatrix), 0.1) + || !((rotationMatrix*rotationMatrixTransposed).is_identity(0.1))) + { + //the rotation matrix is not valid! => invalidate the current element + isValidData = false; + } + + //convert the transform into a igtl type + ConvertAffineTransformationIntoIGTLMatrix(transform, igtlTransform); + + //fill the tracking element with life + tde->SetMatrix(igtlTransform); + tde->SetPosition(position[0], position[1], position[2]); + tde->SetName(nd->GetName()); + + //insert this element into the tracking data message + tdMsg->AddTrackingDataElement(tde); + + //copy the time stamp + //todo find a better way to do that + tdMsg->SetTimeStamp((unsigned int)nd->GetIGTTimeStamp(), 0); + } + tdMsg->Pack(); + //add the igtl message to the mitk::IGTLMessage + output->SetMessage(tdMsg.GetPointer()); + output->SetDataValid(isValidData); +} + +void mitk::NavigationDataToIGTLMessageFilter::SetOperationMode( OperationMode mode ) +{ + m_OperationMode = mode; + this->Modified(); + this->CreateOutputsForAllInputs(); +} + +void mitk::NavigationDataToIGTLMessageFilter::ConnectTo( + mitk::NavigationDataSource* UpstreamFilter) +{ + for (DataObjectPointerArraySizeType i = 0; + i < UpstreamFilter->GetNumberOfOutputs(); i++) + { + this->SetInput(i, UpstreamFilter->GetOutput(i)); + } +} diff --git a/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.h b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.h new file mode 100644 index 0000000000..51cb40448b --- /dev/null +++ b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.h @@ -0,0 +1,188 @@ +/*=================================================================== + +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 _MITKNAVIGATIONDATATOIGTLMessageFILTER_H__ +#define _MITKNAVIGATIONDATATOIGTLMessageFILTER_H__ + +#include "mitkCommon.h" +#include "mitkPointSet.h" +#include "mitkIGTLMessageSource.h" +#include "mitkNavigationData.h" +#include "mitkNavigationDataSource.h" + +namespace mitk { + + /**Documentation + * + * \brief This filter creates IGTL messages from mitk::NavigaitionData objects + * + * + * \ingroup IGT + * + */ + class MitkIGT_EXPORT NavigationDataToIGTLMessageFilter : public IGTLMessageSource + { + public: + mitkClassMacro(NavigationDataToIGTLMessageFilter, IGTLMessageSource); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /**Documentation + * \brief There are four different operation modes. + * + * - ModeSendQTransMsg: every input NavigationData is processed into one + * output message that contains a position and a orientation (quaternion). + * - ModeSendTransMsg: every input NavigationData is processed into one + * output message that contains a 4x4 transformation. + * - ModeSendQTDataMsg:all input NavigationData is processed into one single + * output message that contains a position and orientation (quaternion) for + * each navigation data. + * - ModeSendTDataMsg:all input NavigationData is processed into one single + * output message that contains a 4x4 transformation for + * each navigation data. + */ + enum OperationMode + { + ModeSendQTransMsg, + ModeSendTransMsg, + ModeSendQTDataMsg, + ModeSendTDataMsg + }; + + /**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); + + /** + * 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! + */ + void GenerateOutputInformation() {}; + + /** + *\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. + */ + virtual void ConnectTo(mitk::NavigationDataSource * UpstreamFilter); + + protected: + NavigationDataToIGTLMessageFilter(); + + virtual ~NavigationDataToIGTLMessageFilter(); + + /** + * \brief Generates the output + * + */ +// virtual void GenerateData(); + + /** + * \brief Generates the output for ModeSendQTDataMsg + * + */ + virtual void GenerateDataModeSendQTDataMsg(); + + /** + * \brief Generates the output for ModeSendTDataMsg + */ + virtual void GenerateDataModeSendTDataMsg(); + + /** + * \brief Generates the output for ModeSendQTransMsg + * + */ + virtual void GenerateDataModeSendQTransMsg(); + + /** + * \brief Generates the output for ModeSendTransMsg + */ + virtual void GenerateDataModeSendTransMsg(); + + /** + * \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 // _MITKNAVIGATIONDATATOIGTLMessageFILTER_H__ diff --git a/Modules/IGT/CMakeLists.txt b/Modules/IGT/CMakeLists.txt index 4c9722c526..3b5d60f64d 100644 --- a/Modules/IGT/CMakeLists.txt +++ b/Modules/IGT/CMakeLists.txt @@ -1,57 +1,57 @@ 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_OPTITRACK_TRACKER) set(INCLUDE_DIRS_INTERNAL ${INCLUDE_DIRS_INTERNAL} ${MITK_OPTITRACK_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_OPTITRACK_TRACKER_LIB}) add_definitions( -DMITK_USE_OPTITRACK_TRACKER ) endif(MITK_USE_OPTITRACK_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( SUBPROJECTS MITK-IGT INCLUDE_DIRS Algorithms Common DataManagement ExceptionHandling IO Rendering TrackingDevices TestingHelper INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} - DEPENDS MitkImageStatistics MitkSceneSerialization MitkIGTBase - PACKAGE_DEPENDS ITK|ITKRegistrationCommon tinyxml + DEPENDS MitkImageStatistics MitkSceneSerialization MitkIGTBase MitkOpenIGTLink + PACKAGE_DEPENDS ITK|ITKRegistrationCommon tinyxml OpenIGTLink ADDITIONAL_LIBS "${ADDITIONAL_LIBS}" #WARNINGS_AS_ERRORS disabled for release 2014-03 because of bug 17463 ) 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() if(NOT MODULE_IS_ENABLED) message(STATUS "IGTTutorialStep1 won't be built. Missing: ${_RESULT}") else() ## 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() diff --git a/Modules/IGT/files.cmake b/Modules/IGT/files.cmake index a23020d003..aef21bf3f1 100644 --- a/Modules/IGT/files.cmake +++ b/Modules/IGT/files.cmake @@ -1,90 +1,92 @@ set(CPP_FILES TestingHelper/mitkNavigationToolStorageTestHelper.cpp Algorithms/mitkNavigationDataDelayFilter.cpp Algorithms/mitkNavigationDataDisplacementFilter.cpp Algorithms/mitkNavigationDataEvaluationFilter.cpp Algorithms/mitkNavigationDataLandmarkTransformFilter.cpp Algorithms/mitkNavigationDataReferenceTransformFilter.cpp Algorithms/mitkNavigationDataSmoothingFilter.cpp Algorithms/mitkNavigationDataToMessageFilter.cpp Algorithms/mitkNavigationDataToNavigationDataFilter.cpp Algorithms/mitkNavigationDataToPointSetFilter.cpp Algorithms/mitkNavigationDataTransformFilter.cpp + Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp + Algorithms/mitkNavigationDataToIGTLMessageFilter.cpp Common/mitkIGTTimeStamp.cpp Common/mitkSerialCommunication.cpp Common/mitkTrackingTypes.cpp DataManagement/mitkNavigationData.cpp DataManagement/mitkNavigationDataSet.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/mitkNavigationDataRecorderDeprecated.cpp IO/mitkNavigationDataSequentialPlayer.cpp IO/mitkNavigationToolReader.cpp IO/mitkNavigationToolStorageSerializer.cpp IO/mitkNavigationToolStorageDeserializer.cpp IO/mitkNavigationToolWriter.cpp IO/mitkNavigationDataReaderInterface.cpp IO/mitkNavigationDataReaderXML.cpp IO/mitkNavigationDataReaderCSV.cpp IO/mitkNavigationDataSetWriterXML.cpp IO/mitkNavigationDataSetWriterCSV.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 TrackingDevices/mitkOptitrackErrorMessages.cpp TrackingDevices/mitkOptitrackTrackingDevice.cpp TrackingDevices/mitkOptitrackTrackingTool.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/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui b/Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui index af246a91db..2c4bc42225 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui @@ -1,40 +1,38 @@ QmitkNavigationToolStorageSelectionWidgetControls 0 0 199 111 Form - + 0 0 QmitkServiceListWidget QListWidget
QmitkServiceListWidget.h
- - - +
diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index 9e865cddcc..b27070e511 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,59 +1,61 @@ set(mitk_modules LegacyIO DataTypesExt AlgorithmsExt MapperExt DICOMReader DICOMTesting Qt4Qt5TestModule SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction ImageStatistics LegacyAdaptors SceneSerialization GraphAlgorithms ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation OpenViewCore QmlItems Overlays QtWidgets QtWidgetsExt SegmentationUI DiffusionImaging GPGPU + OpenIGTLink IGTBase IGT CameraCalibration RigidRegistration RigidRegistrationUI DeformableRegistration DeformableRegistrationUI OpenCL OpenCVVideoSupport QtOverlays InputDevices ToFHardware ToFProcessing ToFUI US USUI DicomUI Simulation Remeshing Python Persistence + OpenIGTLinkUI IGTUI VtkShaders DicomRT IOExt XNAT ) if(MITK_ENABLE_PIC_READER) list(APPEND mitk_modules IpPicSupportIO) endif() diff --git a/Modules/OpenIGTLink/CMakeLists.txt b/Modules/OpenIGTLink/CMakeLists.txt new file mode 100644 index 0000000000..f78841da98 --- /dev/null +++ b/Modules/OpenIGTLink/CMakeLists.txt @@ -0,0 +1,22 @@ +#find_package(OpenIGTLink) + +#include(${OpenIGTLink_USE_FILE}) + +#include(${OpenIGTLink_SOURCE_DIR}/Source) + +#SET(OpenIGTLink_INCLUDE_DIRS_BUILD_TREE ${OpenIGTLink_INCLUDE_DIRS_BUILD_TREE} +# ${OpenIGTLink_BINARY_DIR} +# ${OpenIGTLink_SOURCE_DIR}/Source +# ${OpenIGTLink_SOURCE_DIR}/Source/igtlutil +#) + +MITK_CREATE_MODULE( + #SUBPROJECTS MITK-IGTL + DEPENDS MitkCore + PACKAGE_DEPENDS OpenIGTLink + #WARNINGS_AS_ERRORS + #ADDITIONAL_LIBS ${OpenIGTLink_LIBRARIES} /projects/OIGTL-build/bin/libOpenIGTLink.a + #INCLUDE_DIRS ${OpenIGTLink_INCLUDE_DIRS_BUILD_TREE} + #INCLUDE_DIRS /projects/OIGTL-build ${OpenIGTLink_BINARY_DIR} ${OpenIGTLink_SOURCE_DIR}/Source + EXPORT_DEFINE MITK_OPENIGTLINK_EXPORT +) diff --git a/Modules/OpenIGTLink/files.cmake b/Modules/OpenIGTLink/files.cmake new file mode 100644 index 0000000000..e51038f5b4 --- /dev/null +++ b/Modules/OpenIGTLink/files.cmake @@ -0,0 +1,13 @@ +set(CPP_FILES + mitkIGTLClient.cpp + mitkIGTLServer.cpp + mitkIGTLDevice.cpp + mitkIGTLMessageSource.cpp + mitkIGTLDeviceSource.cpp + mitkIGTLMessage.cpp + mitkIGTLMessageFactory.cpp + mitkIGTLMessageCloneHandler.h + mitkIGTLDummyMessage.cpp + mitkIGTLMessageQueue.cpp + mitkIGTLMessageProvider.cpp +) diff --git a/Modules/OpenIGTLink/mitkIGTLClient.cpp b/Modules/OpenIGTLink/mitkIGTLClient.cpp new file mode 100644 index 0000000000..4c0cd66846 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLClient.cpp @@ -0,0 +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 "mitkIGTLClient.h" +//#include "mitkIGTTimeStamp.h" +//#include "mitkIGTHardwareException.h" +#include + +#include +#include + +#include +#include + +typedef itk::MutexLockHolder MutexLockHolder; + + +mitk::IGTLClient::IGTLClient() : +IGTLDevice() +{ +} + +mitk::IGTLClient::~IGTLClient() +{ + +} + +bool mitk::IGTLClient::OpenConnection() +{ + if (this->GetState() != Setup) + { + mitkThrowException(mitk::Exception) << + "Can only try to open the connection if in setup mode"; + return false; + } + + std::string hostname = this->GetHostname(); + int portNumber = this->GetPortNumber(); + + if (portNumber == -1 || hostname.size() <= 0) + { + //port number or hostname was not correct + return false; + } + + //create a new client socket + m_Socket = igtl::ClientSocket::New(); + + //try to connect to the igtl server + int response = dynamic_cast(m_Socket.GetPointer())-> + ConnectToServer(hostname.c_str(), portNumber); + + //check the response + if ( response != 0 ) + { + mitkThrowException(mitk::Exception) << + "The client could not connect to " << hostname << " port: " << portNumber; + return false; + } + + // everything is initialized and connected so the communication can be started + this->SetState(Ready); + + //inform observers about this new client + this->InvokeEvent(NewClientConnectionEvent()); + + return true; +} + +void mitk::IGTLClient::Receive() +{ + //try to receive a message, if the socket is not present anymore stop the + //communication + unsigned int status = this->ReceivePrivate(this->m_Socket); + if ( status == IGTL_STATUS_NOT_PRESENT ) + { + this->StopCommunicationWithSocket(this->m_Socket); + //inform observers about loosing the connection to this socket + this->InvokeEvent(LostConnectionEvent()); + MITK_WARN("IGTLClient") << "Lost connection to server socket."; + } +} + +void mitk::IGTLClient::Send() +{ + igtl::MessageBase::Pointer curMessage; + + //get the latest message from the queue + curMessage = this->m_SendQueue->PullMessage(); + + // there is no message => return + if ( curMessage.IsNull() ) + return; + + if ( this->SendMessagePrivate(curMessage.GetPointer(), this->m_Socket) ) + { + MITK_INFO("IGTLDevice") << "Successfully sent the message."; + } + else + { + MITK_WARN("IGTLDevice") << "Could not send the message."; + } +} + +void mitk::IGTLClient::StopCommunicationWithSocket(igtl::Socket* /*socket*/) +{ + m_StopCommunicationMutex->Lock(); + m_StopCommunication = true; + m_StopCommunicationMutex->Unlock(); +} + +unsigned int mitk::IGTLClient::GetNumberOfConnections() +{ + return this->m_Socket->GetConnected(); +} diff --git a/Modules/OpenIGTLink/mitkIGTLClient.h b/Modules/OpenIGTLink/mitkIGTLClient.h new file mode 100644 index 0000000000..46c2752c1d --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLClient.h @@ -0,0 +1,93 @@ +/*=================================================================== + +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 MITKIGTLCLIENT_H +#define MITKIGTLCLIENT_H + +#include "mitkIGTLDevice.h" + +#include + + +namespace mitk +{ + + /** + * \brief Superclass for OpenIGTLink clients + * + * Implements the IGTLDevice interface for IGTLClients. In certain points it + * behaves different than the IGTLServer. The client connects directly to a + * server (it cannot connect to two different servers). Therefore, it has to + * check only this one connection. + * + * \ingroup OpenIGTLink + */ + class MITK_OPENIGTLINK_EXPORT IGTLClient : public IGTLDevice + { + public: + mitkClassMacro(IGTLClient, IGTLDevice) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** + * \brief Establishes the connection between this client and the IGTL server. + * + * @throw mitk::Exception Throws an exception if the client is not in Setup + * mode or if it cannot connect to the defined host. + */ + virtual bool OpenConnection(); + + /** + * \brief Returns the number of connections of this device + * + * A client can connect to one sever only, therefore, the number is either 0 + * or 1 + */ + virtual unsigned int GetNumberOfConnections(); + + protected: + /** Constructor */ + IGTLClient(); + /** Destructor */ + virtual ~IGTLClient(); + + /** + * \brief Call this method to receive a message. + * + * The message will be saved in the receive queue. If the connection is lost + * it will stop the communication. + */ + virtual void Receive(); + + /** + * \brief Call this method to send a message. + * + * The message will be read from the queue. + */ + virtual void Send(); + + /** + * \brief Stops the communication with the given socket. + * + * The client uses just one socket. Therefore, calling this function causes + * the stop of the communication. + * + */ + virtual void StopCommunicationWithSocket(igtl::Socket*); + }; +} // namespace mitk +#endif /* MITKIGTLCLIENT_H */ diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.cpp b/Modules/OpenIGTLink/mitkIGTLDevice.cpp new file mode 100644 index 0000000000..7ef3757487 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDevice.cpp @@ -0,0 +1,485 @@ +/*=================================================================== + +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 "mitkIGTLDevice.h" +//#include "mitkIGTTimeStamp.h" +#include +#include +#include + +#include +#include + +#include + +//remove later +#include + +#include + +static const int SOCKET_SEND_RECEIVE_TIMEOUT_MSEC = 1; + +typedef itk::MutexLockHolder MutexLockHolder; + +mitk::IGTLDevice::IGTLDevice() : +// m_Data(mitk::DeviceDataUnspecified), + m_State(mitk::IGTLDevice::Setup), + m_Name("Unspecified Device"), + m_StopCommunication(false), + m_PortNumber(-1), + m_MultiThreader(NULL), m_ThreadID(0) +{ + m_StopCommunicationMutex = itk::FastMutexLock::New(); + m_StateMutex = itk::FastMutexLock::New(); +// m_LatestMessageMutex = itk::FastMutexLock::New(); + m_CommunicationFinishedMutex = itk::FastMutexLock::New(); + // execution rights are owned by the application thread at the beginning + m_CommunicationFinishedMutex->Lock(); + m_MultiThreader = itk::MultiThreader::New(); +// m_Data = mitk::DeviceDataUnspecified; +// m_LatestMessage = igtl::MessageBase::New(); + + m_MessageFactory = mitk::IGTLMessageFactory::New(); + m_SendQueue = mitk::IGTLMessageQueue::New(); + m_ReceiveQueue = mitk::IGTLMessageQueue::New(); + m_CommandQueue = mitk::IGTLMessageQueue::New(); +} + + +mitk::IGTLDevice::~IGTLDevice() +{ + /* stop communication and disconnect from igtl device */ + if (GetState() == Running) + { + this->StopCommunication(); + } + if (GetState() == Ready) + { + this->CloseConnection(); + } + /* cleanup tracking thread */ + if ((m_ThreadID != 0) && (m_MultiThreader.IsNotNull())) + { + m_MultiThreader->TerminateThread(m_ThreadID); + } + m_MultiThreader = NULL; +} + +mitk::IGTLDevice::IGTLDeviceState mitk::IGTLDevice::GetState() const +{ + MutexLockHolder lock(*m_StateMutex); + return m_State; +} + + +void mitk::IGTLDevice::SetState( IGTLDeviceState state ) +{ + itkDebugMacro("setting m_State to " << state); + + m_StateMutex->Lock(); +// MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex + + if (m_State == state) + { + m_StateMutex->Unlock(); + return; + } + m_State = state; + m_StateMutex->Unlock(); + this->Modified(); +} + + +bool mitk::IGTLDevice::TestConnection() +{ + + return true; +} + +unsigned int mitk::IGTLDevice::ReceivePrivate(igtl::Socket* socket) +{ + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + int r = + socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), 1); + + if (r == 0) //connection error + { + // an error was received, therefor the communication with this socket + // must be stopped + return IGTL_STATUS_NOT_PRESENT; + } + else if (r == -1 ) //timeout + { + // a timeout was received, this is no error state, thus, do nothing + return IGTL_STATUS_TIME_OUT; + } + else if (r == headerMsg->GetPackSize()) + { + // Deserialize the header and check the CRC + int crcCheck = headerMsg->Unpack(1); + if (crcCheck & igtl::MessageHeader::UNPACK_HEADER) + { + // Allocate a time stamp + igtl::TimeStamp::Pointer ts; + ts = igtl::TimeStamp::New(); + + // Get time stamp + igtlUint32 sec; + igtlUint32 nanosec; + + headerMsg->GetTimeStamp(ts); + ts->GetTimeStamp(&sec, &nanosec); + +// std::cerr << "Time stamp: " +// << sec << "." +// << nanosec << std::endl; + +// std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " " +// << headerMsg->GetDeviceName() << std::endl; + +// headerMsg->Print(std::cout); + + //check the type of the received message + //if it is a GET_, STP_ or RTS_ command push it into the command queue + //otherwise continue reading the whole message from the socket + const char* curDevType = headerMsg->GetDeviceType(); + if ( std::strstr( curDevType, "GET_" ) != NULL || + std::strstr( curDevType, "STP_" ) != NULL || + std::strstr( curDevType, "RTS_" ) != NULL) + { + this->m_CommandQueue->PushMessage(headerMsg); + this->InvokeEvent(CommandReceivedEvent()); + return IGTL_STATUS_OK; + } + + //Create a message according to the header message + igtl::MessageBase::Pointer curMessage; + curMessage = m_MessageFactory->CreateInstance(headerMsg); + + //check if the curMessage is created properly, if not the message type is + //not supported and the message has to be skipped + if ( curMessage.IsNull() ) + { + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + MITK_ERROR("IGTLDevice") << "The received type is not supported. Please " + "add it to the message factory."; + return IGTL_STATUS_NOT_FOUND; + } + + //insert the header to the message and allocate the pack + curMessage->SetMessageHeader(headerMsg); + curMessage->AllocatePack(); + + // Receive transform data from the socket + int receiveCheck = 0; + receiveCheck = socket->Receive(curMessage->GetPackBodyPointer(), + curMessage->GetPackBodySize()); + + if ( receiveCheck > 0 ) + { + int c = curMessage->Unpack(1); + if ( !(c & igtl::MessageHeader::UNPACK_BODY) ) + { +// mitkThrow() << "crc error"; + return IGTL_STATUS_CHECKSUM_ERROR; + } + + //check the type of the received message + //if it is a command push it into the command queue + //otherwise into the normal receive queue + //STP_ commands are handled here because they implemented additional + //member variables that are not stored in the header message + if ( std::strstr( curDevType, "STT_" ) != NULL ) + { + this->m_CommandQueue->PushMessage(curMessage); + this->InvokeEvent(CommandReceivedEvent()); + } + else + { + this->m_ReceiveQueue->PushMessage(curMessage); + this->InvokeEvent(MessageReceivedEvent()); + } + return IGTL_STATUS_OK; + } + else + { + MITK_ERROR("IGTLDevice") << "Received a valid header but could not " + << "read the whole message."; + return IGTL_STATUS_UNKNOWN_ERROR; + } + } + else + { + //CRC check failed + return IGTL_STATUS_CHECKSUM_ERROR; + } + } + else + { + //Message size information and actual data size don't match. + //this state is not suppossed to be reached, return unknown error + return IGTL_STATUS_UNKNOWN_ERROR; + } +} + +void mitk::IGTLDevice::SendMessage(const mitk::IGTLMessage* msg) +{ + this->SendMessage(msg->GetMessage()); +} + +void mitk::IGTLDevice::SendMessage(igtl::MessageBase::Pointer msg) +{ + //add the message to the queue + m_SendQueue->PushMessage(msg); +} + +unsigned int mitk::IGTLDevice::SendMessagePrivate(igtl::MessageBase::Pointer msg, + igtl::Socket::Pointer socket) +{ + //check the input message + if ( msg.IsNull() ) + { + MITK_ERROR("IGTLDevice") << "Could not send message because message is not " + "valid. Please check."; + return false; + } + + // add the name of this device to the message + msg->SetDeviceName(this->GetName().c_str()); + + // Pack (serialize) and send + msg->Pack(); + int sendSuccess = socket->Send(msg->GetPackPointer(), msg->GetPackSize()); + + if (sendSuccess) + return IGTL_STATUS_OK; + else + return IGTL_STATUS_UNKNOWN_ERROR; +} + + +void mitk::IGTLDevice::RunCommunication() +{ + if (this->GetState() != Running) + return; + + // keep lock until end of scope + MutexLockHolder communicationFinishedLockHolder(*m_CommunicationFinishedMutex); + + // Because m_StopCommunication is used by two threads, access has to be guarded + // by a mutex. To minimize thread locking, a local copy is used here + bool localStopCommunication; + + // update the local copy of m_StopCommunication + this->m_StopCommunicationMutex->Lock(); + localStopCommunication = this->m_StopCommunication; + this->m_StopCommunicationMutex->Unlock(); + while ((this->GetState() == Running) && (localStopCommunication == false)) + { + // Check if other igtl devices want to connect with this one. This method + // is overwritten for igtl servers but is doing nothing in case of a igtl + // client + this->Connect(); + + // Check if there is something to receive and store it in the message queue + this->Receive(); + + // Check if there is something to send + this->Send(); + + /* Update the local copy of m_StopCommunication */ + this->m_StopCommunicationMutex->Lock(); + localStopCommunication = m_StopCommunication; + this->m_StopCommunicationMutex->Unlock(); + + // time to relax +// itksys::SystemTools::Delay(1); + } + // StopCommunication was called, thus the mode should be changed back to Ready now + // that the tracking loop has ended. + this->SetState(Ready); + MITK_DEBUG("IGTLDevice::RunCommunication") << "Reached end of communication."; + // returning from this function (and ThreadStartCommunication()) + // this will end the thread + return; +} + + + + +bool mitk::IGTLDevice::StartCommunication() +{ + if (this->GetState() != Ready) + return false; + + // go to mode Running + this->SetState(Running); + + // set a timeout for the sending and receiving + this->m_Socket->SetTimeout(SOCKET_SEND_RECEIVE_TIMEOUT_MSEC); + + // update the local copy of m_StopCommunication + this->m_StopCommunicationMutex->Lock(); + this->m_StopCommunication = false; + this->m_StopCommunicationMutex->Unlock(); + + // transfer the execution rights to tracking thread + m_CommunicationFinishedMutex->Unlock(); + + // start a new thread that executes the communication + m_ThreadID = + m_MultiThreader->SpawnThread(this->ThreadStartCommunication, this); +// mitk::IGTTimeStamp::GetInstance()->Start(this); + return true; +} + +bool mitk::IGTLDevice::StopCommunication() +{ + if (this->GetState() == Running) // Only if the object is in the correct state + { + // m_StopCommunication is used by two threads, so we have to ensure correct + // thread handling + m_StopCommunicationMutex->Lock(); + m_StopCommunication = true; + m_StopCommunicationMutex->Unlock(); + // we have to wait here that the other thread recognizes the STOP-command + // and executes it + m_CommunicationFinishedMutex->Lock(); +// mitk::IGTTimeStamp::GetInstance()->Stop(this); // notify realtime clock + // StopCommunication was called, thus the mode should be changed back + // to Ready now that the tracking loop has ended. + this->SetState(Ready); + } + return true; +} + +bool mitk::IGTLDevice::CloseConnection() +{ + if (this->GetState() == Setup) + { + return true; + } + else if (this->GetState() == Running) + { + this->StopCommunication(); + } + + m_Socket->CloseSocket(); + + /* return to setup mode */ + this->SetState(Setup); + +// this->InvokeEvent(mitk::LostConnectionEvent()); + + return true; +} + +bool mitk::IGTLDevice::SendRTSMessage(const char* type) +{ + //construct the device type for the return message, it starts with RTS_ and + //continues with the requested type + std::string returnType("RTS_"); + returnType.append(type); + //create a return message + igtl::MessageBase::Pointer rtsMsg = + this->m_MessageFactory->CreateInstance(returnType); + //if retMsg is NULL there is no return message defined and thus it is not + //necessary to send one back + if ( rtsMsg.IsNotNull() ) + { + this->SendMessage(rtsMsg); + return true; + } + else + { + return false; + } +} + +void mitk::IGTLDevice::Connect() +{ + +} + +igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextMessage() +{ + //copy the next message into the given msg + igtl::MessageBase::Pointer msg = this->m_ReceiveQueue->PullMessage(); + return msg; +} + +igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextCommand() +{ + //copy the next command into the given msg + igtl::MessageBase::Pointer msg = this->m_CommandQueue->PullMessage(); + return msg; +} + +void mitk::IGTLDevice::EnableInfiniteBufferingMode( + mitk::IGTLMessageQueue::Pointer queue, + bool enable) +{ + queue->EnableInfiniteBuffering(enable); +} + +//std::string mitk::IGTLDevice::GetNextMessageInformation() +//{ +// return this->m_ReceiveQueue->GetNextMsgInformationString(); +//} + +//std::string mitk::IGTLDevice::GetNextMessageDeviceType() +//{ +// return this->m_ReceiveQueue->GetNextMsgDeviceType(); +//} + +//std::string mitk::IGTLDevice::GetNextCommandInformation() +//{ +// return this->m_CommandQueue->GetNextMsgInformationString(); +//} + +//std::string mitk::IGTLDevice::GetNextCommandDeviceType() +//{ +// return this->m_CommandQueue->GetNextMsgDeviceType(); +//} + +ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartCommunication(void* pInfoStruct) +{ + /* extract this pointer from Thread Info structure */ + struct itk::MultiThreader::ThreadInfoStruct * pInfo = + (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; + if (pInfo == NULL) + { + return ITK_THREAD_RETURN_VALUE; + } + if (pInfo->UserData == NULL) + { + return ITK_THREAD_RETURN_VALUE; + } + IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; + if (igtlDevice != NULL) + { + igtlDevice->RunCommunication(); + } + igtlDevice->m_ThreadID = 0; // erase thread id because thread will end. + return ITK_THREAD_RETURN_VALUE; +} diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.h b/Modules/OpenIGTLink/mitkIGTLDevice.h new file mode 100644 index 0000000000..5d4cb64dee --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDevice.h @@ -0,0 +1,384 @@ +/*=================================================================== + +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 MITKIGTLDEVICE_H +#define MITKIGTLDEVICE_H + +#include "mitkCommon.h" + +//itk +#include "itkObject.h" +#include "itkFastMutexLock.h" +#include "itkMultiThreader.h" + +//igtl +#include "igtlSocket.h" +#include "igtlMessageBase.h" +#include "igtlTransformMessage.h" + +//mitkIGTL +#include "MitkOpenIGTLinkExports.h" +#include "mitkIGTLMessageFactory.h" +#include "mitkIGTLMessageQueue.h" +#include "mitkIGTLMessage.h" + + +namespace mitk { + /** + * \brief Interface for all OpenIGTLink Devices + * + * Defines the methods that are common for all devices using OpenIGTLink. It + * can open/close a connection, start/stop a communication and send/receive + * messages. + * + * It uses message queues to store the incoming and outgoing mails. They are + * configurable, you can set buffering on and off. + * + * The device is in one of three different states: Setup, Ready or Running. + * Setup is the initial state. From this state on you can call + * OpenConnection() and arrive in the Ready state. From the Ready state you + * call StartCommunication() to arrive in the Running state. Now the device + * is continuosly checking for new connections, receiving messages and + * sending messages. This runs in a seperate thread. To stop the communication + * call StopCommunication() (to arrive in Ready state) or CloseConnection() + * (to arrive in the Setup state). + * + * \ingroup OpenIGTLink + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLDevice : public itk::Object + { + public: + mitkClassMacro(IGTLDevice, itk::Object) + + /** + * \brief Type for state variable. + * The IGTLDevice is always in one of these states. + * + */ + enum IGTLDeviceState {Setup, Ready, Running}; + + /** + * \brief Opens a connection to the device + * + * This may only be called if there is currently no connection to the + * device. If OpenConnection() is successful, the object will change from + * Setup state to Ready state. + */ + virtual bool OpenConnection() = 0; + + /** + * \brief Closes the connection to the device + * + * This may only be called if there is currently a connection to the + * device, but device is not running (e.g. object is in Ready state) + */ + virtual bool CloseConnection(); + + /** + * \brief Stops the communication between the two devices + * + * This may only be called if the device is in Running state. + */ + virtual bool StopCommunication(); + + /** + * \brief Starts the communication between the two devices + * + * This may only be called if the device is in Ready state. + */ + bool StartCommunication(); + + /** + * \brief Continuously checks for new connections, receives messages and + * sends messages. + * + * This may only be called if the device is in Running state and only from + * a seperate thread. + */ + void RunCommunication(); + + /** + * \brief Adds the given message to the sending queue + * + * This may only be called after the connection to the device has been + * established with a call to OpenConnection(). Note that the message + * is not send directly. This method just adds it to the send queue. + * \param msg The message to be added to the sending queue + */ + void SendMessage(igtl::MessageBase::Pointer msg); + + /** + * \brief Adds the given message to the sending queue + * + * Convenience function to work with mitk::IGTLMessage directly. + * \param msg The message to be added to the sending queue + */ + void SendMessage(const IGTLMessage* msg); + + /** + * \brief Returns current object state (Setup, Ready or Running) + */ + IGTLDeviceState GetState() const; + + /** + * \brief Returns the oldest message in the command queue + * \return The oldest message from the command queue. + */ + igtl::MessageBase::Pointer GetNextCommand(); + + /** + * \brief Returns the oldest message in the receive queue + * \return The oldest message from the receive queue + */ + igtl::MessageBase::Pointer GetNextMessage(); + + /** + * \brief Sets the port number of the device + */ + itkSetMacro(PortNumber,int); + + /** + * \brief Returns the port number of the device + */ + itkGetMacro(PortNumber,int); + + /** + * \brief Sets the ip/hostname of the device + */ + itkSetMacro(Hostname,std::string); + + /** + * \brief Returns the ip/hostname of the device + */ + itkGetMacro(Hostname,std::string); + + /** + * \brief Returns the name of this device + */ + itkGetConstMacro(Name, std::string); + + /** + * \brief Sets the name of this device + */ + itkSetMacro(Name, std::string); + + /** + * \brief Returns a const reference to the receive queue + */ + itkGetConstMacro(ReceiveQueue, mitk::IGTLMessageQueue::Pointer); + + /** + * \brief Returns a const reference to the command queue + */ + itkGetConstMacro(CommandQueue, mitk::IGTLMessageQueue::Pointer); + + /** + * \brief Returns a const reference to the send queue + */ + itkGetConstMacro(SendQueue, mitk::IGTLMessageQueue::Pointer); + + /** + * \brief Returns the message factory + */ + itkGetMacro(MessageFactory, mitk::IGTLMessageFactory::Pointer); + + /** + * \brief static start method for the tracking thread. + * \param data a void pointer to the IGTLDevice object. + */ + static ITK_THREAD_RETURN_TYPE ThreadStartCommunication(void* data); + + /** + * \brief TestConnection() tries to connect to a IGTL device on the current + * ip and port + * + * \todo Implement this method. Send a status message and check the answer. + * + * TestConnection() tries to connect to a IGTL server on the current + * ip and port and returns which device it has found. + * \return It returns the type of the device that answers. Throws an + * exception + * if no device is available on that ip/port. + * @throw mitk::Exception Throws an exception if there are errors + * while connecting to the device. + */ + virtual bool TestConnection(); + + /** + * \brief Send RTS message of given type + */ + bool SendRTSMessage(const char* type); + + /** + * \brief Sets the buffering mode of the given queue + */ + void EnableInfiniteBufferingMode(mitk::IGTLMessageQueue::Pointer queue, + bool enable = true); + + /** + * \brief Returns the number of connections of this device + */ + virtual unsigned int GetNumberOfConnections() = 0; + + protected: + /** + * \brief Sends a message. + * + * This may only be called after the connection to the device has been + * established with a call to OpenConnection(). This method uses the given + * socket to send the given MessageReceivedEvent + * + * \param msg the message to be sent + * \param socket the socket used to communicate with the other device + * + * \retval IGTL_STATUS_OK the message was sent + * \retval IGTL_STATUS_UNKONWN_ERROR the message was not sent because an + * unknown error occurred + */ + unsigned int SendMessagePrivate(igtl::MessageBase::Pointer msg, + igtl::Socket::Pointer socket); + + + /** + * \brief Call this method to receive a message. + * + * The message will be saved in the receive queue. + */ + virtual void Receive() = 0; + + /** + * \brief Call this method to receive a message from the given device. + * + * The message will be saved in the receive queue. + * + * \param device the socket that connects this device with the other one. + * + * \retval IGTL_STATUS_OK a message or a command was received + * \retval IGTL_STATUS_NOT_PRESENT the socket is not connected anymore + * \retval IGTL_STATUS_TIME_OUT the socket timed out + * \retval IGTL_STATUS_CHECKSUM_ERROR the checksum of the received msg was + * incorrect + * \retval IGTL_STATUS_UNKNOWN_ERROR an unknown error occurred + */ + unsigned int ReceivePrivate(igtl::Socket* device); + + /** + * \brief Call this method to send a message. The message will be read from + * the queue. + */ + virtual void Send() = 0; + + /** + * \brief Call this method to check for other devices that want to connect + * to this one. + * + * In case of a client this method is doing nothing. In case of a server it + * is checking for other devices and if there is one it establishes a + * connection. + */ + virtual void Connect(); + + /** + * \brief Stops the communication with the given socket + * + */ + virtual void StopCommunicationWithSocket(igtl::Socket* socket) = 0; + + /** + * \brief change object state + */ + void SetState(IGTLDeviceState state); + + IGTLDevice(); + virtual ~IGTLDevice(); + + /** current object state (Setup, Ready or Running) */ + IGTLDeviceState m_State; + /** the name of this device */ + std::string m_Name; + + /** signal used to stop the thread*/ + bool m_StopCommunication; + /** mutex to control access to m_StopCommunication */ + itk::FastMutexLock::Pointer m_StopCommunicationMutex; + /** mutex used to make sure that the thread is just started once */ + itk::FastMutexLock::Pointer m_CommunicationFinishedMutex; + /** mutex to control access to m_State */ + itk::FastMutexLock::Pointer m_StateMutex; + /** the hostname or ip of the device */ + std::string m_Hostname; + /** the port number of the device */ + int m_PortNumber; + /** the socket used to communicate with other IGTL devices */ + igtl::Socket::Pointer m_Socket; + + /** The message receive queue */ + mitk::IGTLMessageQueue::Pointer m_ReceiveQueue; + /** The message send queue */ + mitk::IGTLMessageQueue::Pointer m_SendQueue; + /** A queue that stores just command messages received by this device */ + mitk::IGTLMessageQueue::Pointer m_CommandQueue; + + /** A message factory that provides the New() method for all msg types */ + mitk::IGTLMessageFactory::Pointer m_MessageFactory; + + private: + /** creates worker thread that continuously polls interface for new + messages */ + itk::MultiThreader::Pointer m_MultiThreader; + /** ID of polling thread */ + int m_ThreadID; + }; + + /** + * \brief connect to this Event to get noticed when a message was received + * + * \note Check if you can invoke this events like this or if you have to make + * it thread-safe. They are not invoked in the main thread!!! + * */ + itkEventMacro( MessageReceivedEvent , itk::AnyEvent ); + + /** + * \brief connect to this Event to get noticed when a command was received + * + * \note Check if you can invoke this events like this or if you have to make + * it thread-safe. They are not invoked in the main thread!!! + * */ + itkEventMacro( CommandReceivedEvent , itk::AnyEvent ); + + /** + * \brief connect to this Event to get noticed when another igtl device + * connects with this device. + * + * \note Check if you can invoke this events like this or if you have to make + * it thread-safe. They are not invoked in the main thread!!! + * */ + itkEventMacro( NewClientConnectionEvent , itk::AnyEvent ); + + /** + * \brief connect to this Event to get noticed when this device looses the + * connection to a socket. + * + * \note Check if you can invoke this events like this or if you have to make + * it thread-safe. They are not invoked in the main thread!!! + * */ + itkEventMacro( LostConnectionEvent , itk::AnyEvent ); + +} // namespace mitk + +#endif /* MITKIGTLDEVICE_H */ diff --git a/Modules/OpenIGTLink/mitkIGTLDeviceSource.cpp b/Modules/OpenIGTLink/mitkIGTLDeviceSource.cpp new file mode 100644 index 0000000000..42426e24df --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDeviceSource.cpp @@ -0,0 +1,291 @@ +/*=================================================================== + +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 "mitkIGTLDeviceSource.h" + +#include "mitkIGTLDevice.h" +#include "mitkIGTLMessage.h" + +//#include "mitkIGTTimeStamp.h" +//#include "mitkIGTException.h" + +//Microservices +#include +#include +#include +#include + +//itk +#include + + +const std::string mitk::IGTLDeviceSource::US_PROPKEY_IGTLDEVICENAME = + mitk::IGTLMessageSource::US_INTERFACE_NAME + ".igtldevicename"; + +mitk::IGTLDeviceSource::IGTLDeviceSource() + : mitk::IGTLMessageSource(), m_IGTLDevice(NULL) +{ + this->SetName("IGTLDeviceSource (no defined type)"); +} + +mitk::IGTLDeviceSource::~IGTLDeviceSource() +{ + if (m_IGTLDevice.IsNotNull()) + { + if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Running) + { + this->StopCommunication(); + } + if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Ready) + { + this->Disconnect(); + } + m_IGTLDevice = NULL; + } +} + +void mitk::IGTLDeviceSource::GenerateData() +{ + if (m_IGTLDevice.IsNull()) + return; + + /* update output with message from the device */ + IGTLMessage* msgOut = this->GetOutput(); + assert(msgOut); + igtl::MessageBase::Pointer msgIn = m_IGTLDevice->GetNextMessage(); + if ( msgIn.IsNotNull() ) + { + assert(msgIn); + + msgOut->SetMessage(msgIn); + msgOut->SetName(msgIn->GetDeviceName()); + } +// else +// { +// MITK_ERROR("IGTLDeviceSource") << "Could not get the latest message."; +// } +} + +void mitk::IGTLDeviceSource::SetIGTLDevice( mitk::IGTLDevice* igtlDevice ) +{ + MITK_DEBUG << "Setting IGTLDevice to " << igtlDevice; + if (this->m_IGTLDevice.GetPointer() != igtlDevice) + { + this->m_IGTLDevice = igtlDevice; + this->CreateOutputs(); + std::stringstream name; // create a human readable name for the source + name << "OIGTL Device Source ( " << igtlDevice->GetName() << " )"; + this->SetName(name.str()); + + //setup a observer that listens to new messages and new commands + typedef itk::SimpleMemberCommand CurCommandType; + CurCommandType::Pointer msgReceivedCommand = CurCommandType::New(); + msgReceivedCommand->SetCallbackFunction( + this, &IGTLDeviceSource::OnIncomingMessage ); + this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), + msgReceivedCommand); + CurCommandType::Pointer cmdReceivedCommand = CurCommandType::New(); + cmdReceivedCommand->SetCallbackFunction( + this, &IGTLDeviceSource::OnIncomingCommand ); + this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), + cmdReceivedCommand); + + } +} + +void mitk::IGTLDeviceSource::CreateOutputs() +{ + //if outputs are set then delete them + if (this->GetNumberOfOutputs() > 0) + { + for (int numOP = this->GetNumberOfOutputs() - 1; numOP >= 0; numOP--) + this->RemoveOutput(numOP); + this->Modified(); + } + + //fill the outputs if a valid OpenIGTLink device is set + if (m_IGTLDevice.IsNull()) + return; + + this->SetNumberOfIndexedOutputs(1); + if (this->GetOutput(0) == NULL) + { + DataObjectPointer newOutput = this->MakeOutput(0); + this->SetNthOutput(0, newOutput); + this->Modified(); + } +} + +void mitk::IGTLDeviceSource::Connect() +{ + if (m_IGTLDevice.IsNull()) + { + throw std::invalid_argument("mitk::IGTLDeviceSource: " + "No OpenIGTLink device set"); + } + if (this->IsConnected()) + { + return; + } + try + { + m_IGTLDevice->OpenConnection(); + } + catch (mitk::Exception &e) + { + throw std::runtime_error(std::string("mitk::IGTLDeviceSource: Could not open" + "connection to OpenIGTLink device. Error: ") + e.GetDescription()); + } +} + +void mitk::IGTLDeviceSource::StartCommunication() +{ + if (m_IGTLDevice.IsNull()) + throw std::invalid_argument("mitk::IGTLDeviceSource: " + "No OpenIGTLink device set"); + if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Running) + return; + if (m_IGTLDevice->StartCommunication() == false) + throw std::runtime_error("mitk::IGTLDeviceSource: " + "Could not start communication"); +} + +void mitk::IGTLDeviceSource::Disconnect() +{ + if (m_IGTLDevice.IsNull()) + throw std::invalid_argument("mitk::IGTLDeviceSource: " + "No OpenIGTLink device set"); + if (m_IGTLDevice->CloseConnection() == false) + throw std::runtime_error("mitk::IGTLDeviceSource: Could not close connection" + " to OpenIGTLink device"); +} + +void mitk::IGTLDeviceSource::StopCommunication() +{ + if (m_IGTLDevice.IsNull()) + throw std::invalid_argument("mitk::IGTLDeviceSource: " + "No OpenIGTLink device set"); + if (m_IGTLDevice->StopCommunication() == false) + throw std::runtime_error("mitk::IGTLDeviceSource: " + "Could not stop communicating"); +} + +void mitk::IGTLDeviceSource::UpdateOutputInformation() +{ + this->Modified(); // make sure that we need to be updated + Superclass::UpdateOutputInformation(); +} + +void mitk::IGTLDeviceSource::SetInput( unsigned int idx, const IGTLMessage* msg ) +{ + if ( msg == NULL ) // if an input is set to NULL, remove it + { + this->RemoveInput(idx); + } + else + { + // ProcessObject is not const-correct so a const_cast is required here + this->ProcessObject::SetNthInput(idx, const_cast(msg)); + } +// this->CreateOutputsForAllInputs(); +} + +bool mitk::IGTLDeviceSource::IsConnected() +{ + if (m_IGTLDevice.IsNull()) + return false; + + return (m_IGTLDevice->GetState() == mitk::IGTLDevice::Ready) || + (m_IGTLDevice->GetState() == mitk::IGTLDevice::Running); +} + +bool mitk::IGTLDeviceSource::IsCommunicating() +{ + if (m_IGTLDevice.IsNull()) + return false; + + return m_IGTLDevice->GetState() == mitk::IGTLDevice::Running; +} + +void mitk::IGTLDeviceSource::RegisterAsMicroservice() +{ + // Get Context + us::ModuleContext* context = us::GetModuleContext(); + + // Define ServiceProps + us::ServiceProperties props; + mitk::UIDGenerator uidGen = + mitk::UIDGenerator ("org.mitk.services.IGTLDeviceSource.id_", 16); + props[ US_PROPKEY_ID ] = uidGen.GetUID(); + props[ US_PROPKEY_DEVICENAME ] = this->GetName(); + props[ US_PROPKEY_IGTLDEVICENAME ] = m_Name; + props[ US_PROPKEY_DEVICETYPE ] = m_Type; + m_ServiceRegistration = context->RegisterService(this, props); +} + + +void mitk::IGTLDeviceSource::OnIncomingMessage() +{ + +} + +void mitk::IGTLDeviceSource::OnIncomingCommand() +{ + +} + +const mitk::IGTLMessage* mitk::IGTLDeviceSource::GetInput( void ) const +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + + return static_cast(this->ProcessObject::GetInput(0)); +} + + +const mitk::IGTLMessage* +mitk::IGTLDeviceSource::GetInput( unsigned int idx ) const +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + + return static_cast(this->ProcessObject::GetInput(idx)); +} + + +const mitk::IGTLMessage* +mitk::IGTLDeviceSource::GetInput(std::string msgName) const +{ + const DataObjectPointerArray& inputs = const_cast(this)->GetInputs(); + for (DataObjectPointerArray::const_iterator it = inputs.begin(); + it != inputs.end(); ++it) + if (std::string(msgName) == + (static_cast(it->GetPointer()))->GetName()) + return static_cast(it->GetPointer()); + return NULL; +} + + +itk::ProcessObject::DataObjectPointerArraySizeType +mitk::IGTLDeviceSource::GetInputIndex( std::string msgName ) +{ + DataObjectPointerArray outputs = this->GetInputs(); + for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i) + if (msgName == + (static_cast(outputs.at(i).GetPointer()))->GetName()) + return i; + throw std::invalid_argument("output name does not exist"); +} diff --git a/Modules/OpenIGTLink/mitkIGTLDeviceSource.h b/Modules/OpenIGTLink/mitkIGTLDeviceSource.h new file mode 100644 index 0000000000..4a04ba3392 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDeviceSource.h @@ -0,0 +1,194 @@ +/*=================================================================== + +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 IGTLDEVICESOURCE_H_HEADER_INCLUDED_ +#define IGTLDEVICESOURCE_H_HEADER_INCLUDED_ + +#include "mitkIGTLDevice.h" +#include "mitkIGTLMessageSource.h" + +namespace mitk { + /** + * \brief Connects a mitk::IGTLDevice to a + * MITK-OpenIGTLink-Message-Filter-Pipeline + * + * This class is the source of most OpenIGTLink pipelines. It encapsulates a + * mitk::IGTLDevice and provides the information/messages of the connected + * OpenIGTLink devices as igtl::MessageBase objects. Note, that there is just + * one single output. + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLDeviceSource : public IGTLMessageSource + { + public: + mitkClassMacro(IGTLDeviceSource, IGTLMessageSource); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** + *\brief These Constants are used in conjunction with Microservices + */ + static const std::string US_PROPKEY_IGTLDEVICENAME; + + /** + * \brief sets the OpenIGTLink device that will be used as a data source + */ + virtual void SetIGTLDevice(mitk::IGTLDevice* td); + + /** + * \brief returns the OpenIGTLink device that is used by this filter + */ + itkGetObjectMacro(IGTLDevice, mitk::IGTLDevice); + + /** + *\brief Registers this object as a Microservice, making it available to every + * module and/or plugin. To unregister, call UnregisterMicroservice(). + */ + virtual void RegisterAsMicroservice(); + + /** + * \brief Establishes a connection to the OpenIGTLink device. If there is + * already a connection the method does nothing. + * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink + * device was set with SetIGTLDevice(). Will throw a std::runtime_error if + * the OpenIGTLink device returns an error. + */ + void Connect(); + + /** + * \brief Closes the connection to the OpenIGTLink device + * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink + * device was set with SetIGTLDevice(). Will throw a std::runtime_error if + * the OpenIGTLink device returns an error. + */ + void Disconnect(); + + /** + * \brief starts the communication of the device. + * This needs to be called before Update() or GetOutput()->Update(). If the + * device is already communicating the method does nothing. + * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink + * device was set with SetIGTLDevice(). Will throw a std::runtime_error if + * the OpenIGTLink device returns an error. + */ + void StartCommunication(); + + /** + * \brief stops the communication of the device. + * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink + * device was set with SetIGTLDevice(). Will throw a std::runtime_error if + * the OpenIGTLink device returns an error. + */ + void StopCommunication(); + + /** + * \brief returns true if a connection to the OpenIGTLink device is established + * + */ + virtual bool IsConnected(); + + /** + * \brief returns true if communication is in progress + * + */ + virtual bool IsCommunicating(); + + /** + * \brief Used for pipeline update + */ + virtual void UpdateOutputInformation(); + + protected: + IGTLDeviceSource(); + virtual ~IGTLDeviceSource(); + + /** + * \brief filter execute method + * + * queries the OpenIGTLink device for new messages and updates its output + * igtl::MessageBase objects with it. + * \warning Will raise a std::out_of_range exception, if tools were added to + * the OpenIGTLink device after it was set as input for this filter + */ + virtual void GenerateData(); + + /** + * \brief Create the necessary outputs for the m_IGTLDevice + * + * This Method is called internally whenever outputs need to be reset. Old + * Outputs are deleted when called. + **/ + void CreateOutputs(); + + /** + * \brief This method is called when the IGTL device hold by this class + * receives a new message + **/ + virtual void OnIncomingMessage(); + + /** + * \brief This method is called when the IGTL device hold by this class + * receives a new command + **/ + virtual void OnIncomingCommand(); + + + using Superclass::SetInput; + + /** + * \brief Set input with id idx of this filter + * + */ + virtual void SetInput( unsigned int idx, const IGTLMessage* msg ); + + /** + * \brief Get the input of this filter + */ + const IGTLMessage* GetInput(void) const; + + /** + * \brief Get the input with id idx of this filter + */ + const IGTLMessage* GetInput(unsigned int idx) const; + + /** + * \brief Get the input with name messageName of this filter + */ + const IGTLMessage* GetInput(std::string msgName) const; + + /** + *\brief return the index of the input with name msgName, throw + * std::invalid_argument exception if that name was not found + * + * \warning if a subclass has inputs that have different data type than + * mitk::IGTLMessage, they have to overwrite this method + */ + DataObjectPointerArraySizeType GetInputIndex(std::string msgName); + + /** + *\brief return the index of the output with name msgName, -1 if no output + * with that name was found + * + * \warning if a subclass has outputs that have different data type than + * mitk::IGTLMessage, they have to overwrite this method + */ + DataObjectPointerArraySizeType GetOutputIndex(std::string msgName); + + /** the OpenIGTLink device that is used as a source for this filter object*/ + mitk::IGTLDevice::Pointer m_IGTLDevice; + }; +} // namespace mitk +#endif /* MITKIGTLDeviceSource_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLDeviceSourceTest.cpp b/Modules/OpenIGTLink/mitkIGTLDeviceSourceTest.cpp new file mode 100644 index 0000000000..5a22ebcc7b --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDeviceSourceTest.cpp @@ -0,0 +1,137 @@ +/*=================================================================== + +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 "mitkVirtualTrackingDevice.h" + +#include "mitkTestingMacros.h" +#include +#include "itksys/SystemTools.hxx" + +/**Documentation + * test for the class "NavigationDataSource". + */ +int mitkTrackingDeviceSourceTest(int /* argc */, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("TrackingDeviceSource"); + + // let's create an object of our class + mitk::TrackingDeviceSource::Pointer mySource = mitk::TrackingDeviceSource::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(mySource.IsNotNull(), "Testing instantiation"); + + mySource->SetTrackingDevice(NULL); + MITK_TEST_CONDITION(mySource->GetTrackingDevice() == NULL, "Testing Set/GetTrackingDevice(NULL)"); + MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 0, "Testing GetNumberOfOutputs with NULL td"); + MITK_TEST_FOR_EXCEPTION(std::invalid_argument, mySource->Connect()); + MITK_TEST_FOR_EXCEPTION(std::invalid_argument, mySource->StartTracking()); + + mitk::VirtualTrackingDevice::Pointer tracker = mitk::VirtualTrackingDevice::New(); + tracker->SetRefreshRate(10); + + + mySource->SetTrackingDevice(tracker); + MITK_TEST_CONDITION(mySource->GetTrackingDevice() == tracker.GetPointer(), "Testing Set/GetTrackingDevice(tracker)"); + MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 0, "Testing GetNumberOfOutputs with no tool tracker"); + tracker = mitk::VirtualTrackingDevice::New(); + mitk::ReferenceCountWatcher::Pointer watch = new mitk::ReferenceCountWatcher(tracker); + + tracker->AddTool("T0"); + tracker->AddTool("T1"); + mySource->SetTrackingDevice(tracker); + MITK_TEST_CONDITION(mySource->GetTrackingDevice() == tracker.GetPointer(), "Testing Set/GetTrackingDevice(tracker2)"); + MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 2, "Testing GetNumberOfOutputs with 2 tools tracker"); + MITK_TEST_CONDITION(mySource->IsConnected() == false, "Testing IsConnected()"); + mySource->Connect(); + MITK_TEST_CONDITION(mySource->IsConnected() == true, "Testing Connect()/IsConnected()"); + MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Ready, "Testing Connect()/IsConnected() 2"); + mySource->Disconnect(); + MITK_TEST_CONDITION(mySource->IsConnected() == false, "Testing Disconnect()/IsConnected()"); + MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Setup, "Testing Disconnect()/IsConnected() 2"); + + mySource->Connect(); + mySource->StartTracking(); + MITK_TEST_CONDITION(mySource->IsConnected() == true, "Testing StartTracking()/IsConnected()"); + MITK_TEST_CONDITION(mySource->IsTracking() == true, "Testing StartTracking()/IsTracking()"); + MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Tracking, "Testing StartTracking()/IsTracking() 2"); + + unsigned long modTime = mySource->GetMTime(); + mySource->UpdateOutputInformation(); + MITK_TEST_CONDITION(mySource->GetMTime() != modTime, "Testing if UpdateOutputInformation() modifies the object"); + + //test getOutput() + mitk::NavigationData* nd0 = mySource->GetOutput(); + MITK_TEST_CONDITION_REQUIRED(nd0!=NULL,"Testing GetOutput() [1]"); + nd0 = mySource->GetOutput(nd0->GetName()); + MITK_TEST_CONDITION_REQUIRED(nd0!=NULL,"Testing GetOutput() [2]"); + + //test getOutputIndex() + MITK_TEST_CONDITION(mySource->GetOutputIndex(nd0->GetName())==0,"Testing GetOutputIndex()"); + + //test GraftNthOutput() + mitk::NavigationData::Pointer ndCopy = mitk::NavigationData::New(); + mySource->GraftNthOutput(1,nd0); + ndCopy = mySource->GetOutput(1); + MITK_TEST_CONDITION(std::string(ndCopy->GetName())==std::string(nd0->GetName()),"Testing GraftNthOutput()"); + + //test GetParameters() + mitk::PropertyList::ConstPointer p = mySource->GetParameters(); + MITK_TEST_CONDITION(p.IsNotNull(),"Testing GetParameters()"); + + nd0->Update(); + mitk::NavigationData::PositionType pos = nd0->GetPosition(); + unsigned long tmpMTime0 = nd0->GetMTime(); + itksys::SystemTools::Delay(500); // allow the tracking thread to advance the tool position + nd0->Update(); + mitk::NavigationData::PositionType newPos = nd0->GetPosition(); + if(nd0->GetMTime() == tmpMTime0) //tool not modified yet + { + MITK_TEST_CONDITION(mitk::Equal(newPos, pos) == true, "Testing if output changes on each update"); + } + else + { + MITK_TEST_CONDITION(mitk::Equal(newPos, pos) == false, "Testing if output changes on each update"); + } + + mySource->StopTracking(); + mySource->Disconnect(); + + tracker = mitk::VirtualTrackingDevice::New(); + mySource->SetTrackingDevice(tracker); + MITK_TEST_CONDITION(watch->GetReferenceCount() == 0, "Testing if reference to previous tracker object is released"); + watch = NULL; + + MITK_TEST_FOR_EXCEPTION(std::runtime_error, mySource->StartTracking()); // new tracker, needs Connect() before StartTracking() + + mySource->Connect(); + mySource->StartTracking(); + // itksys::SystemTools::Delay(800); // wait for tracking thread to start properly //DEBUG ONLY --> race condition. will the thread start before the object is destroyed? --> maybe hold a smartpointer? + try + { + mySource = NULL; // delete source + tracker = NULL; // delete tracker --> both should not result in any exceptions or deadlocks + } + catch (...) + { + MITK_TEST_FAILED_MSG(<< "exception during destruction of source or tracker!"); + } + + // always end with this! + MITK_TEST_END(); +} diff --git a/Modules/OpenIGTLink/mitkIGTLDummyMessage.cpp b/Modules/OpenIGTLink/mitkIGTLDummyMessage.cpp new file mode 100644 index 0000000000..753f5336b8 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDummyMessage.cpp @@ -0,0 +1,66 @@ +/*=================================================================== + +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 "mitkIGTLDummyMessage.h" + +#include "igtlutil/igtl_header.h" +#include "igtlutil/igtl_util.h" + + +mitk::IGTLDummyMessage::IGTLDummyMessage() : StringMessage() +{ + this->m_DefaultBodyType = "DUMMY"; +} + +mitk::IGTLDummyMessage::~IGTLDummyMessage() +{ +} + +void mitk::IGTLDummyMessage::SetDummyString( const std::string& dummyString ) +{ + this->m_dummyString = dummyString; + this->m_String = "This is a dummy string"; +} + +std::string mitk::IGTLDummyMessage::GetDummyString() +{ + return this->m_dummyString; +} + +igtl::MessageBase::Pointer mitk::IGTLDummyMessage::Clone() +{ + //initialize the clone + mitk::IGTLDummyMessage::Pointer clone = mitk::IGTLDummyMessage::New(); + + //copy the data + clone->SetString(this->GetString()); + clone->SetDummyString(this->GetDummyString()); + + return igtl::MessageBase::Pointer(clone.GetPointer()); +} + +/** + * \brief Clones the original message interpreted as transform message + * \param original_ The original message that will be interpreted as transform + * message + * \return The clone of the input message + */ +igtl::MessageBase::Pointer mitk::DummyMsgCloneHandler::Clone(igtl::MessageBase* original_) +{ + mitk::IGTLDummyMessage* original = (mitk::IGTLDummyMessage*)original_; + return original->Clone(); +} diff --git a/Modules/OpenIGTLink/mitkIGTLDummyMessage.h b/Modules/OpenIGTLink/mitkIGTLDummyMessage.h new file mode 100644 index 0000000000..d559bdca68 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDummyMessage.h @@ -0,0 +1,74 @@ +/*=================================================================== + +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 MITKIGTLDUMMYMESSAGE_H +#define MITKIGTLDUMMYMESSAGE_H + +#include "MitkOpenIGTLinkExports.h" + +#include "igtlObject.h" +#include "igtlStringMessage.h" +#include "mitkIGTLMessageCloneHandler.h" + +namespace mitk +{ + +/** Documentation +* \class IGTLDummyMessage +* \brief This class is a dummy message to show the how to implement a new message +* type +*/ +class MITK_OPENIGTLINK_EXPORT IGTLDummyMessage: public igtl::StringMessage +{ +public: + typedef IGTLDummyMessage Self; + typedef StringMessage Superclass; + typedef igtl::SmartPointer Pointer; + typedef igtl::SmartPointer ConstPointer; + + igtlTypeMacro( mitk::IGTLDummyMessage, igtl::StringMessage ); + igtlNewMacro( mitk::IGTLDummyMessage ); + +public: + /** + * Set dummy string + */ + void SetDummyString( const std::string& dummyString ); + + /** + * Get dummy string + */ + std::string GetDummyString(); + + /** + * Returns a clone of itself + */ + igtl::MessageBase::Pointer Clone(); + +protected: + IGTLDummyMessage(); + ~IGTLDummyMessage(); + + std::string m_dummyString; +}; + + +mitkIGTMessageCloneClassMacro(IGTLDummyMessage, DummyMsgCloneHandler); + + +} // namespace mitk + +#endif diff --git a/Modules/OpenIGTLink/mitkIGTLMessage.cpp b/Modules/OpenIGTLink/mitkIGTLMessage.cpp new file mode 100644 index 0000000000..e6b8034019 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessage.cpp @@ -0,0 +1,170 @@ +/*=================================================================== + +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 "mitkIGTLMessage.h" +#include "mitkException.h" +#include "mitkIGTLMessageCommon.h" + +mitk::IGTLMessage::IGTLMessage() : itk::DataObject(), +m_DataValid(false), m_IGTTimeStamp(0.0), m_Name() +{ + m_Message = igtl::MessageBase::New(); +} + + +mitk::IGTLMessage::IGTLMessage(const mitk::IGTLMessage& toCopy) : + itk::DataObject() +{ + // TODO SW: Graft does the same, remove code duplications, set Graft to + // deprecated, remove duplication in tescode + this->Graft(&toCopy); +} + +mitk::IGTLMessage::~IGTLMessage() +{ +} + +mitk::IGTLMessage::IGTLMessage(igtl::MessageBase::Pointer message, + std::string name) +{ + this->SetMessage(message); + this->SetName(name); +} + +void mitk::IGTLMessage::Graft( const DataObject *data ) +{ + // Attempt to cast data to an IGTLMessage + const Self* nd; + try + { + nd = dynamic_cast( data ); + } + catch( ... ) + { + itkExceptionMacro( << "mitk::IGTLMessage::Graft cannot cast " + << typeid(data).name() << " to " + << typeid(const Self *).name() ); + return; + } + if (!nd) + { + // pointer could not be cast back down + itkExceptionMacro( << "mitk::IGTLMessage::Graft cannot cast " + << typeid(data).name() << " to " + << typeid(const Self *).name() ); + return; + } + // Now copy anything that is needed + this->SetMessage(nd->GetMessage()); + this->SetDataValid(nd->IsDataValid()); + this->SetIGTTimeStamp(nd->GetIGTTimeStamp()); + this->SetName(nd->GetName()); +} + +void mitk::IGTLMessage::SetMessage(igtl::MessageBase::Pointer msg) +{ + m_Message = msg; + unsigned int ts = 0; + unsigned int frac = 0; + m_Message->GetTimeStamp(&ts, &frac); + this->SetIGTTimeStamp((double)ts); + this->SetDataValid(true); +} + +bool mitk::IGTLMessage::IsDataValid() const +{ + return m_DataValid; +} + + +void mitk::IGTLMessage::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + this->Superclass::PrintSelf(os, indent); + os << indent << "name: " << this->GetName() << std::endl; + os << indent << "data valid: " << this->IsDataValid() << std::endl; + os << indent << "TimeStamp: " << this->GetIGTTimeStamp() << std::endl; + os << indent << "OpenIGTLinkMessage: " << std::endl; + m_Message->Print(os); +} + + +void mitk::IGTLMessage::CopyInformation( const DataObject* data ) +{ + this->Superclass::CopyInformation( data ); + + const Self * nd = NULL; + try + { + nd = dynamic_cast(data); + } + catch( ... ) + { + // data could not be cast back down + itkExceptionMacro(<< "mitk::IGTLMessage::CopyInformation() cannot cast " + << typeid(data).name() << " to " + << typeid(Self*).name() ); + } + if ( !nd ) + { + // pointer could not be cast back down + itkExceptionMacro(<< "mitk::IGTLMessage::CopyInformation() cannot cast " + << typeid(data).name() << " to " + << typeid(Self*).name() ); + } + /* copy all meta data */ +} + +bool mitk::Equal(const mitk::IGTLMessage& leftHandSide, + const mitk::IGTLMessage& rightHandSide, + ScalarType /*eps*/, bool verbose) +{ + bool returnValue = true; + + if( std::string(rightHandSide.GetName()) != std::string(leftHandSide.GetName()) ) + { + if(verbose) + { + MITK_INFO << "[( IGTLMessage )] Name differs."; + MITK_INFO << "leftHandSide is " << leftHandSide.GetName() + << "rightHandSide is " << rightHandSide.GetName(); + } + returnValue = false; + } + + if( rightHandSide.GetIGTTimeStamp() != leftHandSide.GetIGTTimeStamp() ) + { + if(verbose) + { + MITK_INFO << "[( IGTLMessage )] IGTTimeStamp differs."; + MITK_INFO << "leftHandSide is " << leftHandSide.GetIGTTimeStamp() + << "rightHandSide is " << rightHandSide.GetIGTTimeStamp(); + } + returnValue = false; + } + + return returnValue; +} + +const char* mitk::IGTLMessage::GetIGTLMessageType() const +{ + return this->m_Message->GetDeviceType(); +} + +template < typename IGTLMessageType > +IGTLMessageType* mitk::IGTLMessage::GetMessage() const +{ + return dynamic_cast(this->m_Message); +} diff --git a/Modules/OpenIGTLink/mitkIGTLMessage.h b/Modules/OpenIGTLink/mitkIGTLMessage.h new file mode 100644 index 0000000000..7e47dab70b --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessage.h @@ -0,0 +1,197 @@ +/*=================================================================== + +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 MITKIGTLMESSAGEH_HEADER_INCLUDED_ +#define MITKIGTLMESSAGEH_HEADER_INCLUDED_ + +#include +#include "MitkOpenIGTLinkExports.h" +#include +#include + +#include "igtlMessageBase.h" + +namespace mitk { + + /**Documentation + * \brief A wrapper for the OpenIGTLink message type + * + * This class represents the data object that is passed through the + * MITK-OpenIGTLink filter pipeline. It wraps the OpenIGTLink message type. + * Additionally, it contains a data structure that contains error/plausibility + * information. + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLMessage : public itk::DataObject + { + public: + mitkClassMacro(IGTLMessage, itk::DataObject); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + mitkNewMacro2Param(Self, igtl::MessageBase::Pointer,std::string); + + /** + * \brief type that holds the time at which the data was recorded + */ + typedef double TimeStampType; + + /** + * \brief Sets the OpenIGTLink message + */ + void SetMessage(igtl::MessageBase::Pointer msg); + /** + * \brief returns the OpenIGTLink message + */ + itkGetConstMacro(Message, igtl::MessageBase::Pointer); + /** + * \brief returns true if the object contains valid data + */ + virtual bool IsDataValid() const; + /** + * \brief sets the dataValid flag of the IGTLMessage object indicating if + * the object contains valid data + */ + itkSetMacro(DataValid, bool); + /** + * \brief gets the IGT timestamp of the IGTLMessage object + */ + itkGetConstMacro(IGTTimeStamp, TimeStampType); + /** + * \brief set the name of the IGTLMessage object + */ + itkSetStringMacro(Name); + /** + * \brief returns the name of the IGTLMessage object + */ + itkGetStringMacro(Name); + + /** + * \brief Graft the data and information from one IGTLMessage to another. + * + * Copies the content of data into this object. + * This is a convenience method to setup a second IGTLMessage object with + * all the meta information of another IGTLMessage object. + * Note that this method is different than just using two + * SmartPointers to the same IGTLMessage object since separate DataObjects + * are still maintained. + */ + virtual void Graft(const DataObject *data); + + /** + * \brief copy meta data of a IGTLMessage object + * + * copies all meta data from IGTLMessage data to this object + */ + virtual void CopyInformation(const DataObject* data); + + /** + * \brief Prints the object information to the given stream os. + * \param os The stream which is used to print the output. + * \param indent Defines the indentation of the output. + */ + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + /** Compose with another IGTLMessage + * + * This method composes self with another IGTLMessage of the + * same dimension, modifying self to be the composition of self + * and other. If the argument pre is true, then other is + * precomposed with self; that is, the resulting transformation + * consists of first applying other to the source, followed by + * self. If pre is false or omitted, then other is post-composed + * with self; that is the resulting transformation consists of + * first applying self to the source, followed by other. */ + void Compose(const mitk::IGTLMessage::Pointer n, const bool pre = false); + + /** Returns the OpenIGTL Message type + **/ + const char* GetIGTLMessageType() const; + + template < typename IGTLMessageType > IGTLMessageType* GetMessage() const; + + protected: + mitkCloneMacro(Self); + + IGTLMessage(); + + /** + * Copy constructor internally used. + */ + IGTLMessage(const mitk::IGTLMessage& toCopy); + + /** + * Creates a IGTLMessage object from an igtl::MessageBase and a given name. + */ + IGTLMessage(igtl::MessageBase::Pointer message, std::string name = ""); + + virtual ~IGTLMessage(); + + /** + * \brief holds the actual OpenIGTLink message + */ + igtl::MessageBase::Pointer m_Message; + + /** + * \brief defines if the object contains valid values + */ + bool m_DataValid; + /** + * \brief contains the time at which the tracking data was recorded + */ + TimeStampType m_IGTTimeStamp; + /** + * \brief name of the navigation data + */ + std::string m_Name; + + private: + + // pre = false + static mitk::IGTLMessage::Pointer getComposition( + const mitk::IGTLMessage::Pointer nd1, + const mitk::IGTLMessage::Pointer nd2); + + /** + * \brief sets the IGT timestamp of the IGTLMessage object + */ + itkSetMacro(IGTTimeStamp, TimeStampType); + + }; + + /** + * @brief Equal A function comparing two OpenIGTLink message objects for + * being equal in meta- and imagedata + * + * @ingroup MITKTestingAPI + * + * Following aspects are tested for equality: + * - TBD + * + * @param rightHandSide An IGTLMessage to be compared + * @param leftHandSide An IGTLMessage to be compared + * @param eps Tolarence for comparison. You can use mitk::eps in most cases. + * @param verbose Flag indicating if the user wants detailed console output + * or not. + * @return true, if all subsequent comparisons are true, false otherwise + */ + MITK_OPENIGTLINK_EXPORT bool Equal( const mitk::IGTLMessage& leftHandSide, + const mitk::IGTLMessage& rightHandSide, + ScalarType eps = mitk::eps, + bool verbose = false ); + +} // namespace mitk +#endif /* MITKIGTLMESSAGEH_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageCloneHandler.h b/Modules/OpenIGTLink/mitkIGTLMessageCloneHandler.h new file mode 100644 index 0000000000..80432ee542 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageCloneHandler.h @@ -0,0 +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 MITKIGTLMESSAGECLONE_H_ +#define MITKIGTLMESSAGECLONE_H_ + +#include "itkObject.h" +#include "mitkCommon.h" + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlSocket.h" +#include "igtlMessageBase.h" + +#include "MitkOpenIGTLinkExports.h" + +namespace mitk +{ + /**Documentation + * \brief Base class for clone handlers for igtl::MessageBase derived message + * types + * + * To enable new message types a clone function must be defined and added to the + * message factory. + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLMessageCloneHandler: public itk::Object + { + public: + mitkClassMacro(IGTLMessageCloneHandler, itk::Object); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + public: + virtual igtl::MessageBase::Pointer Clone(igtl::MessageBase*) { return 0; } + + protected: + IGTLMessageCloneHandler() {} + ~IGTLMessageCloneHandler() {} +}; + +/** + * Description: + * The mitkIGTMessageCloneClassMacro() macro is to help developers to + * define message clone handler classes. It generates a chlid class of + * mitk::IGTLMessageCloneHandler. + * The developer only needs to implement Clone() after calling this macro. + * The following code shows how to define a handler that processes IMAGE message: + * + * mitkIGTMessageCloneClassMacro(igtl::ImageMessage, TestImageMessageHandler); + * igtl::MessageBase::Pointer + * TestImageMessageHandler::Clone(igtl::MessageBase * message) + * { + * // do something + * } + **/ +#define mitkIGTMessageCloneClassMacro(messagetype, classname) \ + class classname : public ::mitk::IGTLMessageCloneHandler \ + { \ + public: \ + mitkClassMacro(classname, mitk::IGTLMessageCloneHandler); \ + itkFactorylessNewMacro(Self); \ + itkCloneMacro(Self); \ + public: \ + virtual igtl::MessageBase::Pointer Clone(igtl::MessageBase*); \ + protected: \ + classname(){} \ + ~classname() {} \ + }; + + +} // namespace mitk + +#endif // MITKIGTLMESSAGECLONE_H_ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageCommon.cpp b/Modules/OpenIGTLink/mitkIGTLMessageCommon.cpp new file mode 100644 index 0000000000..238da87839 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageCommon.cpp @@ -0,0 +1,92 @@ +/*=================================================================== + +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 "mitkIGTLMessageCommon.h" +#include "mitkException.h" + +mitk::IGTLMessageCommon::IGTLMessageCommon() : itk::DataObject() +{ +} + + +mitk::IGTLMessageCommon::~IGTLMessageCommon() +{ +} + +//bool mitk::IGTLMessageCommon::Clone(igtl::TransformMessage::Pointer clone, +// igtl::TransformMessage::Pointer original) +//{ +// bool copySuccess = false; + +// //copy all meta data +// copySuccess = clone->Copy(original); + +// if ( !copySuccess ) +// return false; + +// //copy all data that is important for this class +// //copy the matrix +// igtl::Matrix4x4 mat; +// original->GetMatrix(mat); +// clone->SetMatrix(mat); + +// //copy the normals +// float normals[3][3]; +// original->GetNormals(normals); +// clone->SetNormals(normals); + +// //copy the position +// float position[3]; +// original->GetPosition(position); +// clone->SetPosition(position); + +// return true; +//} + +//igtl::MessageBase::Pointer mitk::IGTLMessageCommon::Clone(igtl::TransformMessage::Pointer original) +//{ +// bool copySuccess = false; +// igtl::TransformMessage::Pointer clone_ = igtl::TransformMessage::New(); + +// //initialize the clone +//// clone = igtl::MessageBase::New(); + +// //copy all meta data +// copySuccess = clone_->Copy(original); + +// if ( !copySuccess ) +// return false; + +// //copy all data that is important for this class +// //copy the matrix +// igtl::Matrix4x4 mat; +// original->GetMatrix(mat); +// clone_->SetMatrix(mat); + +// //copy the normals +// float normals[3][3]; +// original->GetNormals(normals); +// clone_->SetNormals(normals); + +// //copy the position +// float position[3]; +// original->GetPosition(position); +// clone_->SetPosition(position); + +// return igtl::MessageBase::Pointer(clone_.GetPointer()); + +//// return true; +//} diff --git a/Modules/OpenIGTLink/mitkIGTLMessageCommon.h b/Modules/OpenIGTLink/mitkIGTLMessageCommon.h new file mode 100644 index 0000000000..baec32a263 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageCommon.h @@ -0,0 +1,73 @@ +/*=================================================================== + +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 MITKIGTLMESSAGECOMMONH_HEADER_INCLUDED_ +#define MITKIGTLMESSAGECOMMONH_HEADER_INCLUDED_ + +#include +#include "MitkOpenIGTLinkExports.h" +#include +#include + +#include "igtlMessageBase.h" +#include "igtlTransformMessage.h" + +namespace mitk { + + /**Documentation + * \brief Helper class for copying OpenIGTLink messages. + * + * This class is a helper class for copying OpenIGTLink messages. + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLMessageCommon : public itk::DataObject + { + public: + mitkClassMacro(IGTLMessageCommon, itk::DataObject); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + /** + * \brief Clones the input message and returns a igtl::MessageBase::Pointer + * to the clone + */ +// static igtl::MessageBase::Pointer Clone(igtl::TransformMessage::Pointer original); + + /** + * \brief Clones the input message and returns a igtl::MessageBase::Pointer + * to the clone + */ +// static igtl::MessageBase::Pointer Clone(igtl::MessageBase::Pointer original); + + + protected: + IGTLMessageCommon(); + + /** + * Copy constructor internally used. + */ +// IGTLMessageCommon(const mitk::IGTLMessageCommon& toCopy); + + virtual ~IGTLMessageCommon(); + + private: + + }; + + +} // namespace mitk +#endif /* MITKIGTLMESSAGECOMMONH_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageFactory.cpp b/Modules/OpenIGTLink/mitkIGTLMessageFactory.cpp new file mode 100644 index 0000000000..6b7637df12 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageFactory.cpp @@ -0,0 +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 "mitkIGTLMessageFactory.h" + +// IGT message types +#include "igtlImageMessage.h" +#include "igtlTransformMessage.h" +#include "igtlPositionMessage.h" +#include "igtlStatusMessage.h" +#include "igtlImageMetaMessage.h" +#include "igtlPointMessage.h" +#include "igtlTrajectoryMessage.h" +#include "igtlStringMessage.h" +#include "igtlSensorMessage.h" +#include "igtlBindMessage.h" +#include "igtlPolyDataMessage.h" +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlCapabilityMessage.h" +#include "igtlNDArrayMessage.h" +#include "igtlTrackingDataMessage.h" +#include "igtlColorTableMessage.h" +#include "igtlLabelMetaMessage.h" + +//own types +#include "mitkIGTLDummyMessage.h" + +#include "mitkIGTLMessageCommon.h" + +#include "itksys/SystemTools.hxx" + + +//------------------------------------------------------------ +// Define message clone classes +// igtlMessageHandlerClassMacro() defines a child class of +// igtl::MessageHandler to handle OpenIGTLink messages for +// the message type specified as the first argument. The +// second argument will be used for the name of this +// message handler class, while the third argument specifies +// a type of data that will be shared with the message functions +// of this handler class. + +mitkIGTMessageCloneClassMacro(igtl::TransformMessage, TransformMsgCloneHandler); + +/** + * \brief Clones the original message interpreted as transform message + * \param original_ The original message that will be interpreted as transform + * message + * \return The clone of the input message + */ +igtl::MessageBase::Pointer TransformMsgCloneHandler::Clone(igtl::MessageBase* original_) +{ + bool copySuccess = false; + igtl::TransformMessage::Pointer clone_ = igtl::TransformMessage::New(); + + //initialize the clone + // clone = igtl::MessageBase::New(); + + igtl::TransformMessage* original = (igtl::TransformMessage*)original_; + + //copy all meta data + copySuccess = clone_->Copy(original); + + if ( !copySuccess ) + return NULL; + + //copy all data that is important for this class + //copy the matrix + igtl::Matrix4x4 mat; + original->GetMatrix(mat); + clone_->SetMatrix(mat); + + //copy the normals + float normals[3][3]; + original->GetNormals(normals); + clone_->SetNormals(normals); + + //copy the position + float position[3]; + original->GetPosition(position); + clone_->SetPosition(position); + + return igtl::MessageBase::Pointer(clone_.GetPointer()); +} + + +mitk::IGTLMessageFactory::IGTLMessageFactory() +{ + //create clone handlers +// mitk::IGTLMessageCloneHandler::Pointer tmch = ; + + this->AddMessageNewMethod("NONE", NULL); + + //OpenIGTLink Types V1 + this->AddMessageNewMethod("IMAGE", (PointerToMessageBaseNew)&igtl::ImageMessage::New); + this->AddMessageNewMethod("TRANSFORM", (PointerToMessageBaseNew)&igtl::TransformMessage::New); + this->AddMessageNewMethod("POSITION", (PointerToMessageBaseNew)&igtl::PositionMessage::New); + this->AddMessageNewMethod("STATUS", (PointerToMessageBaseNew)&igtl::StatusMessage::New); + this->AddMessageNewMethod("CAPABILITY", (PointerToMessageBaseNew)&igtl::StatusMessage::New); + + this->AddMessageNewMethod("GET_IMAGE", (PointerToMessageBaseNew)&igtl::GetImageMessage::New); + this->AddMessageNewMethod("GET_TRANS", (PointerToMessageBaseNew)&igtl::GetTransformMessage::New); +// this->AddMessageNewMethod("GET_POS", (PointerToMessageBaseNew)&igtl::GetPositionMessage::New); //not available??? + this->AddMessageNewMethod("GET_STATUS", (PointerToMessageBaseNew)&igtl::GetStatusMessage::New); + this->AddMessageNewMethod("GET_CAPABIL", (PointerToMessageBaseNew)&igtl::GetCapabilityMessage::New); + +// //OpenIGTLink Types V2 + this->AddMessageNewMethod("IMGMETA", (PointerToMessageBaseNew)&igtl::ImageMetaMessage::New); + this->AddMessageNewMethod("LBMETA", (PointerToMessageBaseNew)&igtl::LabelMetaMessage::New); + this->AddMessageNewMethod("COLORT", (PointerToMessageBaseNew)&igtl::ColorTableMessage::New); + this->AddMessageNewMethod("POINT", (PointerToMessageBaseNew)&igtl::PointMessage::New); + this->AddMessageNewMethod("TRAJ", (PointerToMessageBaseNew)&igtl::TrajectoryMessage::New); + this->AddMessageNewMethod("TDATA", (PointerToMessageBaseNew)&igtl::TrackingDataMessage::New); + this->AddMessageNewMethod("QTDATA", (PointerToMessageBaseNew)&igtl::QuaternionTrackingDataMessage::New); + this->AddMessageNewMethod("SENSOR", (PointerToMessageBaseNew)&igtl::SensorMessage::New); + this->AddMessageNewMethod("STRING", (PointerToMessageBaseNew)&igtl::StringMessage::New); + this->AddMessageNewMethod("NDARRAY", (PointerToMessageBaseNew)&igtl::NDArrayMessage::New); + this->AddMessageNewMethod("BIND", (PointerToMessageBaseNew)&igtl::BindMessage::New); + this->AddMessageNewMethod("POLYDATA", (PointerToMessageBaseNew)&igtl::PolyDataMessage::New); + + this->AddMessageNewMethod("GET_IMGMETA", (PointerToMessageBaseNew)&igtl::GetImageMetaMessage::New); + this->AddMessageNewMethod("GET_LBMETA", (PointerToMessageBaseNew)&igtl::GetLabelMetaMessage::New); + this->AddMessageNewMethod("GET_COLORT", (PointerToMessageBaseNew)&igtl::GetColorTableMessage::New); + this->AddMessageNewMethod("GET_POINT", (PointerToMessageBaseNew)&igtl::GetPointMessage::New); + this->AddMessageNewMethod("GET_TRAJ", (PointerToMessageBaseNew)&igtl::GetTrajectoryMessage::New); +// this->AddMessageNewMethod("GET_TDATA", (PointerToMessageBaseNew)&igtl::GetTrackingDataMessage::New); //not available??? +// this->AddMessageNewMethod("GET_QTDATA", (PointerToMessageBaseNew)&igtl::GetQuaternionTrackingDataMessage::New); +// this->AddMessageNewMethod("GET_SENSOR", (PointerToMessageBaseNew)&igtl::GetSensorMessage::New); +// this->AddMessageNewMethod("GET_STRING", (PointerToMessageBaseNew)&igtl::GetStringMessage::New); +// this->AddMessageNewMethod("GET_NDARRAY", (PointerToMessageBaseNew)&igtl::GetNDArrayMessage::New); + this->AddMessageNewMethod("GET_BIND", (PointerToMessageBaseNew)&igtl::GetBindMessage::New); + this->AddMessageNewMethod("GET_POLYDATA", (PointerToMessageBaseNew)&igtl::GetPolyDataMessage::New); + + this->AddMessageNewMethod("RTS_BIND", (PointerToMessageBaseNew)&igtl::RTSBindMessage::New); + this->AddMessageNewMethod("RTS_QTDATA", (PointerToMessageBaseNew)&igtl::RTSQuaternionTrackingDataMessage::New); + this->AddMessageNewMethod("RTS_TDATA", (PointerToMessageBaseNew)&igtl::RTSTrackingDataMessage::New); + //todo: check if there are more RTS messages + + this->AddMessageNewMethod("STT_BIND", (PointerToMessageBaseNew)&igtl::StartBindMessage::New); + this->AddMessageNewMethod("STT_TDATA", (PointerToMessageBaseNew)&igtl::StartTrackingDataMessage::New); + this->AddMessageNewMethod("STT_QTDATA", (PointerToMessageBaseNew)&igtl::StartQuaternionTrackingDataMessage::New); + //todo: check if there are more STT messages + + this->AddMessageNewMethod("STP_BIND", (PointerToMessageBaseNew)&igtl::StopBindMessage::New); + this->AddMessageNewMethod("STP_TDATA", (PointerToMessageBaseNew)&igtl::StopTrackingDataMessage::New); + this->AddMessageNewMethod("STP_QTDATA", (PointerToMessageBaseNew)&igtl::StopQuaternionTrackingDataMessage::New); + //todo: check if there are more STP messages + + //Own Types + this->AddMessageNewMethod("DUMMY", (PointerToMessageBaseNew)&mitk::IGTLDummyMessage::New); +} + +mitk::IGTLMessageFactory::~IGTLMessageFactory() +{ +} + +void mitk::IGTLMessageFactory::AddMessageType(std::string messageTypeName, + IGTLMessageFactory::PointerToMessageBaseNew messageTypeNewPointer, + mitk::IGTLMessageCloneHandler::Pointer cloneHandler) +{ + this->AddMessageNewMethod(messageTypeName, messageTypeNewPointer); + this->AddMessageCloneHandler(messageTypeName, cloneHandler); +} + +void mitk::IGTLMessageFactory::AddMessageNewMethod(std::string messageTypeName, + IGTLMessageFactory::PointerToMessageBaseNew messageTypeNewPointer ) +{ + this->m_NewMethods[messageTypeName] = messageTypeNewPointer; +} + +void mitk::IGTLMessageFactory::AddMessageCloneHandler(std::string msgTypeName, + mitk::IGTLMessageCloneHandler::Pointer cloneHandler ) +{ + this->m_CloneHandlers[msgTypeName] = cloneHandler; +} + +mitk::IGTLMessageCloneHandler::Pointer +mitk::IGTLMessageFactory::GetCloneHandler(std::string messageTypeName) +{ + if ( this->m_CloneHandlers.find(messageTypeName) != + this->m_CloneHandlers.end() ) + { + return m_CloneHandlers[messageTypeName]; + } + + MITK_ERROR("IGTLMessageFactory") << messageTypeName << + " message type is not registered to factory!"; + + mitkThrow() << messageTypeName << " message type is not registered to factory!"; + + return NULL; +} + +igtl::MessageBase::Pointer +mitk::IGTLMessageFactory::Clone(igtl::MessageBase::Pointer msg) +{ + return this->GetCloneHandler(msg->GetDeviceType())->Clone(msg); +} + +mitk::IGTLMessageFactory::PointerToMessageBaseNew +mitk::IGTLMessageFactory::GetMessageTypeNewPointer(std::string messageTypeName) +{ + if ( this->m_NewMethods.find(messageTypeName) != this->m_NewMethods.end() ) + { + return m_NewMethods[messageTypeName]; + } + + MITK_ERROR("IGTLMessageFactory") << messageTypeName << + " message type is not registered to factory!"; + return NULL; +} + +igtl::MessageBase::Pointer +mitk::IGTLMessageFactory::CreateInstance(std::string messageTypeName) +{ + mitk::IGTLMessageFactory::PointerToMessageBaseNew newPointer = + this->GetMessageTypeNewPointer(messageTypeName); + if ( newPointer != NULL ) + { + return newPointer(); + } + else + { + return NULL; + } +} + +std::list +mitk::IGTLMessageFactory::GetAvailableMessageRequestTypes() +{ + std::list allGetMessages; + for ( std::map::const_iterator it = + this->m_NewMethods.begin(); + it != this->m_NewMethods.end(); ++it) + { + if ( it->first.find("GET_") != std::string::npos || + it->first.find("STT_") != std::string::npos || + it->first.find("STP_") != std::string::npos || + it->first.find("RTS_") != std::string::npos) + { + allGetMessages.push_back(it->first); + } + } + + return allGetMessages; +} + +igtl::MessageBase::Pointer +mitk::IGTLMessageFactory::CreateInstance(igtl::MessageHeader::Pointer msgHeader) +{ + std::string messageType; + + //check the header + if ( msgHeader.IsNull() ) + { + messageType = "NONE"; + } + else + { + messageType = msgHeader->GetDeviceType(); + } + + //make message type uppercase + messageType = itksys::SystemTools::UpperCase(messageType); + + //find the according new method + if ( this->m_NewMethods.find( messageType ) + != this->m_NewMethods.end() ) + { + if ( this->m_NewMethods[messageType] != NULL) + { + // Call tracker New() function if tracker not NULL + return (*this->m_NewMethods[messageType])(); + } + else + return NULL; + } + else + { + MITK_ERROR("IGTLMessageFactory") << "Unknown IGT message type: " + << messageType; + return NULL; + } +} diff --git a/Modules/OpenIGTLink/mitkIGTLMessageFactory.h b/Modules/OpenIGTLink/mitkIGTLMessageFactory.h new file mode 100644 index 0000000000..f1749d1c62 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageFactory.h @@ -0,0 +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. + +===================================================================*/ + +#ifndef MITKIGTLMESSAGEFACTORYH_HEADER_INCLUDED_ +#define MITKIGTLMESSAGEFACTORYH_HEADER_INCLUDED_ + +#include "MitkOpenIGTLinkExports.h" +#include "mitkCommon.h" + +#include "igtlMessageBase.h" +#include "igtlMessageHeader.h" + +#include "mitkIGTLMessageCloneHandler.h" + +namespace mitk { + /** + * \brief Factory class of supported OpenIGTLink message types + * + * This class is a factory for the creation of OpenIGTLink messages. It stores + * pairs of type and pointer to the message new method. Available standard types + * are already added but you can also add your custom types at runtime. + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLMessageFactory : public itk::Object + { + public: + mitkClassMacro(IGTLMessageFactory, itk::Object) + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + /** + * \brief Function pointer for storing New() static methods of + * igtl::MessageBase classes + */ + typedef igtl::MessageBase::Pointer (*PointerToMessageBaseNew)(); + + /** + * \brief Add message type name and pointer to IGTL message new function and + * the clone handler + * \param messageTypeName The name of the message type + * \param messageTypeNewPointer Function pointer to the message type new + * function (e.g. (PointerToMessageBaseNew)&igtl::ImageMessage::New ) + * \param cloneHandler pointer to the message clone object + */ + void AddMessageType(std::string messageTypeName, + IGTLMessageFactory::PointerToMessageBaseNew messageTypeNewPointer, + mitk::IGTLMessageCloneHandler::Pointer cloneHandler); + + /** + * \brief Add message type name and pointer to IGTL message new function + * Usage: + * AddMessageType("IMAGE", (PointerToMessageBaseNew)&igtl::ImageMessage::New); + * \param messageTypeName The name of the message type + * \param messageTypeNewPointer Function pointer to the message type new + * function (e.g. (PointerToMessageBaseNew)&igtl::ImageMessage::New ) + */ + virtual void AddMessageNewMethod(std::string messageTypeName, + IGTLMessageFactory::PointerToMessageBaseNew messageTypeNewPointer); + + /** + * \brief Get pointer to message type new function, or NULL if the message + * type not registered + * Usage: + * igtl::MessageBase::Pointer message = GetMessageTypeNewPointer("IMAGE")(); + */ + virtual IGTLMessageFactory::PointerToMessageBaseNew GetMessageTypeNewPointer( + std::string messageTypeName); + + /** + * \brief Creates a new message instance fitting to the given type. + * + * If this type is not registered it returns NULL + * Usage: + * igtl::MessageBase::Pointer message = CreateInstance("IMAGE"); + */ + igtl::MessageBase::Pointer CreateInstance(std::string messageTypeName); + + /** + * \brief Creates a new message according to the given header + * \param msg The message header that defines the type of the message + * This method checks the data type and creates a new message according to the + * type. + */ + igtl::MessageBase::Pointer CreateInstance(igtl::MessageHeader::Pointer msg); + + /** + * \brief Adds a clone function for the specified message type + * \param msgTypeName The name of the message type + * \param msgCloneHandler Function pointer to the message clone function + * (e.g. TBD ) + */ + virtual void AddMessageCloneHandler(std::string msgTypeName, + mitk::IGTLMessageCloneHandler::Pointer msgCloneHandler); + + /** + * \brief Get pointer to message type clone function, or NULL if the message + * type is not registered + * Usage: + * igtl::TransformMessage::Pointer original = igtl::TransformMessage::New(); + * igtl::MessageBase::Pointer message = + * GetCloneHandler("IMAGE")->Clone(original); + */ + virtual mitk::IGTLMessageCloneHandler::Pointer + GetCloneHandler(std::string messageTypeName); + + /** + * \brief Clones the given message according to the available clone methods + * \param msg The message that has to be cloned + * This method checks the data type and clones the message according to this + * type. + */ + igtl::MessageBase::Pointer Clone(igtl::MessageBase::Pointer msg); + + /** + * \brief Returns available get messages + */ + std::list GetAvailableMessageRequestTypes(); + + protected: + IGTLMessageFactory(); + virtual ~IGTLMessageFactory(); + + /** + * \brief Map igt message types and the Clone() methods + */ + std::map m_CloneHandlers; + + /** + * \brief Map igt message types and the New() static methods of igtl::MessageBase + * classes + */ + std::map m_NewMethods; + + private: + IGTLMessageFactory(const IGTLMessageFactory&); + }; +} + +#endif diff --git a/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp b/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp new file mode 100644 index 0000000000..69942a3288 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp @@ -0,0 +1,371 @@ +/*=================================================================== + +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 "mitkIGTLMessageProvider.h" + +#include "mitkIGTLDevice.h" +#include "mitkIGTLMessage.h" +#include "mitkIGTLMessageFactory.h" + +#include "mitkCallbackFromGUIThread.h" + +//Microservices +#include "usServiceReference.h" +#include "usModuleContext.h" +#include "usServiceEvent.h" +#include "mitkServiceInterface.h" +#include "usGetModuleContext.h" + +//igt (remove this later) +#include "igtlBindMessage.h" +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlTrackingDataMessage.h" + +#ifndef WIN32 +#include +#endif + +mitk::IGTLMessageProvider::IGTLMessageProvider() + : mitk::IGTLDeviceSource() +{ + this->SetName("IGTLMessageProvider"); + m_MultiThreader = itk::MultiThreader::New(); + m_StreamingTimeMutex = itk::FastMutexLock::New(); + m_StopStreamingThreadMutex = itk::FastMutexLock::New(); + m_ThreadId = 0; + m_IsStreaming = false; +} + +mitk::IGTLMessageProvider::~IGTLMessageProvider() +{ + // terminate worker thread on destruction + this->m_StopStreamingThreadMutex->Lock(); + this->m_StopStreamingThread = true; + this->m_StopStreamingThreadMutex->Unlock(); + if ( m_ThreadId >= 0) + { + this->m_MultiThreader->TerminateThread(m_ThreadId); + } +} + +void mitk::IGTLMessageProvider::GenerateData() +{ + if (this->m_IGTLDevice.IsNull()) + return; + + for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++) + { + const IGTLMessage* msg = this->GetInput(index); + assert(msg); + + if ( !msg->IsDataValid() ) + { + continue; + } + + igtl::MessageBase::Pointer igtlMsg = msg->GetMessage(); + + if ( igtlMsg.IsNotNull() ) + { + //send the message + this->m_IGTLDevice->SendMessage(igtlMsg); + } + } +} + +void mitk::IGTLMessageProvider::CreateOutputs() +{ + //if outputs are set then delete them + if (this->GetNumberOfOutputs() > 0) + { + for (int numOP = this->GetNumberOfOutputs() - 1; numOP >= 0; numOP--) + this->RemoveOutput(numOP); + this->Modified(); + } + + //fill the outputs if a valid OpenIGTLink device is set + if (m_IGTLDevice.IsNull()) + return; + + this->SetNumberOfIndexedOutputs(1); + if (this->GetOutput(0) == NULL) + { + DataObjectPointer newOutput = this->MakeOutput(0); + this->SetNthOutput(0, newOutput); + this->Modified(); + } +} + +//void mitk::IGTLMessageProvider::UpdateOutputInformation() +//{ +// this->Modified(); // make sure that we need to be updated +// Superclass::UpdateOutputInformation(); +//} + + +void mitk::IGTLMessageProvider::OnIncomingMessage() +{ + +} + +std::string RemoveRequestPrefixes(std::string requestType) +{ + return requestType.substr(4); +} + +void mitk::IGTLMessageProvider::OnIncomingCommand() +{ + //get the next command + igtl::MessageBase::Pointer curCommand = this->m_IGTLDevice->GetNextCommand(); + //extract the type + const char * requestType = curCommand->GetDeviceType(); + //check the type + std::string reqType(requestType); + bool isGetMsg = !reqType.find("GET_"); + bool isSTTMsg = !reqType.find("STT_"); + bool isSTPMsg = !reqType.find("STP_"); + bool isRTSMsg = !reqType.find("RTS_"); + //get the type from the request type (remove STT_, STP_, GET_, RTS_) + std::string type = RemoveRequestPrefixes(requestType); + //check all microservices if there is a fitting source for the requested type + mitk::IGTLMessageSource::Pointer source = this->GetFittingSource(type.c_str()); + //if there is no fitting source return a RTS message, if there is a RTS + //type defined in the message factory send it + if ( source.IsNull() ) + { + if ( !this->GetIGTLDevice()->SendRTSMessage(type.c_str()) ) + { + //sending RTS message failed, probably because the type is not in the + //message factory + MITK_WARN("IGTLMessageProvider") << "Tried to send a RTS message but did " + "not succeed. Check if this type ( " + << type << " ) was added to the message " + "factory. "; + } + } + else + { + if ( isGetMsg ) //if it is a single value push it into sending queue + { + //first it is necessary to update the source. This needs additional time + //but is necessary. But are we really allowed to call this here? In which + //thread are we? Is the source thread safe? + source->Update(); + mitk::IGTLMessage::Pointer sourceOutput = source->GetOutput(); + if (sourceOutput.IsNotNull() && sourceOutput->IsDataValid()) + { + igtl::MessageBase::Pointer sourceMsg = sourceOutput->GetMessage(); + if ( source.IsNotNull() ) + { + this->GetIGTLDevice()->SendMessage(sourceMsg); + } + } + } + else if ( isSTTMsg ) + { + //read the requested frames per second + int fps = 10; + + //read the fps from the command + igtl::MessageBase* curCommandPt = curCommand.GetPointer(); + if ( std::strcmp( curCommand->GetDeviceType(), "STT_BIND" ) == 0 ) + { + fps = ((igtl::StartBindMessage*)curCommandPt)->GetResolution(); + } + else if ( std::strcmp( curCommand->GetDeviceType(), "STT_QTDATA" ) == 0 ) + { + fps = ((igtl::StartQuaternionTrackingDataMessage*)curCommandPt)->GetResolution(); + } + else if ( std::strcmp( curCommand->GetDeviceType(), "STT_TDATA" ) == 0 ) + { + fps = ((igtl::StartTrackingDataMessage*)curCommandPt)->GetResolution(); + } + + this->StartStreamingOfSource(source, fps); + } + else if ( isSTPMsg ) + { + this->StopStreamingOfSource(source); + } + else + { + //do nothing + } + } +} + +bool mitk::IGTLMessageProvider::IsStreaming() +{ + return m_IsStreaming; +} + +void mitk::IGTLMessageProvider::StartStreamingOfSource(IGTLMessageSource* src, + unsigned int fps) +{ + if ( src == NULL ) + return; + + //so far the provider allows the streaming of a single source only + //if the streaming thread is already running return a RTS message + if ( !m_IsStreaming ) + { + //if it is a stream establish a connection between the provider and the + //source + this->ConnectTo(src); + + // calculate the streaming time + this->m_StreamingTimeMutex->Lock(); + this->m_StreamingTime = 1.0 / (double) fps * 1000.0; + this->m_StreamingTimeMutex->Unlock(); + + // Create a command object. The function will be called later from the + // main thread + this->m_StreamingCommand = ProviderCommand::New(); + m_StreamingCommand->SetCallbackFunction(this, + &mitk::IGTLMessageProvider::Update); + + // For streaming we need a continues time signal, since there is no timer + // available we start a thread that generates a timing signal + // This signal is invoked from the other thread the update of the pipeline + // has to be executed from the main thread. Thus, we use the + // callbackfromGUIThread class to pass the execution to the main thread + this->m_ThreadId = m_MultiThreader->SpawnThread(this->TimerThread, this); + this->m_IsStreaming = true; + } + else + { + MITK_WARN("IGTLMessageProvider") << "This provider just supports the " + "streaming of one source."; + } +} + +void mitk::IGTLMessageProvider::StopStreamingOfSource(IGTLMessageSource* src) +{ + //this is something bad!!! The streaming thread has to be stopped before the + //source is disconnected otherwise it can cause a crash. This has to be added!! + this->DisconnectFrom(src); + + this->m_StopStreamingThreadMutex->Lock(); + this->m_StopStreamingThread = true; + this->m_StopStreamingThreadMutex->Unlock(); + + //does this flag needs a mutex??? + this->m_IsStreaming = false; +} + +mitk::IGTLMessageSource::Pointer mitk::IGTLMessageProvider::GetFittingSource(const char* requestedType) +{ + //get the context + us::ModuleContext* context = us::GetModuleContext(); + //define the interface name + std::string interface = mitk::IGTLMessageSource::US_INTERFACE_NAME; + //specify a filter that defines the requested type + std::string filter = "(" + mitk::IGTLMessageSource::US_PROPKEY_DEVICETYPE + + "=" + requestedType + ")"; + //find the fitting service + std::vector serviceReferences = + context->GetServiceReferences(interface, filter); + + //check if a service reference was found. It is also possible that several + //services were found. This is not checked here, just the first one is taken. + if ( serviceReferences.size() ) + { + mitk::IGTLMessageSource::Pointer curSource = + context->GetService(serviceReferences.front()); + + if ( curSource.IsNotNull() ) + return curSource; + } + //no service reference was found or found service reference has no valid source + return NULL; +} + +void mitk::IGTLMessageProvider::Send(const mitk::IGTLMessage* msg) +{ + if (msg != NULL) + this->m_IGTLDevice->SendMessage(msg); +} + +void +mitk::IGTLMessageProvider::ConnectTo( mitk::IGTLMessageSource* UpstreamFilter ) +{ + for (DataObjectPointerArraySizeType i = 0; + i < UpstreamFilter->GetNumberOfOutputs(); i++) + { + this->SetInput(i, UpstreamFilter->GetOutput(i)); + } +} + +void +mitk::IGTLMessageProvider::DisconnectFrom( mitk::IGTLMessageSource* UpstreamFilter ) +{ + for (DataObjectPointerArraySizeType i = 0; + i < UpstreamFilter->GetNumberOfOutputs(); i++) + { + this->RemoveInput(UpstreamFilter->GetOutput(i)); + } +} + +ITK_THREAD_RETURN_TYPE mitk::IGTLMessageProvider::TimerThread(void* pInfoStruct) +{ + // extract this pointer from thread info structure + struct itk::MultiThreader::ThreadInfoStruct * pInfo = + (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; + mitk::IGTLMessageProvider* thisObject = + static_cast(pInfo->UserData); + + itk::SimpleMutexLock mutex; + mutex.Lock(); + + thisObject->m_StopStreamingThreadMutex->Lock(); + thisObject->m_StopStreamingThread = false; + thisObject->m_StopStreamingThreadMutex->Unlock(); + + thisObject->m_StreamingTimeMutex->Lock(); + unsigned int waitingTime = thisObject->m_StreamingTime; + thisObject->m_StreamingTimeMutex->Unlock(); + + while (true) + { + thisObject->m_StopStreamingThreadMutex->Lock(); + bool stopThread = thisObject->m_StopStreamingThread; + thisObject->m_StopStreamingThreadMutex->Unlock(); + + if (stopThread) + { + break; + } + + //wait for the time given + //I know it is not the nicest solution but we just need an approximate time + //sleeps for 20 ms + #if defined (WIN32) || defined (_WIN32) + Sleep(waitingTime); + #else + usleep(waitingTime * 1000); + #endif + + // Ask to execute that command from the GUI thread + mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread( + thisObject->m_StreamingCommand); + } + + thisObject->m_ThreadId = 0; + + mutex.Unlock(); + + return ITK_THREAD_RETURN_VALUE; +} diff --git a/Modules/OpenIGTLink/mitkIGTLMessageProvider.h b/Modules/OpenIGTLink/mitkIGTLMessageProvider.h new file mode 100644 index 0000000000..f60f765467 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageProvider.h @@ -0,0 +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. + +===================================================================*/ + +#ifndef IGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ +#define IGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ + +#include "mitkIGTLDevice.h" +#include "mitkIGTLDeviceSource.h" + +//itk +#include "itkCommand.h" + +namespace mitk { + /** + * \brief Provides information/objects from a MITK-Pipeline to other OpenIGTLink + * devices + * + * This class is intended as the drain of the pipeline. Other OpenIGTLink + * devices connect with the IGTLDevice hold by this provider. The other device + * asks for a certain data type. The provider checks if there are other + * IGTLMessageSources available that provide this data type. If yes the provider + * connects with this source and sends the message to the requesting device. + * + * If a STT message was received the provider looks for fitting messageSources. + * Once found it connects with it, starts a timing thread (which updates the + * pipeline) and sends the result to the requesting device. + * + * If a GET message was received the provider just calls an update of the + * found source and sends the result without connecting to the source. + * + * If a STP message was received it stops the thread and disconnects from the + * previous source. + * + * So far the provider can just connect with one source. + * + * \ingroup OpenIGTLink + */ + class MITK_OPENIGTLINK_EXPORT IGTLMessageProvider : public IGTLDeviceSource + { + public: + mitkClassMacro(IGTLMessageProvider, IGTLDeviceSource); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + typedef itk::SimpleMemberCommand ProviderCommand; + + /** + * \brief sends the msg to the requesting client + * + * Note: so far it broadcasts the message to all registered clients + */ + void Send(const IGTLMessage* msg); + + /** + * \brief Starts the streaming of the given message source with the given fps. + */ + void StartStreamingOfSource(mitk::IGTLMessageSource* src, + unsigned int fps); + + /** + * \brief Stops the streaming of the given message source. + */ + void StopStreamingOfSource(mitk::IGTLMessageSource* src); + + /** + * \brief Returns the streaming state. + */ + bool IsStreaming(); + + protected: + IGTLMessageProvider(); + virtual ~IGTLMessageProvider(); + + /** + * \brief filter execute method + * + * queries the OpenIGTLink device for new messages and updates its output + * igtl::MessageBase objects with it. + * \warning Will raise a std::out_of_range exception, if tools were added to + * the OpenIGTLink device after it was set as input for this filter + */ + virtual void GenerateData(); + + /** + * \brief Create the necessary outputs for the m_IGTLDevice + * + * This Method is called internally whenever outputs need to be reset. Old + * Outputs are deleted when called. + **/ + void CreateOutputs(); + + /** + * \brief This method is called when the IGTL device hold by this class + * receives a new message + **/ + virtual void OnIncomingMessage(); + + /** + * \brief This method is called when the IGTL device hold by this class + * receives a new command + **/ + virtual void OnIncomingCommand(); + + /** + *\brief Connects the input of this filter to the outputs of the given + * IGTLMessageSource + * + * This method does not support smartpointer. use FilterX.GetPointer() to + * retrieve a dumbpointer. + */ + void ConnectTo( mitk::IGTLMessageSource* UpstreamFilter ); + + /** + *\brief Disconnects this filter from the outputs of the given + * IGTLMessageSource + * + * This method does not support smartpointer. use FilterX.GetPointer() to + * retrieve a dumbpointer. + */ + void DisconnectFrom( mitk::IGTLMessageSource* UpstreamFilter ); + + /** + * \brief Looks for microservices that provide messages with the requested + * type. + **/ + mitk::IGTLMessageSource::Pointer GetFittingSource(const char* requestedType); + + private: + /** + * \brief a command that has to be executed in the main thread + */ + ProviderCommand::Pointer m_StreamingCommand; + + /** + * \brief Timer thread for generating a continuous time signal for the stream + * + * Everyt time the time is passed a time signal is invoked. + * + * \param pInfoStruct pointer to the mitkIGTLMessageProvider object + * \return + */ + static ITK_THREAD_RETURN_TYPE TimerThread(void* pInfoStruct); + + int m_ThreadId; + + /** \brief timer thread will terminate after the next wakeup if set to true */ + bool m_StopStreamingThread; + + itk::SmartPointer m_MultiThreader; + + /** \brief the time used for streaming */ + unsigned int m_StreamingTime; + + /** \brief mutex for guarding m_Time */ + itk::SmartPointer m_StreamingTimeMutex; + + /** \brief mutex for guarding m_StopStreamingThread */ + itk::SmartPointer m_StopStreamingThreadMutex; + + /** \brief flag to indicate if the provider is streaming */ + bool m_IsStreaming; + + }; +} // namespace mitk +#endif /* MITKIGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp b/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp new file mode 100644 index 0000000000..26f3e91d81 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp @@ -0,0 +1,142 @@ +/*=================================================================== + +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 "mitkIGTLMessageQueue.h" +#include +#include "igtlMessageBase.h" + + + +void mitk::IGTLMessageQueue::PushMessage( igtl::MessageBase::Pointer message ) +{ + this->m_Mutex->Lock(); + if ( this->m_BufferingType == IGTLMessageQueue::Infinit ) + { + this->m_Queue.push_back( message ); + } + else //NoBuffering + { + this->m_Queue.clear(); + this->m_Queue.push_back( message ); + } + this->m_Mutex->Unlock(); +} + +igtl::MessageBase::Pointer mitk::IGTLMessageQueue::PullMessage() +{ + this->m_Mutex->Lock(); + igtl::MessageBase::Pointer ret = NULL; + if ( this->m_Queue.size() > 0 ) + { + ret = this->m_Queue.front(); + this->m_Queue.pop_front(); + } + this->m_Mutex->Unlock(); + + return ret; +} + +std::string mitk::IGTLMessageQueue::GetNextMsgInformationString() +{ + this->m_Mutex->Lock(); + std::stringstream s; + if ( this->m_Queue.size() > 0 ) + { + s << "Device Type: " << this->m_Queue.front()->GetDeviceType() << std::endl; + s << "Device Name: " << this->m_Queue.front()->GetDeviceName() << std::endl; + } + else + { + s << "No Msg"; + } + this->m_Mutex->Unlock(); + return s.str(); +} + +std::string mitk::IGTLMessageQueue::GetNextMsgDeviceType() +{ + this->m_Mutex->Lock(); + std::stringstream s; + if ( this->m_Queue.size() > 0 ) + { + s << this->m_Queue.front()->GetDeviceType(); + } + else + { + s << ""; + } + this->m_Mutex->Unlock(); + return s.str(); +} + +std::string mitk::IGTLMessageQueue::GetLatestMsgInformationString() +{ + this->m_Mutex->Lock(); + std::stringstream s; + if ( this->m_Queue.size() > 0 ) + { + s << "Device Type: " << this->m_Queue.back()->GetDeviceType() << std::endl; + s << "Device Name: " << this->m_Queue.back()->GetDeviceName() << std::endl; + } + else + { + s << "No Msg"; + } + this->m_Mutex->Unlock(); + return s.str(); +} + +std::string mitk::IGTLMessageQueue::GetLatestMsgDeviceType() +{ + this->m_Mutex->Lock(); + std::stringstream s; + if ( this->m_Queue.size() > 0 ) + { + s << this->m_Queue.back()->GetDeviceType(); + } + else + { + s << ""; + } + this->m_Mutex->Unlock(); + return s.str(); +} + +int mitk::IGTLMessageQueue::GetSize() +{ + return this->m_Queue.size(); +} + +void mitk::IGTLMessageQueue::EnableInfiniteBuffering(bool enable) +{ + this->m_Mutex->Lock(); + if ( enable ) + this->m_BufferingType = IGTLMessageQueue::Infinit; + else + this->m_BufferingType = IGTLMessageQueue::NoBuffering; + this->m_Mutex->Unlock(); +} + +mitk::IGTLMessageQueue::IGTLMessageQueue() +{ + this->m_Mutex = itk::FastMutexLock::New(); + this->m_BufferingType = IGTLMessageQueue::Infinit; +} + +mitk::IGTLMessageQueue::~IGTLMessageQueue() +{ + this->m_Mutex->Unlock(); +} diff --git a/Modules/OpenIGTLink/mitkIGTLMessageQueue.h b/Modules/OpenIGTLink/mitkIGTLMessageQueue.h new file mode 100644 index 0000000000..9047e8c4d8 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageQueue.h @@ -0,0 +1,118 @@ +/*=================================================================== + +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 IGTLMessageQueue_H +#define IGTLMessageQueue_H + +#include "MitkOpenIGTLinkExports.h" + +#include "itkObject.h" +#include "itkFastMutexLock.h" +#include "mitkCommon.h" + +#include + +#include "igtlMessageBase.h" + + +namespace mitk { + /** + * \class IGTLMessageQueue + * \brief Thread safe message queue to store OpenIGTLink messages. + * + * \ingroup OpenIGTLink + */ + class MITK_OPENIGTLINK_EXPORT IGTLMessageQueue : public itk::Object + { + public: + mitkClassMacro(mitk::IGTLMessageQueue, itk::Object) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** + * \brief Different buffering types + * Infinit buffering means that you can push as many messages as you want + * NoBuffering means that the queue just stores a single message + */ + enum BufferingType {Infinit, NoBuffering}; + + /** + * \brief Adds the message to the queue + */ + void PushMessage( igtl::MessageBase::Pointer message ); + /** + * \brief Returns and removes the oldest message from the queue + */ + igtl::MessageBase::Pointer PullMessage(); + + /** + * \brief Get the number of messages in the queue + */ + int GetSize(); + + /** + * \brief Returns a string with information about the oldest message in the + * queue + */ + std::string GetNextMsgInformationString(); + + /** + * \brief Returns the device type of the oldest message in the queue + */ + std::string GetNextMsgDeviceType(); + + /** + * \brief Returns a string with information about the oldest message in the + * queue + */ + std::string GetLatestMsgInformationString(); + + /** + * \brief Returns the device type of the oldest message in the queue + */ + std::string GetLatestMsgDeviceType(); + + /** + * \brief Sets infinite buffering on/off. + * Initiale value is enabled. + */ + void EnableInfiniteBuffering(bool enable); + + protected: + IGTLMessageQueue(); + virtual ~IGTLMessageQueue(); + + + protected: + /** + * \brief Mutex to take car of the queue + */ + itk::FastMutexLock::Pointer m_Mutex; + + /** + * \brief the queue that stores pointer to the inserted messages + */ + std::deque< igtl::MessageBase::Pointer > m_Queue; + + /** + * \brief defines the kind of buffering + */ + BufferingType m_BufferingType; + }; +} + + +#endif diff --git a/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp b/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp new file mode 100644 index 0000000000..0ff2b4ae5a --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp @@ -0,0 +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. + +===================================================================*/ + +#include "mitkIGTLMessageSource.h" +#include "mitkUIDGenerator.h" + +//Microservices +#include +#include +#include +#include + +const std::string mitk::IGTLMessageSource::US_INTERFACE_NAME = + "org.mitk.services.IGTLMessageSource"; +const std::string mitk::IGTLMessageSource::US_PROPKEY_DEVICENAME = + US_INTERFACE_NAME + ".devicename"; +const std::string mitk::IGTLMessageSource::US_PROPKEY_DEVICETYPE = + US_INTERFACE_NAME + ".devicetype"; +const std::string mitk::IGTLMessageSource::US_PROPKEY_ID = + US_INTERFACE_NAME + ".id"; +const std::string mitk::IGTLMessageSource::US_PROPKEY_ISACTIVE = + US_INTERFACE_NAME + ".isActive"; + +mitk::IGTLMessageSource::IGTLMessageSource() + : itk::ProcessObject(), m_Name("IGTLMessageSource (no defined type)"), + m_Type("NONE"), m_StreamingFPS(0) +{ + m_StreamingFPSMutex = itk::FastMutexLock::New(); +} + +mitk::IGTLMessageSource::~IGTLMessageSource() +{ + this->UnRegisterMicroservice(); +} + +mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput() +{ + if (this->GetNumberOfIndexedOutputs() < 1) + return NULL; + + return static_cast(this->ProcessObject::GetPrimaryOutput()); +} + +mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput( + DataObjectPointerArraySizeType idx) +{ + IGTLMessage* 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( IGTLMessage ).name () ); + } + return out; +} + +mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput( + const std::string& messageName) +{ + DataObjectPointerArray outputs = this->GetOutputs(); + for (DataObjectPointerArray::iterator it = outputs.begin(); + it != outputs.end(); + ++it) + { + if (messageName == + (static_cast(it->GetPointer()))->GetName()) + { + return static_cast(it->GetPointer()); + } + } + return NULL; +} + +itk::ProcessObject::DataObjectPointerArraySizeType +mitk::IGTLMessageSource::GetOutputIndex( std::string messageName ) +{ + DataObjectPointerArray outputs = this->GetOutputs(); + for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i) + { + if (messageName == + (static_cast(outputs.at(i).GetPointer()))->GetName()) + { + return i; + } + } + throw std::invalid_argument("output name does not exist"); +} + +void mitk::IGTLMessageSource::RegisterAsMicroservice() +{ + // Get Context + us::ModuleContext* context = us::GetModuleContext(); + + // Define ServiceProps + us::ServiceProperties props; + mitk::UIDGenerator uidGen = + mitk::UIDGenerator ("org.mitk.services.IGTLMessageSource.id_", 16); + props[ US_PROPKEY_ID ] = uidGen.GetUID(); + props[ US_PROPKEY_DEVICENAME ] = m_Name; + props[ US_PROPKEY_DEVICETYPE ] = m_Type; + m_ServiceRegistration = context->RegisterService(this, props); +} + +void mitk::IGTLMessageSource::UnRegisterMicroservice() +{ + if (m_ServiceRegistration != NULL) m_ServiceRegistration.Unregister(); + m_ServiceRegistration = 0; +} + +std::string mitk::IGTLMessageSource::GetMicroserviceID() +{ + us::Any referenceProperty = + this->m_ServiceRegistration.GetReference().GetProperty(US_PROPKEY_ID); + return referenceProperty.ToString(); +} + +void mitk::IGTLMessageSource::GraftOutput(itk::DataObject *graft) +{ + this->GraftNthOutput(0, graft); +} + +void mitk::IGTLMessageSource::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 IGTLMessage to copy member data + output->Graft( graft ); +} + +itk::DataObject::Pointer mitk::IGTLMessageSource::MakeOutput ( DataObjectPointerArraySizeType /*idx*/ ) +{ + return IGTLMessage::New().GetPointer(); +} + +itk::DataObject::Pointer mitk::IGTLMessageSource::MakeOutput( const DataObjectIdentifierType & name ) +{ + itkDebugMacro("MakeOutput(" << name << ")"); + if( this->IsIndexedOutputName(name) ) + { + return this->MakeOutput( this->MakeIndexFromOutputName(name) ); + } + return static_cast(IGTLMessage::New().GetPointer()); +} + +mitk::PropertyList::ConstPointer mitk::IGTLMessageSource::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); +} + +void mitk::IGTLMessageSource::SetFPS(unsigned int fps) +{ + this->m_StreamingFPSMutex->Lock(); + this->m_StreamingFPS = fps; + this->m_StreamingFPSMutex->Unlock(); +} + + +unsigned int mitk::IGTLMessageSource::GetFPS() +{ + unsigned int fps = 0; + this->m_StreamingFPSMutex->Lock(); + fps = this->m_StreamingFPS; + this->m_StreamingFPSMutex->Unlock(); + return fps; +} diff --git a/Modules/OpenIGTLink/mitkIGTLMessageSource.h b/Modules/OpenIGTLink/mitkIGTLMessageSource.h new file mode 100644 index 0000000000..f366789d46 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageSource.h @@ -0,0 +1,212 @@ +/*=================================================================== + +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 MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ +#define MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ + +#include +#include "mitkPropertyList.h" +#include "MitkOpenIGTLinkExports.h" +#include "mitkIGTLMessage.h" + +// Microservices +#include +#include + +//itk +#include + +namespace mitk { + + /** + * \brief OpenIGTLink message source + * + * Base class for all OpenIGTLink filters that produce OpenIGTLink message + * objects as output. This class defines the output-interface for + * OpenIGTLinkMessageFilters. + * \warning: if Update() is called on any output object, all IGTLMessage filters + * will generate new output data for all outputs, not just the one on which + * Update() was called. + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLMessageSource : public itk::ProcessObject + { + public: + mitkClassMacro(IGTLMessageSource, itk::ProcessObject); + + /** @return Returns a human readable name of this source. There will be a + * default name, or you can set the name with the method SetName() if you + * want to change it. + */ + itkGetMacro(Name,std::string); + + /** @brief Sets the human readable name of this source. There is also a + * default name, but you can use this method if you need to define it on your + * own. + */ + itkSetMacro(Name,std::string); + + /** @return Returns a human readable type of this source. There will be a + * default type, or you can set the name with the method SetType(). You have + * to set this parameter otherwise it will not be found by the message + * provider. + */ + itkGetMacro(Type,std::string); + + /** @return Returns a human readable type of this source. There will be a + * default type, or you can set the name with the method SetType(). You have + * to set this parameter otherwise it will not be found by the message + * provider. + */ + itkSetMacro(Type,std::string); + + /** + *\brief return the output (output with id 0) of the filter + */ + IGTLMessage* GetOutput(void); + + /** + *\brief return the output with id idx of the filter + */ + IGTLMessage* GetOutput(DataObjectPointerArraySizeType idx); + + /** + *\brief return the output with name messageName of the filter + */ + IGTLMessage* GetOutput(const std::string& messageName); + + /** + *\brief return the index of the output with name messageName, -1 if no output + * with that name was found + * + * \warning if a subclass has outputs that have different data type than + * igtl::MessageBase, they have to overwrite this method + */ + DataObjectPointerArraySizeType GetOutputIndex(std::string messageName); + + /** + *\brief Registers this object as a Microservice, making it available to every + * module and/or plugin. To unregister, call UnregisterMicroservice(). + */ + virtual void RegisterAsMicroservice(); + + /** + *\brief Registers this object as a Microservice, making it available to every + * module and/or plugin. + */ + virtual void UnRegisterMicroservice(); + + /** + *\brief Returns the id that this device is registered with. The id will only + * be valid, if the IGTLMessageSource has been registered using + * RegisterAsMicroservice(). + */ + std::string GetMicroserviceID(); + + /** + *\brief These Constants are used in conjunction with Microservices + */ + static const std::string US_INTERFACE_NAME; + static const std::string US_PROPKEY_DEVICENAME; + static const std::string US_PROPKEY_DEVICETYPE; + static const std::string US_PROPKEY_ID; + static const std::string US_PROPKEY_ISACTIVE; //NOT IMPLEMENTED YET! + + /** + *\brief Graft the specified DataObject onto this ProcessObject's output. + * + * See itk::ImageSource::GraftNthOutput for details + */ + virtual void GraftNthOutput(unsigned int idx, itk::DataObject *graft); + + /** + * \brief Graft the specified DataObject onto this ProcessObject's output. + * + * See itk::ImageSource::Graft Output for details + */ + virtual void GraftOutput(itk::DataObject *graft); + + /** + * Allocates a new output object and returns it. Currently the + * index idx is not evaluated. + * @param idx the index of the output for which an object should be created + * @returns the new object + */ + virtual itk::DataObject::Pointer MakeOutput ( DataObjectPointerArraySizeType idx ); + + /** + * This is a default implementation to make sure we have something. + * Once all the subclasses of ProcessObject provide an appopriate + * MakeOutput(), then ProcessObject::MakeOutput() can be made pure + * virtual. + */ + virtual itk::DataObject::Pointer MakeOutput(const DataObjectIdentifierType &name); + + /** + * \brief Set all filter parameters as the PropertyList p + * + * This method allows to set all parameters of a filter with one + * method call. For the names of the parameters, take a look at + * the GetParameters method of the filter + * This method has to be overwritten by each MITK-IGT filter. + */ + virtual void SetParameters(const mitk::PropertyList*){}; + + /** + * \brief Get all filter parameters as a PropertyList + * + * This method allows to get all parameters of a filter with one + * method call. The returned PropertyList must be assigned to a + * SmartPointer immediately, or else it will get destroyed. + * Every filter must overwrite this method to create a filter-specific + * PropertyList. Note that property names must be unique over all + * MITK-IGT filters. Therefore each filter should use its name as a prefix + * for each property name. + * Secondly, each filter should list the property names and data types + * in the method documentation. + */ + virtual mitk::PropertyList::ConstPointer GetParameters() const; + + /** + *\brief Sets the fps used for streaming this source + */ + void SetFPS(unsigned int fps); + + /** + *\brief Gets the fps used for streaming this source + */ + unsigned int GetFPS(); + + protected: + IGTLMessageSource(); + virtual ~IGTLMessageSource(); + + std::string m_Name; + std::string m_Type; + + + /** mutex to control access to m_StreamingFPS */ + itk::FastMutexLock::Pointer m_StreamingFPSMutex; + /** The frames per second used for streaming */ + unsigned int m_StreamingFPS; + + us::ServiceRegistration m_ServiceRegistration; + }; +} // namespace mitk +// This is the microservice declaration. Do not meddle! +MITK_DECLARE_SERVICE_INTERFACE(mitk::IGTLMessageSource, "org.mitk.services.IGTLMessageSource") +#endif /* MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageSourceTest.cpp b/Modules/OpenIGTLink/mitkIGTLMessageSourceTest.cpp new file mode 100644 index 0000000000..a5d810e0f8 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageSourceTest.cpp @@ -0,0 +1,175 @@ +/*=================================================================== + +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); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + void CreateOutput() + { + 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/OpenIGTLink/mitkIGTLServer.cpp b/Modules/OpenIGTLink/mitkIGTLServer.cpp new file mode 100644 index 0000000000..c747e27cb0 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLServer.cpp @@ -0,0 +1,194 @@ +/*=================================================================== + +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 "mitkIGTLServer.h" +#include + +#include +#include + +#include +#include + + +mitk::IGTLServer::IGTLServer() : +IGTLDevice() +{ +} + +mitk::IGTLServer::~IGTLServer() +{ + +} + +bool mitk::IGTLServer::OpenConnection() +{ + if (this->GetState() != Setup) + { + mitkThrowException(mitk::Exception) << + "Can only try to create a server if in setup mode"; + return false; + } + + int portNumber = this->GetPortNumber(); + + if (portNumber == -1 ) + { + //port number was not correct + return false; + } + + //create a new server socket + m_Socket = igtl::ServerSocket::New(); + + //try to create the igtl server + int response = dynamic_cast(m_Socket.GetPointer())-> + CreateServer(portNumber); + + //check the response + if ( response != 0 ) + { + mitkThrowException(mitk::Exception) << + "The server could not be created. Port: " << portNumber; + return false; + } + + // everything is initialized and connected so the communication can be started + this->SetState(Ready); + + return true; +} + +bool mitk::IGTLServer::CloseConnection() +{ + //remove all registered clients + SocketListType allRegisteredSockets = m_RegisteredClients; + this->StopCommunicationWithSocket(allRegisteredSockets); + + return mitk::IGTLDevice::CloseConnection(); +} + +void mitk::IGTLServer::Connect() +{ + igtl::Socket::Pointer socket; + //check if another igtl device wants to connect to this socket + socket = + ((igtl::ServerSocket*)(this->m_Socket.GetPointer()))->WaitForConnection(1); + //if there is a new connection the socket is not null + if ( socket.IsNotNull() ) + { + //add the new client socket to the list of registered clients + this->m_RegisteredClients.push_back(socket); + //inform observers about this new client + this->InvokeEvent(NewClientConnectionEvent()); + MITK_INFO("IGTLServer") << "Connected to a new client."; + } +} + +void mitk::IGTLServer::Receive() +{ + unsigned int status = IGTL_STATUS_OK; + SocketListType socketsToBeRemoved; + + //the server can be connected with several clients, therefore it has to check + //all registered clients + SocketListIteratorType it; + SocketListIteratorType it_end = this->m_RegisteredClients.end(); + for ( it = this->m_RegisteredClients.begin(); it != it_end; ++it ) + { + //it is possible that ReceivePrivate detects that the current socket is + //already disconnected. Therefore, it is necessary to remove this socket + //from the registered clients list + status = this->ReceivePrivate(*it); + if ( status == IGTL_STATUS_NOT_PRESENT ) + { + //remember this socket for later, it is not a good idea to remove it + //from the list directly because we iterator over the list at this point + socketsToBeRemoved.push_back(*it); + MITK_WARN("IGTLServer") << "Lost connection to a client socket. "; + } + } + if ( socketsToBeRemoved.size() > 0 ) + { + //remove the sockets that are not connected anymore + this->StopCommunicationWithSocket(socketsToBeRemoved); + //inform observers about loosing the connection to these sockets + this->InvokeEvent(LostConnectionEvent()); + } +} + +void mitk::IGTLServer::Send() +{ + igtl::MessageBase::Pointer curMessage; + + //get the latest message from the queue + curMessage = this->m_SendQueue->PullMessage(); + + // there is no message => return + if ( curMessage.IsNull() ) + return; + + //the server can be connected with several clients, therefore it has to check + //all registered clients + //sending a message to all registered clients might not be the best solution, + //it could be better to store the client together with the requested type. Then + //the data would be send to the appropriate client and to noone else. + //(I know it is no excuse but PLUS is doing exactly the same, they broadcast + //everything) + SocketListIteratorType it; + SocketListIteratorType it_end = + this->m_RegisteredClients.end(); + for ( it = this->m_RegisteredClients.begin(); it != it_end; ++it ) + { + //maybe there should be a check here if the current socket is still active + this->SendMessagePrivate(curMessage.GetPointer(), *it); + } +} + +void mitk::IGTLServer::StopCommunicationWithSocket( + SocketListType& toBeRemovedSockets) +{ + SocketListIteratorType it = toBeRemovedSockets.begin(); + SocketListIteratorType itEnd = toBeRemovedSockets.end(); + for (; it != itEnd; ++it ) + { + this->StopCommunicationWithSocket(*it); + } +} + +void mitk::IGTLServer::StopCommunicationWithSocket(igtl::Socket* client) +{ + SocketListIteratorType it = this->m_RegisteredClients.begin(); + SocketListIteratorType itEnd = this->m_RegisteredClients.end(); + + for (; it != itEnd; ++it ) + { + if ( (*it) == client ) + { + //close the socket + (*it)->CloseSocket(); + //and remove it from the list + this->m_RegisteredClients.remove(*it); + break; + } + } + MITK_INFO("IGTLServer") << "Removed client socket from server client list."; +} + +unsigned int mitk::IGTLServer::GetNumberOfConnections() +{ + return this->m_RegisteredClients.size(); +} diff --git a/Modules/OpenIGTLink/mitkIGTLServer.h b/Modules/OpenIGTLink/mitkIGTLServer.h new file mode 100644 index 0000000000..053a3301cf --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLServer.h @@ -0,0 +1,125 @@ +/*=================================================================== + +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 MITKIGTLSERVER_H +#define MITKIGTLSERVER_H + +#include "mitkIGTLDevice.h" + +#include + + +namespace mitk +{ + + /** + * \brief Superclass for OpenIGTLink server + * + * Implements the IGTLDevice interface for IGTLServers. In certain points it + * behaves different than the IGTLClient. The client connects directly to a + * server (it cannot connect to two different servers) while the server can + * connect to several clients. Therefore, it is necessary for the server to + * have a list with registered sockets. + * + * \ingroup OpenIGTLink + */ + class MITK_OPENIGTLINK_EXPORT IGTLServer : public IGTLDevice + { + public: + mitkClassMacro(IGTLServer, IGTLDevice) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + typedef std::list SocketListType; + typedef SocketListType::iterator SocketListIteratorType; + + /** + * \brief Initialize the connection for the IGTLServer + * + * + * OpenConnection() starts the IGTLServer socket so that clients can connect + * to it. + * @throw mitk::Exception Throws an exception if the given port is occupied. + */ + virtual bool OpenConnection(); + + /** + * \brief Closes the connection to the device + * + * This may only be called if there is currently a connection to the + * device, but device is not running (e.g. object is in Ready state) + */ + virtual bool CloseConnection(); + + /** + * \brief Returns the number of client connections of this device + */ + virtual unsigned int GetNumberOfConnections(); + + protected: + /** Constructor */ + IGTLServer(); + /** Destructor */ + virtual ~IGTLServer(); + + /** + * \brief Call this method to check for other devices that want to connect + * to this one. + * + * In case of a client this method is doing nothing. In case of a server it + * is checking for other devices and if there is one it establishes a + * connection and adds the socket to m_RegisteredClients. + */ + virtual void Connect(); + + /** + * \brief Call this method to receive a message. + * + * The message will be saved in the receive queue. + */ + virtual void Receive(); + + /** + * \brief Call this method to send a message. + * The message will be read from the queue. So far the message is send to all + * connected sockets (broadcast). + */ + virtual void Send(); + + /** + * \brief Stops the communication with the given sockets. + * + * This method removes the given sockets from the registered clients list + * + */ + virtual void StopCommunicationWithSocket(SocketListType& toBeRemovedSockets); + + /** + * \brief Stops the communication with the given socket. + * + * This method removes the given socket from the registered clients list + * + */ + virtual void StopCommunicationWithSocket(igtl::Socket* client); + + /** + * \brief A list with all registered clients + */ + SocketListType m_RegisteredClients; + }; +} // namespace mitk +#endif /* MITKIGTLSERVER_H */ diff --git a/Modules/OpenIGTLinkUI/CMakeLists.txt b/Modules/OpenIGTLinkUI/CMakeLists.txt new file mode 100644 index 0000000000..11068c425f --- /dev/null +++ b/Modules/OpenIGTLinkUI/CMakeLists.txt @@ -0,0 +1,10 @@ +MITK_CREATE_MODULE( + #SUBPROJECTS MITKOpenIGTLink + INCLUDE_DIRS Qmitk + DEPENDS MitkOpenIGTLink MitkQtWidgetsExt MitkPersistence + #GENERATED_CPP ${TOOL_GUI_CPPS} ${TOOL_CPPS} + EXPORT_DEFINE MITK_OPENIGTLINKUI_EXPORT +) + +## create IGTUI config +#configure_file(mitkIGTUIConfig.h.in ${PROJECT_BINARY_DIR}/mitkIGTUIConfig.h @ONLY) diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp new file mode 100644 index 0000000000..74e8505e67 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp @@ -0,0 +1,282 @@ +/*=================================================================== + +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 "QmitkIGTLDeviceCommandWidget.h" + +//mitk headers +#include +#include +#include +#include + +//qt headers +#include +#include +#include +#include + +//igtl +#include +#include +#include +#include + +//poco headers +#include + +const std::string QmitkIGTLDeviceCommandWidget::VIEW_ID = + "org.mitk.views.igtldevicesourcemanagementwidget"; + +QmitkIGTLDeviceCommandWidget::QmitkIGTLDeviceCommandWidget( + QWidget* parent, Qt::WindowFlags f) + : QWidget(parent, f), m_IsClient(false) +{ + m_Controls = NULL; + this->m_IGTLDevice = NULL; + CreateQtPartControl(this); +} + + +QmitkIGTLDeviceCommandWidget::~QmitkIGTLDeviceCommandWidget() +{ +} + +void QmitkIGTLDeviceCommandWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkIGTLDeviceCommandWidgetControls; + // setup GUI widgets + m_Controls->setupUi(parent); + } + + //connect slots with signals + CreateConnections(); +} + +void QmitkIGTLDeviceCommandWidget::CreateConnections() +{ + if (m_Controls) + { + // connect the widget items with the methods + connect( m_Controls->butSendCommand, SIGNAL(clicked()), + this, SLOT(OnSendCommand())); + connect( m_Controls->commandsComboBox, + SIGNAL(currentIndexChanged(const QString &)), + this, SLOT(OnCommandChanged(const QString &))); + } +} + + +void QmitkIGTLDeviceCommandWidget::OnDeviceStateChanged() +{ + this->AdaptGUIToState(); +} + +void QmitkIGTLDeviceCommandWidget::AdaptGUIToState() +{ + if (this->m_IGTLDevice.IsNotNull()) + { + //check the state of the device + mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); + + switch (state) { + case mitk::IGTLDevice::Setup: + this->m_Controls->commandsComboBox->setEnabled(false); + this->m_Controls->butSendCommand->setEnabled(false); + this->m_Controls->fpsSpinBox->setEnabled(false); + break; + case mitk::IGTLDevice::Ready: + this->m_Controls->commandsComboBox->setEnabled(true); + this->m_Controls->butSendCommand->setEnabled(true); + this->m_Controls->fpsSpinBox->setEnabled(false); + break; + case mitk::IGTLDevice::Running: + if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) + { + //just a server can run and have 0 connections + this->m_Controls->butSendCommand->setEnabled(false); + this->m_Controls->fpsSpinBox->setEnabled(false); + this->m_Controls->commandsComboBox->setEnabled(false); + } + else + { + this->m_Controls->commandsComboBox->setEnabled(true); + this->m_Controls->butSendCommand->setEnabled(true); + // this->m_Controls->fpsSpinBox->setEnabled(true); + } + break; + default: + mitkThrow() << "Invalid Device State"; + break; + } + } + else + { + this->DisableSourceControls(); + } +} + +void QmitkIGTLDeviceCommandWidget::Initialize(mitk::IGTLDevice::Pointer device) +{ + //reset the GUI + DisableSourceControls(); + //reset the observers + if ( this->m_IGTLDevice.IsNotNull() ) + { + this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); + } + + if(device.IsNotNull()) + { + //get the device + this->m_IGTLDevice = device; + + //check if the device is a server or a client + if ( dynamic_cast( + this->m_IGTLDevice.GetPointer()) == NULL ) + { + m_IsClient = false; + } + else + { + m_IsClient = true; + } + + typedef itk::SimpleMemberCommand< QmitkIGTLDeviceCommandWidget > CurCommandType; +// CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); +// messageReceivedCommand->SetCallbackFunction( +// this, &QmitkIGTLDeviceCommandWidget::OnMessageReceived ); +// this->m_MessageReceivedObserverTag = +// this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); + +// CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); +// commandReceivedCommand->SetCallbackFunction( +// this, &QmitkIGTLDeviceCommandWidget::OnCommandReceived ); +// this->m_CommandReceivedObserverTag = +// this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); + + CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); + connectionLostCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceCommandWidget::OnLostConnection ); + this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( + mitk::LostConnectionEvent(), connectionLostCommand); + + CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); + newConnectionCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceCommandWidget::OnNewConnection ); + this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( + mitk::NewClientConnectionEvent(), newConnectionCommand); + + CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); + stateModifiedCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceCommandWidget::OnDeviceStateChanged ); + this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( + itk::ModifiedEvent(), stateModifiedCommand); + + //Fill the commands combo box with all available commands + FillCommandsComboBox(); + } + else + { + m_IGTLDevice = NULL; + } + + this->AdaptGUIToState(); +} + +void QmitkIGTLDeviceCommandWidget::DisableSourceControls() +{ + this->m_Controls->commandsComboBox->setEnabled(false); + this->m_Controls->butSendCommand->setEnabled(false); + this->m_Controls->fpsSpinBox->setEnabled(false); +} + + + + +void QmitkIGTLDeviceCommandWidget::OnSendCommand() +{ + //Set the frames per second of the current command in case of a STT_ command + if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_BIND" ) == 0 ) + { + ((igtl::StartBindMessage*)this->m_CurrentCommand.GetPointer())-> + SetResolution(this->m_Controls->fpsSpinBox->value()); + } + else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_QTDATA" ) == 0 ) + { + ((igtl::StartQuaternionTrackingDataMessage*)m_CurrentCommand.GetPointer())-> + SetResolution(this->m_Controls->fpsSpinBox->value()); + } + else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_TDATA" ) == 0 ) + { + ((igtl::StartTrackingDataMessage*)this->m_CurrentCommand.GetPointer())-> + SetResolution(this->m_Controls->fpsSpinBox->value()); + } + + m_IGTLDevice->SendMessage(m_CurrentCommand.GetPointer()); +} + +void QmitkIGTLDeviceCommandWidget::OnCommandChanged( + const QString & curCommand) +{ + if ( curCommand.isEmpty() ) + return; + + mitk::IGTLMessageFactory::Pointer msgFactory = + this->m_IGTLDevice->GetMessageFactory(); + //create a new message that fits to the selected get message type command + this->m_CurrentCommand = msgFactory->CreateInstance( curCommand.toStdString()); + //enable/disable the FPS spinbox + this->m_Controls->fpsSpinBox->setEnabled(curCommand.contains("STT_")); +} + +void QmitkIGTLDeviceCommandWidget::OnLostConnection() +{ + //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + + this->AdaptGUIToState(); +} + +void QmitkIGTLDeviceCommandWidget::OnNewConnection() +{ + this->AdaptGUIToState(); +} + +void QmitkIGTLDeviceCommandWidget::FillCommandsComboBox() +{ + //load the msg factory from the client (maybe this will be moved later on) + mitk::IGTLMessageFactory::Pointer msgFactory = + this->m_IGTLDevice->GetMessageFactory(); + //get the available commands as std::list + std::list commandsList_ = + msgFactory->GetAvailableMessageRequestTypes(); + //create a string list to convert the std::list + this->m_Controls->commandsComboBox->clear(); + while ( commandsList_.size() ) + { + //fill the combo box with life + this->m_Controls->commandsComboBox->addItem( + QString::fromStdString(commandsList_.front())); + commandsList_.pop_front(); + } +} diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.h new file mode 100644 index 0000000000..b3aa6317ad --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.h @@ -0,0 +1,132 @@ +/*=================================================================== + +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 QMITKIGTLDeviceCommandWIDGET_H +#define QMITKIGTLDeviceCommandWIDGET_H + +//QT headers +#include +#include + +//mitk headers +#include "MitkOpenIGTLinkUIExports.h" +#include "mitkIGTLDeviceSource.h" +#include "mitkIGTLClient.h" +#include "mitkDataStorage.h" + +//itk +#include + +//ui header +#include "ui_QmitkIGTLDeviceCommandWidgetControls.h" + + /** Documentation: + * \brief An object of this class offers an UI to send OpenIGTLink commands. + * + * + * \ingroup OpenIGTLinkUI + */ +class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLDeviceCommandWidget : public QWidget +{ + Q_OBJECT + + public: + static const std::string VIEW_ID; + + /** + * \brief Initializes the widget with the given device. + * + * The old device is + * dropped, so be careful, if the source is not saved somewhere else it might + * be lost. You might want to ask the user if he wants to save the changes + * before calling this method. + * \param device The widget will be initialized corresponding to the state of + * this device. + */ + void Initialize(mitk::IGTLDevice::Pointer device); + + QmitkIGTLDeviceCommandWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + ~QmitkIGTLDeviceCommandWidget(); + + /** + * \brief Is called when the current device received a message + */ + void OnMessageReceived(); + + /** + * \brief Is called when the current device received a command + */ + void OnCommandReceived(); + + /** + * \brief Is called when the current device lost a connection to one of its + * sockets + */ + void OnLostConnection(); + + /** + * \brief Is called when the current device connected to another device + */ + void OnNewConnection(); + + + protected slots: + void OnCommandChanged(const QString& curCommand); + + void OnSendCommand(); + + protected: + + /** + * \brief Adapts the GUI to the state of the device + */ + void AdaptGUIToState(); + + /** + * \brief Calls AdaptGUIToState() + */ + void OnDeviceStateChanged(); + + /// \brief Fills the commands combo box with available commands + void FillCommandsComboBox(); + + /// \brief Creation of the connections + virtual void CreateConnections(); + + virtual void CreateQtPartControl(QWidget *parent); + + Ui::QmitkIGTLDeviceCommandWidgetControls* m_Controls; + + /** @brief holds the OpenIGTLink device */ + mitk::IGTLDevice::Pointer m_IGTLDevice; + + igtl::MessageBase::Pointer m_CurrentCommand; + + + /** @brief flag to indicate if the IGTL device is a client or a server */ + bool m_IsClient; + + unsigned long m_MessageReceivedObserverTag; + unsigned long m_CommandReceivedObserverTag; + unsigned long m_LostConnectionObserverTag; + unsigned long m_NewConnectionObserverTag; + unsigned long m_StateModifiedObserverTag; + + //############## private help methods ####################### + void DisableSourceControls(); + void EnableSourceControls(); +}; +#endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidgetControls.ui b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidgetControls.ui new file mode 100644 index 0000000000..c9959071ab --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidgetControls.ui @@ -0,0 +1,83 @@ + + + QmitkIGTLDeviceCommandWidgetControls + + + + 0 + 0 + 443 + 80 + + + + Form + + + + + + + + false + + + Choose Command Message Type + + + + + + + + 0 + 0 + + + + Frames per second + + + FPS: + + + + + + + false + + + + 0 + 0 + + + + Set the frames per second of the stream + + + 10 + + + + + + + + + false + + + Send the command + + + Send Command + + + + + + + + diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp new file mode 100644 index 0000000000..e5c130a026 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp @@ -0,0 +1,363 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkIGTLDeviceSetupConnectionWidget.h" + +//mitk headers +#include +#include +#include +#include + +//qt headers +#include +#include +#include +#include + +//igtl +#include +#include +#include +#include + +//poco headers +#include + +const std::string QmitkIGTLDeviceSetupConnectionWidget::VIEW_ID = + "org.mitk.views.igtldevicesetupconnectionwidget"; + +QmitkIGTLDeviceSetupConnectionWidget::QmitkIGTLDeviceSetupConnectionWidget( + QWidget* parent, Qt::WindowFlags f) + : QWidget(parent, f), m_IsClient(false) +{ + m_Controls = NULL; + this->m_IGTLDevice = NULL; + CreateQtPartControl(this); +} + + +QmitkIGTLDeviceSetupConnectionWidget::~QmitkIGTLDeviceSetupConnectionWidget() +{ +} + +void QmitkIGTLDeviceSetupConnectionWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkIGTLDeviceSetupConnectionWidgetControls; + // setup GUI widgets + m_Controls->setupUi(parent); + } + + // set the validator for the ip edit box (values must be between 0 and 255 and + // there are four of them, seperated with a point + QRegExpValidator *v = new QRegExpValidator(this); + QRegExp rx("((1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})\\.){3,3}(1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})"); + v->setRegExp(rx); + m_Controls->editIP->setValidator(v); + // set the validator for the port edit box (values must be between 1 and 65535) + m_Controls->editPort->setValidator(new QIntValidator(1, 65535, this)); + + //connect slots with signals + CreateConnections(); +} + +void QmitkIGTLDeviceSetupConnectionWidget::CreateConnections() +{ + if (m_Controls) + { + // connect the widget items with the methods + connect( m_Controls->butConnect, SIGNAL(clicked()), + this, SLOT(OnConnect())); + connect( m_Controls->editPort, SIGNAL(editingFinished()), + this, SLOT(OnPortChanged()) ); + connect( m_Controls->editIP, SIGNAL(editingFinished()), + this, SLOT(OnHostnameChanged()) ); + connect( m_Controls->bufferMsgCheckBox, SIGNAL(stateChanged(int)), + this, SLOT(OnBufferIncomingMessages(int))); + } +} + +void QmitkIGTLDeviceSetupConnectionWidget::OnDeviceStateChanged() +{ + this->AdaptGUIToState(); +} + +void QmitkIGTLDeviceSetupConnectionWidget::AdaptGUIToState() +{ + //check the validity of the device + if ( this->m_IGTLDevice.IsNull() ) + { + return; + } + + //check the state of the device + mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); + + switch (state) { + case mitk::IGTLDevice::Setup: + if ( !m_IsClient ) + { + m_Controls->butConnect->setText("Go Online"); + this->m_Controls->editIP->setEnabled(false); + } + else + { + m_Controls->butConnect->setText("Connect"); + this->m_Controls->editIP->setEnabled(true); + } + this->m_Controls->editPort->setEnabled(true); + this->m_Controls->logSendReceiveMsg->setEnabled(false); + this->m_Controls->bufferMsgCheckBox->setEnabled(false); + this->m_Controls->butConnect->setEnabled(true); + break; + case mitk::IGTLDevice::Ready: + this->m_Controls->butConnect->setText("Disconnect"); + this->m_Controls->editIP->setEnabled(false); + this->m_Controls->editPort->setEnabled(false); + this->m_Controls->logSendReceiveMsg->setEnabled(true); + this->m_Controls->bufferMsgCheckBox->setEnabled(true); + this->m_Controls->butConnect->setEnabled(true); + break; + case mitk::IGTLDevice::Running: + this->m_Controls->butConnect->setText("Disconnect"); + this->m_Controls->editIP->setEnabled(false); + this->m_Controls->editPort->setEnabled(false); + this->m_Controls->logSendReceiveMsg->setEnabled(true); + this->m_Controls->bufferMsgCheckBox->setEnabled(true); + this->m_Controls->butConnect->setEnabled(true); + break; + default: + mitkThrow() << "Invalid Device State"; + break; + } +} + +void QmitkIGTLDeviceSetupConnectionWidget::Initialize( + mitk::IGTLDevice::Pointer device) +{ + //reset the GUI + DisableSourceControls(); + //reset the observers + if ( this->m_IGTLDevice.IsNotNull() ) + { + this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); + } + + if(device.IsNotNull()) + { + this->m_IGTLDevice = device; + + //check if the device is a server or a client + if ( dynamic_cast( + this->m_IGTLDevice.GetPointer()) == NULL ) + { + m_IsClient = false; + } + else + { + m_IsClient = true; + } + + this->AdaptGUIToState(); + + typedef itk::SimpleMemberCommand< QmitkIGTLDeviceSetupConnectionWidget > CurCommandType; + CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); + messageReceivedCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived ); + this->m_MessageReceivedObserverTag = this->m_IGTLDevice->AddObserver( + mitk::MessageReceivedEvent(), messageReceivedCommand); + + CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); + commandReceivedCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSetupConnectionWidget::OnCommandReceived ); + this->m_CommandReceivedObserverTag = this->m_IGTLDevice->AddObserver( + mitk::CommandReceivedEvent(), commandReceivedCommand); + + CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); + connectionLostCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSetupConnectionWidget::OnLostConnection ); + this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( + mitk::LostConnectionEvent(), connectionLostCommand); + + CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); + newConnectionCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSetupConnectionWidget::OnNewConnection ); + this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( + mitk::NewClientConnectionEvent(), newConnectionCommand); + + CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); + stateModifiedCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSetupConnectionWidget::OnDeviceStateChanged ); + this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( + itk::ModifiedEvent(), stateModifiedCommand); + } + else + { + m_IGTLDevice = NULL; + } +} + +void QmitkIGTLDeviceSetupConnectionWidget::DisableSourceControls() +{ + m_Controls->editIP->setEnabled(false); + m_Controls->editPort->setEnabled(false); + m_Controls->butConnect->setEnabled(false); + m_Controls->bufferMsgCheckBox->setEnabled(false); + m_Controls->logSendReceiveMsg->setEnabled(false); +} + +void QmitkIGTLDeviceSetupConnectionWidget::OnConnect() +{ + if(m_Controls->butConnect->text() == "Connect" || + m_Controls->butConnect->text() == "Go Online" ) + { + QString port = m_Controls->editPort->text(); + m_IGTLDevice->SetPortNumber(port.toInt()); + std::string hostname = m_Controls->editIP->text().toStdString(); + m_IGTLDevice->SetHostname(hostname); + //connect with the other OpenIGTLink device => changes the state from Setup + //to Ready + if ( m_IGTLDevice->OpenConnection() ) + { + //starts the communication thread => changes the state from Ready to + //Running + if ( m_IGTLDevice->StartCommunication() ) + { + if ( this->m_IsClient ) + { + MITK_INFO("IGTLDeviceSourceManagementWidget") + << "Successfully connected to " << hostname + << " on port " << port.toStdString(); + } + } + else + { + MITK_ERROR("QmitkIGTLDeviceSetupConnectionWidget") << + "Could not start a communication with the" + "server because the client is in the wrong state"; + } + } + else + { + MITK_ERROR("QmitkIGTLDeviceSetupConnectionWidget") << + "Could not connect to the server. " + "Please check the hostname and port."; + } + } + else + { + m_IGTLDevice->CloseConnection(); + MITK_INFO("QmitkIGTLDeviceSetupConnectionWidget") << "Closed connection"; + } + this->AdaptGUIToState(); +} + + +void QmitkIGTLDeviceSetupConnectionWidget::OnPortChanged() +{ + +} + + +void QmitkIGTLDeviceSetupConnectionWidget::OnHostnameChanged() +{ + +} + +void QmitkIGTLDeviceSetupConnectionWidget::OnLostConnection() +{ + //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + + this->AdaptGUIToState(); + +// unsigned int numConnections = dev->GetNumberOfConnections(); + +// if ( numConnections == 0 ) +// { +// if ( this->m_IsClient ) +// { +// //Setup connection groupbox +// m_Controls->editIP->setEnabled(true); +// m_Controls->editPort->setEnabled(true); +// m_Controls->butConnect->setText("Connect"); +// m_Controls->logSendReceiveMsg->setEnabled(false); +// m_Controls->bufferMsgCheckBox->setEnabled(false); +// } +// } +} + +void QmitkIGTLDeviceSetupConnectionWidget::OnNewConnection() +{ + this->AdaptGUIToState(); + + //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + +// unsigned int numConnections = dev->GetNumberOfConnections(); + +// if ( numConnections != 0 ) +// { +// //Setup connection groupbox +// m_Controls->editIP->setEnabled(false); +// m_Controls->editPort->setEnabled(false); +// m_Controls->butConnect->setText("Disconnect"); +// m_Controls->logSendReceiveMsg->setEnabled(true); +// m_Controls->bufferMsgCheckBox->setEnabled(true); +// } +} + +void QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived() +{ +// //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + + if ( this->m_Controls->logSendReceiveMsg->isChecked() ) + { + MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a message: " + << this->m_IGTLDevice->GetReceiveQueue()->GetLatestMsgInformationString(); + } +} + +void QmitkIGTLDeviceSetupConnectionWidget::OnCommandReceived() +{ +// //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + + if ( this->m_Controls->logSendReceiveMsg->isChecked() ) + { + MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a command: " + << this->m_IGTLDevice->GetCommandQueue()->GetLatestMsgInformationString(); + } +} + + + +void QmitkIGTLDeviceSetupConnectionWidget::OnBufferIncomingMessages(int state) +{ + if ( this->m_IGTLDevice ) + { + this->m_IGTLDevice->EnableInfiniteBufferingMode( + this->m_IGTLDevice->GetReceiveQueue(), (bool)state); + } +} diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.h new file mode 100644 index 0000000000..488322ea94 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.h @@ -0,0 +1,142 @@ +/*=================================================================== + +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 QmitkIGTLDeviceSetupConnectionWidget_H +#define QmitkIGTLDeviceSetupConnectionWidget_H + +//QT headers +#include +#include + +//mitk headers +#include "MitkOpenIGTLinkUIExports.h" +#include "mitkIGTLDeviceSource.h" +#include "mitkIGTLClient.h" +#include "mitkDataStorage.h" + +//itk +#include + +//ui header +#include "ui_QmitkIGTLDeviceSetupConnectionWidgetControls.h" + + /** Documentation: + * \brief An object of this class offers an UI to setup the connection of an + * OpenIGTLink device. + * + * + * \ingroup OpenIGTLinkUI + */ +class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLDeviceSetupConnectionWidget : public QWidget +{ + Q_OBJECT + + public: + static const std::string VIEW_ID; + + /** + * \brief Initializes the widget with the given device. + * + * The old device is + * dropped, so be careful, if the source is not saved somewhere else it might + * be lost. You might want to ask the user if he wants to save the changes + * before calling this method. + * \param device The widget will be initialized corresponding to the state of + * this device. + */ + void Initialize(mitk::IGTLDevice::Pointer device); + + QmitkIGTLDeviceSetupConnectionWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + ~QmitkIGTLDeviceSetupConnectionWidget(); + +// /** +// * \brief Is called when the current device received a message +// */ +// void OnMessageReceived(itk::Object* caller, const itk::EventObject&); + +// /** +// * \brief Is called when the current device received a command +// */ +// void OnCommandReceived(itk::Object* caller, const itk::EventObject&); + + /** + * \brief Is called when the current device lost a connection to one of its + * sockets + */ + void OnLostConnection(); + + /** + * \brief Is called when the current device connected to another device + */ + void OnNewConnection(); + + /** + * \brief Is called when the current device received a message + */ + void OnMessageReceived(); + + /** + * \brief Is called when the current device received a command + */ + void OnCommandReceived(); + + protected slots: + + void OnConnect(); + void OnPortChanged(); + void OnHostnameChanged(); + + /** + * \brief Enables/Disables the buffering of incoming messages + */ + void OnBufferIncomingMessages(int state); + + protected: + + /** + * \brief Adapts the GUI to the state of the device + */ + void AdaptGUIToState(); + + /** + * \brief Calls AdaptGUIToState() + */ + void OnDeviceStateChanged(); + + /** \brief Creation of the connections */ + virtual void CreateConnections(); + + virtual void CreateQtPartControl(QWidget *parent); + + Ui::QmitkIGTLDeviceSetupConnectionWidgetControls* m_Controls; + + /** @brief holds the OpenIGTLink device */ + mitk::IGTLDevice::Pointer m_IGTLDevice; + + /** @brief flag to indicate if the IGTL device is a client or a server */ + bool m_IsClient; + + unsigned long m_MessageReceivedObserverTag; + unsigned long m_CommandReceivedObserverTag; + unsigned long m_LostConnectionObserverTag; + unsigned long m_NewConnectionObserverTag; + unsigned long m_StateModifiedObserverTag; + + //############## private help methods ####################### + void DisableSourceControls(); +// void EnableSourceControls(); +}; +#endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidgetControls.ui b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidgetControls.ui new file mode 100644 index 0000000000..ab9774356a --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidgetControls.ui @@ -0,0 +1,137 @@ + + + QmitkIGTLDeviceSetupConnectionWidgetControls + + + + 0 + 0 + 443 + 169 + + + + Form + + + + + + false + + + Connect with the host/Start server + + + Connect + + + false + + + false + + + false + + + false + + + false + + + + + + + false + + + Enable this checkbox to log the send and receive message events + + + Log Send and Receive Messages + + + + + + + + + Port + + + + + + + Server-IP + + + + + + + false + + + Enter the port number of the host + + + 18944 + + + 5 + + + true + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Port + + + + + + + false + + + Enter the IP address of the host + + + 127.0.0.1 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + false + + + If this checkbox is set the device stores all incoming messages in the queue. If it is not set it always overwrites the current value. + + + Buffer Incoming Messages + + + true + + + + + + + + diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp new file mode 100644 index 0000000000..7fdd56d625 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp @@ -0,0 +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. + +===================================================================*/ + +#include "QmitkIGTLDeviceSourceManagementWidget.h" + +//mitk headers +#include +#include +#include +#include + +//qt headers +#include +#include +#include +#include + +//igtl +#include +#include +#include +#include + +//poco headers +#include + +const std::string QmitkIGTLDeviceSourceManagementWidget::VIEW_ID = + "org.mitk.views.igtldevicesourcemanagementwidget"; + +QmitkIGTLDeviceSourceManagementWidget::QmitkIGTLDeviceSourceManagementWidget( + QWidget* parent, Qt::WindowFlags f) + : QWidget(parent, f), m_IsClient(false) +{ + m_Controls = NULL; + this->m_IGTLDevice = NULL; + CreateQtPartControl(this); +} + + +QmitkIGTLDeviceSourceManagementWidget::~QmitkIGTLDeviceSourceManagementWidget() +{ +} + +void QmitkIGTLDeviceSourceManagementWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkIGTLDeviceSourceManagementWidgetControls; + // setup GUI widgets + m_Controls->setupUi(parent); + } + + //connect slots with signals + CreateConnections(); +} + +void QmitkIGTLDeviceSourceManagementWidget::CreateConnections() +{ + if (m_Controls) + { + connect( m_Controls->butSend, SIGNAL(clicked()), + this, SLOT(OnSendMessage())); + } +} + +void QmitkIGTLDeviceSourceManagementWidget::OnDeviceStateChanged() +{ + this->AdaptGUIToState(); +} + +void QmitkIGTLDeviceSourceManagementWidget::AdaptGUIToState() +{ + if (this->m_IGTLDeviceSource.IsNotNull()) + { + //check the state of the device + mitk::IGTLDevice::IGTLDeviceState state = + this->m_IGTLDeviceSource->GetIGTLDevice()->GetState(); + + switch (state) { + case mitk::IGTLDevice::Setup: + this->m_Controls->editSend->setEnabled(false); + this->m_Controls->butSend->setEnabled(false); + break; + case mitk::IGTLDevice::Ready: + this->m_Controls->editSend->setEnabled(false); + this->m_Controls->butSend->setEnabled(false); + break; + case mitk::IGTLDevice::Running: + if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) + { + //just a server can run and have 0 connections + this->m_Controls->editSend->setEnabled(false); + this->m_Controls->butSend->setEnabled(false); + } + else + { + this->m_Controls->editSend->setEnabled(true); + this->m_Controls->butSend->setEnabled(true); + } + break; + default: + mitkThrow() << "Invalid Device State"; + break; + } + m_Controls->selectedSourceLabel->setText( + m_IGTLDeviceSource->GetName().c_str()); + } + else + { + this->DisableSourceControls(); + } +} + +void QmitkIGTLDeviceSourceManagementWidget::LoadSource( + mitk::IGTLDeviceSource::Pointer sourceToLoad) +{ + //reset the GUI + DisableSourceControls(); + //reset the observers + if ( this->m_IGTLDevice.IsNotNull() ) + { + this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); + } + + if(sourceToLoad.IsNotNull()) + { + this->m_IGTLDeviceSource = sourceToLoad; + + //get the device + this->m_IGTLDevice = this->m_IGTLDeviceSource->GetIGTLDevice(); + + //initialize the other GUI elements + this->m_Controls->connectionSetupWidget->Initialize(this->m_IGTLDevice); + this->m_Controls->commandWidget->Initialize(this->m_IGTLDevice); + + //check if the device is a server or a client + if ( dynamic_cast( + this->m_IGTLDeviceSource->GetIGTLDevice()) == NULL ) + { + m_IsClient = false; + } + else + { + m_IsClient = true; + } + + typedef itk::SimpleMemberCommand< QmitkIGTLDeviceSourceManagementWidget > CurCommandType; + CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); + messageReceivedCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived ); + this->m_MessageReceivedObserverTag = + this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); + + CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); + commandReceivedCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived ); + this->m_CommandReceivedObserverTag = + this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); + + CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); + connectionLostCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSourceManagementWidget::OnLostConnection ); + this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( + mitk::LostConnectionEvent(), connectionLostCommand); + + CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); + newConnectionCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSourceManagementWidget::OnNewConnection ); + this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( + mitk::NewClientConnectionEvent(), newConnectionCommand); + + CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); + stateModifiedCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSourceManagementWidget::OnDeviceStateChanged ); + this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( + itk::ModifiedEvent(), stateModifiedCommand); + } + else + { + m_IGTLDeviceSource = NULL; + } + this->AdaptGUIToState(); +} + +void QmitkIGTLDeviceSourceManagementWidget::DisableSourceControls() +{ + m_Controls->selectedSourceLabel->setText(""); + m_Controls->editSend->setEnabled(false); + m_Controls->butSend->setEnabled(false); +} + + +void QmitkIGTLDeviceSourceManagementWidget::OnSendMessage() +{ + std::string toBeSend = m_Controls->editSend->text().toStdString(); + + igtl::StringMessage::Pointer msg = igtl::StringMessage::New(); + msg->SetString(toBeSend); + this->m_IGTLDevice->SendMessage(msg.GetPointer()); +} + +void QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived() +{ +// //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + +// if ( this->m_Controls->logSendReceiveMsg->isChecked() ) +// { +// MITK_INFO("IGTLDeviceSourceManagementWidget") << "Received a message: " +// << dev->GetReceiveQueue()->GetLatestMsgInformationString(); +// } +} + +void QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived() +{ +// //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + +// if ( this->m_Controls->logSendReceiveMsg->isChecked() ) +// { +// MITK_INFO("IGTLDeviceSourceManagementWidget") << "Received a command: " +// << dev->GetCommandQueue()->GetLatestMsgInformationString(); +// } +} + +void QmitkIGTLDeviceSourceManagementWidget::OnLostConnection() +{ + this->AdaptGUIToState(); +// //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + +// unsigned int numConnections = dev->GetNumberOfConnections(); + +// if ( numConnections == 0 ) +// { +// if ( this->m_IsClient ) +// { +// //Setup connection groupbox +// m_Controls->editIP->setEnabled(true); +// m_Controls->editPort->setEnabled(true); +// m_Controls->butConnect->setText("Connect"); +// m_Controls->logSendReceiveMsg->setEnabled(false); +// m_Controls->bufferMsgCheckBox->setEnabled(false); +// //send string messages groupbox +// m_Controls->editSend->setEnabled(false); +// m_Controls->butSend->setEnabled(false); +// //send command messages groupbox +// m_Controls->butSendCommand->setEnabled(false); +// m_Controls->fpsSpinBox->setEnabled(false); +// m_Controls->commandsComboBox->setEnabled(false); +// } +// else +// { +// //send string messages groupbox +// m_Controls->editSend->setEnabled(false); +// m_Controls->butSend->setEnabled(false); +// //send command messages groupbox +// m_Controls->butSendCommand->setEnabled(false); +// m_Controls->fpsSpinBox->setEnabled(false); +// m_Controls->commandsComboBox->setEnabled(false); +// } +// } +} + +void QmitkIGTLDeviceSourceManagementWidget::OnNewConnection() +{ + this->AdaptGUIToState(); +// //get the IGTL device that invoked this event +// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + +// unsigned int numConnections = dev->GetNumberOfConnections(); + +// if ( numConnections != 0 ) +// { +// //Setup connection groupbox +// m_Controls->editIP->setEnabled(false); +// m_Controls->editPort->setEnabled(false); +// m_Controls->butConnect->setText("Disconnect"); +// m_Controls->logSendReceiveMsg->setEnabled(true); +// m_Controls->bufferMsgCheckBox->setEnabled(true); +// //send string messages groupbox +// m_Controls->editSend->setEnabled(true); +// m_Controls->butSend->setEnabled(true); +// //send command messages groupbox +// m_Controls->butSendCommand->setEnabled(true); +//// m_Controls->fpsSpinBox->setEnabled(false); +// m_Controls->commandsComboBox->setEnabled(true); +// } +} diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h new file mode 100644 index 0000000000..5d34e22183 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h @@ -0,0 +1,126 @@ +/*=================================================================== + +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 QMITKIGTLDeviceSourceMANAGEMENTWIDGET_H +#define QMITKIGTLDeviceSourceMANAGEMENTWIDGET_H + +//QT headers +#include +#include + +//mitk headers +#include "MitkOpenIGTLinkUIExports.h" +#include "mitkIGTLDeviceSource.h" +#include "mitkIGTLClient.h" +#include "mitkDataStorage.h" + +//itk +#include + +//ui header +#include "ui_QmitkIGTLDeviceSourceManagementWidgetControls.h" + + /** Documentation: + * \brief An object of this class offers an UI to manage OpenIGTLink Device + * Sources and OpenIGTLink Devices. + * + * + * \ingroup OpenIGTLinkUI + */ +class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLDeviceSourceManagementWidget : public QWidget +{ + Q_OBJECT + + public: + static const std::string VIEW_ID; + + /** Loads a source to the widget. The old source is dropped, so be careful, + * if the source is not saved somewhere else it might be lost. You might + * want to ask the user if he wants to save the changes before calling this + * method. + * @param sourceToLoad This source will be loaded and might be modified + * by the user. + */ + void LoadSource(mitk::IGTLDeviceSource::Pointer sourceToLoad); + + QmitkIGTLDeviceSourceManagementWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + ~QmitkIGTLDeviceSourceManagementWidget(); + + /** + * \brief Is called when the current device received a message + */ + void OnMessageReceived(); + + /** + * \brief Is called when the current device received a command + */ + void OnCommandReceived(); + + /** + * \brief Is called when the current device lost a connection to one of its + * sockets + */ + void OnLostConnection(); + + /** + * \brief Is called when the current device connected to another device + */ + void OnNewConnection(); + + + protected slots: + void OnSendMessage(); + + protected: + /** + * \brief Adapts the GUI to the state of the device + */ + void AdaptGUIToState(); + + /** + * \brief Calls AdaptGUIToState() + */ + void OnDeviceStateChanged(); + + /// \brief Fills the commands combo box with available commands + void FillCommandsComboBox(); + + /// \brief Creation of the connections + virtual void CreateConnections(); + + virtual void CreateQtPartControl(QWidget *parent); + + Ui::QmitkIGTLDeviceSourceManagementWidgetControls* m_Controls; + + /** @brief holds the OpenIGTLink device */ + mitk::IGTLDevice::Pointer m_IGTLDevice; + + /** @brief holds the IGTLDeviceSource we are working with. */ + mitk::IGTLDeviceSource::Pointer m_IGTLDeviceSource; + + /** @brief flag to indicate if the IGTL device is a client or a server */ + bool m_IsClient; + + unsigned long m_MessageReceivedObserverTag; + unsigned long m_CommandReceivedObserverTag; + unsigned long m_LostConnectionObserverTag; + unsigned long m_NewConnectionObserverTag; + unsigned long m_StateModifiedObserverTag; + + //############## private help methods ####################### + void DisableSourceControls(); +}; +#endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui new file mode 100644 index 0000000000..a848361a9a --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui @@ -0,0 +1,125 @@ + + + QmitkIGTLDeviceSourceManagementWidgetControls + + + + 0 + 0 + 443 + 781 + + + + Form + + + + + + + + The selected IGTL device source + + + Selected IGTL Device Source: + + + + + + + <none> + + + + + + + + + Setup Connection + + + + + + + + + + + + Send String Messages + + + + + + false + + + Enter the string to be sent + + + + + + + false + + + Sends a message with the given string to the connected device + + + Send String + + + + + + + + + + Send Command Messages + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkIGTLDeviceCommandWidget + QWidget +
QmitkIGTLDeviceCommandWidget.h
+ 1 +
+ + QmitkIGTLDeviceSetupConnectionWidget + QWidget +
QmitkIGTLDeviceSetupConnectionWidget.h
+ 1 +
+
+ + +
diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidget.cpp new file mode 100644 index 0000000000..13a6df754d --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidget.cpp @@ -0,0 +1,86 @@ +/*=================================================================== + +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 "QmitkIGTLDeviceSourceSelectionWidget.h" + +//mitk headers +#include +#include + + + +QmitkIGTLDeviceSourceSelectionWidget::QmitkIGTLDeviceSourceSelectionWidget(QWidget* parent, Qt::WindowFlags f) +: QWidget(parent, f) +{ + m_Controls = NULL; + CreateQtPartControl(this); +} + + +QmitkIGTLDeviceSourceSelectionWidget::~QmitkIGTLDeviceSourceSelectionWidget() +{ + +} + +void QmitkIGTLDeviceSourceSelectionWidget::CreateQtPartControl(QWidget *parent) +{ + if ( !m_Controls ) + { + // create GUI widgets + m_Controls = new Ui::QmitkIGTLDeviceSourceSelectionWidgetControls; + // setup GUI widgets + m_Controls->setupUi(parent); + } + + CreateConnections(); +} + +void QmitkIGTLDeviceSourceSelectionWidget::CreateConnections() +{ + if ( m_Controls ) + { + connect( m_Controls->m_ServiceListWidget, + SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), + this, SLOT(IGTLDeviceSourceSelected(us::ServiceReferenceU)) ); + + //initialize service list widget + std::string empty = ""; + m_Controls->m_ServiceListWidget->Initialize( + mitk::IGTLDeviceSource::US_PROPKEY_IGTLDEVICENAME,empty); + } +} + +void QmitkIGTLDeviceSourceSelectionWidget::IGTLDeviceSourceSelected(us::ServiceReferenceU s) + { + if (!s) //nothing selected + { + //reset everything + this->m_CurrentIGTLDeviceSource = NULL; + emit IGTLDeviceSourceSelected(this->m_CurrentIGTLDeviceSource); + return; + } + + // Get storage + us::ModuleContext* context = us::GetModuleContext(); + this->m_CurrentIGTLDeviceSource = + context->GetService(s); + emit IGTLDeviceSourceSelected(this->m_CurrentIGTLDeviceSource); + } + +mitk::IGTLDeviceSource::Pointer QmitkIGTLDeviceSourceSelectionWidget::GetSelectedIGTLDeviceSource() + { + return this->m_CurrentIGTLDeviceSource; + } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidget.h new file mode 100644 index 0000000000..2654465b0a --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidget.h @@ -0,0 +1,84 @@ +/*=================================================================== + +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 QmitkIGTLDeviceSourceSelectionWidget_H +#define QmitkIGTLDeviceSourceSelectionWidget_H + +//QT headers +#include + +//mitk headers +#include "MitkOpenIGTLinkUIExports.h" +#include "mitkIGTLDeviceSource.h" +//#include +//#include +#include +//ui header +#include "ui_QmitkIGTLDeviceSourceSelectionWidgetControls.h" + + + /** Documentation: + * \brief This widget allows the user to select a OpenIGTLink device source. + * + * The widget lists all OpenIGTLink device sources which are available + * as microservice via the module context. + * + * A signal is emmited whenever the device selection changes. + * + * \ingroup OpenIGTLinkUI + */ +class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLDeviceSourceSelectionWidget : public QWidget +{ + Q_OBJECT + + public: + static const std::string VIEW_ID; + + QmitkIGTLDeviceSourceSelectionWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + ~QmitkIGTLDeviceSourceSelectionWidget(); + + /** @return Returns the currently selected OpenIGTLink device source. + * Returns null if no source is selected at the moment. */ + mitk::IGTLDeviceSource::Pointer GetSelectedIGTLDeviceSource(); + + signals: + /** @brief This signal is emitted when a new OpenIGTLink device source is + * selected. + * @param source Holds the new selected OpenIGTLink device source. Is null + * if the old source is deselected and no new source is selected. + */ + void IGTLDeviceSourceSelected(mitk::IGTLDeviceSource::Pointer source); + + protected slots: + + void IGTLDeviceSourceSelected(us::ServiceReferenceU s); + + + protected: + + /// \brief Creation of the connections + virtual void CreateConnections(); + + virtual void CreateQtPartControl(QWidget *parent); + + Ui::QmitkIGTLDeviceSourceSelectionWidgetControls* m_Controls; + + mitk::IGTLDeviceSource::Pointer m_CurrentIGTLDeviceSource; + + + +}; +#endif diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidgetControls.ui similarity index 74% copy from Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui copy to Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidgetControls.ui index af246a91db..33d036f579 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceSelectionWidgetControls.ui @@ -1,40 +1,38 @@ - QmitkNavigationToolStorageSelectionWidgetControls - + QmitkIGTLDeviceSourceSelectionWidgetControls + 0 0 199 111 Form - + 0 0 QmitkServiceListWidget QListWidget
QmitkServiceListWidget.h
- - - +
diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidget.cpp new file mode 100644 index 0000000000..234992bc88 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidget.cpp @@ -0,0 +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. + +===================================================================*/ + +#include "QmitkIGTLMessageSourceSelectionWidget.h" + +//mitk headers +#include +#include + + + +QmitkIGTLMessageSourceSelectionWidget::QmitkIGTLMessageSourceSelectionWidget( + QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) +{ + m_Controls = NULL; + m_CurrentIGTLMessageSource = NULL; + CreateQtPartControl(this); +} + + +QmitkIGTLMessageSourceSelectionWidget::~QmitkIGTLMessageSourceSelectionWidget() +{ + +} + +void QmitkIGTLMessageSourceSelectionWidget::CreateQtPartControl(QWidget *parent) +{ + if ( !m_Controls ) + { + // create GUI widgets + m_Controls = new Ui::QmitkIGTLMessageSourceSelectionWidgetControls; + // setup GUI widgets + m_Controls->setupUi(parent); + } + + CreateConnections(); +} + +void QmitkIGTLMessageSourceSelectionWidget::CreateConnections() +{ + if ( m_Controls ) + { + connect( m_Controls->m_ServiceListWidget, + SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), + this, SLOT(IGTLMessageSourceSelected(us::ServiceReferenceU)) ); + + //initialize service list widget + std::string empty = ""; + m_Controls->m_ServiceListWidget->Initialize( + mitk::IGTLMessageSource::US_PROPKEY_DEVICENAME, empty); + } +} + +void QmitkIGTLMessageSourceSelectionWidget::IGTLMessageSourceSelected(us::ServiceReferenceU s) + { + if (!s) //nothing selected + { + //reset everything + this->m_CurrentIGTLMessageSource = NULL; + emit IGTLMessageSourceSelected(this->m_CurrentIGTLMessageSource); + return; + } + + // Get storage + us::ModuleContext* context = us::GetModuleContext(); + this->m_CurrentIGTLMessageSource = + context->GetService(s); + emit IGTLMessageSourceSelected(this->m_CurrentIGTLMessageSource); + } + +mitk::IGTLMessageSource::Pointer QmitkIGTLMessageSourceSelectionWidget::GetSelectedIGTLMessageSource() +{ + return this->m_CurrentIGTLMessageSource; +} diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidget.h new file mode 100644 index 0000000000..0584c17559 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidget.h @@ -0,0 +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 QmitkIGTLMessageSourceSelectionWidget_H +#define QmitkIGTLMessageSourceSelectionWidget_H + +//QT headers +#include + +//mitk headers +#include "MitkOpenIGTLinkUIExports.h" +#include "mitkIGTLMessageSource.h" + +//us +#include + +//ui header +#include "ui_QmitkIGTLMessageSourceSelectionWidgetControls.h" + + + /** Documentation: + * \brief This widget allows the user to select a OpenIGTLink message source. + * + * The widget lists all OpenIGTLink message sources which are available + * as microservice via the module context. + * + * A signal is emmited whenever the selection changes. + * + * \ingroup OpenIGTLinkUI + */ +class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLMessageSourceSelectionWidget : + public QWidget +{ + Q_OBJECT + + public: + static const std::string VIEW_ID; + + QmitkIGTLMessageSourceSelectionWidget(QWidget* parent = 0, + Qt::WindowFlags f = 0); + ~QmitkIGTLMessageSourceSelectionWidget(); + + /** @return Returns the currently selected OpenIGTLink message source. + * Returns null if no source is selected at the moment. */ + mitk::IGTLMessageSource::Pointer GetSelectedIGTLMessageSource(); + + signals: + /** @brief This signal is emitted when a new OpenIGTLink message source is + * selected. + * @param source Holds the new selected OpenIGTLink device source. Is null + * if the old source is deselected and no new source is selected. + */ + void IGTLMessageSourceSelected(mitk::IGTLMessageSource::Pointer source); + + protected slots: + + void IGTLMessageSourceSelected(us::ServiceReferenceU s); + + + protected: + + /// \brief Creation of the connections + virtual void CreateConnections(); + + virtual void CreateQtPartControl(QWidget *parent); + + Ui::QmitkIGTLMessageSourceSelectionWidgetControls* m_Controls; + + mitk::IGTLMessageSource::Pointer m_CurrentIGTLMessageSource; + + + +}; +#endif diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidgetControls.ui similarity index 74% copy from Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui copy to Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidgetControls.ui index af246a91db..ec8cc34ada 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLMessageSourceSelectionWidgetControls.ui @@ -1,40 +1,38 @@ - QmitkNavigationToolStorageSelectionWidgetControls - + QmitkIGTLMessageSourceSelectionWidgetControls + 0 0 199 111 Form - + 0 0 QmitkServiceListWidget QListWidget
QmitkServiceListWidget.h
- - - +
diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingConnector.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingConnector.cpp new file mode 100644 index 0000000000..565e56d0f4 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingConnector.cpp @@ -0,0 +1,108 @@ +/*=================================================================== + +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 "QmitkIGTLStreamingConnector.h" + +//mitk headers +#include +#include +#include +#include + +//qt headers +#include +#include +#include +#include + +//igtl +#include +#include +#include +#include + +//poco headers +//#include + +const std::string QmitkIGTLStreamingConnector::VIEW_ID = + "org.mitk.views.igtldevicesourcemanagementwidget"; + +const unsigned int +QmitkIGTLStreamingConnector::MILISECONDS_BETWEEN_FPS_CHECK = 50; + +QmitkIGTLStreamingConnector::QmitkIGTLStreamingConnector( + QObject* parent) + : QObject(parent) +{ +} + + +QmitkIGTLStreamingConnector::~QmitkIGTLStreamingConnector() +{ +} + +void QmitkIGTLStreamingConnector::Initialize( + mitk::IGTLMessageSource::Pointer msgSource, + mitk::IGTLMessageProvider::Pointer msgProvider) +{ + this->m_IGTLMessageProvider = msgProvider; + this->m_IGTLMessageSource = msgSource; + + connect(&this->m_CheckFPSTimer, SIGNAL(timeout()), + this, SLOT(OnCheckFPS())); + connect(&this->m_StreamingTimer, SIGNAL(timeout()), + this, SLOT(OnUpdateSource())); + + this->m_CheckFPSTimer.start(MILISECONDS_BETWEEN_FPS_CHECK); +} + +void QmitkIGTLStreamingConnector::OnCheckFPS() +{ + //get the fps from the source + unsigned int fps = this->m_IGTLMessageSource->GetFPS(); + + //check if the fps is set + if ( fps > 0 ) + { + if (!this->m_StreamingTimer.isActive()) + { + //it is set, so the streaming has to be started + int ms = 1.0 / (double)fps * 1000; + this->m_StreamingTimer.start( ms ); + } + } + else + { + //stop the streaming + this->m_StreamingTimer.stop(); + } +} + +void QmitkIGTLStreamingConnector::OnUpdateSource() +{ + //update the message source + this->m_IGTLMessageSource->Update(); + + //get the latest message + mitk::IGTLMessage* curMsg = this->m_IGTLMessageSource->GetOutput(); + + //check if this message is valid + if ( curMsg->IsDataValid() ) + { + //send the latest output to the message provider + this->m_IGTLMessageProvider->Send(curMsg); + } +} diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingConnector.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingConnector.h new file mode 100644 index 0000000000..9075008b72 --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingConnector.h @@ -0,0 +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 QMITKIGTLSTREAMINGCONNECTOR_H +#define QMITKIGTLSTREAMINGCONNECTOR_H + +//QT headers +#include + +//mitk headers +#include "MitkOpenIGTLinkUIExports.h" +#include "mitkIGTLMessageSource.h" +#include "mitkIGTLMessageProvider.h" + + /** Documentation: + * \brief This class is used to stream messages from a IGTL message source + * into the sending queue of a message provider. + * + * The data from the queue will be send to the requesting device. + * + * This class is just needed because of the qtimer functionality. Check also + * the MessageProvider for more information. + * + * \ingroup OpenIGTLinkUI + */ +class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLStreamingConnector : public QObject +{ + Q_OBJECT + + public: + static const std::string VIEW_ID; + + QmitkIGTLStreamingConnector(QObject* parent = 0); + ~QmitkIGTLStreamingConnector(); + + /** @brief Sets the message source that is the end of the pipeline and the + * message provider which will send the message + */ + void Initialize(mitk::IGTLMessageSource::Pointer msgSource, + mitk::IGTLMessageProvider::Pointer msgProvider); + + protected slots: + /** @brief checks the fps of the message source, if it is unequal 0 the + * streaming is started. + */ + void OnCheckFPS(); + /** @brief updates the message source and sends the latest output to the + * provider + */ + void OnUpdateSource(); + + protected: + /** @brief holds the message source that has to stream its data */ + mitk::IGTLMessageSource::Pointer m_IGTLMessageSource; + + /** @brief holds the message provider that will send the stream data from the + * source + */ + mitk::IGTLMessageProvider::Pointer m_IGTLMessageProvider; + + /** @brief the timer that is configured depending on the fps, if it is + * fired the pipeline is updated and the IGTLMessage added to the sending + * queue + */ + QTimer m_StreamingTimer; + + /** @brief Everytime this timer is fired the fps of the message source are + * checked and the streaming is started or stopped + */ + QTimer m_CheckFPSTimer; + + static const unsigned int MILISECONDS_BETWEEN_FPS_CHECK; +}; +#endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.cpp new file mode 100644 index 0000000000..f4608eb86f --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.cpp @@ -0,0 +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. + +===================================================================*/ + +#include "QmitkIGTLStreamingManagementWidget.h" + +//mitk headers +#include +#include +#include +#include + +//qt headers +#include +#include +#include +#include + +//igtl +#include +#include +#include +#include + +//poco headers +#include + +const std::string QmitkIGTLStreamingManagementWidget::VIEW_ID = + "org.mitk.views.igtldevicesourcemanagementwidget"; + +QmitkIGTLStreamingManagementWidget::QmitkIGTLStreamingManagementWidget( + QWidget* parent, Qt::WindowFlags f) + : QWidget(parent, f), m_IsClient(false) +{ + m_Controls = NULL; + this->m_IGTLDevice = NULL; + CreateQtPartControl(this); +} + + +QmitkIGTLStreamingManagementWidget::~QmitkIGTLStreamingManagementWidget() +{ +} + +void QmitkIGTLStreamingManagementWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkIGTLStreamingManagementWidgetControls; + // setup GUI widgets + m_Controls->setupUi(parent); + } + + //connect slots with signals + CreateConnections(); +} + +void QmitkIGTLStreamingManagementWidget::CreateConnections() +{ + if (m_Controls) + { + connect( (QObject*)(m_Controls->messageSourceSelectionWidget), + SIGNAL(IGTLMessageSourceSelected(mitk::IGTLMessageSource::Pointer)), + this, + SLOT(SourceSelected(mitk::IGTLMessageSource::Pointer)) ); + connect( m_Controls->startStreamPushButton, SIGNAL(clicked()), + this, SLOT(OnStartStreaming())); + connect( m_Controls->stopStreamPushButton, SIGNAL(clicked()), + this, SLOT(OnStopStreaming())); + } +} + +void QmitkIGTLStreamingManagementWidget::AdaptGUIToState() +{ + if (this->m_IGTLMsgProvider.IsNotNull()) + { + //get the state of the device + mitk::IGTLDevice::IGTLDeviceState state = + this->m_IGTLDevice->GetState(); + + switch (state) + { + case mitk::IGTLDevice::Setup: + case mitk::IGTLDevice::Ready: + m_Controls->messageSourceSelectionWidget->setEnabled(false); + m_Controls->selectedSourceLabel->setText(""); + m_Controls->startStreamPushButton->setEnabled(false); + m_Controls->selectedSourceLabel->setEnabled(false); + m_Controls->label->setEnabled(false); + m_Controls->stopStreamPushButton->setEnabled(false); + m_Controls->fpsLabel->setEnabled(false); + m_Controls->fpsSpinBox->setEnabled(false); + break; + case mitk::IGTLDevice::Running: + //check the number of connections of the device, a server can be in + //the running state even if there is no connected device, this part of + //the GUI shall just be available when there is a connection + if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) + { + m_Controls->messageSourceSelectionWidget->setEnabled(false); + m_Controls->selectedSourceLabel->setText(""); + m_Controls->startStreamPushButton->setEnabled(false); + m_Controls->selectedSourceLabel->setEnabled(false); + m_Controls->label->setEnabled(false); + m_Controls->stopStreamPushButton->setEnabled(false); + m_Controls->fpsLabel->setEnabled(false); + m_Controls->fpsSpinBox->setEnabled(false); + } + else //there is a connection + { + //check if the user already selected a source to stream + if ( this->m_IGTLMsgSource.IsNull() ) // he did not so far + { + m_Controls->messageSourceSelectionWidget->setEnabled(true); + m_Controls->selectedSourceLabel->setText(""); + m_Controls->startStreamPushButton->setEnabled(false); + m_Controls->selectedSourceLabel->setEnabled(false); + m_Controls->label->setEnabled(false); + m_Controls->stopStreamPushButton->setEnabled(false); + m_Controls->fpsLabel->setEnabled(false); + m_Controls->fpsSpinBox->setEnabled(false); + } + else //user already selected a source + { + QString nameOfSource = + QString::fromStdString(m_IGTLMsgSource->GetName()); + m_Controls->messageSourceSelectionWidget->setEnabled(true); + m_Controls->selectedSourceLabel->setText(nameOfSource); + m_Controls->selectedSourceLabel->setEnabled(true); + m_Controls->label->setEnabled(true); + + //check if the streaming is already running + if (this->m_IGTLMsgProvider->IsStreaming()) + { + m_Controls->startStreamPushButton->setEnabled(false); + m_Controls->stopStreamPushButton->setEnabled(true); + m_Controls->fpsLabel->setEnabled(false); + m_Controls->fpsSpinBox->setEnabled(false); + } + else + { + m_Controls->startStreamPushButton->setEnabled(true); + m_Controls->stopStreamPushButton->setEnabled(false); + m_Controls->fpsLabel->setEnabled(true); + m_Controls->fpsSpinBox->setEnabled(true); + } + } + } + break; + default: + mitkThrow() << "Invalid Device State"; + break; + } + } + else + { + this->DisableSourceControls(); + } +} + +void QmitkIGTLStreamingManagementWidget::LoadSource( + mitk::IGTLMessageProvider::Pointer provider) +{ + //reset the GUI + DisableSourceControls(); + + if ( provider.IsNull() ) + return; + + //reset the observers + if ( this->m_IGTLDevice.IsNotNull() ) + { +// this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); +// this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); + } + + + this->m_IGTLMsgProvider = provider; + + //get the device + this->m_IGTLDevice = this->m_IGTLMsgProvider->GetIGTLDevice(); + + //check if the device is a server or a client + if ( dynamic_cast( + this->m_IGTLDevice.GetPointer()) == NULL ) + { + m_IsClient = false; + } + else + { + m_IsClient = true; + } + + typedef itk::SimpleMemberCommand< QmitkIGTLStreamingManagementWidget > CurCommandType; +// CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); +// messageReceivedCommand->SetCallbackFunction( +// this, &QmitkIGTLStreamingManagementWidget::OnMessageReceived ); +// this->m_MessageReceivedObserverTag = +// this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); + +// CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); +// commandReceivedCommand->SetCallbackFunction( +// this, &QmitkIGTLStreamingManagementWidget::OnCommandReceived ); +// this->m_CommandReceivedObserverTag = +// this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); + + CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); + connectionLostCommand->SetCallbackFunction( + this, &QmitkIGTLStreamingManagementWidget::OnLostConnection ); + this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( + mitk::LostConnectionEvent(), connectionLostCommand); + + CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); + newConnectionCommand->SetCallbackFunction( + this, &QmitkIGTLStreamingManagementWidget::OnNewConnection ); + this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( + mitk::NewClientConnectionEvent(), newConnectionCommand); + + CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); + stateModifiedCommand->SetCallbackFunction( + this, &QmitkIGTLStreamingManagementWidget::OnDeviceStateChanged ); + this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( + itk::ModifiedEvent(), stateModifiedCommand); + + this->AdaptGUIToState(); +} + +void QmitkIGTLStreamingManagementWidget::DisableSourceControls() +{ + m_Controls->selectedSourceLabel->setText(""); + m_Controls->startStreamPushButton->setEnabled(false); + m_Controls->stopStreamPushButton->setEnabled(false); + m_Controls->fpsLabel->setEnabled(false); + m_Controls->fpsSpinBox->setEnabled(false); + m_Controls->selectedSourceLabel->setEnabled(false); + m_Controls->label->setEnabled(false); + m_Controls->messageSourceSelectionWidget->setEnabled(false); +} + +void QmitkIGTLStreamingManagementWidget::SourceSelected( + mitk::IGTLMessageSource::Pointer source) +{ + //reset everything + this->DisableSourceControls(); + + if (source.IsNotNull()) //no source selected + { + this->m_IGTLMsgSource = source; + } + + this->AdaptGUIToState(); +} + +void QmitkIGTLStreamingManagementWidget::OnStartStreaming() +{ + unsigned int fps = this->m_Controls->fpsSpinBox->value(); + this->m_IGTLMsgProvider->StartStreamingOfSource(this->m_IGTLMsgSource, fps); + this->AdaptGUIToState(); +} + +void QmitkIGTLStreamingManagementWidget::OnStopStreaming() +{ + this->m_IGTLMsgProvider->StopStreamingOfSource(this->m_IGTLMsgSource); + this->AdaptGUIToState(); +} + +void QmitkIGTLStreamingManagementWidget::OnMessageReceived() +{ +} + +void QmitkIGTLStreamingManagementWidget::OnCommandReceived() +{ +} + +void QmitkIGTLStreamingManagementWidget::OnDeviceStateChanged() +{ + this->AdaptGUIToState(); +} + +void QmitkIGTLStreamingManagementWidget::OnLostConnection() +{ + this->AdaptGUIToState(); +} + +void QmitkIGTLStreamingManagementWidget::OnNewConnection() +{ + //get the current selection and call SourceSelected which will call AdaptGUI + mitk::IGTLMessageSource::Pointer curSelSrc = + m_Controls->messageSourceSelectionWidget->GetSelectedIGTLMessageSource(); + SourceSelected(curSelSrc); +} diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.h new file mode 100644 index 0000000000..b89d5af0bb --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.h @@ -0,0 +1,135 @@ +/*=================================================================== + +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 QMITKIGTLStreamingMANAGEMENTWIDGET_H +#define QMITKIGTLStreamingMANAGEMENTWIDGET_H + +//QT headers +#include +#include + +//mitk headers +#include "MitkOpenIGTLinkUIExports.h" +#include "mitkIGTLMessageProvider.h" +#include "mitkIGTLClient.h" +#include "mitkDataStorage.h" + +//itk +#include + +//ui header +#include "ui_QmitkIGTLStreamingManagementWidgetControls.h" + + /** Documentation: + * \brief An object of this class offers an UI to manage the streaming of + * message sources. + * + * + * \ingroup OpenIGTLinkUI + */ +class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLStreamingManagementWidget : public QWidget +{ + Q_OBJECT + + public: + static const std::string VIEW_ID; + + /** Loads a provider to the widget. The old source is dropped, so be careful, + * if the source is not saved somewhere else it might be lost. You might + * want to ask the user if he wants to save the changes before calling this + * method. + * @param provider This provider will be loaded and might be modified + * by the user. + */ + void LoadSource(mitk::IGTLMessageProvider::Pointer provider); + + QmitkIGTLStreamingManagementWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + ~QmitkIGTLStreamingManagementWidget(); + + /** + * \brief Is called when the current device received a message + */ + void OnMessageReceived(); + + /** + * \brief Is called when the current device received a command + */ + void OnCommandReceived(); + + /** + * \brief Is called when the current device lost a connection to one of its + * sockets + */ + void OnLostConnection(); + + /** + * \brief Is called when the current device connected to another device + */ + void OnNewConnection(); + + + protected slots: + void OnStartStreaming(); + void OnStopStreaming(); + + /** \brief Is called when a new source is selected. + * @param source the newly selected source + */ + void SourceSelected(mitk::IGTLMessageSource::Pointer source); + + protected: + /** + * \brief Adapts the GUI to the state of the device + */ + void AdaptGUIToState(); + + /** + * \brief Calls AdaptGUIToState() + */ + void OnDeviceStateChanged(); + + /// \brief Fills the commands combo box with available commands + void FillCommandsComboBox(); + + /// \brief Creation of the connections + virtual void CreateConnections(); + + virtual void CreateQtPartControl(QWidget *parent); + + Ui::QmitkIGTLStreamingManagementWidgetControls* m_Controls; + + /** @brief holds the OpenIGTLink device */ + mitk::IGTLDevice::Pointer m_IGTLDevice; + + /** @brief holds the IGTL Message Provider that will send the stream */ + mitk::IGTLMessageProvider::Pointer m_IGTLMsgProvider; + + /** @brief holds the IGTLDeviceSource we are working with. */ + mitk::IGTLMessageSource::Pointer m_IGTLMsgSource; + + /** @brief flag to indicate if the IGTL device is a client or a server */ + bool m_IsClient; + + unsigned long m_MessageReceivedObserverTag; + unsigned long m_CommandReceivedObserverTag; + unsigned long m_LostConnectionObserverTag; + unsigned long m_NewConnectionObserverTag; + unsigned long m_StateModifiedObserverTag; + + //############## private help methods ####################### + void DisableSourceControls(); +}; +#endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidgetControls.ui b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidgetControls.ui new file mode 100644 index 0000000000..7ec546085a --- /dev/null +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidgetControls.ui @@ -0,0 +1,134 @@ + + + QmitkIGTLStreamingManagementWidgetControls + + + + 0 + 0 + 443 + 371 + + + + Form + + + + + + false + + + + + + + + + false + + + The selected IGTL device source + + + Selected IGTL Message Source: + + + + + + + false + + + <none> + + + + + + + + + + + false + + + Start Stream + + + + + + + false + + + Stop Stream + + + + + + + false + + + + 0 + 0 + + + + FPS: + + + + + + + false + + + + 0 + 0 + + + + 150 + + + 10 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkIGTLMessageSourceSelectionWidget + QTextEdit +
QmitkIGTLMessageSourceSelectionWidget.h
+
+
+ + +
diff --git a/Modules/OpenIGTLinkUI/files.cmake b/Modules/OpenIGTLinkUI/files.cmake new file mode 100644 index 0000000000..186d97d944 --- /dev/null +++ b/Modules/OpenIGTLinkUI/files.cmake @@ -0,0 +1,32 @@ +set(CPP_FILES + Qmitk/QmitkIGTLDeviceSourceSelectionWidget.cpp + Qmitk/QmitkIGTLMessageSourceSelectionWidget.cpp + Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp + Qmitk/QmitkIGTLStreamingManagementWidget.cpp + Qmitk/QmitkIGTLStreamingConnector.cpp + Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp + Qmitk/QmitkIGTLDeviceCommandWidget.cpp +) + +set(UI_FILES + Qmitk/QmitkIGTLDeviceSourceSelectionWidgetControls.ui + Qmitk/QmitkIGTLMessageSourceSelectionWidgetControls.ui + Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui + Qmitk/QmitkIGTLStreamingManagementWidgetControls.ui + Qmitk/QmitkIGTLDeviceSetupConnectionWidgetControls.ui + Qmitk/QmitkIGTLDeviceCommandWidgetControls.ui +) + +set(MOC_H_FILES + Qmitk/QmitkIGTLDeviceSourceSelectionWidget.h + Qmitk/QmitkIGTLMessageSourceSelectionWidget.h + Qmitk/QmitkIGTLDeviceSourceManagementWidget.h + Qmitk/QmitkIGTLStreamingManagementWidget.h + Qmitk/QmitkIGTLStreamingConnector.h + Qmitk/QmitkIGTLDeviceSetupConnectionWidget.h + Qmitk/QmitkIGTLDeviceCommandWidget.h +) + +set(QRC_FILES + #resources/OpenIGTLinkUI.qrc +) diff --git a/Modules/OpenIGTLinkUI/mitkIGTUIConfig.h.in b/Modules/OpenIGTLinkUI/mitkIGTUIConfig.h.in new file mode 100644 index 0000000000..17365e6892 --- /dev/null +++ b/Modules/OpenIGTLinkUI/mitkIGTUIConfig.h.in @@ -0,0 +1,4 @@ +/* + mitkIGTUIConfig.h + this file is generated. Do not change! +*/ diff --git a/Modules/OpenIGTLinkUI/resources/OpenIGTLinkUI.qrc b/Modules/OpenIGTLinkUI/resources/OpenIGTLinkUI.qrc new file mode 100644 index 0000000000..816d0858ba --- /dev/null +++ b/Modules/OpenIGTLinkUI/resources/OpenIGTLinkUI.qrc @@ -0,0 +1,19 @@ + + + + + diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index d6b37284cb..09d7e190c1 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,50 +1,51 @@ # Plug-ins must be ordered according to their dependencies set(MITK_EXT_PLUGINS org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.diffusionimaging:OFF org.mitk.simulation:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.dtiatlasapp:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF + org.mitk.gui.qt.igtlplugin:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.registration:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.simulation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF ) diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/CMakeLists.txt b/Plugins/org.mitk.gui.qt.igtlplugin/CMakeLists.txt new file mode 100644 index 0000000000..8748012389 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/CMakeLists.txt @@ -0,0 +1,8 @@ +project(org_mitk_gui_qt_igtlplugin) + +MACRO_CREATE_MITK_CTK_PLUGIN( + DEPENDS + EXPORT_DIRECTIVE IGTLPLUGIN_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkOpenIGTLink MitkOpenIGTLinkUI MitkIGT +) diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.igtlplugin/documentation/UserManual/Manual.dox new file mode 100644 index 0000000000..c94e724867 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/documentation/UserManual/Manual.dox @@ -0,0 +1,17 @@ +/** +\page org_mitk_gui_qt_igtlplugin The Igtlplugin + +\imageMacro{icon.png,"Icon of Igtlplugin",2.00} + +\tableofcontents + +\section org_mitk_gui_qt_igtlpluginOverview Overview +Describe the features of your awesome plugin here +
    +
  • Increases productivity +
  • Creates beautiful images +
  • Generates PhD thesis +
  • Brings world peace +
+ +*/ diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/documentation/UserManual/icon.xpm b/Plugins/org.mitk.gui.qt.igtlplugin/documentation/UserManual/icon.xpm new file mode 100644 index 0000000000..9057c20bc6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/documentation/UserManual/icon.xpm @@ -0,0 +1,21 @@ +/* XPM */ +static const char * icon_xpm[] = { +"16 16 2 1", +" c #FF0000", +". c #000000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.igtlplugin/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..7da567195c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/documentation/doxygen/modules.dox @@ -0,0 +1,16 @@ +/** + \defgroup org_mitk_gui_qt_igtlplugin org.mitk.gui.qt.igtlplugin + \ingroup MITKPlugins + + \brief Describe your plugin here. + +*/ + +/** + \defgroup org_mitk_gui_qt_igtlplugin_internal Internal + \ingroup org_mitk_gui_qt_igtlplugin + + \brief This subcategory includes the internal classes of the org.mitk.gui.qt.igtlplugin plugin. Other + plugins must not rely on these classes. They contain implementation details and their interface + may change at any time. We mean it. +*/ diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/files.cmake b/Plugins/org.mitk.gui.qt.igtlplugin/files.cmake new file mode 100644 index 0000000000..623ed923af --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/files.cmake @@ -0,0 +1,50 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_igtlplugin_Activator.cpp + OpenIGTLinkManager.cpp + OpenIGTLinkExample.cpp + OpenIGTLinkProviderExample.cpp +) + +set(UI_FILES + src/internal/OpenIGTLinkProviderExampleControls.ui + src/internal/OpenIGTLinkExampleControls.ui + src/internal/OpenIGTLinkManagerControls.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_gui_qt_igtlplugin_Activator.h + src/internal/OpenIGTLinkProviderExample.h + src/internal/OpenIGTLinkExample.h + src/internal/OpenIGTLinkManager.h +) + +# list of resource files which can be used by the plug-in +# system without loading the plug-ins shared library, +# for example the icon used in the menu and tabs for the +# plug-in views in the workbench +set(CACHED_RESOURCE_FILES + resources/manager.png + resources/example.png + resources/provider.png + plugin.xml +) + +# list of Qt .qrc files which contain additional resources +# specific to this plugin +set(QRC_FILES + +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.igtlplugin/manifest_headers.cmake new file mode 100644 index 0000000000..72e7125730 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "Igtlplugin") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ") +set(Plugin-ContactAddress "") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/plugin.xml b/Plugins/org.mitk.gui.qt.igtlplugin/plugin.xml new file mode 100644 index 0000000000..f34b3b1988 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/plugin.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/resources/example.png b/Plugins/org.mitk.gui.qt.igtlplugin/resources/example.png new file mode 100644 index 0000000000..7b13daf633 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.igtlplugin/resources/example.png differ diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/resources/manager.png b/Plugins/org.mitk.gui.qt.igtlplugin/resources/manager.png new file mode 100644 index 0000000000..52d18e59a2 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.igtlplugin/resources/manager.png differ diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/resources/provider.png b/Plugins/org.mitk.gui.qt.igtlplugin/resources/provider.png new file mode 100644 index 0000000000..85eef0c203 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.igtlplugin/resources/provider.png differ diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExample.cpp b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExample.cpp new file mode 100644 index 0000000000..e3767d44ff --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExample.cpp @@ -0,0 +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. + +===================================================================*/ + + +// Blueberry +#include +#include + +// Qmitk +#include "QmitkRenderWindow.h" + +// Qt +#include + +// mitk +#include +#include +#include +#include +#include + +// vtk +#include + +// +#include "OpenIGTLinkExample.h" + +//igtl +#include "igtlStringMessage.h" +#include "igtlTrackingDataMessage.h" + + +const std::string OpenIGTLinkExample::VIEW_ID = "org.mitk.views.OpenIGTLinkExample"; + +void OpenIGTLinkExample::SetFocus() +{ +} + +OpenIGTLinkExample::~OpenIGTLinkExample() +{ + this->GetDataStorage()->Remove(m_DemoNodeT1); + this->GetDataStorage()->Remove(m_DemoNodeT2); + this->GetDataStorage()->Remove(m_DemoNodeT3); +} + +void OpenIGTLinkExample::CreateQtPartControl( QWidget *parent ) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi( parent ); + + // connect the widget items with the methods + connect( m_Controls.butStart, SIGNAL(clicked()), + this, SLOT(Start()) ); + connect( &m_Timer, SIGNAL(timeout()), this, SLOT(UpdatePipeline())); + + //Setup the pipeline + this->CreatePipeline(); +} + +void OpenIGTLinkExample::CreatePipeline() +{ + //create a new OpenIGTLinkExample Client + m_IGTLClient = mitk::IGTLClient::New(); + m_IGTLClient->SetName("OIGTL Example Client Device"); + + //create a new OpenIGTLinkExample Device source + m_IGTLDeviceSource = mitk::IGTLDeviceSource::New(); + + //set the client as the source for the device source + m_IGTLDeviceSource->SetIGTLDevice(m_IGTLClient); + + m_IGTLDeviceSource->RegisterAsMicroservice(); + + //create a filter that converts OpenIGTLinkExample messages into navigation data + m_IGTLMsgToNavDataFilter = mitk::IGTLMessageToNavigationDataFilter::New(); + + //create a visualization filter + m_VisFilter = mitk::NavigationDataObjectVisualizationFilter::New(); + + //we expect a tracking data message with three tools. Since we cannot change + //the outputs at runtime we have to set it manually. + m_IGTLMsgToNavDataFilter->SetNumberOfExpectedOutputs(3); + + //connect the filters with each other + //the OpenIGTLinkExample messages will be passed to the first filter that converts + //it to navigation data, then it is passed to the visualization filter that + //will visualize the transformation + m_IGTLMsgToNavDataFilter->ConnectTo(m_IGTLDeviceSource); + m_VisFilter->ConnectTo(m_IGTLMsgToNavDataFilter); + + //create an object that will be moved respectively to the navigation data + m_DemoNodeT1 = mitk::DataNode::New(); + m_DemoNodeT1->SetName("DemoNode IGTLExmpl T1"); + m_DemoNodeT2 = mitk::DataNode::New(); + m_DemoNodeT2->SetName("DemoNode IGTLExmpl T2"); + m_DemoNodeT3 = mitk::DataNode::New(); + m_DemoNodeT3->SetName("DemoNode IGTLExmpl T3"); + + //create small sphere and use it as surface + mitk::Surface::Pointer mySphere = mitk::Surface::New(); + vtkSphereSource *vtkData = vtkSphereSource::New(); + vtkData->SetRadius(2.0f); + vtkData->SetCenter(0.0, 0.0, 0.0); + vtkData->Update(); + mySphere->SetVtkPolyData(vtkData->GetOutput()); + vtkData->Delete(); + m_DemoNodeT1->SetData(mySphere); + + mitk::Surface::Pointer mySphere2 = mySphere->Clone(); + m_DemoNodeT2->SetData(mySphere2); + mitk::Surface::Pointer mySphere3 = mySphere->Clone(); + m_DemoNodeT3->SetData(mySphere3); + + // add node to DataStorage + this->GetDataStorage()->Add(m_DemoNodeT1); + this->GetDataStorage()->Add(m_DemoNodeT2); + this->GetDataStorage()->Add(m_DemoNodeT3); + + //use this sphere as representation object + m_VisFilter->SetRepresentationObject(0, mySphere); + m_VisFilter->SetRepresentationObject(1, mySphere2); + m_VisFilter->SetRepresentationObject(2, mySphere3); +} + +void OpenIGTLinkExample::DestroyPipeline() +{ + m_VisFilter = NULL; + this->GetDataStorage()->Remove(m_DemoNodeT1); + this->GetDataStorage()->Remove(m_DemoNodeT2); + this->GetDataStorage()->Remove(m_DemoNodeT3); +} + +void OpenIGTLinkExample::Start() +{ + if ( this->m_Controls.butStart->text().contains("Start Pipeline") ) + { + m_Timer.setInterval(90); + m_Timer.start(); + this->m_Controls.butStart->setText("Stop Pipeline"); + } + else + { + m_Timer.stop(); + igtl::StopTrackingDataMessage::Pointer stopStreaming = + igtl::StopTrackingDataMessage::New(); + this->m_IGTLClient->SendMessage(stopStreaming.GetPointer()); + this->m_Controls.butStart->setText("Start Pipeline"); + } +} + +void OpenIGTLinkExample::UpdatePipeline() +{ + //update the pipeline + m_VisFilter->Update(); + + //update the boundings + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); + + //Update rendering + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExample.h b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExample.h new file mode 100644 index 0000000000..1ddedc5621 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExample.h @@ -0,0 +1,84 @@ +/*=================================================================== + +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 OpenIGTLinkExample_h +#define OpenIGTLinkExample_h + +#include + +#include + +#include "ui_OpenIGTLinkExampleControls.h" +#include "mitkIGTLClient.h" +#include "mitkIGTLServer.h" +#include "mitkIGTLDeviceSource.h" +#include "mitkNavigationDataObjectVisualizationFilter.h" +#include "mitkIGTLMessageToNavigationDataFilter.h" + +#include "qtimer.h" + +/** + \brief OpenIGTLinkExample + + \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. + + \sa QmitkAbstractView + \ingroup ${plugin_target}_internal +*/ +class OpenIGTLinkExample : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + + public: + ~OpenIGTLinkExample(); + + static const std::string VIEW_ID; + + protected slots: + + void Start(); + void UpdatePipeline(); + + + protected: + + virtual void CreateQtPartControl(QWidget *parent); + + virtual void SetFocus(); + + void CreatePipeline(); + void DestroyPipeline(); + + Ui::OpenIGTLinkExampleControls m_Controls; + mitk::IGTLClient::Pointer m_IGTLClient; + mitk::IGTLDeviceSource::Pointer m_IGTLDeviceSource; + mitk::IGTLMessageToNavigationDataFilter::Pointer m_IGTLMsgToNavDataFilter; + mitk::NavigationDataObjectVisualizationFilter::Pointer m_VisFilter; + mitk::DataNode::Pointer m_DemoNodeT1; + mitk::DataNode::Pointer m_DemoNodeT2; + mitk::DataNode::Pointer m_DemoNodeT3; + + //REMOVE LATER +// mitk::IGTLServer::Pointer m_IGTLServer; +// mitk::IGTLDeviceSource::Pointer m_IGTLDeviceSource2; + + QTimer m_Timer; +}; + +#endif // OpenIGTLinkExample_h diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExampleControls.ui b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExampleControls.ui new file mode 100644 index 0000000000..7151dd71b8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkExampleControls.ui @@ -0,0 +1,52 @@ + + + OpenIGTLinkExampleControls + + + + 0 + 0 + 668 + 392 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + + + Start Pipeline + + + + + + + Qt::Vertical + + + + 20 + 220 + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManager.cpp b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManager.cpp new file mode 100644 index 0000000000..72397c9036 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManager.cpp @@ -0,0 +1,84 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +// Blueberry +#include +#include + +// +#include "OpenIGTLinkManager.h" + + +const std::string OpenIGTLinkManager::VIEW_ID = + "org.mitk.views.openigtlinkmanager"; + +OpenIGTLinkManager::OpenIGTLinkManager() +: QmitkAbstractView() +{ +} + +OpenIGTLinkManager::~OpenIGTLinkManager() +{ + for(unsigned int i=0; i < m_AllSourcesHandledByThisWidget.size(); i++) + m_AllSourcesHandledByThisWidget.at(i)->UnRegisterMicroservice(); +} + +void OpenIGTLinkManager::SetFocus() +{ +} + +void OpenIGTLinkManager::CreateQtPartControl( QWidget *parent ) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi( parent ); + + // create GUI widgets from the Qt Designer's .ui file +// connect( (QObject*)(m_Controls.m_SourceManagerWidget), +// SIGNAL(NewSourceAdded(mitk::IGTLDeviceSource::Pointer, std::string)), +// this, +// SLOT(NewSourceByWidget(mitk::IGTLDeviceSource::Pointer,std::string)) ); + connect( (QObject*)(m_Controls.m_SourceListWidget), + SIGNAL(IGTLDeviceSourceSelected(mitk::IGTLDeviceSource::Pointer)), + this, + SLOT(SourceSelected(mitk::IGTLDeviceSource::Pointer)) ); +} + + +void OpenIGTLinkManager::NewSourceByWidget( + mitk::IGTLDeviceSource::Pointer source,std::string /*sourceName*/) +{ + source->RegisterAsMicroservice(/*sourceName*/); + m_AllSourcesHandledByThisWidget.push_back(source); +} + +void OpenIGTLinkManager::SourceSelected( + mitk::IGTLDeviceSource::Pointer source) +{ + if (source.IsNull()) //no source selected + { + //reset everything + return; + } + + this->m_Controls.m_SourceManagerWidget->LoadSource(source); + + //check if the current selected source is also a message provider + mitk::IGTLMessageProvider::Pointer msgProvider = + mitk::IGTLMessageProvider::New(); + msgProvider = dynamic_cast(source.GetPointer()); + this->m_Controls.m_StreamManagerWidget->LoadSource(msgProvider); +} diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManager.h b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManager.h new file mode 100644 index 0000000000..b82c756ccf --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManager.h @@ -0,0 +1,71 @@ +/*=================================================================== + +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 OpenIGTLinkManager_h +#define OpenIGTLinkManager_h + +#include + +#include + +#include "ui_OpenIGTLinkManagerControls.h" +#include "mitkIGTLClient.h" +#include "mitkIGTLDeviceSource.h" + +/** + \brief OpenIGTLinkManager + + \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. + + \sa QmitkAbstractView + \ingroup ${plugin_target}_internal +*/ +class OpenIGTLinkManager : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + + public: + + static const std::string VIEW_ID; + + OpenIGTLinkManager(); + virtual ~OpenIGTLinkManager(); + + public slots: + void NewSourceByWidget(mitk::IGTLDeviceSource::Pointer source, std::string); + void SourceSelected(mitk::IGTLDeviceSource::Pointer source); + + protected: + + virtual void CreateQtPartControl(QWidget *parent); + + virtual void SetFocus(); + + void CreatePipeline(); + void DestroyPipeline(); + + Ui::OpenIGTLinkManagerControls m_Controls; + + /** Someone needs to hold the smart pointers of new sources, otherwise the + * objects will be lost although they are listed as microservice. + */ + std::vector m_AllSourcesHandledByThisWidget; +}; + +#endif // OpenIGTLinkManager_h diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManagerControls.ui b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManagerControls.ui new file mode 100644 index 0000000000..fc8aeba7ed --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkManagerControls.ui @@ -0,0 +1,98 @@ + + + OpenIGTLinkManagerControls + + + + 0 + 0 + 668 + 392 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + + 12 + 75 + true + + + + Select OpenIGTLink Device Source: + + + + + + + + + + + 12 + 75 + true + + + + Manage Device: + + + + + + + + + + + 12 + 75 + true + + + + Manage Streams: + + + + + + + + + + + + QmitkIGTLDeviceSourceSelectionWidget + QTextEdit +
QmitkIGTLDeviceSourceSelectionWidget.h
+
+ + QmitkIGTLDeviceSourceManagementWidget + QWidget +
QmitkIGTLDeviceSourceManagementWidget.h
+ 1 +
+ + QmitkIGTLStreamingManagementWidget + QWidget +
QmitkIGTLStreamingManagementWidget.h
+ 1 +
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExample.cpp b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExample.cpp new file mode 100644 index 0000000000..eb9a447021 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExample.cpp @@ -0,0 +1,239 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +// Blueberry +#include +#include + +// Qmitk +#include "QmitkRenderWindow.h" + +// Qt +#include +#include + +// mitk +#include +#include +#include +#include +#include +#include + +// vtk +#include + +// +#include "OpenIGTLinkProviderExample.h" + +//igtl +#include "igtlStringMessage.h" + + +const std::string OpenIGTLinkProviderExample::VIEW_ID = + "org.mitk.views.OpenIGTLinkProviderExample"; + +OpenIGTLinkProviderExample::~OpenIGTLinkProviderExample() +{ + this->GetDataStorage()->Remove(m_DemoNodeT1); + this->GetDataStorage()->Remove(m_DemoNodeT2); + this->GetDataStorage()->Remove(m_DemoNodeT3); +} + +void OpenIGTLinkProviderExample::SetFocus() +{ +} + +void OpenIGTLinkProviderExample::CreateQtPartControl( QWidget *parent ) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi( parent ); + + // connect the widget items with the methods + connect( m_Controls.butStart, SIGNAL(clicked()), + this, SLOT(Start()) ); + connect( m_Controls.butOpenNavData, SIGNAL(clicked()), + this, SLOT(OnOpenFile()) ); + connect( &m_VisualizerTimer, SIGNAL(timeout()), + this, SLOT(UpdateVisualization())); +} + +void OpenIGTLinkProviderExample::CreatePipeline() +{ + //create a new OpenIGTLink Client + m_IGTLServer = mitk::IGTLServer::New(); + m_IGTLServer->SetName("OIGTL Provider Example Device"); + + //create a new OpenIGTLink Device source + m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); + + //set the OpenIGTLink server as the source for the device source + m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); + + //register the provider so that it can be configured with the IGTL manager + //plugin. This could be hardcoded but now I already have the fancy plugin. + m_IGTLMessageProvider->RegisterAsMicroservice(); + + //create a filter that converts navigation data into IGTL messages + m_NavDataToIGTLMsgFilter = mitk::NavigationDataToIGTLMessageFilter::New(); + + //define the operation mode for this filter, we want to send tracking data + //messages + m_NavDataToIGTLMsgFilter->SetOperationMode( + mitk::NavigationDataToIGTLMessageFilter::ModeSendTDataMsg); +// mitk::NavigationDataToIGTLMessageFilter::ModeSendTransMsg); + + //set the name of this filter to identify it easier + m_NavDataToIGTLMsgFilter->SetName("Tracking Data Source From Example"); + + //register this filter as micro service. The message provider looks for + //provided IGTLMessageSources, once it found this microservice and someone + //requested this data type then the provider will connect with this filter + //automatically (this is not implemented so far, check m_StreamingConnector + //for more information) + m_NavDataToIGTLMsgFilter->RegisterAsMicroservice(); + + //create a navigation data player object that will play nav data from a + //recorded file + m_NavDataPlayer = mitk::NavigationDataPlayer::New(); + + //set the currently read navigation data set + m_NavDataPlayer->SetNavigationDataSet(m_NavDataSet); + + //connect the filters with each other + //the navigation data player reads a file with recorded navigation data, + //passes this data to a filter that converts it into a IGTLMessage. + //The provider is not connected because it will search for fitting services. + //Once it found the filter it will automatically connect to it (this is not + // implemented so far, check m_StreamingConnector for more information). + m_NavDataToIGTLMsgFilter->ConnectTo(m_NavDataPlayer); + + //create an object that will be moved respectively to the navigation data + m_DemoNodeT1 = mitk::DataNode::New(); + m_DemoNodeT1->SetName("DemoNode IGTLProviderExmpl T1"); + m_DemoNodeT2 = mitk::DataNode::New(); + m_DemoNodeT2->SetName("DemoNode IGTLProviderExmpl T2"); + m_DemoNodeT3 = mitk::DataNode::New(); + m_DemoNodeT3->SetName("DemoNode IGTLProviderExmpl T3"); + + //create small sphere and use it as surface + mitk::Surface::Pointer mySphere = mitk::Surface::New(); + vtkSphereSource *vtkData = vtkSphereSource::New(); + vtkData->SetRadius(2.0f); + vtkData->SetCenter(0.0, 0.0, 0.0); + vtkData->Update(); + mySphere->SetVtkPolyData(vtkData->GetOutput()); + vtkData->Delete(); + m_DemoNodeT1->SetData(mySphere); + + mitk::Surface::Pointer mySphere2 = mySphere->Clone(); + m_DemoNodeT2->SetData(mySphere2); + mitk::Surface::Pointer mySphere3 = mySphere->Clone(); + m_DemoNodeT3->SetData(mySphere3); + + // add node to DataStorage + this->GetDataStorage()->Add(m_DemoNodeT1); + this->GetDataStorage()->Add(m_DemoNodeT2); + this->GetDataStorage()->Add(m_DemoNodeT3); + + //initialize the streaming connector + //the streaming connector is checking if the data from the filter has to be + //streamed. The message provider is used for sending the messages. +// m_StreamingConnector.Initialize(m_NavDataToIGTLMsgFilter.GetPointer(), +// m_IGTLMessageProvider); + + //also create a visualize filter to visualize the data + m_NavDataVisualizer = mitk::NavigationDataObjectVisualizationFilter::New(); + m_NavDataVisualizer->SetRepresentationObject(0, mySphere); + m_NavDataVisualizer->SetRepresentationObject(1, mySphere2); + m_NavDataVisualizer->SetRepresentationObject(2, mySphere3); + m_NavDataVisualizer->ConnectTo(m_NavDataPlayer); + + //start the player + this->Start(); + + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); +} + +void OpenIGTLinkProviderExample::DestroyPipeline() +{ + m_NavDataPlayer->StopPlaying(); + this->GetDataStorage()->Remove(m_DemoNodeT1); +} + +void OpenIGTLinkProviderExample::Start() +{ + if ( this->m_Controls.butStart->text().contains("Start") ) + { + m_NavDataPlayer->SetRepeat(true); + m_NavDataPlayer->StartPlaying(); + this->m_Controls.butStart->setText("Stop Playing Recorded Navigation Data "); + + //start the visualization + this->m_VisualizerTimer.start(100); + } + else + { + m_NavDataPlayer->StopPlaying(); + this->m_Controls.butStart->setText("Start Playing Recorded Navigation Data "); + + //stop the visualization + this->m_VisualizerTimer.stop(); + } +} + +void OpenIGTLinkProviderExample::OnOpenFile(){ + mitk::NavigationDataReaderXML::Pointer reader = mitk::NavigationDataReaderXML::New(); + + // FIXME Filter for correct files and use correct Reader + QString fileName = + QFileDialog::getOpenFileName(NULL, "Open Navigation Data Set", "", "XML files (*.xml)"); + if ( fileName.isNull() ) { return; } // user pressed cancel + + try + { + m_NavDataSet = reader->Read(fileName.toStdString()); + } + catch ( const mitk::Exception &e ) + { + MITK_WARN("NavigationDataPlayerView") << "could not open file " << fileName.toStdString(); + QMessageBox::critical(0, "Error Reading File", "The file '" + fileName + +"' could not be read.\n" + e.GetDescription() ); + return; + } + + this->m_Controls.butStart->setEnabled(true); + + //Setup the pipeline + this->CreatePipeline(); + + // Update Labels +// m_Controls->m_LblFilePath->setText(fileName); +// m_Controls->m_LblTools->setText(QString::number(m_NavDataSet->GetNumberOfTools())); +} + +void OpenIGTLinkProviderExample::UpdateVisualization() +{ + //update the filter + this->m_NavDataVisualizer->Update(); + + //update the bounds + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); + + //update rendering + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExample.h b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExample.h new file mode 100644 index 0000000000..edec2ae0b5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExample.h @@ -0,0 +1,85 @@ +/*=================================================================== + +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 OpenIGTLinkProviderExample_h +#define OpenIGTLinkProviderExample_h + +#include + +#include +#include + +#include "ui_OpenIGTLinkProviderExampleControls.h" +#include "mitkIGTLServer.h" +#include "mitkIGTLMessageProvider.h" +#include "mitkNavigationDataToIGTLMessageFilter.h" +#include "mitkNavigationDataPlayer.h" +#include "mitkNavigationDataObjectVisualizationFilter.h" + +#include "qtimer.h" + +/** + \brief OpenIGTLinkProviderExample + + \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. + + \sa QmitkAbstractView + \ingroup ${plugin_target}_internal +*/ +class OpenIGTLinkProviderExample : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + + public: + ~OpenIGTLinkProviderExample(); + + static const std::string VIEW_ID; + + protected slots: + + void Start(); + void OnOpenFile(); + void UpdateVisualization(); + + + protected: + + virtual void CreateQtPartControl(QWidget *parent); + + virtual void SetFocus(); + + void CreatePipeline(); + void DestroyPipeline(); + + Ui::OpenIGTLinkProviderExampleControls m_Controls; + mitk::IGTLServer::Pointer m_IGTLServer; + mitk::IGTLMessageProvider::Pointer m_IGTLMessageProvider; + mitk::NavigationDataToIGTLMessageFilter::Pointer m_NavDataToIGTLMsgFilter; + mitk::NavigationDataPlayer::Pointer m_NavDataPlayer; + mitk::NavigationDataObjectVisualizationFilter::Pointer m_NavDataVisualizer; + mitk::DataNode::Pointer m_DemoNodeT1; + mitk::DataNode::Pointer m_DemoNodeT2; + mitk::DataNode::Pointer m_DemoNodeT3; + mitk::NavigationDataSet::Pointer m_NavDataSet; + QmitkIGTLStreamingConnector m_StreamingConnector; + + QTimer m_VisualizerTimer; +}; + +#endif // OpenIGTLinkProviderExample_h diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExampleControls.ui b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExampleControls.ui new file mode 100644 index 0000000000..c1cedf25bd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/OpenIGTLinkProviderExampleControls.ui @@ -0,0 +1,62 @@ + + + OpenIGTLinkProviderExampleControls + + + + 0 + 0 + 668 + 392 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + + + Open Recorded Navigation Data + + + + + + + false + + + Start Playing Recorded Navigation Data + + + + + + + Qt::Vertical + + + + 20 + 220 + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/org_mitk_gui_qt_igtlplugin_Activator.cpp b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/org_mitk_gui_qt_igtlplugin_Activator.cpp new file mode 100644 index 0000000000..97565d5aea --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/org_mitk_gui_qt_igtlplugin_Activator.cpp @@ -0,0 +1,42 @@ +/*=================================================================== + +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 "org_mitk_gui_qt_igtlplugin_Activator.h" + +#include + +#include "OpenIGTLinkProviderExample.h" +#include "OpenIGTLinkExample.h" +#include "OpenIGTLinkManager.h" + +namespace mitk { + +void org_mitk_gui_qt_igtlplugin_Activator::start(ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(OpenIGTLinkProviderExample, context) + BERRY_REGISTER_EXTENSION_CLASS(OpenIGTLinkExample, context) + BERRY_REGISTER_EXTENSION_CLASS(OpenIGTLinkManager, context) +} + +void org_mitk_gui_qt_igtlplugin_Activator::stop(ctkPluginContext* context) +{ + Q_UNUSED(context) +} + +} + +Q_EXPORT_PLUGIN2(org_mitk_gui_qt_igtlplugin, mitk::org_mitk_gui_qt_igtlplugin_Activator) diff --git a/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/org_mitk_gui_qt_igtlplugin_Activator.h b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/org_mitk_gui_qt_igtlplugin_Activator.h new file mode 100644 index 0000000000..0dd12b6550 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/org_mitk_gui_qt_igtlplugin_Activator.h @@ -0,0 +1,40 @@ +/*=================================================================== + +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 org_mitk_gui_qt_igtlplugin_Activator_h +#define org_mitk_gui_qt_igtlplugin_Activator_h + +#include + +namespace mitk { + +class org_mitk_gui_qt_igtlplugin_Activator : + public QObject, public ctkPluginActivator +{ + Q_OBJECT + Q_INTERFACES(ctkPluginActivator) + +public: + + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + +}; // org_mitk_gui_qt_igtlplugin_Activator + +} + +#endif // org_mitk_gui_qt_igtlplugin_Activator_h diff --git a/SuperBuild.cmake b/SuperBuild.cmake index 139a52ec67..7a23cb3d22 100644 --- a/SuperBuild.cmake +++ b/SuperBuild.cmake @@ -1,492 +1,496 @@ #----------------------------------------------------------------------------- # Convenient macro allowing to download a file #----------------------------------------------------------------------------- macro(downloadFile url dest) file(DOWNLOAD ${url} ${dest} STATUS status) list(GET status 0 error_code) list(GET status 1 error_msg) if(error_code) message(FATAL_ERROR "error: Failed to download ${url} - ${error_msg}") endif() endmacro() #----------------------------------------------------------------------------- # MITK Prerequisites #----------------------------------------------------------------------------- if(UNIX AND NOT APPLE) include(mitkFunctionCheckPackageHeader) # Check for libxt-dev mitkFunctionCheckPackageHeader(StringDefs.h libxt-dev /usr/include/X11/) # Check for libtiff4-dev mitkFunctionCheckPackageHeader(tiff.h libtiff4-dev) # Check for libwrap0-dev mitkFunctionCheckPackageHeader(tcpd.h libwrap0-dev) endif() #----------------------------------------------------------------------------- # Qt options for external projects and MITK #----------------------------------------------------------------------------- if(MITK_USE_QT) set(qt_project_args -DDESIRED_QT_VERSION:STRING=${DESIRED_QT_VERSION}) else() set(qt_project_args ) endif() if(MITK_USE_Qt4) list(APPEND qt_project_args -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} ) endif() #----------------------------------------------------------------------------- # ExternalProjects #----------------------------------------------------------------------------- # These are ordered by dependencies set(external_projects ZLIB Python Numpy tinyxml GLUT ANN CppUnit GLEW VTK ACVD GDCM OpenCV Poco ITK Boost DCMTK CTK SOFA MITKData Qwt PCRE Swig SimpleITK Eigen + OpenIGTLink ) # These are "hard" dependencies and always set to ON set(MITK_USE_tinyxml 1) set(MITK_USE_GLEW 1) set(MITK_USE_GDCM 1) set(MITK_USE_ITK 1) set(MITK_USE_VTK 1) # Semi-hard dependencies, enabled by user-controlled variables if(MITK_USE_QT) set(MITK_USE_Qwt 1) endif() if(MITK_USE_SOFA) set(MITK_USE_GLUT 1) endif() if(NOT MITK_USE_SYSTEM_PYTHON) set(MITK_USE_ZLIB 1) endif() if(MITK_USE_SimpleITK OR MITK_USE_Python) set(MITK_USE_SWIG 1) if(UNIX) set(MITK_USE_PCRE 1) endif() endif() # A list of "nice" external projects, playing well together with CMake set(nice_external_projects ${external_projects}) list(REMOVE_ITEM nice_external_projects Boost) foreach(proj ${nice_external_projects}) if(MITK_USE_${proj}) set(EXTERNAL_${proj}_DIR "${${proj}_DIR}" CACHE PATH "Path to ${proj} build directory") mark_as_advanced(EXTERNAL_${proj}_DIR) if(EXTERNAL_${proj}_DIR) set(${proj}_DIR ${EXTERNAL_${proj}_DIR}) endif() endif() endforeach() if(MITK_USE_Boost) set(EXTERNAL_BOOST_ROOT "${BOOST_ROOT}" CACHE PATH "Path to Boost directory") mark_as_advanced(EXTERNAL_BOOST_ROOT) if(EXTERNAL_BOOST_ROOT) set(BOOST_ROOT ${EXTERNAL_BOOST_ROOT}) endif() endif() # Setup file for setting custom ctest vars configure_file( CMake/SuperbuildCTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) if(BUILD_TESTING) set(EXTERNAL_MITK_DATA_DIR "${MITK_DATA_DIR}" CACHE PATH "Path to the MITK data directory") mark_as_advanced(EXTERNAL_MITK_DATA_DIR) if(EXTERNAL_MITK_DATA_DIR) set(MITK_DATA_DIR ${EXTERNAL_MITK_DATA_DIR}) endif() endif() # Look for git early on, if needed if((BUILD_TESTING AND NOT EXTERNAL_MITK_DATA_DIR) OR (MITK_USE_CTK AND NOT EXTERNAL_CTK_DIR)) find_package(Git REQUIRED) endif() #----------------------------------------------------------------------------- # External project settings #----------------------------------------------------------------------------- include(ExternalProject) set(ep_base "${CMAKE_BINARY_DIR}/CMakeExternals") set_property(DIRECTORY PROPERTY EP_BASE ${ep_base}) set(ep_install_dir ${ep_base}/Install) #set(ep_build_dir ${ep_base}/Build) set(ep_source_dir ${ep_base}/Source) #set(ep_parallelism_level) set(ep_build_shared_libs ON) set(ep_build_testing OFF) if(NOT MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL) set(MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL http://mitk.org/download/thirdparty) endif() # Compute -G arg for configuring external projects with the same CMake generator: if(CMAKE_EXTRA_GENERATOR) set(gen "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}") else() set(gen "${CMAKE_GENERATOR}") endif() # Use this value where semi-colons are needed in ep_add args: set(sep "^^") ## if(MSVC_VERSION) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /bigobj /MP") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /MP") endif() set(ep_common_args -DBUILD_TESTING:BOOL=${ep_build_testing} -DCMAKE_INSTALL_PREFIX:PATH=${ep_install_dir} -DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH} -DBUILD_SHARED_LIBS:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} #debug flags -DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} -DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG} #release flags -DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE} -DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE} #relwithdebinfo -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_C_FLAGS_RELWITHDEBINFO} #link flags -DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS} ) # Pass the CMAKE_OSX variables to external projects if(APPLE) set(MAC_OSX_ARCHITECTURE_ARGS -DCMAKE_OSX_ARCHITECTURES:PATH=${CMAKE_OSX_ARCHITECTURES} -DCMAKE_OSX_DEPLOYMENT_TARGET:PATH=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT} ) set(ep_common_args ${MAC_OSX_ARCHITECTURE_ARGS} ${ep_common_args} ) endif() # Include external projects foreach(p ${external_projects}) include(CMakeExternals/${p}.cmake) endforeach() #----------------------------------------------------------------------------- # Set superbuild boolean args #----------------------------------------------------------------------------- set(mitk_cmake_boolean_args BUILD_SHARED_LIBS WITH_COVERAGE BUILD_TESTING MITK_USE_QT MITK_BUILD_ALL_PLUGINS MITK_BUILD_ALL_APPS MITK_BUILD_TUTORIAL # Deprecated. Use MITK_BUILD_EXAMPLES instead MITK_BUILD_EXAMPLES MITK_USE_ACVD MITK_USE_ANN MITK_USE_BLUEBERRY MITK_USE_Boost MITK_USE_CppUnit MITK_USE_CTK MITK_USE_DCMTK MITK_USE_Eigen MITK_USE_GLEW MITK_USE_OpenCL MITK_USE_OpenCV + MITK_USE_OpenIGTLink MITK_USE_Poco MITK_USE_Python MITK_USE_SOFA MITK_USE_SYSTEM_Boost MITK_ENABLE_PIC_READER ) #----------------------------------------------------------------------------- # Create the final variable containing superbuild boolean args #----------------------------------------------------------------------------- set(mitk_superbuild_boolean_args) foreach(mitk_cmake_arg ${mitk_cmake_boolean_args}) list(APPEND mitk_superbuild_boolean_args -D${mitk_cmake_arg}:BOOL=${${mitk_cmake_arg}}) endforeach() if(MITK_BUILD_ALL_PLUGINS) list(APPEND mitk_superbuild_boolean_args -DBLUEBERRY_BUILD_ALL_PLUGINS:BOOL=ON) endif() #----------------------------------------------------------------------------- # MITK Utilities #----------------------------------------------------------------------------- set(proj MITK-Utilities) ExternalProject_Add(${proj} DOWNLOAD_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS # Mandatory dependencies ${tinyxml_DEPENDS} ${ANN_DEPENDS} ${VTK_DEPENDS} ${ITK_DEPENDS} # Optionnal dependencies ${ACVD_DEPENDS} ${CppUnit_DEPENDS} ${Eigen_DEPENDS} ${GLUT_DEPENDS} ${GLEW_DEPENDS} ${Boost_DEPENDS} ${CTK_DEPENDS} ${DCMTK_DEPENDS} ${OpenCV_DEPENDS} + ${OpenIGTLink_DEPENDS} ${Poco_DEPENDS} ${SOFA_DEPENDS} ${MITK-Data_DEPENDS} ${Qwt_DEPENDS} ${ZLIB_DEPENDS} ${SimpleITK_DEPENDS} ${Numpy_DEPENDS} ) #----------------------------------------------------------------------------- # Additional MITK CXX/C Flags #----------------------------------------------------------------------------- set(MITK_ADDITIONAL_C_FLAGS "" CACHE STRING "Additional C Flags for MITK") set(MITK_ADDITIONAL_C_FLAGS_RELEASE "" CACHE STRING "Additional Release C Flags for MITK") set(MITK_ADDITIONAL_C_FLAGS_DEBUG "" CACHE STRING "Additional Debug C Flags for MITK") mark_as_advanced(MITK_ADDITIONAL_C_FLAGS MITK_ADDITIONAL_C_FLAGS_DEBUG MITK_ADDITIONAL_C_FLAGS_RELEASE) set(MITK_ADDITIONAL_CXX_FLAGS "" CACHE STRING "Additional CXX Flags for MITK") set(MITK_ADDITIONAL_CXX_FLAGS_RELEASE "" CACHE STRING "Additional Release CXX Flags for MITK") set(MITK_ADDITIONAL_CXX_FLAGS_DEBUG "" CACHE STRING "Additional Debug CXX Flags for MITK") mark_as_advanced(MITK_ADDITIONAL_CXX_FLAGS MITK_ADDITIONAL_CXX_FLAGS_DEBUG MITK_ADDITIONAL_CXX_FLAGS_RELEASE) set(MITK_ADDITIONAL_EXE_LINKER_FLAGS "" CACHE STRING "Additional exe linker flags for MITK") set(MITK_ADDITIONAL_SHARED_LINKER_FLAGS "" CACHE STRING "Additional shared linker flags for MITK") set(MITK_ADDITIONAL_MODULE_LINKER_FLAGS "" CACHE STRING "Additional module linker flags for MITK") mark_as_advanced(MITK_ADDITIONAL_EXE_LINKER_FLAGS MITK_ADDITIONAL_SHARED_LINKER_FLAGS MITK_ADDITIONAL_MODULE_LINKER_FLAGS) #----------------------------------------------------------------------------- # MITK Configure #----------------------------------------------------------------------------- if(MITK_INITIAL_CACHE_FILE) set(mitk_initial_cache_arg -C "${MITK_INITIAL_CACHE_FILE}") endif() set(mitk_optional_cache_args ) foreach(type RUNTIME ARCHIVE LIBRARY) if(DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY) list(APPEND mitk_optional_cache_args -DCTK_PLUGIN_${type}_OUTPUT_DIRECTORY:PATH=${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}) endif() endforeach() # Optional python variables if(MITK_USE_Python) list(APPEND mitk_optional_cache_args -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} -DMITK_USE_SYSTEM_PYTHON:BOOL=${MITK_USE_SYSTEM_PYTHON} -DMITK_BUILD_org.mitk.gui.qt.python:BOOL=ON ) if( NOT MITK_USE_SYSTEM_PYTHON ) list(APPEND mitk_optional_cache_args # Folders are needed to create an installer -DPython_DIR:PATH=${Python_DIR} -DNumpy_DIR:PATH=${Numpy_DIR} ) endif() endif() if(MITK_USE_QT) if(DESIRED_QT_VERSION MATCHES "5") list(APPEND mitk_optional_cache_args -DQT5_INSTALL_PREFIX:PATH=${QT5_INSTALL_PREFIX} ) endif() endif() set(proj MITK-Configure) ExternalProject_Add(${proj} LIST_SEPARATOR ^^ DOWNLOAD_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_CACHE_ARGS # --------------- Build options ---------------- -DBUILD_TESTING:BOOL=${ep_build_testing} -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/MITK-build/install -DBUILD_SHARED_LIBS:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} # --------------- Compile options ---------------- -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${MITK_ADDITIONAL_C_FLAGS}" "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${MITK_ADDITIONAL_CXX_FLAGS}" # debug flags "-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} ${MITK_ADDITIONAL_CXX_FLAGS_DEBUG}" "-DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG} ${MITK_ADDITIONAL_C_FLAGS_DEBUG}" # release flags "-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE} ${MITK_ADDITIONAL_CXX_FLAGS_RELEASE}" "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE} ${MITK_ADDITIONAL_C_FLAGS_RELEASE}" # relwithdebinfo -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_C_FLAGS_RELWITHDEBINFO} # link flags "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} ${MITK_ADDITIONAL_EXE_LINKER_FLAGS}" "-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} ${MITK_ADDITIONAL_SHARED_LINKER_FLAGS}" "-DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS} ${MITK_ADDITIONAL_MODULE_LINKER_FLAGS}" # Output directories -DMITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY} -DMITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY} -DMITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY} # ------------- Boolean build options -------------- ${mitk_superbuild_boolean_args} ${mitk_optional_cache_args} -DMITK_USE_SUPERBUILD:BOOL=OFF -DMITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION} -DCTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS} # ----------------- Miscellaneous --------------- -DMITK_CTEST_SCRIPT_MODE:STRING=${MITK_CTEST_SCRIPT_MODE} -DMITK_SUPERBUILD_BINARY_DIR:PATH=${MITK_BINARY_DIR} -DMITK_MODULES_TO_BUILD:INTERNAL=${MITK_MODULES_TO_BUILD} -DMITK_WHITELIST:STRING=${MITK_WHITELIST} -DMITK_WHITELISTS_EXTERNAL_PATH:STRING=${MITK_WHITELISTS_EXTERNAL_PATH} -DMITK_WHITELISTS_INTERNAL_PATH:STRING=${MITK_WHITELISTS_INTERNAL_PATH} ${qt_project_args} -DMITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES} -DMITK_ACCESSBYITK_FLOATING_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES} -DMITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES} -DMITK_ACCESSBYITK_VECTOR_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES} -DMITK_ACCESSBYITK_DIMENSIONS:STRING=${MITK_ACCESSBYITK_DIMENSIONS} # --------------- External project dirs --------------- -DCppMicroServices_DIR:PATH=${CppMicroServices_DIR} -DMITK_KWSTYLE_EXECUTABLE:FILEPATH=${MITK_KWSTYLE_EXECUTABLE} -DCTK_DIR:PATH=${CTK_DIR} -DDCMTK_DIR:PATH=${DCMTK_DIR} -DEigen_DIR:PATH=${Eigen_DIR} -Dtinyxml_DIR:PATH=${tinyxml_DIR} -DGLUT_DIR:PATH=${GLUT_DIR} -DGLEW_DIR:PATH=${GLEW_DIR} -DANN_DIR:PATH=${ANN_DIR} -DCppUnit_DIR:PATH=${CppUnit_DIR} -DVTK_DIR:PATH=${VTK_DIR} # FindVTK expects VTK_DIR -DITK_DIR:PATH=${ITK_DIR} # FindITK expects ITK_DIR -DACVD_DIR:PATH=${ACVD_DIR} -DOpenCV_DIR:PATH=${OpenCV_DIR} + -DOpenIGTLink_DIR:PATH=${OpenIGTLink_DIR} -DPoco_DIR:PATH=${Poco_DIR} -DSOFA_DIR:PATH=${SOFA_DIR} -DGDCM_DIR:PATH=${GDCM_DIR} -DBOOST_ROOT:PATH=${BOOST_ROOT} -DMITK_USE_Boost_LIBRARIES:STRING=${MITK_USE_Boost_LIBRARIES} -DMITK_DATA_DIR:PATH=${MITK_DATA_DIR} -DQwt_DIR:PATH=${Qwt_DIR} -DSimpleITK_DIR:PATH=${SimpleITK_DIR} -DNumpy_DIR:PATH=${Numpy_DIR} CMAKE_ARGS ${mitk_initial_cache_arg} ${MAC_OSX_ARCHITECTURE_ARGS} SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} BINARY_DIR ${CMAKE_BINARY_DIR}/MITK-build BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS MITK-Utilities ) #----------------------------------------------------------------------------- # MITK #----------------------------------------------------------------------------- if(CMAKE_GENERATOR MATCHES ".*Makefiles.*") set(mitk_build_cmd "$(MAKE)") else() set(mitk_build_cmd ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/MITK-build --config ${CMAKE_CFG_INTDIR}) endif() if(NOT DEFINED SUPERBUILD_EXCLUDE_MITKBUILD_TARGET OR NOT SUPERBUILD_EXCLUDE_MITKBUILD_TARGET) set(MITKBUILD_TARGET_ALL_OPTION "ALL") else() set(MITKBUILD_TARGET_ALL_OPTION "") endif() add_custom_target(MITK-build ${MITKBUILD_TARGET_ALL_OPTION} COMMAND ${mitk_build_cmd} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/MITK-build DEPENDS MITK-Configure ) #----------------------------------------------------------------------------- # Custom target allowing to drive the build of the MITK project itself #----------------------------------------------------------------------------- add_custom_target(MITK COMMAND ${mitk_build_cmd} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/MITK-build )