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 534d1bb473..faf9bb3e02 100644 --- a/CMake/mitkFunctionGetLibrarySearchPaths.cmake +++ b/CMake/mitkFunctionGetLibrarySearchPaths.cmake @@ -1,180 +1,186 @@ 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() if(REDLAND_INSTALL_DIR) list(APPEND _dir_candidates "${REDLAND_INSTALL_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() if(REDLAND_INSTALL_DIR) list(APPEND _dir_candidates "${REDLAND_INSTALL_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..f3c8dc876b --- /dev/null +++ b/CMakeExternals/OpenIGTLink.cmake @@ -0,0 +1,50 @@ +#----------------------------------------------------------------------------- +# 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() + + ExternalProject_Add(${proj} + SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src + BINARY_DIR ${proj}-build + PREFIX ${proj}-cmake + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/OpenIGTLink-54df50de.tar.gz + URL_MD5 b9fd8351b059f4ec615f2dfd74ab2458 + INSTALL_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} + 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 8d5a63225c..0a26c53eab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1094 +1,1095 @@ 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) find_package(Qt5XmlPatterns ${MITK_QT5_MINIMUM_VERSION} REQUIRED) find_package(Qt5UiTools ${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_Redland "Use the Redland RDF library" OFF) 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 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() 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..889f56ccdb --- /dev/null +++ b/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp @@ -0,0 +1,455 @@ +/*=================================================================== + +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]); + quaternion.put(3, quaternion_[3]); + 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..345fd6ddfe --- /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(this->GetNumberOfIndexedInputs()); + // set the type for this filter + this->SetType("QTDATA"); + break; + case ModeSendTDataMsg: + // create one message output for all navigation data inputs + this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); + // set the type for this filter + this->SetType("TDATA"); + break; + case ModeSendQTransMsg: + // create one message output for all navigation data input together + this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); + // set the type for this filter + this->SetType("POSITION"); + break; + case ModeSendTransMsg: + // create one message output for all navigation data input together + this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); + // 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..f83ba064dd --- /dev/null +++ b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.h @@ -0,0 +1,169 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#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 + }; + + /** + * \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/Testing/files.cmake b/Modules/IGT/Testing/files.cmake index 8a89a47489..cc77978970 100644 --- a/Modules/IGT/Testing/files.cmake +++ b/Modules/IGT/Testing/files.cmake @@ -1,64 +1,65 @@ set(MODULE_TESTS # IMPORTANT: If you plan to deactivate / comment out a test please write a bug number to the commented out line of code. # # Example: #mitkMyTest #this test is commented out because of bug 12345 # # It is important that the bug is open and that the test will be activated again before the bug is closed. This assures that # no test is forgotten after it was commented out. If there is no bug for your current problem, please add a new one and # mark it as critical. ################## ON THE FENCE TESTS ################################################# # none ################## DISABLED TESTS ##################################################### # mitkNavigationToolStorageDeserializerTest.cpp # This test was disabled because of bug 17303. # mitkNavigationToolStorageSerializerAndDeserializerIntegrationTest.cpp # This test was disabled because of bug 17181. # mitkNavigationToolStorageSerializerTest.cpp # This test was disabled because of bug 18671 ################# RUNNING TESTS ####################################################### mitkCameraVisualizationTest.cpp mitkClaronInterfaceTest.cpp mitkClaronToolTest.cpp mitkClaronTrackingDeviceTest.cpp mitkInternalTrackingToolTest.cpp mitkNavigationDataDisplacementFilterTest.cpp mitkNavigationDataLandmarkTransformFilterTest.cpp mitkNavigationDataObjectVisualizationFilterTest.cpp mitkNavigationDataSetTest.cpp mitkNavigationDataTest.cpp mitkNavigationDataRecorderTest.cpp mitkNavigationDataReferenceTransformFilterTest.cpp mitkNavigationDataSequentialPlayerTest.cpp mitkNavigationDataSetReaderWriterXMLTest.cpp mitkNavigationDataSetReaderWriterCSVTest.cpp mitkNavigationDataSourceTest.cpp mitkNavigationDataToMessageFilterTest.cpp mitkNavigationDataToNavigationDataFilterTest.cpp mitkNavigationDataToPointSetFilterTest.cpp + mitkNavigationDataToIGTLMessageFilterTest.cpp mitkNavigationDataTransformFilterTest.cpp mitkNDIPassiveToolTest.cpp mitkNDIProtocolTest.cpp mitkNDITrackingDeviceTest.cpp mitkTimeStampTest.cpp mitkTrackingVolumeGeneratorTest.cpp mitkTrackingDeviceTest.cpp mitkTrackingToolTest.cpp mitkVirtualTrackingDeviceTest.cpp # mitkNavigationDataPlayerTest.cpp # random fails see bug 16485. # We decided to won't fix because of complete restructuring via bug 15959. mitkTrackingDeviceSourceTest.cpp mitkTrackingDeviceSourceConfiguratorTest.cpp mitkNavigationDataEvaluationFilterTest.cpp mitkTrackingTypesTest.cpp # ------------------ Navigation Tool Management Tests ------------------- mitkNavigationToolStorageTest.cpp mitkNavigationToolTest.cpp mitkNavigationToolReaderAndWriterTest.cpp # ----------------------------------------------------------------------- ) set(MODULE_CUSTOM_TESTS mitkNDIAuroraHardwareTest.cpp mitkNDIPolarisHardwareTest.cpp mitkClaronTrackingDeviceHardwareTest.cpp ) diff --git a/Modules/IGT/Testing/mitkNavigationDataToIGTLMessageFilterTest.cpp b/Modules/IGT/Testing/mitkNavigationDataToIGTLMessageFilterTest.cpp new file mode 100644 index 0000000000..cb37e65683 --- /dev/null +++ b/Modules/IGT/Testing/mitkNavigationDataToIGTLMessageFilterTest.cpp @@ -0,0 +1,261 @@ +/*=================================================================== + +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 "mitkNavigationDataSequentialPlayer.h" +#include "mitkNavigationDataReaderXML.h" +#include +#include +#include +#include +#include +#include + +#include + +/** +* Simple test for the class "NavigationDataToIGTLMessageFilter". +* +* argc and argv are the command line parameters which were passed to +* the ADD_TEST command in the CMakeLists.txt file. For the automatic +* tests, argv is either empty for the simple tests or contains the filename +* of a test image for the image tests (see CMakeLists.txt). +*/ + +mitk::NavigationDataToIGTLMessageFilter::Pointer m_NavigationDataToIGTLMessageFilter; + +static void Setup() +{ + m_NavigationDataToIGTLMessageFilter = mitk::NavigationDataToIGTLMessageFilter::New(); +} + +static void SetInputs() +{ + //Build up test data + mitk::NavigationData::Pointer nd0 = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd2 = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd3 = mitk::NavigationData::New(); + + mitk::NavigationData::PositionType point0; + point0[0] = 1.0; + point0[1] = 2.0; + point0[2] = 3.0; + mitk::NavigationData::OrientationType orientation0; + orientation0.put(0, 1.0); + orientation0.put(1, 0.0); + orientation0.put(2, 0.0); + orientation0.put(3, 0.0); + nd0->SetPosition(point0); + nd0->SetOrientation(orientation0); + nd0->SetDataValid(true); + + mitk::NavigationData::PositionType point1; + point1[0] = 4.0; + point1[1] = 5.0; + point1[2] = 6.0; + mitk::NavigationData::OrientationType orientation1; + orientation1.put(0, 21.0); + orientation1.put(1, 22.0); + orientation1.put(2, 23.0); + orientation1.put(3, 24.0); + nd1->SetPosition(point1); + nd1->SetOrientation(orientation1); + nd1->SetDataValid(true); + + mitk::NavigationData::PositionType point2; + point2[0] = 7.0; + point2[1] = 8.0; + point2[2] = 9.0; + mitk::NavigationData::OrientationType orientation2; + orientation2.put(0, 31.0); + orientation2.put(1, 32.0); + orientation2.put(2, 33.0); + orientation2.put(3, 34.0); + nd2->SetPosition(point2); + nd2->SetOrientation(orientation2); + nd2->SetDataValid(true); + + mitk::NavigationData::PositionType point3; + point3[0] = 10.0; + point3[1] = 11.0; + point3[2] = 12.0; + mitk::NavigationData::OrientationType orientation3; + orientation3.put(0, 0.0); + orientation3.put(1, 0.0); + orientation3.put(2, 0.0); + orientation3.put(3, 1.0); + nd3->SetPosition(point3); + nd3->SetOrientation(orientation3); + nd3->SetDataValid(true); + + m_NavigationDataToIGTLMessageFilter->SetInput(0, nd0); + m_NavigationDataToIGTLMessageFilter->SetInput(1, nd1); + m_NavigationDataToIGTLMessageFilter->SetInput(2, nd2); + m_NavigationDataToIGTLMessageFilter->SetInput(3, nd3); +} + +static void TestModeQTransMsg() +{ + Setup(); + SetInputs(); + m_NavigationDataToIGTLMessageFilter->SetOperationMode( + mitk::NavigationDataToIGTLMessageFilter::ModeSendQTransMsg); + + //Process + mitk::IGTLMessage::Pointer msg0 = m_NavigationDataToIGTLMessageFilter->GetOutput(); + mitk::IGTLMessage::Pointer msg1 = m_NavigationDataToIGTLMessageFilter->GetOutput(1); + mitk::IGTLMessage::Pointer msg2 = m_NavigationDataToIGTLMessageFilter->GetOutput(2); + mitk::IGTLMessage::Pointer msg3 = m_NavigationDataToIGTLMessageFilter->GetOutput(3); + + msg0->Update(); + + igtl::PositionMessage::Pointer igtlMsg0 = + dynamic_cast(msg0->GetMessage().GetPointer()); + igtl::PositionMessage::Pointer igtlMsg3 = + dynamic_cast(msg3->GetMessage().GetPointer()); + + MITK_TEST_OUTPUT(<< "Testing the converted OpenIGTLink messages:"); + MITK_TEST_CONDITION(igtlMsg0.IsNotNull(), "Message0 is not null?"); + MITK_TEST_CONDITION(igtlMsg3.IsNotNull(), "Message3 is not null?"); + + //Convert the data from the igtl message back to mitk types + float pos0_[3]; + float orientation0_[4]; + igtlMsg0->GetPosition(pos0_); + igtlMsg0->GetQuaternion(orientation0_); + mitk::NavigationData::PositionType pos0; + pos0[0] = pos0_[0]; + pos0[1] = pos0_[1]; + pos0[2] = pos0_[2]; + mitk::NavigationData::OrientationType orientation0; + orientation0[0] = orientation0_[0]; + orientation0[1] = orientation0_[1]; + orientation0[2] = orientation0_[2]; + orientation0[3] = orientation0_[3]; + float pos3_[3]; + float orientation3_[4]; + igtlMsg3->GetPosition(pos3_); + igtlMsg3->GetQuaternion(orientation3_); + mitk::NavigationData::PositionType pos3; + pos3[0] = pos3_[0]; + pos3[1] = pos3_[1]; + pos3[2] = pos3_[2]; + mitk::NavigationData::OrientationType orientation3; + orientation3[0] = orientation3_[0]; + orientation3[1] = orientation3_[1]; + orientation3[2] = orientation3_[2]; + orientation3[3] = orientation3_[3]; + + MITK_TEST_OUTPUT(<< "Testing the conversion of navigation data object to QTrans OpenIGTLink messages:"); + MITK_TEST_CONDITION(mitk::Equal(pos0, m_NavigationDataToIGTLMessageFilter->GetInput(0)->GetPosition()), "Position0 correct?"); + MITK_TEST_CONDITION(mitk::Equal(pos3, m_NavigationDataToIGTLMessageFilter->GetInput(3)->GetPosition()), "Position3 correct?"); + MITK_TEST_CONDITION(mitk::Equal(orientation0, m_NavigationDataToIGTLMessageFilter->GetInput(0)->GetOrientation()), "Orientation0 correct?"); + MITK_TEST_CONDITION(mitk::Equal(orientation3, m_NavigationDataToIGTLMessageFilter->GetInput(3)->GetOrientation()), "Orientation3 correct?"); +} + +static void TestModeTransMsg() +{ + Setup(); + SetInputs(); + m_NavigationDataToIGTLMessageFilter->SetOperationMode( + mitk::NavigationDataToIGTLMessageFilter::ModeSendTransMsg); + + //Process + mitk::IGTLMessage::Pointer msg0 = m_NavigationDataToIGTLMessageFilter->GetOutput(); + mitk::IGTLMessage::Pointer msg1 = m_NavigationDataToIGTLMessageFilter->GetOutput(1); + mitk::IGTLMessage::Pointer msg2 = m_NavigationDataToIGTLMessageFilter->GetOutput(2); + mitk::IGTLMessage::Pointer msg3 = m_NavigationDataToIGTLMessageFilter->GetOutput(3); + + msg0->Update(); + + igtl::TransformMessage::Pointer igtlMsg0 = + dynamic_cast(msg0->GetMessage().GetPointer()); + igtl::TransformMessage::Pointer igtlMsg3 = + dynamic_cast(msg3->GetMessage().GetPointer()); + + MITK_TEST_OUTPUT(<< "Testing the converted OpenIGTLink messages:"); + MITK_TEST_CONDITION(igtlMsg0.IsNotNull(), "Message0 is not null?"); + MITK_TEST_CONDITION(igtlMsg3.IsNotNull(), "Message3 is not null?"); + + //Convert the data from the igtl message back to mitk types + mitk::AffineTransform3D::Pointer affineTransformation0 = + mitk::AffineTransform3D::New(); + igtl::Matrix4x4 transformation0_; + mitk::Matrix3D transformation0; + mitk::Vector3D offset0; + igtlMsg0->GetMatrix(transformation0_); + for ( unsigned int r = 0; r < 3; r++ ) + { + for ( unsigned int c = 0; c < 3; c++ ) + { + transformation0.GetVnlMatrix().set( r , c , transformation0_[r][c] ); + } + offset0.SetElement(r, transformation0_[r][3]); + } + //convert the igtl matrix here and set it in the affine transformation + affineTransformation0->SetMatrix(transformation0); + affineTransformation0->SetOffset(offset0); + //the easiest way to convert the affine transform to position and quaternion + mitk::NavigationData::Pointer nd0 = + mitk::NavigationData::New(affineTransformation0, true); + + + mitk::AffineTransform3D::Pointer affineTransformation3 = + mitk::AffineTransform3D::New(); + igtl::Matrix4x4 transformation3_; + mitk::Matrix3D transformation3; + mitk::Vector3D offset3; + igtlMsg3->GetMatrix(transformation3_); + for ( unsigned int r = 0; r < 3; r++ ) + { + for ( unsigned int c = 0; c < 3; c++ ) + { + transformation3.GetVnlMatrix().set( r , c , transformation3_[r][c] ); + } + offset3.SetElement(r, transformation3_[r][3]); + } + //convert the igtl matrix here and set it in the affine transformation + affineTransformation3->SetMatrix(transformation3); + affineTransformation3->SetOffset(offset3); + //the easiest way to convert the affine transform to position and quaternion + mitk::NavigationData::Pointer nd3 = + mitk::NavigationData::New(affineTransformation3, true); + + MITK_TEST_OUTPUT(<< "Testing the conversion of navigation data object to Trans OpenIGTLink messages:"); + MITK_TEST_CONDITION(mitk::Equal(nd0->GetPosition(), m_NavigationDataToIGTLMessageFilter->GetInput(0)->GetPosition()), "Position0 correct?"); + MITK_TEST_CONDITION(mitk::Equal(nd3->GetPosition(), m_NavigationDataToIGTLMessageFilter->GetInput(3)->GetPosition()), "Position3 correct?"); + MITK_TEST_CONDITION(mitk::Equal(nd0->GetOrientation(), m_NavigationDataToIGTLMessageFilter->GetInput(0)->GetOrientation()), "Orientation0 correct?"); + MITK_TEST_CONDITION(mitk::Equal(nd3->GetOrientation(), m_NavigationDataToIGTLMessageFilter->GetInput(3)->GetOrientation()), "Orientation3 correct?"); +} + +static void NavigationDataToIGTLMessageFilterContructor_DefaultCall_IsNotEmpty() +{ + Setup(); + MITK_TEST_CONDITION_REQUIRED(m_NavigationDataToIGTLMessageFilter.IsNotNull(),"Testing instantiation"); + //I think this test is meaningless, because it will never ever fail. I keep it for know just to be save. +} + +int mitkNavigationDataToIGTLMessageFilterTest(int /* argc */, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("NavigationDataToIGTLMessageFilter"); + + NavigationDataToIGTLMessageFilterContructor_DefaultCall_IsNotEmpty(); + TestModeQTransMsg(); + TestModeTransMsg(); + + MITK_TEST_END(); +} 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 c58b506a16..d68fe5a6ea 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,62 +1,64 @@ set(mitk_modules RDF LegacyIO DataTypesExt Overlays LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMTesting Qt4Qt5TestModule SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction ImageStatistics LegacyAdaptors SceneSerialization GraphAlgorithms Multilabel ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation OpenViewCore QmlItems 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..459768a580 --- /dev/null +++ b/Modules/OpenIGTLink/CMakeLists.txt @@ -0,0 +1,29 @@ +#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 +) + +if(MODULE_IS_ENABLED) +## create IGT config +#configure_file(mitkIGTConfig.h.in ${PROJECT_BINARY_DIR}/mitkIGTConfig.h @ONLY) + +add_subdirectory(Testing) +endif() diff --git a/Modules/OpenIGTLink/Testing/CMakeLists.txt b/Modules/OpenIGTLink/Testing/CMakeLists.txt new file mode 100644 index 0000000000..153cd81e2e --- /dev/null +++ b/Modules/OpenIGTLink/Testing/CMakeLists.txt @@ -0,0 +1 @@ +MITK_CREATE_MODULE_TESTS() diff --git a/Modules/OpenIGTLink/Testing/files.cmake b/Modules/OpenIGTLink/Testing/files.cmake new file mode 100644 index 0000000000..8fe09ed5d9 --- /dev/null +++ b/Modules/OpenIGTLink/Testing/files.cmake @@ -0,0 +1,18 @@ +set(MODULE_TESTS + # IMPORTANT: If you plan to deactivate / comment out a test please write a bug number to the commented out line of code. + # + # Example: #mitkMyTest #this test is commented out because of bug 12345 + # + # It is important that the bug is open and that the test will be activated again before the bug is closed. This assures that + # no test is forgotten after it was commented out. If there is no bug for your current problem, please add a new one and + # mark it as critical. + + ################## ON THE FENCE TESTS ################################################# + # none + + ################## DISABLED TESTS ##################################################### + # none + + ################# RUNNING TESTS ####################################################### + #mitkNavigationDataToIGTLMessageFilterTest.cpp +) diff --git a/Modules/OpenIGTLink/Testing/mitkNavigationDataToIGTLMessageFilterTest.cpp b/Modules/OpenIGTLink/Testing/mitkNavigationDataToIGTLMessageFilterTest.cpp new file mode 100644 index 0000000000..8bb4d8d7a8 --- /dev/null +++ b/Modules/OpenIGTLink/Testing/mitkNavigationDataToIGTLMessageFilterTest.cpp @@ -0,0 +1,240 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkNavigationDataToPointSetFilter.h" +#include "mitkNavigationDataSequentialPlayer.h" +#include "mitkNavigationDataReaderXML.h" +#include +#include + +#include + +/** +* Simple example for a test for the (non-existent) class "NavigationDataToPointSetFilter". +* +* argc and argv are the command line parameters which were passed to +* the ADD_TEST command in the CMakeLists.txt file. For the automatic +* tests, argv is either empty for the simple tests or contains the filename +* of a test image for the image tests (see CMakeLists.txt). +*/ + +mitk::NavigationDataToPointSetFilter::Pointer m_NavigationDataToPointSetFilter; + +static void Setup() +{ + m_NavigationDataToPointSetFilter = mitk::NavigationDataToPointSetFilter::New(); +} + +static void TestMode3D() +{ + Setup(); + m_NavigationDataToPointSetFilter->SetOperationMode(mitk::NavigationDataToPointSetFilter::Mode3D); + + //Build up test data + mitk::NavigationData::Pointer nd0 = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd2 = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd3 = mitk::NavigationData::New(); + + mitk::NavigationData::PositionType point0; + point0[0] = 1.0; + point0[1] = 2.0; + point0[2] = 3.0; + nd0->SetPosition(point0); + nd0->SetDataValid(true); + + mitk::NavigationData::PositionType point1; + point1[0] = 4.0; + point1[1] = 5.0; + point1[2] = 6.0; + nd1->SetPosition(point1); + nd1->SetDataValid(true); + + mitk::NavigationData::PositionType point2; + point2[0] = 7.0; + point2[1] = 8.0; + point2[2] = 9.0; + nd2->SetPosition(point2); + nd2->SetDataValid(true); + + mitk::NavigationData::PositionType point3; + point3[0] = 10.0; + point3[1] = 11.0; + point3[2] = 12.0; + nd3->SetPosition(point3); + nd3->SetDataValid(true); + + m_NavigationDataToPointSetFilter->SetInput(0, nd0); + m_NavigationDataToPointSetFilter->SetInput(1, nd1); + m_NavigationDataToPointSetFilter->SetInput(2, nd2); + m_NavigationDataToPointSetFilter->SetInput(3, nd3); + + //Process + mitk::PointSet::Pointer pointSet0 = m_NavigationDataToPointSetFilter->GetOutput(); + mitk::PointSet::Pointer pointSet1 = m_NavigationDataToPointSetFilter->GetOutput(1); + mitk::PointSet::Pointer pointSet2 = m_NavigationDataToPointSetFilter->GetOutput(2); + mitk::PointSet::Pointer pointSet3 = m_NavigationDataToPointSetFilter->GetOutput(3); + + pointSet0->Update(); + + MITK_TEST_OUTPUT(<< "Testing the conversion of navigation data object to PointSets in Mode 3D:"); + MITK_TEST_CONDITION(mitk::Equal(pointSet0->GetPoint(0), point0), "Pointset 0 correct?"); + MITK_TEST_CONDITION(mitk::Equal(pointSet1->GetPoint(0), point1), "Pointset 1 correct?"); + MITK_TEST_CONDITION(mitk::Equal(pointSet2->GetPoint(0), point2), "Pointset 2 correct?"); + MITK_TEST_CONDITION(mitk::Equal(pointSet3->GetPoint(0), point3), "Pointset 3 correct?"); +} + +static void TestMode4D() +{ + Setup(); + m_NavigationDataToPointSetFilter->SetOperationMode(mitk::NavigationDataToPointSetFilter::Mode4D); + m_NavigationDataToPointSetFilter->SetRingBufferSize(2); + + //Build up test data + mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd2 = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd3 = mitk::NavigationData::New(); + mitk::NavigationData::Pointer nd4 = mitk::NavigationData::New(); + + mitk::NavigationData::PositionType point; + + point[0] = 1.0; + point[1] = 2.0; + point[2] = 3.0; + nd->SetPosition(point); + + point[0] = 4.0; + point[1] = 5.0; + point[2] = 6.0; + nd2->SetPosition(point); + + point[0] = 7.0; + point[1] = 8.0; + point[2] = 9.0; + nd3->SetPosition(point); + + point[0] = 10.0; + point[1] = 11.0; + point[2] = 12.0; + nd4->SetPosition(point); + + m_NavigationDataToPointSetFilter->SetInput(0, nd); + m_NavigationDataToPointSetFilter->SetInput(1, nd2); + + mitk::PointSet::Pointer pointSet = m_NavigationDataToPointSetFilter->GetOutput(); + pointSet->Update(); + + MITK_TEST_CONDITION( pointSet->GetPoint(0,0)[0] == 1.0 && pointSet->GetPoint(0,0)[1] == 2.0 && pointSet->GetPoint(0,0)[2] == 3.0 && + pointSet->GetPoint(1,0)[0] == 4.0 && pointSet->GetPoint(1,0)[1] == 5.0 && pointSet->GetPoint(1,0)[2] == 6.0 + , "Testing the conversion of navigation data object to one point set in Mode 4D in first timestep" ); + + m_NavigationDataToPointSetFilter->SetInput(0, nd3); + m_NavigationDataToPointSetFilter->SetInput(1, nd4); + m_NavigationDataToPointSetFilter->Update(); + pointSet = m_NavigationDataToPointSetFilter->GetOutput(); + + MITK_TEST_CONDITION( pointSet->GetPoint(0,0)[0] == 1.0 && pointSet->GetPoint(0,0)[1] == 2.0 && pointSet->GetPoint(0,0)[2] == 3.0 && + pointSet->GetPoint(1,0)[0] == 4.0 && pointSet->GetPoint(1,0)[1] == 5.0 && pointSet->GetPoint(1,0)[2] == 6.0 && + pointSet->GetPoint(0,1)[0] == 7.0 && pointSet->GetPoint(0,1)[1] == 8.0 && pointSet->GetPoint(0,1)[2] == 9.0 && + pointSet->GetPoint(1,1)[0] == 10.0 && pointSet->GetPoint(1,1)[1] == 11.0 && pointSet->GetPoint(1,1)[2] == 12.0 + , "Testing the conversion of navigation data object to one point set in Mode 4D in second timestep" ); + + m_NavigationDataToPointSetFilter->SetInput(0, nd3); + m_NavigationDataToPointSetFilter->SetInput(1, nd4); + pointSet = m_NavigationDataToPointSetFilter->GetOutput(); + pointSet->Update(); + + MITK_TEST_CONDITION( pointSet->GetPoint(0,0)[0] == 7.0 && pointSet->GetPoint(0,0)[1] == 8.0 && pointSet->GetPoint(0,0)[2] == 9.0 && + pointSet->GetPoint(1,0)[0] == 10.0 && pointSet->GetPoint(1,0)[1] == 11.0 && pointSet->GetPoint(1,0)[2] == 12.0 && + pointSet->GetPoint(0,1)[0] == 7.0 && pointSet->GetPoint(0,1)[1] == 8.0 && pointSet->GetPoint(0,1)[2] == 9.0 && + pointSet->GetPoint(1,1)[0] == 10.0 && pointSet->GetPoint(1,1)[1] == 11.0 && pointSet->GetPoint(1,1)[2] == 12.0 + , "Testing the correct ring buffer behavior" ); +} + +static void TestMode3DMean() +{ + Setup(); + m_NavigationDataToPointSetFilter->SetOperationMode(mitk::NavigationDataToPointSetFilter::Mode3DMean); + int numberForMean = 5; + m_NavigationDataToPointSetFilter->SetNumberForMean(numberForMean); + + MITK_TEST_CONDITION(mitk::Equal(m_NavigationDataToPointSetFilter->GetNumberForMean(), numberForMean), "Testing get/set for numberForMean"); + + mitk::NavigationDataSequentialPlayer::Pointer player = mitk::NavigationDataSequentialPlayer::New(); + + std::string file(MITK_IGT_DATA_DIR); + file.append("/NavigationDataTestData_2Tools.xml"); + + mitk::NavigationDataReaderXML::Pointer reader = mitk::NavigationDataReaderXML::New(); + + player->SetNavigationDataSet( reader->Read(file) ); + + for (unsigned int i = 0; i< player->GetNumberOfOutputs(); i++) + { + m_NavigationDataToPointSetFilter->SetInput(i, player->GetOutput(i)); + } + + mitk::PointSet::Pointer pointSet0 = m_NavigationDataToPointSetFilter->GetOutput(); + mitk::PointSet::Pointer pointSet1 = m_NavigationDataToPointSetFilter->GetOutput(1); + + m_NavigationDataToPointSetFilter->Update(); + + MITK_TEST_CONDITION(pointSet0->GetPoint(0)[0]==3.0 && pointSet0->GetPoint(0)[1]==2.0 && pointSet0->GetPoint(0)[2]==5.0, + "Testing the average of first input"); + + MITK_TEST_CONDITION(pointSet1->GetPoint(0)[0]==30.0 && pointSet1->GetPoint(0)[1]==20.0 && pointSet1->GetPoint(0)[2]==50.0, + "Testing the average of second input"); +} + +static void NavigationDataToPointSetFilterContructor_DefaultCall_IsNotEmpty() +{ + Setup(); + MITK_TEST_CONDITION_REQUIRED(m_NavigationDataToPointSetFilter.IsNotNull(),"Testing instantiation"); + //I think this test is meaningless, because it will never ever fail. I keep it for know just to be save. +} + +static void NavigationDataToPointSetFilterSetInput_SimplePoint_EqualsGroundTruth() +{ + Setup(); + + mitk::NavigationData::Pointer nd_in = mitk::NavigationData::New(); + const mitk::NavigationData* nd_out = mitk::NavigationData::New(); + mitk::NavigationData::PositionType point; + + point[0] = 1.0; + point[1] = 2.0; + point[2] = 3.0; + nd_in->SetPosition(point); + + m_NavigationDataToPointSetFilter->SetInput(nd_in); + nd_out = m_NavigationDataToPointSetFilter->GetInput(); + + MITK_TEST_CONDITION( nd_out->GetPosition() == nd_in->GetPosition(), + "Testing get/set input" ); +} + +int mitkNavigationDataToPointSetFilterTest(int /* argc */, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("NavigationDataToPointSetFilter"); + + NavigationDataToPointSetFilterContructor_DefaultCall_IsNotEmpty(); + NavigationDataToPointSetFilterSetInput_SimplePoint_EqualsGroundTruth(); + TestMode3D(); + TestMode4D(); +// TestMode3DMean(); //infinite loop in debug mode, see bug 17763 + + MITK_TEST_END(); +} diff --git a/Modules/OpenIGTLink/files.cmake b/Modules/OpenIGTLink/files.cmake new file mode 100644 index 0000000000..58f7e85ddd --- /dev/null +++ b/Modules/OpenIGTLink/files.cmake @@ -0,0 +1,14 @@ +set(CPP_FILES + mitkIGTLClient.cpp + mitkIGTLServer.cpp + mitkIGTLDevice.cpp + mitkIGTLMessageSource.cpp + mitkIGTLMessageCommon.cpp + mitkIGTLDeviceSource.cpp + mitkIGTLMessage.cpp + mitkIGTLMessageFactory.cpp + mitkIGTLMessageCloneHandler.h + mitkIGTLDummyMessage.cpp + mitkIGTLMessageQueue.cpp + mitkIGTLMessageProvider.cpp +) \ No newline at end of file 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 b4ff345857..907e217cb2 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,51 +1,52 @@ # 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.geometrytools: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..cf9b299d68 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/org_mitk_gui_qt_igtlplugin_Activator.cpp @@ -0,0 +1,44 @@ +/*=================================================================== + +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) +} + +} + +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + Q_EXPORT_PLUGIN2(org_mitk_gui_qt_igtlplugin, mitk::org_mitk_gui_qt_igtlplugin_Activator) +#endif 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..3d26668f32 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.igtlplugin/src/internal/org_mitk_gui_qt_igtlplugin_Activator.h @@ -0,0 +1,43 @@ +/*=================================================================== + +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 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_igtlplugin") +#endif + 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 d428ccd336..7c4573d1c5 100644 --- a/SuperBuild.cmake +++ b/SuperBuild.cmake @@ -1,529 +1,533 @@ #----------------------------------------------------------------------------- # Convenient macro allowing to download a file #----------------------------------------------------------------------------- if(NOT MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL) set(MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL http://mitk.org/download/thirdparty) endif() macro(downloadFile url dest) file(DOWNLOAD ${url} ${dest} STATUS status) list(GET status 0 error_code) list(GET status 1 error_msg) if(error_code) message(FATAL_ERROR "error: Failed to download ${url} - ${error_msg}") endif() endmacro() #----------------------------------------------------------------------------- # MITK Prerequisites #----------------------------------------------------------------------------- if(UNIX AND NOT APPLE) include(mitkFunctionCheckPackageHeader) # Check for libxt-dev mitkFunctionCheckPackageHeader(StringDefs.h libxt-dev /usr/include/X11/) # Check for libtiff4-dev mitkFunctionCheckPackageHeader(tiff.h libtiff4-dev) # Check for libwrap0-dev mitkFunctionCheckPackageHeader(tcpd.h libwrap0-dev) endif() # We need a proper patch program. On Linux and MacOS, we assume # that "patch" is available. On Windows, we download patch.exe # if not patch program is found. find_program(PATCH_COMMAND patch) if((NOT PATCH_COMMAND OR NOT EXISTS ${PATCH_COMMAND}) AND WIN32) downloadFile(${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/patch.exe ${CMAKE_CURRENT_BINARY_DIR}/patch.exe) find_program(PATCH_COMMAND patch ${CMAKE_CURRENT_BINARY_DIR}) endif() if(NOT PATCH_COMMAND) message(FATAL_ERROR "No patch program found.") endif() #----------------------------------------------------------------------------- # 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 raptor2 rasqal redland + 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_Redland) set(REDLAND_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/Redland-install) set(MITK_USE_raptor2 1) set(MITK_USE_PCRE 1) set(MITK_USE_rasqal 1) set(MITK_USE_redland 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) # 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} -DCMAKE_INCLUDE_PATH:PATH=${CMAKE_INCLUDE_PATH} -DCMAKE_LIBRARY_PATH:PATH=${CMAKE_LIBRARY_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_Redland 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} ${PCRE_DEPENDS} ${Swig_DEPENDS} ${raptor2_DEPENDS} ${rasqal_DEPENDS} ${redland_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} ) 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} -DPCRE_DIR:PATH=${PCRE_DIR} -DSwig_DIR:PATH=${Swig_DIR} -DRaptor2_DIR:PATH=${raptor2_DIR} -DRasqal_DIR:PATH=${rasqal_DIR} -DRedland_DIR:PATH=${redland_DIR} -DREDLAND_INSTALL_DIR:PATH=${REDLAND_INSTALL_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 )