diff --git a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt index 409be62fba..29f65bc1a5 100644 --- a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt +++ b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt @@ -1,388 +1,366 @@ cmake_minimum_required(VERSION 2.8.4) # Change project and application name to your own set(MY_PROJECT_NAME $(project-name)) set(MY_APP_NAME $(project-app-name)) #----------------------------------------------------------------------------- # 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 + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(${MY_PROJECT_NAME}_USE_SUPERBUILD "Build ${MY_PROJECT_NAME} and the projects it depends on via SuperBuild.cmake." ON) if(${MY_PROJECT_NAME}_USE_SUPERBUILD) project(${MY_PROJECT_NAME}-superbuild) set(${MY_PROJECT_NAME}_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(${MY_PROJECT_NAME}_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(${MY_PROJECT_NAME}) 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 ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${${MY_PROJECT_NAME}_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- include(MacroEmptyExternalProject) #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- foreach(type LIBRARY RUNTIME ARCHIVE) set(output_dir ${${MY_PROJECT_NAME}_BINARY_DIR}/bin) 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 Options (also shown during superbuild) #----------------------------------------------------------------------------- option(BUILD_SHARED_LIBS "Build ${MY_PROJECT_NAME} with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) option(${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS "Build all ${MY_PROJECT_NAME} plugins" OFF) - + mark_as_advanced(${MY_PROJECT_NAME}_INSTALL_RPATH_RELATIVE ${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS ) -#----------------------------------------------------------------------------- -# Additional CXX/C Flags -#----------------------------------------------------------------------------- - -set(ADDITIONAL_C_FLAGS "" CACHE STRING "Additional C Flags") -mark_as_advanced(ADDITIONAL_C_FLAGS) -set(ADDITIONAL_CXX_FLAGS "" CACHE STRING "Additional CXX Flags") -mark_as_advanced(ADDITIONAL_CXX_FLAGS) - #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(${MY_PROJECT_NAME}_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # Prerequesites #----------------------------------------------------------------------------- find_package(MITK REQUIRED) if(COMMAND mitkFunctionCheckMitkCompatibility) mitkFunctionCheckMitkCompatibility(VERSIONS MITK_VERSION_PLUGIN_SYSTEM 1 REQUIRED) else() message(SEND_ERROR "Your MITK version is too old. Please use Git hash b86bf28 or newer") endif() link_directories(${MITK_LINK_DIRECTORIES}) #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) - + include(mitkFunctionCheckCompilerFlags) include(mitkFunctionGetGccVersion) include(mitkFunctionGetVersion) #----------------------------------------------------------------------------- # Set project specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- set(${PROJECT_NAME}_VERSION_MAJOR "0") set(${PROJECT_NAME}_VERSION_MINOR "1") set(${PROJECT_NAME}_VERSION_PATCH "1") set(${PROJECT_NAME}_VERSION_STRING "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}") # Ask the user if a console window should be shown with the applications option(${PROJECT_NAME}_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting GUI Applications" ON) mark_as_advanced(${PROJECT_NAME}_SHOW_CONSOLE_WINDOW) if(NOT UNIX AND NOT MINGW) set(MITK_WIN32_FORCE_STATIC "STATIC") endif() set(${PROJECT_NAME}_MODULES_PACKAGE_DEPENDS_DIR "${PROJECT_SOURCE_DIR}/CMake/PackageDepends") list(APPEND MODULES_PACKAGE_DEPENDS_DIRS ${${PROJECT_NAME}_MODULES_PACKAGE_DEPENDS_DIR}) #----------------------------------------------------------------------------- # Get project version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${PROJECT_SOURCE_DIR} ${PROJECT_NAME}) #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on Mac OSX all CTK plugins get copied into every # application bundle (.app directory) specified here set(MACOSX_BUNDLE_NAMES) if(APPLE) list(APPEND MACOSX_BUNDLE_NAMES ${MY_APP_NAME}) endif(APPLE) #----------------------------------------------------------------------------- # 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) # The MITK module build system does not yet support default hidden visibility set(VISIBILITY_CXX_FLAGS ) # "-fvisibility=hidden -fvisibility-inlines-hidden") endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if(CMAKE_COMPILER_IS_GNUCXX) set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # Project C/CXX Flags #----------------------------------------------------------------------------- -set(${PROJECT_NAME}_C_FLAGS "${COVERAGE_C_FLAGS} ${ADDITIONAL_C_FLAGS}") -set(${PROJECT_NAME}_CXX_FLAGS "${VISIBILITY_CXX_FLAGS} ${COVERAGE_CXX_FLAGS} ${ADDITIONAL_CXX_FLAGS}") - -if(CMAKE_COMPILER_IS_GNUCXX) - set(cflags "-Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -D_FORTIFY_SOURCE=2") - - mitkFunctionCheckCompilerFlags("-fdiagnostics-show-option" cflags) - mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" cflags) - # Enable link dependency optimization to only link libraries which satisfy undefined - # symbol references. This aligns the link behavior with the one from the Windows linker. - mitkFunctionCheckCompilerFlags("-Wl,--as-needed" cflags) +set(${PROJECT_NAME}_C_FLAGS "${MITK_C_FLAGS} ${COVERAGE_C_FLAGS}") +set(${PROJECT_NAME}_C_FLAGS_DEBUG ${MITK_C_FLAGS_DEBUG}) +set(${PROJECT_NAME}_C_FLAGS_RELEASE ${MITK_C_FLAGS_RELEASE}) +set(${PROJECT_NAME}_CXX_FLAGS "${MITK_CXX_FLAGS} ${VISIBILITY_CXX_FLAGS} ${COVERAGE_CXX_FLAGS}") +set(${PROJECT_NAME}_CXX_FLAGS_DEBUG ${MITK_CXX_FLAGS_DEBUG}) +set(${PROJECT_NAME}_CXX_FLAGS_RELEASE ${MITK_CXX_FLAGS_RELEASE}) - 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")) - mitkFunctionCheckCompilerFlags("-fstack-protector-all" cflags) - endif() - if(MINGW) - # suppress warnings about auto imported symbols - set(${PROJECT_NAME}_CXX_FLAGS "-Wl,--enable-auto-import ${${PROJECT_NAME}_CXX_FLAGS}") - # we need to define a Windows version - set(${PROJECT_NAME}_CXX_FLAGS "-D_WIN32_WINNT=0x0500 ${${PROJECT_NAME}_CXX_FLAGS}") - endif() - - set(${PROJECT_NAME}_C_FLAGS "${cflags} ${${PROJECT_NAME}_C_FLAGS}") - set(${PROJECT_NAME}_CXX_FLAGS "${cflags} -Woverloaded-virtual -Wstrict-null-sentinel -Wsign-promo ${${PROJECT_NAME}_CXX_FLAGS}") - # The following line produces a lot of warnings in MITK header files... - #set(${PROJECT_NAME}_CXX_FLAGS "${cflags} -Woverloaded-virtual -Wold-style-cast -Wstrict-null-sentinel -Wsign-promo ${${PROJECT_NAME}_CXX_FLAGS}") -endif() +set(${PROJECT_NAME}_EXE_LINKER_FLAGS ${MITK_EXE_LINKER_FLAGS}) +set(${PROJECT_NAME}_SHARED_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) +set(${PROJECT_NAME}_MODULE_LINKER_FLAGS ${MITK_MODULE_LINKER_FLAGS}) #----------------------------------------------------------------------------- # Set C/CXX Flags #----------------------------------------------------------------------------- -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${PROJECT_NAME}_CXX_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${${PROJECT_NAME}_C_FLAGS}") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${${PROJECT_NAME}_C_FLAGS_DEBUG}") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${${PROJECT_NAME}_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${PROJECT_NAME}_CXX_FLAGS}") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${${PROJECT_NAME}_CXX_FLAGS_DEBUG}") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${${PROJECT_NAME}_CXX_FLAGS_RELEASE}") + +set(CMAKE_EXE_LINKER_FLAGS ${${PROJECT_NAME}_EXE_LINKER_FLAGS}) +set(CMAKE_SHARED_LINKER_FLAGS ${${PROJECT_NAME}_SHARED_LINKER_FLAGS}) +set(CMAKE_MODULE_LINKER_FLAGS ${${PROJECT_NAME}_MODULE_LINKER_FLAGS}) #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${CMAKE_CURRENT_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; } ") endif() #----------------------------------------------------------------------------- # ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR isn't defined, it means this project is # *NOT* build using Superbuild. In that specific case, ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR # should default to PROJECT_BINARY_DIR if(NOT DEFINED ${PROJECT_NAME}_SUPERBUILD_BINARY_DIR) set(${PROJECT_NAME}_SUPERBUILD_BINARY_DIR ${PROJECT_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Qt support #----------------------------------------------------------------------------- if(MITK_USE_QT) set(QT_QMAKE_EXECUTABLE ${MITK_QMAKE_EXECUTABLE}) add_definitions(-DQWT_DLL) endif() #----------------------------------------------------------------------------- # MITK modules #----------------------------------------------------------------------------- # This project's directory holding module config files #set(${PROJECT_NAME}_MODULES_CONF_DIR "${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME}") # Append this projects's module config directory to the global list # (This is used to get include directories for the Exports.h files right) #list(APPEND MODULES_CONF_DIRS ${${PROJECT_NAME}_MODULES_CONF_DIR}) # Clean the modulesConf directory. This ensures that modules are sorted # according to their dependencies in the Modules/CMakeLists.txt file #file(GLOB _modules_conf_files ${${PROJECT_NAME}_MODULES_CONF_DIR}/*.cmake) #if(_modules_conf_files) # file(REMOVE ${_modules_conf_files}) #endif() #add_subdirectory(Modules) #----------------------------------------------------------------------------- # CTK plugins #----------------------------------------------------------------------------- # The CMake code in this section *must* be in the top-level CMakeLists.txt file macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin "^$(project-plugin-base)_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin OUTPUT_VARIABLE ${varname}) endmacro() include(${CMAKE_CURRENT_SOURCE_DIR}/Plugins/Plugins.cmake) ctkMacroSetupPlugins(${PROJECT_PLUGINS} BUILD_OPTION_PREFIX ${MY_PROJECT_NAME}_ BUILD_ALL ${${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS}) #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Apps/$(project-app-name)) #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables include(mitkSetupCPack) # Customize CPack variables for this project include(CPackSetup) list(APPEND CPACK_CREATE_DESKTOP_LINKS "${MY_APP_NAME}") configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}CPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}CPackOptions.cmake") # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- # 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("${PROJECT_SOURCE_DIR}/CMake/StartVS.bat.in" ${PROJECT_BINARY_DIR}/StartVS_${VS_BUILD_TYPE}.bat ${VS_BUILD_TYPE}) endforeach() endif(WIN32) diff --git a/Applications/PluginGenerator/ProjectTemplate/SuperBuild.cmake b/Applications/PluginGenerator/ProjectTemplate/SuperBuild.cmake index 5a58d72b39..ca8696bbc5 100644 --- a/Applications/PluginGenerator/ProjectTemplate/SuperBuild.cmake +++ b/Applications/PluginGenerator/ProjectTemplate/SuperBuild.cmake @@ -1,167 +1,220 @@ #----------------------------------------------------------------------------- # ExternalProjects #----------------------------------------------------------------------------- set(external_projects MITK ) set(EXTERNAL_MITK_DIR "${MITK_DIR}" CACHE PATH "Path to MITK build directory") mark_as_advanced(EXTERNAL_MITK_DIR) if(EXTERNAL_MITK_DIR) set(MITK_DIR ${EXTERNAL_MITK_DIR}) endif() # Look for git early on, if needed if(NOT MITK_DIR AND MITK_USE_CTK AND NOT 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 "${CMAKE_BINARY_DIR}/CMakeExternals/Install") set(ep_suffix "-cmake") 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(MSVC90 OR MSVC10) +if(MSVC_VERSION) set(ep_common_C_FLAGS "${CMAKE_C_FLAGS} /bigobj /MP") set(ep_common_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /MP") -else() - set(ep_common_C_FLAGS "${CMAKE_C_FLAGS} -DLINUX_EXTRA") - set(ep_common_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLINUX_EXTRA") endif() set(ep_common_args -DBUILD_TESTING:BOOL=${ep_build_testing} -DCMAKE_INSTALL_PREFIX:PATH=${ep_install_dir} -DBUILD_SHARED_LIBS:BOOL=${ep_build_shared_libs} -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=${ep_common_C_FLAGS}" - "-DCMAKE_CXX_FLAGS:STRING=${ep_common_CXX_FLAGS}" + -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} ) # Include external projects foreach(p ${external_projects}) include(CMakeExternals/${p}.cmake) endforeach() #----------------------------------------------------------------------------- # Set superbuild boolean args #----------------------------------------------------------------------------- set(my_cmake_boolean_args WITH_COVERAGE BUILD_TESTING ${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS ) #----------------------------------------------------------------------------- # Create the final variable containing superbuild boolean args #----------------------------------------------------------------------------- set(my_superbuild_boolean_args) foreach(my_cmake_arg ${my_cmake_boolean_args}) list(APPEND my_superbuild_boolean_args -D${my_cmake_arg}:BOOL=${${my_cmake_arg}}) endforeach() #----------------------------------------------------------------------------- # Project Utilities #----------------------------------------------------------------------------- set(proj ${MY_PROJECT_NAME}-Utilities) ExternalProject_Add(${proj} DOWNLOAD_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS # Mandatory dependencies ${MITK_DEPENDS} # Optional dependencies ) +#----------------------------------------------------------------------------- +# Additional Project CXX/C Flags +#----------------------------------------------------------------------------- + +set(${MY_PROJECT_NAME}_ADDITIONAL_C_FLAGS "" CACHE STRING "Additional C Flags for ${MY_PROJECT_NAME}") +set(${MY_PROJECT_NAME}_ADDITIONAL_C_FLAGS_RELEASE "" CACHE STRING "Additional Release C Flags for ${MY_PROJECT_NAME}") +set(${MY_PROJECT_NAME}_ADDITIONAL_C_FLAGS_DEBUG "" CACHE STRING "Additional Debug C Flags for ${MY_PROJECT_NAME}") +mark_as_advanced(${MY_PROJECT_NAME}_ADDITIONAL_C_FLAGS ${MY_PROJECT_NAME}_ADDITIONAL_C_FLAGS_DEBUG ${MY_PROJECT_NAME}_ADDITIONAL_C_FLAGS_RELEASE) + +set(${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS "" CACHE STRING "Additional CXX Flags for ${MY_PROJECT_NAME}") +set(${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS_RELEASE "" CACHE STRING "Additional Release CXX Flags for ${MY_PROJECT_NAME}") +set(${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS_DEBUG "" CACHE STRING "Additional Debug CXX Flags for ${MY_PROJECT_NAME}") +mark_as_advanced(${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS ${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS_DEBUG ${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS_RELEASE) + +set(${MY_PROJECT_NAME}_ADDITIONAL_EXE_LINKER_FLAGS "" CACHE STRING "Additional exe linker flags for ${MY_PROJECT_NAME}") +set(${MY_PROJECT_NAME}_ADDITIONAL_SHARED_LINKER_FLAGS "" CACHE STRING "Additional shared linker flags for ${MY_PROJECT_NAME}") +set(${MY_PROJECT_NAME}_ADDITIONAL_MODULE_LINKER_FLAGS "" CACHE STRING "Additional module linker flags for ${MY_PROJECT_NAME}") +mark_as_advanced(${MY_PROJECT_NAME}_ADDITIONAL_EXE_LINKER_FLAGS ${MY_PROJECT_NAME}_ADDITIONAL_SHARED_LINKER_FLAGS ${MY_PROJECT_NAME}_ADDITIONAL_MODULE_LINKER_FLAGS) + #----------------------------------------------------------------------------- # Project Configure #----------------------------------------------------------------------------- set(proj ${MY_PROJECT_NAME}-Configure) ExternalProject_Add(${proj} DOWNLOAD_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_CACHE_ARGS - ${ep_common_args} + # --------------- Build options ---------------- + -DBUILD_TESTING:BOOL=${ep_build_testing} + -DCMAKE_INSTALL_PREFIX:PATH=${ep_install_dir} + -DBUILD_SHARED_LIBS:BOOL=${ep_build_shared_libs} + -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} ${${MY_PROJECT_NAME}_ADDITIONAL_C_FLAGS}" + "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS}" + # debug flags + "-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} ${${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS_DEBUG}" + "-DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG} ${${MY_PROJECT_NAME}_ADDITIONAL_C_FLAGS_DEBUG}" + # release flags + "-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE} ${${MY_PROJECT_NAME}_ADDITIONAL_CXX_FLAGS_RELEASE}" + "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE} ${${MY_PROJECT_NAME}_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} ${${MY_PROJECT_NAME}_ADDITIONAL_EXE_LINKER_FLAGS}" + "-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} ${${MY_PROJECT_NAME}_ADDITIONAL_SHARED_LINKER_FLAGS}" + "-DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS} ${${MY_PROJECT_NAME}_ADDITIONAL_MODULE_LINKER_FLAGS}" + # ------------- Boolean build options -------------- ${my_superbuild_boolean_args} -D${MY_PROJECT_NAME}_USE_SUPERBUILD:BOOL=OFF -D${MY_PROJECT_NAME}_CONFIGURED_VIA_SUPERBUILD:BOOL=ON -DCTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS} + # ----------------- Miscellaneous --------------- -D${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR:PATH=${PROJECT_BINARY_DIR} -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} -DMITK_DIR:PATH=${MITK_DIR} -DITK_DIR:PATH=${ITK_DIR} -DVTK_DIR:PATH=${VTK_DIR} SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} BINARY_DIR ${CMAKE_BINARY_DIR}/${MY_PROJECT_NAME}-build BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${MY_PROJECT_NAME}-Utilities ) #----------------------------------------------------------------------------- # Project #----------------------------------------------------------------------------- if(CMAKE_GENERATOR MATCHES ".*Makefiles.*") set(_build_cmd "$(MAKE)") else() set(_build_cmd ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/${MY_PROJECT_NAME}-build --config ${CMAKE_CFG_INTDIR}) endif() # The variable SUPERBUILD_EXCLUDE_${MY_PROJECT_NAME}BUILD_TARGET should be set when submitting to a dashboard if(NOT DEFINED SUPERBUILD_EXCLUDE_${MY_PROJECT_NAME}BUILD_TARGET OR NOT SUPERBUILD_EXCLUDE_${MY_PROJECT_NAME}BUILD_TARGET) set(_target_all_option "ALL") else() set(_target_all_option "") endif() add_custom_target(${MY_PROJECT_NAME}-build ${_target_all_option} COMMAND ${_build_cmd} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${MY_PROJECT_NAME}-build DEPENDS ${MY_PROJECT_NAME}-Configure ) #----------------------------------------------------------------------------- # Custom target allowing to drive the build of the project itself #----------------------------------------------------------------------------- add_custom_target(${MY_PROJECT_NAME} COMMAND ${_build_cmd} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${MY_PROJECT_NAME}-build ) diff --git a/BlueBerry/Bundles/org.blueberry.test/CMakeLists.txt b/BlueBerry/Bundles/org.blueberry.test/CMakeLists.txt index fa2813aea1..2c87a4b468 100644 --- a/BlueBerry/Bundles/org.blueberry.test/CMakeLists.txt +++ b/BlueBerry/Bundles/org.blueberry.test/CMakeLists.txt @@ -1,8 +1,9 @@ project(org_blueberry_test) MACRO_CREATE_CTK_PLUGIN( EXPORT_DIRECTIVE BERRY_TEST_EXPORT EXPORTED_INCLUDE_SUFFIXES src src/harness + NO_INSTALL ) target_link_libraries(${PROJECT_NAME} optimized CppUnit debug CppUnitd) diff --git a/BlueBerry/Bundles/org.blueberry.uitest/CMakeLists.txt b/BlueBerry/Bundles/org.blueberry.uitest/CMakeLists.txt index aa85a84802..8bd9696385 100644 --- a/BlueBerry/Bundles/org.blueberry.uitest/CMakeLists.txt +++ b/BlueBerry/Bundles/org.blueberry.uitest/CMakeLists.txt @@ -1,8 +1,9 @@ project(org_blueberry_uitest) MACRO_CREATE_CTK_PLUGIN( EXPORT_DIRECTIVE BERRY_UITEST_EXPORT EXPORTED_INCLUDE_SUFFIXES src src/harness src/util + NO_INSTALL ) target_link_libraries(${PROJECT_NAME} optimized CppUnit debug CppUnitd) diff --git a/BlueBerry/CMake/FunctionCreateProvisioningFile.cmake b/BlueBerry/CMake/FunctionCreateProvisioningFile.cmake index ac578f88c6..17b5374df6 100644 --- a/BlueBerry/CMake/FunctionCreateProvisioningFile.cmake +++ b/BlueBerry/CMake/FunctionCreateProvisioningFile.cmake @@ -1,218 +1,222 @@ #! #! \brief Create a provisioning file #! #! \param FILE (required) An absolute filename for #! the new provisioning file. #! \param INCLUDE (optional) A list of additional provisioning files #! which should be included. #! \param PLUGINS (optional) A list of target names for which provisioning #! entries should be created. The entries must be valid targets or #! be of the form [subdir/]target_name:OFF (this is the same form as #! passed to the ctkMacroSetupPlugins macro) If the list is empty, #! all known plug-in targets (external or internal) are considered. #! \param EXCLUDE_PLUGINS (optional) A list of plug-in symbolic names which should be excluded #! from the provisioning entries. #! \param NO_INSTALL (option) Suppress the creation of an additional provisioning file suitable for packaging. #! #! This function creates a provisioning file which can be used to provision a BlueBerry #! application. The syntax of entries in the file is #! \code #! (READ|INSTALL|START) #! \endcode #! READ includes the file at and interprets it as a provisioning file, INSTALL installs , #! and START installs and starts as a plug-in in the framework. #! #!

#! For example the following provisioning file instructs the BlueBerry framework to read the entries in #! a file called SomeApp.provisioning and subsequently INSTALL and START the plug-in com.mycompany.plugin #! \code #! READ file:///opt/etc/SomeApp.provisioning #! START file:///opt/mycompany/plugins/libcom_mycompany_plugin.so #! \endcode #! #!

#! An example invocation of this macro may look like: #! \code #! set(_my_prov_file "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MyApp.provisioning") #! set(_my_plugins #! com.mycompany.plugin #! org.mitk.gui.qt.extapplication #! ) #! FunctionCreateProvisioningFile(FILE ${_my_prov_file} PLUGINS ${_my_plugins}) #! \endcode #! #! \note This function will automatically create entries for all plug-in #! dependencies of the specified plug-ins. #! function(FunctionCreateProvisioningFile) macro_parse_arguments(_PROV "FILE;INCLUDE;PLUGINS;EXCLUDE_PLUGINS;PLUGIN_DIR" "NO_INSTALL" ${ARGN}) if(_PROV_PLUGIN_DIR) message(WARNING "The PLUGIN_DIR argument is no longer supported. Either use FunctionCreateProvisioningFile_legacy or adapt your CMake function call.") endif() if(NOT _PROV_FILE) message(SEND_ERROR "FILE argument must not be empty") return() endif() set(out_var ) set(out_var_install ) if(WIN32) set(file_url "file:///") else() set(file_url "file://") endif() # Include other provisioning files foreach(incl ${_PROV_INCLUDE}) get_filename_component(incl_filename "${incl}" NAME) set(out_var "${out_var}READ ${file_url}${incl}\n") set(out_var_install "${out_var_install}READ ${file_url}@EXECUTABLE_DIR/${incl_filename}\n") endforeach() if(_PROV_INCLUDE) set(out_var "${out_var}\n") set(out_var_install "${out_var_install}\n") endif() set(_plugin_list ) if(_PROV_PLUGINS) foreach(_plugin ${_PROV_PLUGINS}) string(REPLACE "." "_" _plugin_target ${_plugin}) list(APPEND _plugin_list ${_plugin_target}) endforeach() # get all plug-in dependencies ctkFunctionGetPluginDependencies(_plugin_deps PLUGINS ${_plugin_list} ALL) # add the dependencies to the list of plug-ins list(APPEND _plugin_list ${_plugin_deps}) else() # Fill the _plugin_list variable with external and internal plug-in target names. ctkFunctionGetAllPluginTargets(_plugin_list) endif() + if(_plugin_list) + list(REMOVE_DUPLICATES _plugin_list) + endif() + set(_exclude_targets ) if(_PROV_EXCLUDE_PLUGINS) # Convert the plug-in symbolic names to valid target names foreach(_exclude_entry ${_PROV_EXCLUDE_PLUGINS}) string(REPLACE "." "_" _exclude_target ${_exclude_entry}) list(APPEND _exclude_targets ${_exclude_target}) endforeach() list(REMOVE_ITEM _plugin_list ${_exclude_targets}) endif() # Go through the list of plug-ins foreach(plugin ${_plugin_list}) set(_plugin_target) if(TARGET ${plugin}) # The entry already is a valid target (either imported or declared in the current project) set(_plugin_target ${plugin}) else() # Check if the entry if of the form "Some/Dir/org.my.plugin:OPTION" ctkFunctionExtractOptionNameAndValue(${plugin} plugin_name_with_dirs plugin_value) string(REPLACE "/" ";" _tokens ${plugin_name_with_dirs}) list(GET _tokens -1 plugin_name) string(REPLACE "." "_" _plugin_target_name ${plugin_name}) if(TARGET ${_plugin_target_name}) # Check if the extracted last directory entry is a valid target set(_plugin_target ${_plugin_target_name}) endif() endif() if(_plugin_target) # We got a valid target, either imported or from this project. set(_plugin_location) get_target_property(_is_imported ${_plugin_target} IMPORTED) if(_is_imported) get_target_property(_plugin_location ${_plugin_target} IMPORTED_LOCATION) if(NOT _plugin_location) get_target_property(_plugin_configs ${_plugin_target} IMPORTED_CONFIGURATIONS) foreach(_plugin_config ${_plugin_configs}) get_target_property(_plugin_location ${_plugin_target} IMPORTED_LOCATION_${_plugin_config}) if(_plugin_location) if(CMAKE_CONFIGURATION_TYPES) # Strip the last directory and filename string(REGEX REPLACE "(.*)/[^/]*/[^/]*$" "\\1" _plugin_location "${_plugin_location}") else() # Just strip the filename get_filename_component(_plugin_location "${_plugin_location}" PATH) endif() break() endif() endforeach() endif() else() if(WIN32) get_target_property(_plugin_location ${_plugin_target} RUNTIME_OUTPUT_DIRECTORY) else() get_target_property(_plugin_location ${_plugin_target} LIBRARY_OUTPUT_DIRECTORY) endif() endif() set(plugin_url "${file_url}${_plugin_location}/lib${_plugin_target}${CMAKE_SHARED_LIBRARY_SUFFIX}") set(plugin_url_install "${file_url}@EXECUTABLE_DIR/plugins/lib${_plugin_target}${CMAKE_SHARED_LIBRARY_SUFFIX}") set(out_var "${out_var}START ${plugin_url}\n") set(out_var_install "${out_var_install}START ${plugin_url_install}\n") else() #message(WARNING "Ignoring unknown plug-in target \"${plugin}\" for provisioning.") endif() endforeach() file(WRITE ${_PROV_FILE} "${out_var}") if(NOT _PROV_NO_INSTALL) file(WRITE ${_PROV_FILE}.install "${out_var_install}") endif() endfunction() function(FunctionCreateProvisioningFile_legacy) macro_parse_arguments(_PROV "FILE;INCLUDE;PLUGIN_DIR;PLUGINS" "" ${ARGN}) set(out_var ) set(out_var_install ) if(WIN32) set(file_url "file:///") else() set(file_url "file://") endif() foreach(incl ${_PROV_INCLUDE}) get_filename_component(incl_filename "${incl}" NAME) set(out_var "${out_var}READ ${file_url}${incl}\n") set(out_var_install "${out_var_install}READ ${file_url}@EXECUTABLE_DIR/${incl_filename}\n") endforeach() if(_PROV_INCLUDE) set(out_var "${out_var}\n") set(out_var_install "${out_var_install}\n") endif() string(REPLACE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" "@EXECUTABLE_DIR" _PROV_PLUGIN_DIR_install ${_PROV_PLUGIN_DIR}) foreach(plugin ${_PROV_PLUGINS}) ctkFunctionExtractOptionNameAndValue(${plugin} plugin_name_with_dirs plugin_value) string(REPLACE "/" ";" _tokens ${plugin_name_with_dirs}) list(GET _tokens -1 plugin_name) string(REPLACE "." "_" plugin_target ${plugin_name}) set(plugin_url "${file_url}${_PROV_PLUGIN_DIR}/lib${plugin_target}${CMAKE_SHARED_LIBRARY_SUFFIX}") set(plugin_url_install "${file_url}${_PROV_PLUGIN_DIR_install}/lib${plugin_target}${CMAKE_SHARED_LIBRARY_SUFFIX}") if(${${plugin_name_with_dirs}_option_name}) set(out_var "${out_var}START ${plugin_url}\n") set(out_var_install "${out_var_install}START ${plugin_url_install}\n") #else() # set(out_var "${out_var}STOP ${plugin_url}\n") # set(out_var_install "${out_var_install}STOP ${plugin_url_install}\n") endif() endforeach() file(WRITE ${_PROV_FILE} "${out_var}") file(WRITE ${_PROV_FILE}.install "${out_var_install}") endfunction() diff --git a/BlueBerry/CMake/MacroCreateCTKPlugin.cmake b/BlueBerry/CMake/MacroCreateCTKPlugin.cmake index 27605d8f17..631922fc59 100644 --- a/BlueBerry/CMake/MacroCreateCTKPlugin.cmake +++ b/BlueBerry/CMake/MacroCreateCTKPlugin.cmake @@ -1,189 +1,190 @@ #! \brief Creates a CTK plugin. #! #! This macro should be called from the plugins CMakeLists.txt file. #! The target name is available after the macro call as ${PLUGIN_TARGET} #! to add additional libraries in your CMakeLists.txt. Include paths and link #! libraries are set depending on the value of the Required-Plugins header #! in your manifest_headers.cmake file. #! #! This macro internally calls ctkMacroBuildPlugin() and adds support #! for Qt Help files and installers. #! #! \param EXPORT_DIRECTIVE (required) The export directive to use in the generated #! _Exports.h file. #! \param EXPORTED_INCLUDE_SUFFIXES (optional) a list of sub-directories which should #! be added to the current source directory. The resulting directories #! will be available in the set of include directories of depending plug-ins. #! \param DOXYGEN_TAGFILES (optional) Which external tag files should be available for the plugin documentation #! \param TEST_PLUGIN (option) Mark this plug-in as a testing plug-in. +#! \param NO_INSTALL (option) Don't install this plug-in. macro(MACRO_CREATE_CTK_PLUGIN) - MACRO_PARSE_ARGUMENTS(_PLUGIN "EXPORT_DIRECTIVE;EXPORTED_INCLUDE_SUFFIXES;DOXYGEN_TAGFILES" "TEST_PLUGIN;NO_QHP_TRANSFORM" ${ARGN}) + MACRO_PARSE_ARGUMENTS(_PLUGIN "EXPORT_DIRECTIVE;EXPORTED_INCLUDE_SUFFIXES;DOXYGEN_TAGFILES" "TEST_PLUGIN;NO_INSTALL;NO_QHP_TRANSFORM" ${ARGN}) message(STATUS "Creating CTK plugin ${PROJECT_NAME}") set(PLUGIN_TARGET ${PROJECT_NAME}) include(files.cmake) set(_PLUGIN_CPP_FILES ${CPP_FILES}) set(_PLUGIN_MOC_H_FILES ${MOC_H_FILES}) set(_PLUGIN_UI_FILES ${UI_FILES}) set(_PLUGIN_CACHED_RESOURCE_FILES ${CACHED_RESOURCE_FILES}) set(_PLUGIN_TRANSLATION_FILES ${TRANSLATION_FILES}) set(_PLUGIN_QRC_FILES ${QRC_FILES}) set(_PLUGIN_H_FILES ${H_FILES}) set(_PLUGIN_TXX_FILES ${TXX_FILES}) set(_PLUGIN_DOX_FILES ${DOX_FILES}) set(_PLUGIN_CMAKE_FILES ${CMAKE_FILES} files.cmake) set(_PLUGIN_FILE_DEPENDENCIES ${FILE_DEPENDENCIES}) if(CTK_PLUGINS_OUTPUT_DIR) set(_output_dir "${CTK_PLUGINS_OUTPUT_DIR}") else() set(_output_dir "") endif() if(_PLUGIN_TEST_PLUGIN) set(is_test_plugin "TEST_PLUGIN") else() set(is_test_plugin) endif() # Compute the plugin dependencies ctkFunctionGetTargetLibraries(_PLUGIN_target_libraries) #------------------------------------------------------------# #------------------ Qt Help support -------------------------# set(PLUGIN_GENERATED_QCH_FILES ) if(BLUEBERRY_USE_QT_HELP AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_INPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/documentation/UserManual") # Create a list of Doxygen tag files from the plug-in dependencies set(PLUGIN_DOXYGEN_TAGFILES) foreach(_dep_target ${_PLUGIN_target_libraries}) string(REPLACE _ . _dep ${_dep_target}) get_target_property(_is_imported ${_dep_target} IMPORTED) if(_is_imported) get_target_property(_import_loc_debug ${_dep_target} IMPORTED_LOCATION_DEBUG) get_target_property(_import_loc_release ${_dep_target} IMPORTED_LOCATION_RELEASE) # There is not necessarily a debug and release build if(_import_loc_release) set(_import_loc ${_import_loc_release}) else() set(_import_loc ${_import_loc_debug}) endif() get_filename_component(_target_filename "${_import_loc}" NAME) # on windows there might be a Debug or Release subdirectory string(REGEX REPLACE "/bin/plugins/(Debug/|Release/)?${_target_filename}" "/Plugins/${_dep}/documentation/UserManual" plugin_tag_dir "${_import_loc}" ) else() set(plugin_tag_dir "${CMAKE_BINARY_DIR}/Plugins/${_dep}/documentation/UserManual") endif() set(_tag_file "${plugin_tag_dir}/${_dep_target}.tag") if(EXISTS ${_tag_file}) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} ${_tag_file}=qthelp://${_dep}/bundle/") endif() endforeach() if(_PLUGIN_DOXYGEN_TAGFILES) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} ${_PLUGIN_DOXYGEN_TAGFILES}") endif() #message("PLUGIN_DOXYGEN_TAGFILES: ${PLUGIN_DOXYGEN_TAGFILES}") if(_PLUGIN_NO_QHP_TRANSFORM) set(_use_qhp_xsl 0) else() set(_use_qhp_xsl 1) endif() _FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP(PLUGIN_GENERATED_QCH_FILES ${_use_qhp_xsl}) list(APPEND _PLUGIN_CACHED_RESOURCE_FILES ${PLUGIN_GENERATED_QCH_FILES}) endif() #------------------------------------------------------------# #------------------ Create Plug-in --------------------------# ctkMacroBuildPlugin( NAME ${PLUGIN_TARGET} EXPORT_DIRECTIVE ${_PLUGIN_EXPORT_DIRECTIVE} SRCS ${_PLUGIN_CPP_FILES} MOC_SRCS ${_PLUGIN_MOC_H_FILES} UI_FORMS ${_PLUGIN_UI_FILES} EXPORTED_INCLUDE_SUFFIXES ${_PLUGIN_EXPORTED_INCLUDE_SUFFIXES} RESOURCES ${_PLUGIN_QRC_FILES} TARGET_LIBRARIES ${_PLUGIN_target_libraries} CACHED_RESOURCEFILES ${_PLUGIN_CACHED_RESOURCE_FILES} TRANSLATIONS ${_PLUGIN_TRANSLATION_FILES} OUTPUT_DIR ${_output_dir} ${is_test_plugin} ) if(mbilog_FOUND) target_link_libraries(${PLUGIN_TARGET} mbilog) endif() include_directories(${Poco_INCLUDE_DIRS}) include_directories(${BlueBerry_BINARY_DIR}) target_link_libraries(${PLUGIN_TARGET} optimized PocoFoundation debug PocoFoundationd optimized PocoUtil debug PocoUtild optimized PocoXML debug PocoXMLd ) # Set compiler flags get_target_property(_plugin_compile_flags ${PLUGIN_TARGET} COMPILE_FLAGS) if(NOT _plugin_compile_flags) set(_plugin_compile_flags "") endif() if(WIN32) set(_plugin_compile_flags "${_plugin_compile_flags} -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") endif() set_target_properties(${PLUGIN_TARGET} PROPERTIES COMPILE_FLAGS "${_plugin_compile_flags}") set(_PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") list(APPEND _PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") endif() MACRO_ORGANIZE_SOURCES( SOURCE ${_PLUGIN_CPP_FILES} HEADER ${_PLUGIN_H_FILES} TXX ${_PLUGIN_TXX_FILES} DOC ${_PLUGIN_DOX_FILES} UI ${_PLUGIN_UI_FILES} QRC ${_PLUGIN_QRC_FILES} ${_PLUGIN_CACHED_RESOURCE_FILES} META ${_PLUGIN_META_FILES} MOC ${MY_MOC_CPP} GEN_UI ${MY_UI_CPP} GEN_QRC ${MY_QRC_SRCS} ) #------------------------------------------------------------# #------------------ Installer support -----------------------# - if(NOT _PLUGIN_TEST_PLUGIN) + if(NOT _PLUGIN_NO_INSTALL) set(install_directories "") if(NOT MACOSX_BUNDLE_NAMES) set(install_directories bin/plugins) else(NOT MACOSX_BUNDLE_NAMES) foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND install_directories ${bundle_name}.app/Contents/MacOS/plugins) endforeach(bundle_name) endif(NOT MACOSX_BUNDLE_NAMES) foreach(install_subdir ${install_directories}) MACRO_INSTALL_CTK_PLUGIN(TARGETS ${PLUGIN_TARGET} DESTINATION ${install_subdir}) endforeach() endif() endmacro() diff --git a/CMake/PackageDepends/MITK_PythonLibs_Config.cmake b/CMake/PackageDepends/MITK_PythonLibs_Config.cmake new file mode 100644 index 0000000000..11fb617c3e --- /dev/null +++ b/CMake/PackageDepends/MITK_PythonLibs_Config.cmake @@ -0,0 +1,5 @@ +FIND_PACKAGE(PythonLibs REQUIRED) +list(APPEND ALL_LIBRARIES ${PYTHON_LIBRARIES}) +#include_directories(${PYTHON_INCLUDE_DIRS}) +list(APPEND ALL_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_DIRS}) +#link_directories(${PYTHON_LIBRARIES}) diff --git a/CMake/mitkFunctionCheckCompilerFlags.cmake b/CMake/mitkFunctionCheckCompilerFlags.cmake index db3a3e1ecd..3df3f41ad5 100644 --- a/CMake/mitkFunctionCheckCompilerFlags.cmake +++ b/CMake/mitkFunctionCheckCompilerFlags.cmake @@ -1,47 +1,80 @@ # # Helper macro allowing to check if the given flags are supported # by the underlying build tool # # If the flag(s) is/are supported, they will be appended to the string identified by RESULT_VAR # # Usage: -# MITKFunctionCheckCompilerFlags(FLAGS_TO_CHECK VALID_FLAGS_VAR) +# mitkFunctionCheckCompilerFlags(FLAGS_TO_CHECK VALID_FLAGS_VAR) +# +# The above example uses the C++ compiler to check the flags. To individually check with +# the C and C++ compiler, use: +# +# mitkFunctionCheckCompilerFlags2(FLAGS_TO_CHECK VALID_C_FLAGS_VAR VALID_CXX_FLAGS_VAR) # # Example: # # set(myflags) # mitkFunctionCheckCompilerFlags("-fprofile-arcs" myflags) # message(1-myflags:${myflags}) # mitkFunctionCheckCompilerFlags("-fauto-bugfix" myflags) # message(2-myflags:${myflags}) # mitkFunctionCheckCompilerFlags("-Wall" myflags) # message(1-myflags:${myflags}) # # The output will be: # 1-myflags: -fprofile-arcs # 2-myflags: -fprofile-arcs # 3-myflags: -fprofile-arcs -Wall include(TestCXXAcceptsFlag) +include(CheckCXXCompilerFlag) +include(CheckCCompilerFlag) function(mitkFunctionCheckCompilerFlags CXX_FLAG_TO_TEST RESULT_VAR) if(CXX_FLAG_TO_TEST STREQUAL "") message(FATAL_ERROR "CXX_FLAG_TO_TEST shouldn't be empty") endif() # Internally, the macro CMAKE_CXX_ACCEPTS_FLAG calls TRY_COMPILE. To avoid # the cost of compiling the test each time the project is configured, the variable set by # the macro is added to the cache so that following invocation of the macro with # the same variable name skip the compilation step. # For that same reason, ctkFunctionCheckCompilerFlags function appends a unique suffix to # the HAS_FLAG variable. This suffix is created using a 'clean version' of the flag to test. - string(REGEX REPLACE "-\\s\\$\\+\\*\\{\\}\\(\\)\\#" "" suffix ${CXX_FLAG_TO_TEST}) + string(REGEX REPLACE "[, \\$\\+\\*\\{\\}\\(\\)\\#]" "" suffix ${CXX_FLAG_TO_TEST}) CHECK_CXX_ACCEPTS_FLAG(${CXX_FLAG_TO_TEST} HAS_FLAG_${suffix}) if(HAS_FLAG_${suffix}) set(${RESULT_VAR} "${${RESULT_VAR}} ${CXX_FLAG_TO_TEST}" PARENT_SCOPE) endif() endfunction() +function(mitkFunctionCheckCompilerFlags2 FLAG_TO_TEST C_RESULT_VAR CXX_RESULT_VAR) + + if(FLAG_TO_TEST STREQUAL "") + message(FATAL_ERROR "FLAG_TO_TEST shouldn't be empty") + endif() + + # Internally, the macro CMAKE_CXX_ACCEPTS_FLAG calls TRY_COMPILE. To avoid + # the cost of compiling the test each time the project is configured, the variable set by + # the macro is added to the cache so that following invocation of the macro with + # the same variable name skip the compilation step. + # For that same reason, ctkFunctionCheckCompilerFlags function appends a unique suffix to + # the HAS_FLAG variable. This suffix is created using a 'clean version' of the flag to test. + string(REGEX REPLACE "[, \\$\\+\\*\\{\\}\\(\\)\\#]" "" suffix ${FLAG_TO_TEST}) + CHECK_CXX_COMPILER_FLAG(${FLAG_TO_TEST} HAS_CXX_FLAG_${suffix}) + + if(HAS_CXX_FLAG_${suffix}) + set(${CXX_RESULT_VAR} "${${CXX_RESULT_VAR}} ${FLAG_TO_TEST}" PARENT_SCOPE) + endif() + + CHECK_C_COMPILER_FLAG(${FLAG_TO_TEST} HAS_C_FLAG_${suffix}) + + if(HAS_C_FLAG_${suffix}) + set(${C_RESULT_VAR} "${${C_RESULT_VAR}} ${FLAG_TO_TEST}" PARENT_SCOPE) + endif() + +endfunction() diff --git a/CMake/mitkInstallRules.cmake b/CMake/mitkInstallRules.cmake index b66cdf4149..af513a3b1d 100644 --- a/CMake/mitkInstallRules.cmake +++ b/CMake/mitkInstallRules.cmake @@ -1,108 +1,103 @@ MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/mitk.ico ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/mitk.bmp ) -#STATEMACHINE XML -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Config/mitkLevelWindowPresets.xml ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Config/mitkRigidRegistrationPresets.xml ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Config/mitkRigidRegistrationTestPresets.xml ) - # Install CTK Qt (designer) plugins if(MITK_USE_CTK) if(EXISTS ${CTK_QTDESIGNERPLUGINS_DIR}) set(_qtplugin_install_destinations) if(MACOSX_BUNDLE_NAMES) foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qtplugin_install_destinations ${bundle_name}.app/Contents/MacOS/${_install_DESTINATION}/plugins/designer) endforeach() else() list(APPEND _qtplugin_install_destinations bin/plugins/designer) endif() if(NOT CMAKE_CFG_INTDIR STREQUAL ".") set(_matching_pattern_release FILES_MATCHING PATTERN "*Release*") set(_matching_pattern_debug FILES_MATCHING PATTERN "*Debug*") else() set(_matching_pattern_release ) set(_matching_pattern_debug ) endif() foreach(_qtplugin_install_dir ${_qtplugin_install_destinations}) install(DIRECTORY ${CTK_QTDESIGNERPLUGINS_DIR}/designer/ DESTINATION ${_qtplugin_install_dir} CONFIGURATIONS Release ${_matching_pattern_release} ) install(DIRECTORY ${CTK_QTDESIGNERPLUGINS_DIR}/designer/ DESTINATION ${_qtplugin_install_dir} CONFIGURATIONS Debug ${_matching_pattern_debug} ) endforeach() endif() endif() if(WIN32) #DCMTK Dlls install target (shared libs on gcc only) if(MINGW AND DCMTK_ofstd_LIBRARY) set(_dcmtk_libs ${DCMTK_dcmdata_LIBRARY} ${DCMTK_dcmimgle_LIBRARY} ${DCMTK_dcmnet_LIBRARY} ${DCMTK_ofstd_LIBRARY} ) foreach(_dcmtk_lib ${_dcmtk_libs}) MITK_INSTALL(FILES ${_dcmtk_lib} ) endforeach() endif() #BlueBerry # Since this file is also included from external projects, you # can only use variables which are made available through MITKConfig.cmake if(MITK_USE_BLUEBERRY) if(MINGW) MITK_INSTALL(FILES ${MITK_BINARY_DIR}/bin/plugins/liborg_blueberry_osgi.dll) else() if(NOT APPLE) MITK_INSTALL(FILES ${MITK_BINARY_DIR}/bin/plugins/debug/liborg_blueberry_osgi.dll CONFIGURATIONS Debug) MITK_INSTALL(FILES ${MITK_BINARY_DIR}/bin/plugins/release/liborg_blueberry_osgi.dll CONFIGURATIONS Release) endif(NOT APPLE) endif() endif() #MinGW dll if(MINGW) find_library(MINGW_RUNTIME_DLL "mingwm10.dll" HINTS ${CMAKE_FIND_ROOT_PATH}/sys-root/mingw/bin) if(MINGW_RUNTIME_DLL) MITK_INSTALL(FILES ${MINGW_RUNTIME_DLL} ) else() message(SEND_ERROR "Could not find mingwm10.dll which is needed for a proper install") endif() find_library(MINGW_GCC_RUNTIME_DLL "libgcc_s_dw2-1.dll" HINTS ${CMAKE_FIND_ROOT_PATH}/sys-root/mingw/bin) if(MINGW_GCC_RUNTIME_DLL) MITK_INSTALL(FILES ${MINGW_GCC_RUNTIME_DLL} ) else() message(SEND_ERROR "Could not find libgcc_s_dw2-1.dll which is needed for a proper install") endif() endif() else() #DCMTK Dlls install target (shared libs on gcc only) if(DCMTK_ofstd_LIBRARY) set(_dcmtk_libs ${DCMTK_dcmdata_LIBRARY} ${DCMTK_dcmimgle_LIBRARY} ${DCMTK_dcmnet_LIBRARY} ${DCMTK_ofstd_LIBRARY} ) foreach(_dcmtk_lib ${_dcmtk_libs}) #MITK_INSTALL(FILES ${_dcmtk_lib} DESTINATION lib) endforeach() endif() endif() diff --git a/CMake/mitkMacroCreateCTKPlugin.cmake b/CMake/mitkMacroCreateCTKPlugin.cmake index 2ae5667220..068ca7b78a 100644 --- a/CMake/mitkMacroCreateCTKPlugin.cmake +++ b/CMake/mitkMacroCreateCTKPlugin.cmake @@ -1,69 +1,76 @@ macro(MACRO_CREATE_MITK_CTK_PLUGIN) - MACRO_PARSE_ARGUMENTS(_PLUGIN "EXPORT_DIRECTIVE;EXPORTED_INCLUDE_SUFFIXES;MODULE_DEPENDENCIES;SUBPROJECTS" "TEST_PLUGIN" ${ARGN}) + MACRO_PARSE_ARGUMENTS(_PLUGIN "EXPORT_DIRECTIVE;EXPORTED_INCLUDE_SUFFIXES;MODULE_DEPENDENCIES;SUBPROJECTS" "TEST_PLUGIN;NO_INSTALL" ${ARGN}) MITK_CHECK_MODULE(_MODULE_CHECK_RESULT Mitk ${_PLUGIN_MODULE_DEPENDENCIES}) if(NOT _MODULE_CHECK_RESULT) MITK_USE_MODULE(Mitk ${_PLUGIN_MODULE_DEPENDENCIES}) link_directories(${ALL_LIBRARY_DIRS}) include_directories(${ALL_INCLUDE_DIRECTORIES}) if(_PLUGIN_TEST_PLUGIN) set(is_test_plugin "TEST_PLUGIN") + set(_PLUGIN_NO_INSTALL 1) else() set(is_test_plugin) endif() + if(_PLUGIN_NO_INSTALL) + set(plugin_no_install "NO_INSTALL") + else() + set(plugin_no_install) + endif() + MACRO_CREATE_CTK_PLUGIN(EXPORT_DIRECTIVE ${_PLUGIN_EXPORT_DIRECTIVE} EXPORTED_INCLUDE_SUFFIXES ${_PLUGIN_EXPORTED_INCLUDE_SUFFIXES} DOXYGEN_TAGFILES ${_PLUGIN_DOXYGEN_TAGFILES} - ${is_test_plugin}) + ${is_test_plugin} ${plugin_no_install}) target_link_libraries(${PLUGIN_TARGET} ${ALL_LIBRARIES}) if(ALL_META_DEPENDENCIES) add_dependencies(${PLUGIN_TARGET} ${ALL_META_DEPENDENCIES}) endif() if(MITK_DEFAULT_SUBPROJECTS AND NOT MY_SUBPROJECTS) set(MY_SUBPROJECTS ${MITK_DEFAULT_SUBPROJECTS}) endif() if(MY_SUBPROJECTS) set_property(TARGET ${PLUGIN_TARGET} PROPERTY LABELS ${MY_SUBPROJECTS}) foreach(subproject ${MY_SUBPROJECTS}) add_dependencies(${subproject} ${PLUGIN_TARGET}) endforeach() endif() #------------------------------------------------------------# #------------------ Installer support -----------------------# - if(NOT _PLUGIN_TEST_PLUGIN) + if(NOT _PLUGIN_NO_INSTALL) set(_autoload_targets ) foreach(_dependency ${ALL_DEPENDENCIES}) get_target_property(_dep_autoloads ${_dependency} MITK_AUTOLOAD_TARGETS) if (_dep_autoloads) list(APPEND _autoload_targets ${_dep_autoloads}) endif() endforeach() # The MITK_AUTOLOAD_TARGETS property is used in the mitkFunctionInstallAutoLoadModules # macro which expects a list of plug-in targets. if (_autoload_targets) list(REMOVE_DUPLICATES _autoload_targets) set_target_properties(${PLUGIN_TARGET} PROPERTIES MITK_AUTOLOAD_TARGETS "${_autoload_targets}") endif() endif() else(NOT _MODULE_CHECK_RESULT) if(NOT MITK_BUILD_ALL_PLUGINS) message(SEND_ERROR "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_MODULE_CHECK_RESULT}") else() message(STATUS "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_MODULE_CHECK_RESULT}") endif() endif(NOT _MODULE_CHECK_RESULT) endmacro() diff --git a/CMake/mitkMacroCreateModule.cmake b/CMake/mitkMacroCreateModule.cmake index b9b7d3e481..35ca062e2f 100644 --- a/CMake/mitkMacroCreateModule.cmake +++ b/CMake/mitkMacroCreateModule.cmake @@ -1,376 +1,407 @@ ################################################################## # # MITK_CREATE_MODULE # #! Creates a module for the automatic module dependency system within MITK. #! Configurations are generated in the moduleConf directory. #! #! USAGE: #! #! \code #! MITK_CREATE_MODULE( #! [INCLUDE_DIRS ] #! [INTERNAL_INCLUDE_DIRS ] #! [DEPENDS ] #! [PACKAGE_DEPENDS ] #! [TARGET_DEPENDS #! [EXPORT_DEFINE ] #! [QT_MODULE] #! [HEADERS_ONLY] #! [WARNINGS_AS_ERRORS] #! \endcode #! #! \param MODULE_NAME_IN The name for the new module #! \param HEADERS_ONLY specify this if the modules just contains header files. ################################################################## macro(MITK_CREATE_MODULE MODULE_NAME_IN) set(_macro_params SUBPROJECTS # list of CDash labels VERSION # module version number, e.g. "1.2.0" INCLUDE_DIRS # exported include dirs (used in mitkMacroCreateModuleConf.cmake) INTERNAL_INCLUDE_DIRS # include dirs internal to this module DEPENDS # list of modules this module depends on DEPENDS_INTERNAL # list of modules this module internally depends on PACKAGE_DEPENDS # list of "packages this module depends on (e.g. Qt, VTK, etc.) TARGET_DEPENDS # list of CMake targets this module should depend on EXPORT_DEFINE # export macro name for public symbols of this module AUTOLOAD_WITH # a module target name identifying the module which will trigger the # automatic loading of this module ADDITIONAL_LIBS # list of addidtional libraries linked to this module GENERATED_CPP # not used (?) ) set(_macro_options QT_MODULE # the module makes use of Qt features and needs moc and ui generated files FORCE_STATIC # force building this module as a static library HEADERS_ONLY # this module is a headers-only library GCC_DEFAULT_VISIBILITY # do not use gcc visibility flags - all symbols will be exported NO_INIT # do not create CppMicroServices initialization code WARNINGS_AS_ERRORS # treat all compiler warnings as errors ) MACRO_PARSE_ARGUMENTS(MODULE "${_macro_params}" "${_macro_options}" ${ARGN}) set(MODULE_NAME ${MODULE_NAME_IN}) if(MODULE_HEADERS_ONLY) set(MODULE_PROVIDES ) if(MODULE_AUTOLOAD_WITH) message(SEND_ERROR "A headers only module cannot be auto-loaded") endif() else() set(MODULE_PROVIDES ${MODULE_NAME}) if(NOT MODULE_NO_INIT AND NOT MODULE_NAME STREQUAL "Mitk") # Add a dependency to the "Mitk" module list(APPEND MODULE_DEPENDS Mitk) endif() endif() if(NOT MODULE_SUBPROJECTS) if(MITK_DEFAULT_SUBPROJECTS) set(MODULE_SUBPROJECTS ${MITK_DEFAULT_SUBPROJECTS}) endif() endif() # check if the subprojects exist as targets if(MODULE_SUBPROJECTS) foreach(subproject ${MODULE_SUBPROJECTS}) if(NOT TARGET ${subproject}) message(SEND_ERROR "The subproject ${subproject} does not have a corresponding target") endif() endforeach() endif() # check and set-up auto-loading if(MODULE_AUTOLOAD_WITH) if(NOT TARGET "${MODULE_AUTOLOAD_WITH}") message(SEND_ERROR "The module target \"${MODULE_AUTOLOAD_WITH}\" specified as the auto-loading module for \"${MODULE_NAME}\" does not exist") endif() # create a meta-target if it does not already exist set(_module_autoload_meta_target "${MODULE_AUTOLOAD_WITH}-universe") if(NOT TARGET ${_module_autoload_meta_target}) add_custom_target(${_module_autoload_meta_target}) endif() endif() # assume worst case set(MODULE_IS_ENABLED 0) # first we check if we have an explicit module build list if(MITK_MODULES_TO_BUILD) list(FIND MITK_MODULES_TO_BUILD ${MODULE_NAME} _MOD_INDEX) if(_MOD_INDEX EQUAL -1) set(MODULE_IS_EXCLUDED 1) endif() endif() if(NOT MODULE_IS_EXCLUDED AND NOT (MODULE_QT_MODULE AND NOT MITK_USE_QT)) # first of all we check for the dependencies MITK_CHECK_MODULE(_MISSING_DEP ${MODULE_DEPENDS}) if(_MISSING_DEP) message("Module ${MODULE_NAME} won't be built, missing dependency: ${_MISSING_DEP}") set(MODULE_IS_ENABLED 0) else(_MISSING_DEP) set(MODULE_IS_ENABLED 1) # now check for every package if it is enabled. This overlaps a bit with # MITK_CHECK_MODULE ... foreach(_package ${MODULE_PACKAGE_DEPENDS}) if((DEFINED MITK_USE_${_package}) AND NOT (MITK_USE_${_package})) message("Module ${MODULE_NAME} won't be built. Turn on MITK_USE_${_package} if you want to use it.") set(MODULE_IS_ENABLED 0) endif() endforeach() if(MODULE_IS_ENABLED) # clear variables defined in files.cmake set(RESOURCE_FILES ) set(CPP_FILES ) set(H_FILES ) set(TXX_FILES ) set(DOX_FILES ) set(UI_FILES ) set(MOC_H_FILES ) set(QRC_FILES ) # clear other variables set(Q${KITNAME}_GENERATED_MOC_CPP ) set(Q${KITNAME}_GENERATED_QRC_CPP ) set(Q${KITNAME}_GENERATED_UI_CPP ) _MITK_CREATE_MODULE_CONF() if(NOT MODULE_EXPORT_DEFINE) set(MODULE_EXPORT_DEFINE ${MODULE_NAME}_EXPORT) endif(NOT MODULE_EXPORT_DEFINE) if(MITK_GENERATE_MODULE_DOT) message("MODULEDOTNAME ${MODULE_NAME}") foreach(dep ${MODULE_DEPENDS}) message("MODULEDOT \"${MODULE_NAME}\" -> \"${dep}\" ; ") endforeach(dep) endif(MITK_GENERATE_MODULE_DOT) set(DEPENDS "${MODULE_DEPENDS}") set(DEPENDS_BEFORE "not initialized") set(PACKAGE_DEPENDS "${MODULE_PACKAGE_DEPENDS}") MITK_USE_MODULE("${MODULE_DEPENDS}") # ok, now create the module itself include_directories(. ${ALL_INCLUDE_DIRECTORIES}) include(files.cmake) - set(module_compile_flags ) - if(WIN32) - set(module_compile_flags "${module_compile_flags} -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") - endif() + set(module_c_flags ) + set(module_c_flags_debug ) + set(module_c_flags_release ) + set(module_cxx_flags ) + set(module_cxx_flags_debug ) + set(module_cxx_flags_release ) if(MODULE_GCC_DEFAULT_VISIBILITY) set(use_visibility_flags 0) else() # We only support hidden visibility for gcc for now. Clang 3.0 still has troubles with # correctly marking template declarations and explicit template instantiations as exported. # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 # and http://llvm.org/bugs/show_bug.cgi?id=10113 if(CMAKE_COMPILER_IS_GNUCXX) set(use_visibility_flags 1) else() # set(use_visibility_flags 0) endif() endif() if(CMAKE_COMPILER_IS_GNUCXX) # MinGW does not export all symbols automatically, so no need to set flags. # # With gcc < 4.5, RTTI symbols from classes declared in third-party libraries # which are not "gcc visibility aware" are marked with hidden visibility in # DSOs which include the class declaration and which are compiled with # hidden visibility. This leads to dynamic_cast and exception handling problems. # While this problem could be worked around by sandwiching the include # directives for the third-party headers between "#pragma visibility push/pop" # statements, it is generally safer to just use default visibility with # gcc < 4.5. if(${GCC_VERSION} VERSION_LESS "4.5" OR MINGW) set(use_visibility_flags 0) endif() endif() if(use_visibility_flags) - mitkFunctionCheckCompilerFlags("-fvisibility=hidden" module_compile_flags) - mitkFunctionCheckCompilerFlags("-fvisibility-inlines-hidden" module_compile_flags) + mitkFunctionCheckCompilerFlags2("-fvisibility=hidden" module_c_flags module_cxx_flags) + mitkFunctionCheckCompilerFlags2("-fvisibility-inlines-hidden" module_c_flags module_cxx_flags) endif() configure_file(${MITK_SOURCE_DIR}/CMake/moduleExports.h.in ${CMAKE_BINARY_DIR}/${MODULES_CONF_DIRNAME}/${MODULE_NAME}Exports.h @ONLY) if(MODULE_WARNINGS_AS_ERRORS) if(MSVC_VERSION) - mitkFunctionCheckCompilerFlags("/WX" module_compile_flags) + mitkFunctionCheckCompilerFlags2("/WX" module_c_flags module_cxx_flags) else() - mitkFunctionCheckCompilerFlags("-Werror" module_compile_flags) + mitkFunctionCheckCompilerFlags2("-Werror" module_c_flags module_cxx_flags) # The flag "c++0x-static-nonintegral-init" has been renamed in newer Clang # versions to "static-member-init", see # http://clang-developers.42468.n3.nabble.com/Wc-0x-static-nonintegral-init-gone-td3999651.html # # Also, older Clang and seemingly all gcc versions do not warn if unknown # "-no-*" flags are used, so CMake will happily append any -Wno-* flag to the # command line. This may get confusing if unrelated compiler errors happen and - # the error output then additinally contains errors about unknown flags (which + # the error output then additionally contains errors about unknown flags (which # is not the case if there were no compile errors). # # So instead of using -Wno-* we use -Wno-error=*, which will be properly rejected by # the compiler and if applicable, prints the specific warning as a real warning and # not as an error (although -Werror was given). - mitkFunctionCheckCompilerFlags("-Wno-error=c++0x-static-nonintegral-init" module_compile_flags) - mitkFunctionCheckCompilerFlags("-Wno-error=static-member-init" module_compile_flags) - mitkFunctionCheckCompilerFlags("-Wno-unknown-warning-option" module_compile_flags) - mitkFunctionCheckCompilerFlags("-Wno-error=gnu" module_compile_flags) + mitkFunctionCheckCompilerFlags2("-Wno-error=c++0x-static-nonintegral-init" module_c_flags module_cxx_flags) + mitkFunctionCheckCompilerFlags2("-Wno-error=static-member-init" module_c_flags module_cxx_flags) + mitkFunctionCheckCompilerFlags2("-Wno-error=unknown-warning" module_c_flags module_cxx_flags) + mitkFunctionCheckCompilerFlags2("-Wno-error=gnu" module_c_flags module_cxx_flags) # VNL headers throw a lot of these, not fixable for us at least in ITK 3 - mitkFunctionCheckCompilerFlags("-Wno-error=unused-parameter" module_compile_flags) + mitkFunctionCheckCompilerFlags2("-Wno-error=unused-parameter" module_c_flags module_cxx_flags) # Some DICOM header file in ITK - mitkFunctionCheckCompilerFlags("-Wno-error=cast-align" module_compile_flags) + mitkFunctionCheckCompilerFlags2("-Wno-error=cast-align" module_c_flags module_cxx_flags) endif() endif(MODULE_WARNINGS_AS_ERRORS) if(MODULE_FORCE_STATIC) set(_STATIC STATIC) else() set(_STATIC ) endif(MODULE_FORCE_STATIC) if(NOT MODULE_NO_INIT) set(MODULE_LIBNAME ${MODULE_PROVIDES}) usFunctionGenerateModuleInit(CPP_FILES NAME ${MODULE_NAME} LIBRARY_NAME ${MODULE_LIBNAME} DEPENDS ${MODULE_DEPENDS} ${MODULE_DEPENDS_INTERNAL} ${MODULE_PACKAGE_DEPENDS} #VERSION ${MODULE_VERSION} ) if(RESOURCE_FILES) + set(res_dir Resources) + set(binary_res_files ) + set(source_res_files ) + foreach(res_file ${RESOURCE_FILES}) + if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${res_dir}/${res_file}) + list(APPEND binary_res_files "${res_file}") + else() + list(APPEND source_res_files "${res_file}") + endif() + endforeach() + + set(res_macro_args ) + if(binary_res_files) + list(APPEND res_macro_args ROOT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${res_dir} + FILES ${binary_res_files}) + endif() + if(source_res_files) + list(APPEND res_macro_args ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${res_dir} + FILES ${source_res_files}) + endif() + usFunctionEmbedResources(CPP_FILES LIBRARY_NAME ${MODULE_LIBNAME} - ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Resources - FILES ${RESOURCE_FILES}) + ${res_macro_args}) endif() endif() if(MODULE_QT_MODULE) if(UI_FILES) QT4_WRAP_UI(Q${KITNAME}_GENERATED_UI_CPP ${UI_FILES}) endif(UI_FILES) if(MOC_H_FILES) QT4_WRAP_CPP(Q${KITNAME}_GENERATED_MOC_CPP ${MOC_H_FILES}) endif(MOC_H_FILES) if(QRC_FILES) QT4_ADD_RESOURCES(Q${KITNAME}_GENERATED_QRC_CPP ${QRC_FILES}) endif(QRC_FILES) set(Q${KITNAME}_GENERATED_CPP ${Q${KITNAME}_GENERATED_CPP} ${Q${KITNAME}_GENERATED_UI_CPP} ${Q${KITNAME}_GENERATED_MOC_CPP} ${Q${KITNAME}_GENERATED_QRC_CPP}) endif() ORGANIZE_SOURCES(SOURCE ${CPP_FILES} HEADER ${H_FILES} TXX ${TXX_FILES} DOC ${DOX_FILES} UI ${UI_FILES} QRC ${QRC_FILES} MOC ${Q${KITNAME}_GENERATED_MOC_CPP} GEN_QRC ${Q${KITNAME}_GENERATED_QRC_CPP} GEN_UI ${Q${KITNAME}_GENERATED_UI_CPP}) set(coverage_sources ${CPP_FILES} ${H_FILES} ${GLOBBED__H_FILES} ${CORRESPONDING__H_FILES} ${TXX_FILES} ${TOOL_CPPS} ${TOOL_GUI_CPPS}) if(MODULE_SUBPROJECTS) set_property(SOURCE ${coverage_sources} APPEND PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() if(NOT MODULE_HEADERS_ONLY) if(ALL_LIBRARY_DIRS) # LINK_DIRECTORIES applies only to targets which are added after the call to LINK_DIRECTORIES link_directories(${ALL_LIBRARY_DIRS}) endif(ALL_LIBRARY_DIRS) add_library(${MODULE_PROVIDES} ${_STATIC} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES}) if(MODULE_TARGET_DEPENDS) add_dependencies(${MODULE_PROVIDES} ${MODULE_TARGET_DEPENDS}) endif() if(MODULE_SUBPROJECTS) set_property(TARGET ${MODULE_PROVIDES} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) foreach(subproject ${MODULE_SUBPROJECTS}) add_dependencies(${subproject} ${MODULE_PROVIDES}) endforeach() endif() if(ALL_LIBRARIES) target_link_libraries(${MODULE_PROVIDES} ${ALL_LIBRARIES}) endif(ALL_LIBRARIES) if(MODULE_QT_MODULE AND QT_LIBRARIES) target_link_libraries(${MODULE_PROVIDES} ${QT_LIBRARIES}) endif() if(MINGW) target_link_libraries(${MODULE_PROVIDES} ssp) # add stack smash protection lib endif() # Apply properties to the module target. - set_target_properties(${MODULE_PROVIDES} PROPERTIES - COMPILE_FLAGS "${module_compile_flags}") + # We cannot use set_target_properties like below since there is no way to + # differentiate C/C++ and Releas/Debug flags using target properties. + # See http://www.cmake.org/Bug/view.php?id=6493 + #set_target_properties(${MODULE_PROVIDES} PROPERTIES + # COMPILE_FLAGS "${module_compile_flags}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${module_c_flags}") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${module_c_flags_debug}") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${module_c_flags_release}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${module_cxx_flags}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${module_cxx_flags_debug}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${module_cxx_flags_release}") # add the target name to a global property which is used in the top-level # CMakeLists.txt file to export the target set_property(GLOBAL APPEND PROPERTY MITK_MODULE_TARGETS ${MODULE_PROVIDES}) if(MODULE_AUTOLOAD_WITH) # for auto-loaded modules, adapt the output directory add_dependencies(${_module_autoload_meta_target} ${MODULE_PROVIDES}) if(WIN32) set(_module_output_prop RUNTIME_OUTPUT_DIRECTORY) else() set(_module_output_prop LIBRARY_OUTPUT_DIRECTORY) endif() set(_module_output_dir ${CMAKE_${_module_output_prop}}/${MODULE_AUTOLOAD_WITH}) get_target_property(_module_is_imported ${MODULE_AUTOLOAD_WITH} IMPORTED) if(NOT _module_is_imported) # if the auto-loading module is not imported, get its location # and put the auto-load module relative to it. get_target_property(_module_output_dir ${MODULE_AUTOLOAD_WITH} ${_module_output_prop}) set_target_properties(${MODULE_PROVIDES} PROPERTIES ${_module_output_prop} ${_module_output_dir}/${MODULE_AUTOLOAD_WITH}) else() set_target_properties(${MODULE_PROVIDES} PROPERTIES ${_module_output_prop} ${CMAKE_${_module_output_prop}}/${MODULE_AUTOLOAD_WITH}) endif() set_target_properties(${MODULE_PROVIDES} PROPERTIES MITK_AUTOLOAD_DIRECTORY ${MODULE_AUTOLOAD_WITH}) # add the auto-load module name as a property set_property(TARGET ${MODULE_AUTOLOAD_WITH} APPEND PROPERTY MITK_AUTOLOAD_TARGETS ${MODULE_PROVIDES}) else() # Add meta dependencies (e.g. on auto-load modules from depending modules) if(ALL_META_DEPENDENCIES) add_dependencies(${MODULE_PROVIDES} ${ALL_META_DEPENDENCIES}) endif() endif() endif() endif(MODULE_IS_ENABLED) endif(_MISSING_DEP) endif(NOT MODULE_IS_EXCLUDED AND NOT (MODULE_QT_MODULE AND NOT MITK_USE_QT)) if(NOT MODULE_IS_ENABLED) _MITK_CREATE_MODULE_CONF() endif(NOT MODULE_IS_ENABLED) endmacro(MITK_CREATE_MODULE) diff --git a/CMakeExternals/Boost.cmake b/CMakeExternals/Boost.cmake index 8d62e1c297..62520b4a5f 100644 --- a/CMakeExternals/Boost.cmake +++ b/CMakeExternals/Boost.cmake @@ -1,71 +1,78 @@ #----------------------------------------------------------------------------- # Boost #----------------------------------------------------------------------------- if(MITK_USE_Boost) # Sanity checks if(DEFINED BOOST_ROOT AND NOT EXISTS ${BOOST_ROOT}) message(FATAL_ERROR "BOOST_ROOT variable is defined but corresponds to non-existing directory") endif() set(proj Boost) set(proj_DEPENDENCIES ) set(Boost_DEPENDS ${proj}) if(NOT DEFINED BOOST_ROOT AND NOT MITK_USE_SYSTEM_Boost) set(_boost_libs ) + set(INSTALL_COMMAND "") if(MITK_USE_Boost_LIBRARIES) + + # Set the boost root to the libraries install directory + set(BOOST_ROOT "${CMAKE_CURRENT_BINARY_DIR}/${proj}-install") + # We need binary boost libraries foreach(_boost_lib ${MITK_USE_Boost_LIBRARIES}) set(_boost_libs ${_boost_libs} --with-${_boost_lib}) endforeach() if(WIN32) set(_boost_variant "") set(_shell_extension .bat) else() if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(_boost_variant "variant=debug") else() set(_boost_variant "variant=release") endif() set(_shell_extension .sh) endif() + if(APPLE) + set(APPLE_CMAKE_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/${proj}-cmake/ChangeBoostLibsInstallNameForMac.cmake) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeExternals/ChangeBoostLibsInstallNameForMac.cmake.in ${APPLE_CMAKE_SCRIPT} @ONLY) + set(INSTALL_COMMAND ${CMAKE_COMMAND} -P ${APPLE_CMAKE_SCRIPT}) + endif() + set(_boost_cfg_cmd ${CMAKE_CURRENT_BINARY_DIR}/${proj}-src/bootstrap${_shell_extension}) set(_boost_build_cmd ${CMAKE_CURRENT_BINARY_DIR}/${proj}-src/bjam --build-dir=${CMAKE_CURRENT_BINARY_DIR}/${proj}-build --prefix=${CMAKE_CURRENT_BINARY_DIR}/${proj}-install ${_boost_variant} ${_boost_libs} link=shared,static threading=multi runtime-link=shared -q install) else() + # If no libraries are specified set the boost root to the boost src directory + set(BOOST_ROOT "${CMAKE_CURRENT_BINARY_DIR}/${proj}-src") set(_boost_cfg_cmd ) set(_boost_build_cmd ) endif() ExternalProject_Add(${proj} SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src # Boost needs in-source builds BINARY_DIR ${proj}-src PREFIX ${proj}-cmake URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/boost_1_45_0.tar.bz2 URL_MD5 d405c606354789d0426bc07bea617e58 INSTALL_DIR ${proj}-install CONFIGURE_COMMAND "${_boost_cfg_cmd}" BUILD_COMMAND "${_boost_build_cmd}" - INSTALL_COMMAND "" + INSTALL_COMMAND "${INSTALL_COMMAND}" DEPENDS ${proj_DEPENDENCIES} ) - if(MITK_USE_Boost_LIBRARIES) - set(BOOST_ROOT "${CMAKE_CURRENT_BINARY_DIR}/${proj}-install") - else() - set(BOOST_ROOT "${CMAKE_CURRENT_BINARY_DIR}/${proj}-src") - endif() - else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/CTK.cmake b/CMakeExternals/CTK.cmake index 065ac082e9..2ed5c14fb8 100644 --- a/CMakeExternals/CTK.cmake +++ b/CMakeExternals/CTK.cmake @@ -1,81 +1,83 @@ #----------------------------------------------------------------------------- # CTK #----------------------------------------------------------------------------- if(MITK_USE_CTK) # Sanity checks if(DEFINED CTK_DIR AND NOT EXISTS ${CTK_DIR}) message(FATAL_ERROR "CTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj CTK) set(proj_DEPENDENCIES ) set(CTK_DEPENDS ${proj}) if(NOT DEFINED CTK_DIR) - set(revision_tag 4e6ac62e) + set(revision_tag fef76cef) #IF(${proj}_REVISION_TAG) # SET(revision_tag ${${proj}_REVISION_TAG}) #ENDIF() set(ctk_optional_cache_args ) if(MITK_USE_Python) list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=ON + -DCTK_ENABLE_Python_Wrapping:BOOL=ON + -DCTK_APP_ctkSimplePythonShell:BOOL=ON ) endif() if(MITK_USE_DCMTK) list(APPEND ctk_optional_cache_args -DDCMTK_DIR:PATH=${DCMTK_DIR} ) list(APPEND proj_DEPENDENCIES DCMTK) else() list(APPEND ctk_optional_cache_args -DDCMTK_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/CTK_DCMTK_085525e6.tar.gz ) endif() 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() ExternalProject_Add(${proj} SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src BINARY_DIR ${proj}-build PREFIX ${proj}-cmake URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/CTK_${revision_tag}.tar.gz - URL_MD5 dc553f3da6591d490b4175fb66892276 + URL_MD5 4d001d855cc3f722827a6cd95bfb7d9c UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${ctk_optional_cache_args} -DDESIRED_QT_VERSION:STRING=4 -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} -DGit_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DCTK_LIB_CommandLineModules/Backend/LocalProcess:BOOL=ON -DCTK_LIB_CommandLineModules/Frontend/QtGui:BOOL=ON -DCTK_LIB_PluginFramework:BOOL=ON -DCTK_LIB_DICOM/Widgets:BOOL=ON -DCTK_PLUGIN_org.commontk.eventadmin:BOOL=ON -DCTK_PLUGIN_org.commontk.configadmin:BOOL=ON -DCTK_USE_GIT_PROTOCOL:BOOL=OFF -DDCMTK_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/CTK_DCMTK_085525e6.tar.gz DEPENDS ${proj_DEPENDENCIES} ) set(CTK_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}-build) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/ChangeBoostLibsInstallNameForMac.cmake.in b/CMakeExternals/ChangeBoostLibsInstallNameForMac.cmake.in new file mode 100644 index 0000000000..a61175fb5d --- /dev/null +++ b/CMakeExternals/ChangeBoostLibsInstallNameForMac.cmake.in @@ -0,0 +1,18 @@ +# Scan the MITK-Superbuild/Boost-install/lib directory for *.dylib files and change their install names for mac +# On Mac OS X system each shared library usually has a install name which is the absolute path of the library. +# For some reasons boost libs do not contain the absolute path but just their name +# (e.g. "libboost_thread.dylib" should be named "") + +# Get all the shared libraries which are located in the Boost-install/lib directory +file(GLOB dylibFiles @BOOST_ROOT@/lib/*.dylib) + +# For each shared library call the install_name_tool in order to change the install name of the according library +foreach(_dylib ${dylibFiles}) + message("Fixing boost install name for lib: ${_dylib}") + execute_process(COMMAND install_name_tool -id ${_dylib} ${_dylib}) +endforeach() + + + + + diff --git a/CMakeExternals/DCMTK.cmake b/CMakeExternals/DCMTK.cmake index 8d6b36a1bd..c72ba49bcf 100644 --- a/CMakeExternals/DCMTK.cmake +++ b/CMakeExternals/DCMTK.cmake @@ -1,70 +1,70 @@ #----------------------------------------------------------------------------- # DCMTK #----------------------------------------------------------------------------- if(MITK_USE_DCMTK) # Sanity checks if(DEFINED DCMTK_DIR AND NOT EXISTS ${DCMTK_DIR}) message(FATAL_ERROR "DCMTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMTK) set(proj_DEPENDENCIES ) set(DCMTK_DEPENDS ${proj}) if(CMAKE_GENERATOR MATCHES Xcode) set(DCMTK_PATCH_COMMAND ${CMAKE_COMMAND} -DTEMPLATE_FILE:FILEPATH=${MITK_SOURCE_DIR}/CMakeExternals/EmptyFileForPatching.dummy -P ${MITK_SOURCE_DIR}/CMakeExternals/PatchDCMTK-20122202.cmake) endif() if(NOT DEFINED DCMTK_DIR) if(UNIX) set(DCMTK_CXX_FLAGS "-fPIC") set(DCMTK_C_FLAGS "-fPIC") endif(UNIX) if(DCMTK_DICOM_ROOT_ID) set(DCMTK_CXX_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") set(DCMTK_C_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") endif() set (dcmtk_shared_flags "-DBUILD_SHARED_LIBS:BOOL=${MITK_DCMTK_BUILD_SHARED_LIBS}") if (NOT MITK_DCMTK_BUILD_SHARED_LIBS) set (dcmtk_shared_flags ${dcmtk_shared_flags} "-DDCMTK_FORCE_FPIC_ON_UNIX:BOOL=ON") endif() ExternalProject_Add(${proj} SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src BINARY_DIR ${proj}-build PREFIX ${proj}-cmake URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmtk-3.6.1_20120222.tar.gz URL_MD5 86fa9e0f91e4e0c6b44d513ea48391d6 INSTALL_DIR ${proj}-install PATCH_COMMAND ${DCMTK_PATCH_COMMAND} CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} -DDCMTK_OVERWRITE_WIN32_COMPILER_FLAGS:BOOL=OFF ${dcmtk_shared_flags} - "-DCMAKE_CXX_FLAGS:STRING=${ep_common_CXX_FLAGS} ${DCMTK_CXX_FLAGS}" - "-DCMAKE_C_FLAGS:STRING=${ep_common_C_FLAGS} ${DCMTK_C_FLAGS}" + "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${DCMTK_CXX_FLAGS}" + "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${DCMTK_C_FLAGS}" -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/${proj}-install -DDCMTK_INSTALL_BINDIR:STRING=bin/${CMAKE_CFG_INTDIR} -DDCMTK_INSTALL_LIBDIR:STRING=lib/${CMAKE_CFG_INTDIR} -DDCMTK_WITH_DOXYGEN:BOOL=OFF -DDCMTK_WITH_ZLIB:BOOL=OFF # see bug #9894 -DDCMTK_WITH_OPENSSL:BOOL=OFF # see bug #9894 -DDCMTK_WITH_PNG:BOOL=OFF # see bug #9894 -DDCMTK_WITH_TIFF:BOOL=OFF # see bug #9894 -DDCMTK_WITH_XML:BOOL=OFF # see bug #9894 -DDCMTK_WITH_ICONV:BOOL=OFF # see bug #9894 DEPENDS ${proj_DEPENDENCIES} ) set(DCMTK_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}-install) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/ITK.cmake b/CMakeExternals/ITK.cmake index 3b099de8ab..64d28cc45a 100644 --- a/CMakeExternals/ITK.cmake +++ b/CMakeExternals/ITK.cmake @@ -1,66 +1,82 @@ #----------------------------------------------------------------------------- # ITK #----------------------------------------------------------------------------- # Sanity checks if(DEFINED ITK_DIR AND NOT EXISTS ${ITK_DIR}) message(FATAL_ERROR "ITK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj ITK) set(proj_DEPENDENCIES GDCM) if(MITK_USE_Python) list(APPEND proj_DEPENDENCIES CableSwig) endif() set(ITK_DEPENDS ${proj}) if(NOT DEFINED ITK_DIR) set(additional_cmake_args ) if(MINGW) set(additional_cmake_args -DCMAKE_USE_WIN32_THREADS:BOOL=ON -DCMAKE_USE_PTHREADS:BOOL=OFF) endif() if(MITK_USE_Python) + list(APPEND additional_cmake_args -DUSE_WRAP_ITK:BOOL=ON -DITK_USE_REVIEW:BOOL=ON + -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} + -DPYTHON_DEBUG_LIBRARY=${PYTHON_DEBUG_LIBRARY} + -DPYTHON_INCLUDE_DIR=${PYTHON_INCLUDE_DIR} + -DPYTHON_LIBRARY=${PYTHON_LIBRARY} + #-DPYTHON_LIBRARIES=${PYTHON_LIBRARY} + #-DPYTHON_DEBUG_LIBRARIES=${PYTHON_DEBUG_LIBRARIES} -DCableSwig_DIR:PATH=${CableSwig_DIR} -DWRAP_ITK_JAVA:BOOL=OFF -DWRAP_ITK_TCL:BOOL=OFF + -DWRAP_unsigned_char:BOOL=ON + #-DWRAP_double:BOOL=ON + -DWRAP_rgb_unsigned_char:BOOL=ON + #-DWRAP_rgba_unsigned_char:BOOL=ON + -DWRAP_signed_char:BOOL=ON + #-DWRAP_signed_long:BOOL=ON + -DWRAP_signed_short:BOOL=ON + -DWRAP_short:BOOL=ON + -DWRAP_unsigned_long:BOOL=ON ) endif() if(GDCM_IS_2_0_18) set(ITK_PATCH_COMMAND ${CMAKE_COMMAND} -DTEMPLATE_FILE:FILEPATH=${MITK_SOURCE_DIR}/CMakeExternals/EmptyFileForPatching.dummy -P ${MITK_SOURCE_DIR}/CMakeExternals/PatchITK-3.20.cmake) endif() ExternalProject_Add(${proj} SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src BINARY_DIR ${proj}-build PREFIX ${proj}-cmake URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/InsightToolkit-3.20.1.tar.gz URL_MD5 90342ffa78bd88ae48b3f62866fbf050 INSTALL_COMMAND "" PATCH_COMMAND ${ITK_PATCH_COMMAND} CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} -DBUILD_TESTING:BOOL=OFF -DBUILD_EXAMPLES:BOOL=OFF -DITK_USE_SYSTEM_GDCM:BOOL=ON -DGDCM_DIR:PATH=${GDCM_DIR} DEPENDS ${proj_DEPENDENCIES} ) set(ITK_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}-build) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/OpenCV.cmake b/CMakeExternals/OpenCV.cmake index 82bbfeb82e..8ac74e701c 100644 --- a/CMakeExternals/OpenCV.cmake +++ b/CMakeExternals/OpenCV.cmake @@ -1,65 +1,77 @@ #----------------------------------------------------------------------------- # OpenCV #----------------------------------------------------------------------------- if(MITK_USE_OpenCV) # Sanity checks if(DEFINED OpenCV_DIR AND NOT EXISTS ${OpenCV_DIR}) message(FATAL_ERROR "OpenCV_DIR variable is defined but corresponds to non-existing directory") endif() set(proj OpenCV) set(proj_DEPENDENCIES) set(OpenCV_DEPENDS ${proj}) if(NOT DEFINED OpenCV_DIR) set(additional_cmake_args ) if(MITK_USE_Python) + #message(STATUS "PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}") + #message(STATUS "PYTHON_DEBUG_LIBRARY: ${PYTHON_DEBUG_LIBRARY}") + #message(STATUS "PYTHON_INCLUDE_DIR: ${PYTHON_INCLUDE_DIR}") + #message(STATUS "PYTHON_LIBRARY: ${PYTHON_LIBRARY}") + list(APPEND additional_cmake_args - -DBUILD_NEW_PYTHON_SUPPORT:BOOL=ON + -DBUILD_opencv_python:BOOL=ON + -DBUILD_NEW_PYTHON_SUPPORT:BOOL=ON + -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} + -DPYTHON_DEBUG_LIBRARY=${PYTHON_DEBUG_LIBRARY} + -DPYTHON_INCLUDE_DIR=${PYTHON_INCLUDE_DIR} + -DPYTHON_LIBRARY=${PYTHON_LIBRARY} + #-DPYTHON_LIBRARIES=${PYTHON_LIBRARY} + #-DPYTHON_DEBUG_LIBRARIES=${PYTHON_DEBUG_LIBRARIES} ) endif() # 12-05-02, muellerm, added QT usage by OpenCV if QT is used in MITK # 12-09-11, muellerm, removed automatic usage again, since this will struggle with the MITK Qt application object if(MITK_USE_QT) list(APPEND additional_cmake_args -DWITH_QT:BOOL=OFF -DWITH_QT_OPENGL:BOOL=OFF -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} ) endif() set(opencv_url ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/OpenCV-2.4.2.tar.bz2) set(opencv_url_md5 d5d13c4a65dc96cdfaad54767e428215) ExternalProject_Add(${proj} SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src BINARY_DIR ${proj}-build PREFIX ${proj}-cmake URL ${opencv_url} URL_MD5 ${opencv_url_md5} INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} -DBUILD_DOCS:BOOL=OFF -DBUILD_TESTS:BOOL=OFF -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_DOXYGEN_DOCS:BOOL=OFF -DWITH_CUDA:BOOL=ON ${additional_cmake_args} DEPENDS ${proj_DEPENDENCIES} ) set(OpenCV_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}-build) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/VTK.cmake b/CMakeExternals/VTK.cmake index cb93fb5c24..33d6170d00 100644 --- a/CMakeExternals/VTK.cmake +++ b/CMakeExternals/VTK.cmake @@ -1,88 +1,94 @@ #----------------------------------------------------------------------------- # VTK #----------------------------------------------------------------------------- if(WIN32) option(VTK_USE_SYSTEM_FREETYPE OFF) else(WIN32) option(VTK_USE_SYSTEM_FREETYPE ON) endif(WIN32) # Sanity checks if(DEFINED VTK_DIR AND NOT EXISTS ${VTK_DIR}) message(FATAL_ERROR "VTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj VTK) set(proj_DEPENDENCIES ) set(VTK_DEPENDS ${proj}) if(NOT DEFINED VTK_DIR) set(additional_cmake_args ) if(MINGW) set(additional_cmake_args -DCMAKE_USE_WIN32_THREADS:BOOL=ON -DCMAKE_USE_PTHREADS:BOOL=OFF -DVTK_USE_VIDEO4WINDOWS:BOOL=OFF # no header files provided by MinGW ) endif() if(MITK_USE_Python) list(APPEND additional_cmake_args -DVTK_WRAP_PYTHON:BOOL=ON -DVTK_USE_TK:BOOL=OFF -DVTK_WINDOWS_PYTHON_DEBUGGABLE:BOOL=OFF + -DPYTHON_DEBUG_LIBRARY=${PYTHON_DEBUG_LIBRARY} + -DPYTHON_INCLUDE_DIR=${PYTHON_INCLUDE_DIR} + -DPYTHON_LIBRARY=${PYTHON_LIBRARY} + -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} + #-DPYTHON_LIBRARIES=${PYTHON_LIBRARY} + #-DPYTHON_DEBUG_LIBRARIES=${PYTHON_DEBUG_LIBRARIES} ) endif() if(MITK_USE_QT) list(APPEND additional_cmake_args -DDESIRED_QT_VERSION:STRING=4 -DVTK_USE_GUISUPPORT:BOOL=ON -DVTK_USE_QVTK_QTOPENGL:BOOL=OFF -DVTK_USE_QT:BOOL=ON -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} ) endif() set(VTK_URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/vtk-5.10.0.tar.gz) set(VTK_URL_MD5 a0363f78910f466ba8f1bd5ab5437cb9) if(APPLE) set(VTK_PATCH_COMMAND ${CMAKE_COMMAND} -DTEMPLATE_FILE:FILEPATH=${MITK_SOURCE_DIR}/CMakeExternals/EmptyFileForPatching.dummy -P ${MITK_SOURCE_DIR}/CMakeExternals/PatchVTK-5.10-Mac.cmake) endif() ExternalProject_Add(${proj} SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src BINARY_DIR ${proj}-build PREFIX ${proj}-cmake URL ${VTK_URL} URL_MD5 ${VTK_URL_MD5} INSTALL_COMMAND "" PATCH_COMMAND ${VTK_PATCH_COMMAND} CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} -DVTK_WRAP_TCL:BOOL=OFF -DVTK_WRAP_PYTHON:BOOL=OFF -DVTK_WRAP_JAVA:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=ON -DVTK_USE_PARALLEL:BOOL=ON -DVTK_USE_CHARTS:BOOL=OFF -DVTK_USE_QTCHARTS:BOOL=ON -DVTK_USE_GEOVIS:BOOL=OFF -DVTK_USE_SYSTEM_FREETYPE:BOOL=${VTK_USE_SYSTEM_FREETYPE} -DVTK_USE_QVTK_QTOPENGL:BOOL=OFF -DVTK_LEGACY_REMOVE:BOOL=ON ${additional_cmake_args} DEPENDS ${proj_DEPENDENCIES} ) set(VTK_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}-build) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 333f3c1b1f..024875dec7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,963 +1,975 @@ if(APPLE) # With XCode 4.3, the SDK location changed. Older CMake # versions are not able to find it. cmake_minimum_required(VERSION 2.8.8) else() cmake_minimum_required(VERSION 2.8.4) 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 ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(mitkMacroEmptyExternalProject) include(mitkFunctionGenerateProjectXml) include(mitkFunctionSuppressWarnings) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_USE_SUPERBUILD) set(output_dir ${MITK_BINARY_DIR}/bin) if(NOT DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_BINARY_DIR}/MITK-build/bin) endif() else() if(NOT DEFINED MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(output_dir ${MITK_BINARY_DIR}/bin) else() set(output_dir ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) endif() endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${output_dir} CACHE INTERNAL "Single output directory for building all libraries.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Additional MITK Options (also shown during superbuild) #----------------------------------------------------------------------------- option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) set(MITK_BUILD_TUTORIAL OFF CACHE INTERNAL "Deprecated! Use MITK_BUILD_EXAMPLES instead!") option(MITK_BUILD_EXAMPLES "Build the MITK Examples" ${MITK_BUILD_TUTORIAL}) option(MITK_USE_Boost "Use the Boost C++ library" OFF) option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) option(MITK_USE_CTK "Use CTK in MITK" ${MITK_USE_BLUEBERRY}) option(MITK_USE_QT "Use Nokia's Qt library" ${MITK_USE_CTK}) option(MITK_USE_DCMTK "EXPERIMENTAL, superbuild only: Use DCMTK in MITK" ${MITK_USE_CTK}) option(MITK_DCMTK_BUILD_SHARED_LIBS "EXPERIMENTAL, superbuild only: build DCMTK as shared libs" OFF) option(MITK_USE_OpenCV "Use Intel's OpenCV library" OFF) option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) option(MITK_USE_SOFA "Use Simulation Open Framework Architecture" OFF) option(MITK_USE_Python "Use Python wrapping in MITK" OFF) set(MITK_USE_CableSwig ${MITK_USE_Python}) +if(MITK_USE_Python) + FIND_PACKAGE(PythonLibs REQUIRED) + FIND_PACKAGE(PythonInterp REQUIRED) +endif() mark_as_advanced(MITK_BUILD_ALL_APPS MITK_USE_CTK MITK_USE_DCMTK ) 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) if(NOT MITK_USE_QT) message("Forcing MITK_USE_QT to ON because of MITK_USE_CTK") set(MITK_USE_QT ON CACHE BOOL "Use Nokia's Qt library in MITK" FORCE) endif() if(NOT MITK_USE_DCMTK) message("Setting MITK_USE_DCMTK to ON because DCMTK needs to be build for CTK") set(MITK_USE_DCMTK ON CACHE BOOL "Use DCMTK in MITK" FORCE) endif() endif() if(MITK_USE_QT) # find the package at the very beginning, so that QT4_FOUND is available find_package(Qt4 4.6.2 REQUIRED) endif() # Customize the default pixel types for multiplex macros set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") mark_as_advanced(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS ) # consistency checks if(NOT MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES) set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES) set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES) set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() -#----------------------------------------------------------------------------- -# Additional CXX/C Flags -#----------------------------------------------------------------------------- - -set(ADDITIONAL_C_FLAGS "" CACHE STRING "Additional C Flags") -mark_as_advanced(ADDITIONAL_C_FLAGS) -set(ADDITIONAL_CXX_FLAGS "" CACHE STRING "Additional CXX Flags") -mark_as_advanced(ADDITIONAL_CXX_FLAGS) - #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) if(MITK_USE_BLUEBERRY) list(APPEND CTEST_PROJECT_SUBPROJECTS BlueBerry) endif() list(APPEND CTEST_PROJECT_SUBPROJECTS MITK-Core MITK-CoreUI MITK-IGT MITK-ToF MITK-DTI MITK-Registration MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CheckCXXSourceCompiles) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionGetGccVersion) include(MacroParseArguments) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkFunctionOrganizeSources) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionCreateWindowsBatchScript) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionCompileSnippets) include(mitkMacroCreateModuleConf) include(mitkMacroCreateModule) include(mitkMacroCheckModule) include(mitkMacroCreateModuleTests) include(mitkFunctionAddCustomModuleTest) include(mitkMacroUseModule) include(mitkMacroMultiplexPicType) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) #----------------------------------------------------------------------------- # Prerequesites #----------------------------------------------------------------------------- find_package(ITK REQUIRED) find_package(VTK REQUIRED) if(ITK_USE_SYSTEM_GDCM) find_package(GDCM PATHS ${ITK_GDCM_DIR} REQUIRED) endif() #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- # ASK THE USER TO SHOW THE CONSOLE WINDOW FOR CoreApp and mitkWorkbench option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING 1) endif() endif() #----------------------------------------------------------------------------- # Get MITK version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK) mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK) #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on Mac OSX all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) list(GET target_info_list 0 app_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) set(MACOSX_BUNDLE_NAMES ${MACOSX_BUNDLE_NAMES} ${app_name}) endif() endforeach() endif() #----------------------------------------------------------------------------- # Set symbol visibility Flags #----------------------------------------------------------------------------- # MinGW does not export all symbols automatically, so no need to set flags if(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW) set(VISIBILITY_CXX_FLAGS ) #"-fvisibility=hidden -fvisibility-inlines-hidden") endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # MITK C/CXX Flags #----------------------------------------------------------------------------- -set(MITK_C_FLAGS "${COVERAGE_C_FLAGS} ${ADDITIONAL_C_FLAGS}") -set(MITK_CXX_FLAGS "${VISIBILITY_CXX_FLAGS} ${COVERAGE_CXX_FLAGS} ${ADDITIONAL_CXX_FLAGS}") +set(MITK_C_FLAGS "${COVERAGE_C_FLAGS}") +set(MITK_C_FLAGS_DEBUG ) +set(MITK_C_FLAGS_RELEASE ) +set(MITK_CXX_FLAGS "${VISIBILITY_CXX_FLAGS} ${COVERAGE_CXX_FLAGS}") +set(MITK_CXX_FLAGS_DEBUG ) +set(MITK_CXX_FLAGS_RELEASE ) + +set(MITK_EXE_LINKER_FLAGS ) +set(MITK_SHARED_LINKER_FLAGS ) include(mitkSetupC++0xVariables) -set(cflags ) if(WIN32) - set(cflags "${cflags} -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") + set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -D_WIN32_WINNT=0x0501 -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") endif() + if(NOT MSVC_VERSION) foreach(_flag -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings - -Wno-gnu + -Wno-error=gnu + -Woverloaded-virtual + -Wstrict-null-sentinel + #-Wold-style-cast + #-Wsign-promo -fdiagnostics-show-option ) - mitkFunctionCheckCompilerFlags(${_flag} cflags) + mitkFunctionCheckCompilerFlags2(${_flag} MITK_C_FLAGS MITK_CXX_FLAGS) endforeach() endif() if(CMAKE_COMPILER_IS_GNUCXX) - mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" cflags) - mitkFunctionCheckCompilerFlags("-Wl,--as-needed" cflags) + mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) + mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) if(MITK_USE_C++0x) mitkFunctionCheckCompilerFlags("-std=c++0x" MITK_CXX_FLAGS) endif() 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")) - mitkFunctionCheckCompilerFlags("-fstack-protector-all" cflags) + mitkFunctionCheckCompilerFlags2("-fstack-protector-all" MITK_C_FLAGS MITK_CXX_FLAGS) endif() if(MINGW) # suppress warnings about auto imported symbols - set(MITK_CXX_FLAGS "-Wl,--enable-auto-import ${MITK_CXX_FLAGS}") - # we need to define a Windows version - set(MITK_CXX_FLAGS "-D_WIN32_WINNT=0x0500 ${MITK_CXX_FLAGS}") + set(MITK_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import ${MITK_SHARED_LINKER_FLAGS}") endif() - #set(MITK_CXX_FLAGS "-Woverloaded-virtual -Wold-style-cast -Wstrict-null-sentinel -Wsign-promo ${MITK_CXX_FLAGS}") - set(MITK_CXX_FLAGS "-Woverloaded-virtual -Wstrict-null-sentinel ${MITK_CXX_FLAGS}") set(MITK_CXX_FLAGS_RELEASE "-D_FORTIFY_SOURCE=2 ${MITK_CXX_FLAGS_RELEASE}") endif() -set(MITK_C_FLAGS "${cflags} ${MITK_C_FLAGS}") -set(MITK_CXX_FLAGS "${cflags} ${MITK_CXX_FLAGS}") +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_GUI_TESTING OFF "Enable the MITK GUI tests") # 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 Flags for MITK code +# 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}") if(MITK_USE_QT) add_definitions(-DQWT_DLL) endif() #----------------------------------------------------------------------------- # 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 #----------------------------------------------------------------------------- link_directories(${MITK_LINK_DIRECTORIES}) add_subdirectory(Core) include(${CMAKE_CURRENT_BINARY_DIR}/Core/Code/CppMicroServices/CppMicroServicesConfig.cmake) add_subdirectory(Modules) if(MITK_USE_BLUEBERRY) find_package(BlueBerry REQUIRED) set(MITK_DEFAULT_SUBPROJECTS MITK-Plugins) # Plug-in testing (needs some work to be enabled again) if(BUILD_TESTING) include(berryTestingHelpers) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp") get_target_property(_is_macosx_bundle CoreApp MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp.app/Contents/MacOS/CoreApp") endif() set(BLUEBERRY_TEST_APP_ID "org.mitk.qt.coreapplication") endif() include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") set(mitk_plugins_fullpath ) foreach(mitk_plugin ${MITK_EXT_PLUGINS}) list(APPEND mitk_plugins_fullpath Plugins/${mitk_plugin}) endforeach() if(EXISTS ${MITK_PRIVATE_MODULES}/PluginList.cmake) include(${MITK_PRIVATE_MODULES}/PluginList.cmake) foreach(mitk_plugin ${MITK_PRIVATE_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PRIVATE_MODULES}/${mitk_plugin}) endforeach() endif() # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_[a-zA-Z0-9_]+$") set(re_ctkplugin_bb "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk re_ctkplugin_bb OUTPUT_VARIABLE ${varname}) endmacro() # Get infos about application directories and build options include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") set(mitk_apps_fullpath ) foreach(mitk_app ${MITK_APPS}) list(APPEND mitk_apps_fullpath "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${mitk_app}") endforeach() ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() + # 11.3.13, change, muellerm: activate python bundle if python and blueberry is active + if( MITK_USE_Python ) + set(MITK_BUILD_org.mitk.gui.qt.python ON) + endif() + endif() # Construct a list of paths containing runtime directories # for MITK applications on Windows set(MITK_RUNTIME_PATH "${VTK_LIBRARY_DIRS}/%VS_BUILD_TYPE%;${ITK_LIBRARY_DIRS}/%VS_BUILD_TYPE%;${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/%VS_BUILD_TYPE%" ) if(QT4_FOUND) set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${QT_LIBRARY_DIR}/../bin") endif() if(MITK_USE_BLUEBERRY) set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${CTK_RUNTIME_LIBRARY_DIRS}/%VS_BUILD_TYPE%") if(DEFINED CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY) if(IS_ABSOLUTE "${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}") set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}/%VS_BUILD_TYPE%") else() set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CTK_PLUGIN_RUNTIME_OUTPUT_DIRECTORY}/%VS_BUILD_TYPE%") endif() else() set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/plugins/%VS_BUILD_TYPE%") endif() endif() if(GDCM_DIR) set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${GDCM_DIR}/bin/%VS_BUILD_TYPE%") endif() if(OpenCV_DIR) set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${OpenCV_DIR}/bin/%VS_BUILD_TYPE%") endif() if(SOFA_DIR) set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${SOFA_DIR}/bin/%VS_BUILD_TYPE%") endif() # DCMTK is statically build #if(DCMTK_DIR) # set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${DCMTK_DIR}/bin/%VS_BUILD_TYPE%") #endif() if(MITK_USE_Boost AND MITK_USE_Boost_LIBRARIES AND NOT MITK_USE_SYSTEM_Boost) set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${Boost_LIBRARY_DIRS}") endif() #----------------------------------------------------------------------------- # Python Wrapping #----------------------------------------------------------------------------- +option(MITK_USE_Python "Build Python integration for MITK (requires CableSwig)." OFF) -set(MITK_WRAPPING_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Wrapping) -set(MITK_WRAPPING_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Wrapping) -option(MITK_USE_Python "Build cswig Python wrapper support (requires CableSwig)." OFF) if(MITK_USE_Python) - add_subdirectory(Wrapping) + set(MITK_RUNTIME_PATH "${MITK_RUNTIME_PATH};${CTK_PYTHONQT_INSTALL_DIR}/bin") 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 #----------------------------------------------------------------------------- # This is for installation support of external projects depending on # MITK plugins and modules. The export file should not be used for linking to MITK # libraries without using LINK_DIRECTORIES, since the exports are incomplete # yet (depending libraries are not exported). 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() 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(VECMATH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/vecmath) set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc) set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) file(GLOB _MODULES_CONF_FILES RELATIVE ${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME} ${PROJECT_BINARY_DIR}/${MODULES_CONF_DIRNAME}/*.cmake) set(MITK_MODULE_NAMES) foreach(_module ${_MODULES_CONF_FILES}) string(REPLACE Config.cmake "" _module_name ${_module}) list(APPEND MITK_MODULE_NAMES ${_module_name}) endforeach() configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY) # If we are under Windows, create two batch files which correctly # set up the environment for the application and for Visual Studio if(WIN32) include(mitkFunctionCreateWindowsBatchScript) set(VS_SOLUTION_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.sln") foreach(VS_BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript("${MITK_SOURCE_DIR}/CMake/StartVS.bat.in" ${PROJECT_BINARY_DIR}/StartVS_${VS_BUILD_TYPE}.bat ${VS_BUILD_TYPE}) endforeach() endif(WIN32) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) #----------------------------------------------------------------------------- # MITK Examples #----------------------------------------------------------------------------- if(MITK_BUILD_EXAMPLES) # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Examples) endif() diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonPerspective.h b/Core/Code/Common/mitkCoreServices.cpp similarity index 51% rename from Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonPerspective.h rename to Core/Code/Common/mitkCoreServices.cpp index 97c8e7b1f6..cd12960ee9 100644 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonPerspective.h +++ b/Core/Code/Common/mitkCoreServices.cpp @@ -1,39 +1,38 @@ /*=================================================================== 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 "mitkCoreServices.h" -#ifndef QMITKPYTHONPERSPECTIVE_H_ -#define QMITKPYTHONPERSPECTIVE_H_ +#include "mitkIShaderRepository.h" -#include -#include +#include "mitkGetModuleContext.h" +#include "mitkModuleContext.h" +#include "mitkServiceReference.h" -struct QmitkPythonPerspective : public QObject, public berry::IPerspectiveFactory -{ - - Q_OBJECT - - void CreateInitialLayout(berry::IPageLayout::Pointer layout); +namespace mitk { - QmitkPythonPerspective(const QmitkPythonPerspective& other) +IShaderRepository* CoreServices::GetShaderRepository() +{ + IShaderRepository* shaderRepo = NULL; + ServiceReference serviceRef = GetModuleContext()->GetServiceReference(); + if (serviceRef) { - Q_UNUSED(other) - throw std::runtime_error("Copy constructor not implemented"); + shaderRepo = GetModuleContext()->GetService(serviceRef); } + return shaderRepo; +} -}; - -#endif /* QMITKEXTDEFAULTPERSPECTIVE_H_ */ +} diff --git a/Core/Code/Common/mitkCoreServices.h b/Core/Code/Common/mitkCoreServices.h new file mode 100644 index 0000000000..b8b20f6385 --- /dev/null +++ b/Core/Code/Common/mitkCoreServices.h @@ -0,0 +1,48 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKCORESERVICES_H +#define MITKCORESERVICES_H + +namespace mitk { + +struct IShaderRepository; + +/** + * @brief Access MITK core services. + * + * This class can be used inside the MITK Core to conveniently access + * common service objects. + * + * It is not exported and not meant to be used by other MITK modules. + */ +class CoreServices +{ +public: + + static IShaderRepository* GetShaderRepository(); + +private: + + // purposely not implemented + CoreServices(); + CoreServices(const CoreServices&); + CoreServices& operator=(const CoreServices&); +}; + +} + +#endif // MITKCORESERVICES_H diff --git a/Core/Code/Controllers/mitkCoreActivator.cpp b/Core/Code/Controllers/mitkCoreActivator.cpp index ca124745f1..180810703e 100644 --- a/Core/Code/Controllers/mitkCoreActivator.cpp +++ b/Core/Code/Controllers/mitkCoreActivator.cpp @@ -1,170 +1,224 @@ /*=================================================================== 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 "mitkRenderingManager.h" #include "mitkPlanePositionManager.h" #include "mitkCoreDataNodeReader.h" +#include "mitkShaderRepository.h" #include "mitkStandardFileLocations.h" #include #include +#include +#include +#include +#include void HandleMicroServicesMessages(mitk::MsgType type, const char* msg) { switch (type) { case mitk::DebugMsg: MITK_DEBUG << msg; break; case mitk::InfoMsg: MITK_INFO << msg; break; case mitk::WarningMsg: MITK_WARN << msg; break; case mitk::ErrorMsg: MITK_ERROR << msg; break; } } #if defined(_WIN32) || defined(_WIN64) std::string GetProgramPath() { char path[512]; std::size_t index = std::string(path, GetModuleFileName(NULL, path, 512)).find_last_of('\\'); return std::string(path, index); } #elif defined(__APPLE__) #include std::string GetProgramPath() { char path[512]; uint32_t size = sizeof(path); if (_NSGetExecutablePath(path, &size) == 0) { std::size_t index = std::string(path).find_last_of('/'); std::string strPath = std::string(path, index); const char* execPath = strPath.c_str(); mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(execPath,false); return strPath; } return std::string(); } #else #include #include #include std::string GetProgramPath() { std::stringstream ss; ss << "/proc/" << getpid() << "/exe"; - char proc[512]; + char proc[512] = {0}; ssize_t ch = readlink(ss.str().c_str(), proc, 512); if (ch == -1) return std::string(); std::size_t index = std::string(proc).find_last_of('/'); return std::string(proc, index); } #endif void AddMitkAutoLoadPaths(const std::string& programPath) { mitk::ModuleSettings::AddAutoLoadPath(programPath); #ifdef __APPLE__ // Walk up three directories since that is where the .dylib files are located // for build trees. std::string additionalPath = programPath; bool addPath = true; for(int i = 0; i < 3; ++i) { std::size_t index = additionalPath.find_last_of('/'); if (index != std::string::npos) { additionalPath = additionalPath.substr(0, index); } else { addPath = false; break; } } if (addPath) { mitk::ModuleSettings::AddAutoLoadPath(additionalPath); } #endif } /* * This is the module activator for the "Mitk" module. It registers core services * like ... */ class MitkCoreActivator : public mitk::ModuleActivator { public: void Load(mitk::ModuleContext* context) { // Handle messages from CppMicroServices mitk::installMsgHandler(HandleMicroServicesMessages); // Add the current application directory to the auto-load paths. // This is useful for third-party executables. std::string programPath = GetProgramPath(); if (programPath.empty()) { MITK_WARN << "Could not get the program path."; } else { AddMitkAutoLoadPaths(programPath); } //m_RenderingManager = mitk::RenderingManager::New(); //context->RegisterService(renderingManager.GetPointer()); m_PlanePositionManager = mitk::PlanePositionManagerService::New(); context->RegisterService(m_PlanePositionManager); m_CoreDataNodeReader = mitk::CoreDataNodeReader::New(); context->RegisterService(m_CoreDataNodeReader); + m_ShaderRepository = mitk::ShaderRepository::New(); + context->RegisterService(m_ShaderRepository); + + context->AddModuleListener(this, &MitkCoreActivator::HandleModuleEvent); + /* There IS an option to exchange ALL vtkTexture instances against vtkNeverTranslucentTextureFactory. This code is left here as a reminder, just in case we might need to do that some time. vtkNeverTranslucentTextureFactory* textureFactory = vtkNeverTranslucentTextureFactory::New(); vtkObjectFactory::RegisterFactory( textureFactory ); textureFactory->Delete(); */ } void Unload(mitk::ModuleContext* ) { // The mitk::ModuleContext* argument of the Unload() method // will always be 0 for the Mitk library. It makes no sense // to use it at this stage anyway, since all libraries which // know about the module system have already been unloaded. } private: + void HandleModuleEvent(const mitk::ModuleEvent moduleEvent); + + std::map > moduleIdToShaderIds; + //mitk::RenderingManager::Pointer m_RenderingManager; mitk::PlanePositionManagerService::Pointer m_PlanePositionManager; mitk::CoreDataNodeReader::Pointer m_CoreDataNodeReader; + mitk::ShaderRepository::Pointer m_ShaderRepository; }; +void MitkCoreActivator::HandleModuleEvent(const mitk::ModuleEvent moduleEvent) +{ + if (moduleEvent.GetType() == mitk::ModuleEvent::LOADED) + { + // search and load shader files + std::vector shaderResoruces = + moduleEvent.GetModule()->FindResources("Shaders", "*.xml", true); + for (std::vector::iterator i = shaderResoruces.begin(); + i != shaderResoruces.end(); ++i) + { + if (*i) + { + mitk::ModuleResourceStream rs(*i); + int id = m_ShaderRepository->LoadShader(rs, i->GetBaseName()); + if (id >= 0) + { + moduleIdToShaderIds[moduleEvent.GetModule()->GetModuleId()].push_back(id); + } + } + } + } + else if (moduleEvent.GetType() == mitk::ModuleEvent::UNLOADED) + { + std::map >::iterator shaderIdsIter = + moduleIdToShaderIds.find(moduleEvent.GetModule()->GetModuleId()); + if (shaderIdsIter != moduleIdToShaderIds.end()) + { + for (std::vector::iterator idIter = shaderIdsIter->second.begin(); + idIter != shaderIdsIter->second.end(); ++idIter) + { + m_ShaderRepository->UnloadShader(*idIter); + } + moduleIdToShaderIds.erase(shaderIdsIter); + } + } + + +} + US_EXPORT_MODULE_ACTIVATOR(Mitk, MitkCoreActivator) diff --git a/Core/Code/Controllers/mitkReferenceCountWatcher.h b/Core/Code/Controllers/mitkReferenceCountWatcher.h index d1a0710f96..1734aee3ba 100644 --- a/Core/Code/Controllers/mitkReferenceCountWatcher.h +++ b/Core/Code/Controllers/mitkReferenceCountWatcher.h @@ -1,107 +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 "itkCommand.h" #include +#include namespace mitk { //##Documentation //## @brief Keeps track of the reference count of an object even if //## it is destroyed. //## //## Example usage: //## \code //## SomeFilter* filter = GetSomeFilter(); //## ReferenceCountWatcher::Pointer filterWatcher; //## filterWatcher = new ReferenceCountWatcher(filter, "name of filter"); //## filterWatcher->GetReferenceCount(); //## \endcode //## @ingroup Testing class ReferenceCountWatcher : public itk::Object { public: typedef itk::SimpleMemberCommand CommandType; mitkClassMacro(ReferenceCountWatcher, itk::Object); protected: //##Documentation //## @brief Object to be watched itk::Object* m_Object; //##Documentation //## @brief Optional comment, e.g. for debugging output std::string m_Comment; //##Documentation //## @brief If \a true, \a m_Object is no longer valid //## and the returned reference count will be 0. bool m_Deleted; //##Documentation //## @brief itk::Command to get a notification when the object //## is deleted. CommandType::Pointer m_DeleteCommand; public: //##Documentation //## @brief Constructor requiring object to be watched and allowing //## an optional comment. ReferenceCountWatcher(itk::Object* o, const char *comment="") : m_Object(o), m_Comment(comment), m_Deleted(false), m_ObserverTag(0) { m_DeleteCommand = CommandType::New(); m_DeleteCommand->SetCallbackFunction(this, &ReferenceCountWatcher::DeleteObserver); if(m_Object!=NULL) m_ObserverTag = m_Object->AddObserver(itk::DeleteEvent(), m_DeleteCommand); m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); } //##Documentation //## @brief Destructor: remove observer ~ReferenceCountWatcher() { if((m_Deleted == false) && (m_Object != NULL)) { m_Object->RemoveObserver(m_ObserverTag); } } //##Documentation //## @brief Return the reference count of the watched object or //## 0 if it has been destroyed int GetReferenceCount() const { if(m_Object == NULL) return -1; if(m_Deleted) return 0; return m_Object->GetReferenceCount(); } //##Documentation //## @brief Return the optional string comment itkGetStringMacro(Comment); protected: //##Documentation //## @brief Callback called on itk::DeleteEvent() of wathched object. void DeleteObserver() { m_Deleted = true; } unsigned long m_ObserverTag; }; } diff --git a/Core/Code/Controllers/mitkSliceNavigationController.cpp b/Core/Code/Controllers/mitkSliceNavigationController.cpp index 3e277092f3..2d6219fc19 100644 --- a/Core/Code/Controllers/mitkSliceNavigationController.cpp +++ b/Core/Code/Controllers/mitkSliceNavigationController.cpp @@ -1,737 +1,737 @@ /*=================================================================== 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 "mitkSliceNavigationController.h" #include "mitkBaseRenderer.h" #include "mitkSlicedGeometry3D.h" #include "mitkPlaneGeometry.h" #include "mitkOperation.h" #include "mitkOperationActor.h" #include "mitkStateEvent.h" #include "mitkCrosshairPositionEvent.h" #include "mitkPositionEvent.h" #include "mitkInteractionConst.h" #include "mitkAction.h" #include "mitkGlobalInteraction.h" #include "mitkEventMapper.h" #include "mitkFocusManager.h" #include "mitkVtkPropRenderer.h" #include "mitkRenderingManager.h" #include "mitkInteractionConst.h" #include "mitkPointOperation.h" #include "mitkPlaneOperation.h" #include "mitkUndoController.h" #include "mitkOperationEvent.h" #include "mitkNodePredicateDataType.h" #include "mitkStatusBar.h" #include "mitkMemoryUtilities.h" #include namespace mitk { SliceNavigationController::SliceNavigationController( const char *type ) : BaseController( type ), m_InputWorldGeometry( NULL ), m_CreatedWorldGeometry( NULL ), m_ViewDirection( Axial ), m_DefaultViewDirection( Axial ), m_RenderingManager( NULL ), m_Renderer( NULL ), m_Top( false ), m_FrontSide( false ), m_Rotated( false ), m_BlockUpdate( false ), m_SliceLocked( false ), m_SliceRotationLocked( false ), m_OldPos(0) { typedef itk::SimpleMemberCommand< SliceNavigationController > SNCCommandType; SNCCommandType::Pointer sliceStepperChangedCommand, timeStepperChangedCommand; sliceStepperChangedCommand = SNCCommandType::New(); timeStepperChangedCommand = SNCCommandType::New(); sliceStepperChangedCommand->SetCallbackFunction( this, &SliceNavigationController::SendSlice ); timeStepperChangedCommand->SetCallbackFunction( this, &SliceNavigationController::SendTime ); m_Slice->AddObserver( itk::ModifiedEvent(), sliceStepperChangedCommand ); m_Time->AddObserver( itk::ModifiedEvent(), timeStepperChangedCommand ); m_Slice->SetUnitName( "mm" ); m_Time->SetUnitName( "ms" ); m_Top = false; m_FrontSide = false; m_Rotated = false; } SliceNavigationController::~SliceNavigationController() { } void SliceNavigationController::SetInputWorldGeometry( const Geometry3D *geometry ) { if ( geometry != NULL ) { if ( const_cast< BoundingBox * >( geometry->GetBoundingBox()) ->GetDiagonalLength2() < eps ) { itkWarningMacro( "setting an empty bounding-box" ); geometry = NULL; } } if ( m_InputWorldGeometry != geometry ) { m_InputWorldGeometry = geometry; this->Modified(); } } RenderingManager * SliceNavigationController::GetRenderingManager() const { mitk::RenderingManager* renderingManager = m_RenderingManager.GetPointer(); if (renderingManager != NULL) return renderingManager; if ( m_Renderer != NULL ) { renderingManager = m_Renderer->GetRenderingManager(); if (renderingManager != NULL) return renderingManager; } return mitk::RenderingManager::GetInstance(); } void SliceNavigationController::SetViewDirectionToDefault() { m_ViewDirection = m_DefaultViewDirection; } void SliceNavigationController::Update() { if ( !m_BlockUpdate ) { if ( m_ViewDirection == Axial ) { this->Update( Axial, false, false, true ); } else { this->Update( m_ViewDirection ); } } } void SliceNavigationController::Update( SliceNavigationController::ViewDirection viewDirection, bool top, bool frontside, bool rotated ) { const TimeSlicedGeometry* worldTimeSlicedGeometry = dynamic_cast< const TimeSlicedGeometry * >( m_InputWorldGeometry.GetPointer() ); if( m_BlockUpdate || m_InputWorldGeometry.IsNull() || ( (worldTimeSlicedGeometry != NULL) && (worldTimeSlicedGeometry->GetTimeSteps() == 0) ) ) { return; } m_BlockUpdate = true; if ( m_LastUpdateTime < m_InputWorldGeometry->GetMTime() ) { Modified(); } this->SetViewDirection( viewDirection ); this->SetTop( top ); this->SetFrontSide( frontside ); this->SetRotated( rotated ); if ( m_LastUpdateTime < GetMTime() ) { m_LastUpdateTime = GetMTime(); // initialize the viewplane SlicedGeometry3D::Pointer slicedWorldGeometry = NULL; m_CreatedWorldGeometry = NULL; switch ( viewDirection ) { case Original: if ( worldTimeSlicedGeometry != NULL ) { m_CreatedWorldGeometry = static_cast< TimeSlicedGeometry * >( m_InputWorldGeometry->Clone().GetPointer() ); worldTimeSlicedGeometry = m_CreatedWorldGeometry.GetPointer(); slicedWorldGeometry = dynamic_cast< SlicedGeometry3D * >( m_CreatedWorldGeometry->GetGeometry3D( this->GetTime()->GetPos() ) ); if ( slicedWorldGeometry.IsNotNull() ) { break; } } else { const SlicedGeometry3D *worldSlicedGeometry = dynamic_cast< const SlicedGeometry3D * >( m_InputWorldGeometry.GetPointer()); if ( worldSlicedGeometry != NULL ) { slicedWorldGeometry = static_cast< SlicedGeometry3D * >( m_InputWorldGeometry->Clone().GetPointer()); break; } } //else: use Axial: no "break" here!! case Axial: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes( m_InputWorldGeometry, PlaneGeometry::Axial, top, frontside, rotated ); slicedWorldGeometry->SetSliceNavigationController( this ); break; case Frontal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes( m_InputWorldGeometry, PlaneGeometry::Frontal, top, frontside, rotated ); slicedWorldGeometry->SetSliceNavigationController( this ); break; case Sagittal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes( m_InputWorldGeometry, PlaneGeometry::Sagittal, top, frontside, rotated ); slicedWorldGeometry->SetSliceNavigationController( this ); break; default: itkExceptionMacro("unknown ViewDirection"); } m_Slice->SetPos( 0 ); m_Slice->SetSteps( (int)slicedWorldGeometry->GetSlices() ); if ( m_CreatedWorldGeometry.IsNull() ) { // initialize TimeSlicedGeometry m_CreatedWorldGeometry = TimeSlicedGeometry::New(); } if ( worldTimeSlicedGeometry == NULL ) { m_CreatedWorldGeometry->InitializeEvenlyTimed( slicedWorldGeometry, 1 ); m_Time->SetSteps( 0 ); m_Time->SetPos( 0 ); m_Time->InvalidateRange(); } else { m_BlockUpdate = true; m_Time->SetSteps( worldTimeSlicedGeometry->GetTimeSteps() ); m_Time->SetPos( 0 ); const TimeBounds &timeBounds = worldTimeSlicedGeometry->GetTimeBounds(); m_Time->SetRange( timeBounds[0], timeBounds[1] ); m_BlockUpdate = false; assert( worldTimeSlicedGeometry->GetGeometry3D( this->GetTime()->GetPos() ) != NULL ); slicedWorldGeometry->SetTimeBounds( worldTimeSlicedGeometry->GetGeometry3D( this->GetTime()->GetPos() )->GetTimeBounds() ); //@todo implement for non-evenly-timed geometry! m_CreatedWorldGeometry->InitializeEvenlyTimed( slicedWorldGeometry, worldTimeSlicedGeometry->GetTimeSteps() ); } } // unblock update; we may do this now, because if m_BlockUpdate was already // true before this method was entered, then we will never come here. m_BlockUpdate = false; // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry and time/slice data. this->SendCreatedWorldGeometry(); this->SendSlice(); this->SendTime(); // Adjust the stepper range of slice stepper according to geometry this->AdjustSliceStepperRange(); } void SliceNavigationController::SendCreatedWorldGeometry() { // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry. if ( !m_BlockUpdate ) { this->InvokeEvent( GeometrySendEvent(m_CreatedWorldGeometry, 0) ); } } void SliceNavigationController::SendCreatedWorldGeometryUpdate() { if ( !m_BlockUpdate ) { this->InvokeEvent( GeometryUpdateEvent(m_CreatedWorldGeometry, m_Slice->GetPos()) ); } } void SliceNavigationController::SendSlice() { if ( !m_BlockUpdate ) { if ( m_CreatedWorldGeometry.IsNotNull() ) { this->InvokeEvent( GeometrySliceEvent(m_CreatedWorldGeometry, m_Slice->GetPos()) ); // send crosshair event crosshairPositionEvent.Send(); // Request rendering update for all views this->GetRenderingManager()->RequestUpdateAll(); } } } void SliceNavigationController::SendTime() { if ( !m_BlockUpdate ) { if ( m_CreatedWorldGeometry.IsNotNull() ) { this->InvokeEvent( GeometryTimeEvent(m_CreatedWorldGeometry, m_Time->GetPos()) ); // Request rendering update for all views this->GetRenderingManager()->RequestUpdateAll(); } } } void SliceNavigationController::SetGeometry( const itk::EventObject & ) { } void SliceNavigationController ::SetGeometryTime( const itk::EventObject &geometryTimeEvent ) { const SliceNavigationController::GeometryTimeEvent *timeEvent = dynamic_cast< const SliceNavigationController::GeometryTimeEvent * >( &geometryTimeEvent); assert( timeEvent != NULL ); TimeSlicedGeometry *timeSlicedGeometry = timeEvent->GetTimeSlicedGeometry(); assert( timeSlicedGeometry != NULL ); if ( m_CreatedWorldGeometry.IsNotNull() ) { int timeStep = (int) timeEvent->GetPos(); ScalarType timeInMS; timeInMS = timeSlicedGeometry->TimeStepToMS( timeStep ); timeStep = m_CreatedWorldGeometry->MSToTimeStep( timeInMS ); this->GetTime()->SetPos( timeStep ); } } void SliceNavigationController ::SetGeometrySlice(const itk::EventObject & geometrySliceEvent) { const SliceNavigationController::GeometrySliceEvent* sliceEvent = dynamic_cast( &geometrySliceEvent); assert(sliceEvent!=NULL); this->GetSlice()->SetPos(sliceEvent->GetPos()); } void SliceNavigationController::SelectSliceByPoint( const Point3D &point ) { //@todo add time to PositionEvent and use here!! SlicedGeometry3D* slicedWorldGeometry = dynamic_cast< SlicedGeometry3D * >( m_CreatedWorldGeometry->GetGeometry3D( this->GetTime()->GetPos() ) ); if ( slicedWorldGeometry ) { int bestSlice = -1; double bestDistance = itk::NumericTraits::max(); int s, slices; slices = slicedWorldGeometry->GetSlices(); if ( slicedWorldGeometry->GetEvenlySpaced() ) { mitk::Geometry2D *plane = slicedWorldGeometry->GetGeometry2D( 0 ); const Vector3D &direction = slicedWorldGeometry->GetDirectionVector(); Point3D projectedPoint; plane->Project( point, projectedPoint ); // Check whether the point is somewhere within the slice stack volume; // otherwise, the defualt slice (0) will be selected if ( direction[0] * (point[0] - projectedPoint[0]) + direction[1] * (point[1] - projectedPoint[1]) + direction[2] * (point[2] - projectedPoint[2]) >= 0 ) { bestSlice = (int)(plane->Distance( point ) / slicedWorldGeometry->GetSpacing()[2] + 0.5); } } else { Point3D projectedPoint; for ( s = 0; s < slices; ++s ) { slicedWorldGeometry->GetGeometry2D( s )->Project( point, projectedPoint ); Vector3D distance = projectedPoint - point; ScalarType currentDistance = distance.GetSquaredNorm(); if ( currentDistance < bestDistance ) { bestDistance = currentDistance; bestSlice = s; } } } if ( bestSlice >= 0 ) { this->GetSlice()->SetPos( bestSlice ); } else { this->GetSlice()->SetPos( 0 ); } this->SendCreatedWorldGeometryUpdate(); } } void SliceNavigationController::ReorientSlices( const Point3D &point, const Vector3D &normal ) { PlaneOperation op( OpORIENT, point, normal ); m_CreatedWorldGeometry->ExecuteOperation( &op ); this->SendCreatedWorldGeometryUpdate(); } void SliceNavigationController::ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1 ) { PlaneOperation op( OpORIENT, point, axisVec0, axisVec1 ); m_CreatedWorldGeometry->ExecuteOperation( &op ); this->SendCreatedWorldGeometryUpdate(); } const mitk::TimeSlicedGeometry * SliceNavigationController::GetCreatedWorldGeometry() { return m_CreatedWorldGeometry; } const mitk::Geometry3D * SliceNavigationController::GetCurrentGeometry3D() { if ( m_CreatedWorldGeometry.IsNotNull() ) { return m_CreatedWorldGeometry->GetGeometry3D( this->GetTime()->GetPos() ); } else { return NULL; } } const mitk::PlaneGeometry * SliceNavigationController::GetCurrentPlaneGeometry() { const mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast< const mitk::SlicedGeometry3D * > ( this->GetCurrentGeometry3D() ); if ( slicedGeometry ) { const mitk::PlaneGeometry *planeGeometry = dynamic_cast< mitk::PlaneGeometry * > ( slicedGeometry->GetGeometry2D(this->GetSlice()->GetPos()) ); return planeGeometry; } else { return NULL; } } void SliceNavigationController::SetRenderer( BaseRenderer *renderer ) { m_Renderer = renderer; } BaseRenderer * SliceNavigationController::GetRenderer() const { return m_Renderer; } void SliceNavigationController::AdjustSliceStepperRange() { const mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast< const mitk::SlicedGeometry3D * > ( this->GetCurrentGeometry3D() ); const Vector3D &direction = slicedGeometry->GetDirectionVector(); int c = 0; int i, k = 0; for ( i = 0; i < 3; ++i ) { if ( fabs( (float) direction[i] ) < 0.000000001 ) { ++c; } else { k = i; } } if ( c == 2 ) { ScalarType min = m_InputWorldGeometry->GetOrigin()[k]; ScalarType max = min + m_InputWorldGeometry->GetExtentInMM( k ); m_Slice->SetRange( min, max ); } else { m_Slice->InvalidateRange(); } } void SliceNavigationController::ExecuteOperation( Operation *operation ) { // switch on type // - select best slice for a given point // - rotate created world geometry according to Operation->SomeInfo() if ( !operation ) { return; } switch ( operation->GetOperationType() ) { case OpMOVE: // should be a point operation { if ( !m_SliceLocked ) //do not move the cross position { // select a slice PointOperation *po = dynamic_cast< PointOperation * >( operation ); if ( po && po->GetIndex() == -1 ) { this->SelectSliceByPoint( po->GetPoint() ); } else if ( po && po->GetIndex() != -1 ) // undo case because index != -1, index holds the old position of this slice { this->GetSlice()->SetPos( po->GetIndex() ); } } break; } case OpRESTOREPLANEPOSITION: { m_CreatedWorldGeometry->ExecuteOperation( operation ); this->SendCreatedWorldGeometryUpdate(); break; } default: { // do nothing break; } } } // Relict from the old times, when automous decisions were accepted // behavior. Remains in here, because some RenderWindows do exist outside // of StdMultiWidgets. bool SliceNavigationController ::ExecuteAction( Action* action, StateEvent const* stateEvent ) { bool ok = false; const PositionEvent* posEvent = dynamic_cast< const PositionEvent * >( stateEvent->GetEvent() ); if ( posEvent != NULL ) { if ( m_CreatedWorldGeometry.IsNull() ) { return true; } switch (action->GetActionId()) { case AcMOVE: { BaseRenderer *baseRenderer = posEvent->GetSender(); if ( !baseRenderer ) { baseRenderer = const_cast( GlobalInteraction::GetInstance()->GetFocus() ); } if ( baseRenderer ) if ( baseRenderer->GetMapperID() == 1 ) { PointOperation doOp(OpMOVE, posEvent->GetWorldPosition()); this->ExecuteOperation( &doOp ); // If click was performed in this render window than we have to update the status bar information about position and pixel value. if(baseRenderer == m_Renderer) { { std::string statusText; TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = baseRenderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); mitk::Point3D worldposition = posEvent->GetWorldPosition(); int maxlayer = -32768; mitk::Image::Pointer image3D; // find image with largest layer, that is the image shown on top in the render window for (unsigned int x = 0; x < nodes->size(); x++) { //Just consider image data that is no helper object. E.g. do not consider nodes created for the slice interpolation bool isHelper (false); nodes->at(x)->GetBoolProperty("helper object", isHelper); if(nodes->at(x)->GetData()->GetGeometry()->IsInside(worldposition) && isHelper == false) { int layer = 0; if(!(nodes->at(x)->GetIntProperty("layer", layer))) continue; if(layer > maxlayer) { if(static_cast(nodes->at(x))->IsVisible(m_Renderer)) { image3D = dynamic_cast(nodes->at(x)->GetData()); maxlayer = layer; } } } } std::stringstream stream; stream.imbue(std::locale::classic()); // get the position and gray value from the image and build up status bar text if(image3D.IsNotNull()) { Index3D p; image3D->GetGeometry()->WorldToIndex(worldposition, p); stream.precision(2); stream<<"Position: <" << std::fixed < mm"; stream<<"; Index: <"< "; mitk::ScalarType pixelValue = image3D->GetPixelValueByIndex(p, baseRenderer->GetTimeStep()); - if (fabs(pixelValue)>1000000) + if (fabs(pixelValue)>1000000 || fabs(pixelValue) < 0.01) { - stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; + stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: " << std::scientific<< pixelValue <<" "; } else { - stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; + stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<< pixelValue <<" "; } } else { stream << "No image information at this position!"; } statusText = stream.str(); mitk::StatusBar::GetInstance()->DisplayGreyValueText(statusText.c_str()); } } ok = true; break; } } default: ok = true; break; } return ok; } const DisplayPositionEvent *displPosEvent = dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() ); if ( displPosEvent != NULL ) { return true; } return false; } } // namespace diff --git a/Core/Code/CppMicroServices/CMake/usFunctionCreateTestModule.cmake b/Core/Code/CppMicroServices/CMake/usFunctionCreateTestModule.cmake index 6317e5301b..6d90dc0ae4 100644 --- a/Core/Code/CppMicroServices/CMake/usFunctionCreateTestModule.cmake +++ b/Core/Code/CppMicroServices/CMake/usFunctionCreateTestModule.cmake @@ -1,51 +1,51 @@ macro(_us_create_test_module_helper) if(_res_files) usFunctionEmbedResources(_srcs LIBRARY_NAME ${name} ROOT_DIR ${_res_root} FILES ${_res_files}) endif() add_library(${name} ${_srcs}) if(NOT US_BUILD_SHARED_LIBS) set_property(TARGET ${name} APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE) endif() if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") get_property(_compile_flags TARGET ${name} PROPERTY COMPILE_FLAGS) set_property(TARGET ${name} PROPERTY COMPILE_FLAGS "${_compile_flags} -fPIC") endif() target_link_libraries(${name} ${US_LINK_LIBRARIES}) if(NOT US_ENABLE_SERVICE_FACTORY_SUPPORT) target_link_libraries(${name} ${US_BASECLASS_LIBRARIES}) endif() set(_us_test_module_libs "${_us_test_module_libs};${name}" CACHE INTERNAL "" FORCE) endmacro() function(usFunctionCreateTestModuleWithAutoLoadDir name autoload_dir) set(_srcs ${ARGN}) usFunctionGenerateModuleInit(_srcs NAME "${name} Module" LIBRARY_NAME ${name} AUTOLOAD_DIR ${autoload_dir}) _us_create_test_module_helper() endfunction() function(usFunctionCreateTestModule name) set(_srcs ${ARGN}) set(_res_files ) usFunctionGenerateModuleInit(_srcs NAME "${name} Module" LIBRARY_NAME ${name}) _us_create_test_module_helper() endfunction() function(usFunctionCreateTestModuleWithResources name) MACRO_PARSE_ARGUMENTS(US_TEST "SOURCES;RESOURCES;RESOURCES_ROOT" "" ${ARGN}) set(_srcs ${US_TEST_SOURCES}) set(_res_files ${US_TEST_RESOURCES}) - if (US_TEST_RESOURCES_ROOT) + if(US_TEST_RESOURCES_ROOT) set(_res_root ${US_TEST_RESOURCES_ROOT}) else() set(_res_root resources) endif() usFunctionGenerateModuleInit(_srcs NAME "${name} Module" LIBRARY_NAME ${name}) _us_create_test_module_helper() endfunction() diff --git a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake index edec0a7485..c34601206a 100644 --- a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake +++ b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake @@ -1,97 +1,145 @@ #! Embed resources into a shared library or executable. #! #! This CMake function uses an external command line program to generate a source #! file containing data from external resources such as text files or images. The path #! to the generated source file is appended to the \c src_var variable. #! #! Each module can call this function (at most once) to embed resources and make them #! available at runtime through the Module class. Resources can also be embedded into #! executables, using the EXECUTABLE_NAME argument instead of LIBRARY_NAME. #! #! Example usage: #! \verbatim #! set(module_srcs ) #! usFunctionEmbedResources(module_srcs #! LIBRARY_NAME "mylib" #! ROOT_DIR resources #! FILES config.properties logo.png #! ) +#! \endverbatim #! #! \param LIBRARY_NAME (required if EXECUTABLE_NAME is empty) The library name of the module #! which will include the generated source file, without extension. #! \param EXECUTABLE_NAME (required if LIBRARY_NAME is empty) The name of the executable #! which will include the generated source file. +#! \param COMPRESSION_LEVEL (optional) The zip compression level. Defaults to the default zip +#! level. Level 0 disables compression. +#! \param COMPRESSION_THRESHOLD (optional) The compression threshold ranging from 0 to 100 for +#! actually compressing the resource data. The default threshold is 30, meaning a size +#! reduction of 30 percent or better results in the resource data being compressed. #! \param ROOT_DIR (optional) The root path for all resources listed after the FILES argument. #! If no or a relative path is given, it is considered relativ to the current CMake source directory. #! \param FILES (optional) A list of resources (paths to external files in the file system) relative #! to the ROOT_DIR argument or the current CMake source directory if ROOT_DIR is empty. #! +#! The ROOT_DIR and FILES arguments may be repeated any number of times to merge files from +#! different root directories into the embedded resource tree (hence the relative file paths +#! after the FILES argument must be unique). +#! function(usFunctionEmbedResources src_var) - MACRO_PARSE_ARGUMENTS(US_RESOURCE "LIBRARY_NAME;EXECUTABLE_NAME;ROOT_DIR;FILES" "" ${ARGN}) + set(prefix US_RESOURCE) + set(arg_names LIBRARY_NAME EXECUTABLE_NAME COMPRESSION_LEVEL COMPRESSION_THRESHOLD ROOT_DIR FILES) + foreach(arg_name ${arg_names}) + set(${prefix}_${arg_name}) + endforeach(arg_name) + + set(cmd_line_args ) + set(absolute_res_files ) + set(current_arg_name DEFAULT_ARGS) + set(current_arg_list) + set(current_root_dir ${CMAKE_CURRENT_SOURCE_DIR}) + foreach(arg ${ARGN}) + + list(FIND arg_names "${arg}" is_arg_name) + + if(is_arg_name GREATER -1) + set(${prefix}_${current_arg_name} ${current_arg_list}) + set(current_arg_name "${arg}") + set(current_arg_list) + else() + set(current_arg_list ${current_arg_list} "${arg}") + if(current_arg_name STREQUAL "ROOT_DIR") + set(current_root_dir "${arg}") + if(NOT IS_ABSOLUTE ${current_root_dir}) + set(current_root_dir "${CMAKE_CURRENT_SOURCE_DIR}/${current_root_dir}") + endif() + if(NOT IS_DIRECTORY ${current_root_dir}) + message(SEND_ERROR "The ROOT_DIR argument is not a directory: ${current_root_dir}") + endif() + get_filename_component(current_root_dir "${current_root_dir}" REALPATH) + file(TO_NATIVE_PATH "${current_root_dir}" current_root_dir_native) + list(APPEND cmd_line_args -d "${current_root_dir_native}") + elseif(current_arg_name STREQUAL "FILES") + set(res_file "${current_root_dir}/${arg}") + file(TO_NATIVE_PATH "${res_file}" res_file_native) + if(IS_DIRECTORY ${res_file}) + message(SEND_ERROR "A resource cannot be a directory: ${res_file_native}") + endif() + if(NOT EXISTS ${res_file}) + message(SEND_ERROR "Resource does not exists: ${res_file_native}") + endif() + list(APPEND absolute_res_files ${res_file}) + file(TO_NATIVE_PATH "${arg}" res_filename_native) + list(APPEND cmd_line_args "${res_filename_native}") + endif() + endif(is_arg_name GREATER -1) + + endforeach(arg ${ARGN}) + + set(${prefix}_${current_arg_name} ${current_arg_list}) if(NOT src_var) message(SEND_ERROR "Output variable name not specified.") endif() if(US_RESOURCE_EXECUTABLE_NAME AND US_RESOURCE_LIBRARY_NAME) message(SEND_ERROR "Only one of LIBRARY_NAME or EXECUTABLE_NAME can be specified.") endif() if(NOT US_RESOURCE_LIBRARY_NAME AND NOT US_RESOURCE_EXECUTABLE_NAME) message(SEND_ERROR "LIBRARY_NAME or EXECUTABLE_NAME argument not specified.") endif() if(NOT US_RESOURCE_FILES) message(WARNING "No FILES argument given. Skipping resource processing.") return() endif() - if(NOT US_RESOURCE_ROOT_DIR) - set(US_RESOURCE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - endif() - if(NOT IS_ABSOLUTE ${US_RESOURCE_ROOT_DIR}) - set(US_RESOURCE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${US_RESOURCE_ROOT_DIR}") + list(GET cmd_line_args 0 first_arg) + if(NOT first_arg STREQUAL "-d") + set(cmd_line_args -d "${CMAKE_CURRENT_SOURCE_DIR}" ${cmd_line_args}) endif() - if(NOT IS_DIRECTORY ${US_RESOURCE_ROOT_DIR}) - message(SEND_ERROR "The ROOT_DIR argument is not a directory: ${US_RESOURCE_ROOT_DIR}") + + if(US_RESOURCE_COMPRESSION_LEVEL) + set(cmd_line_args -c ${US_RESOURCE_COMPRESSION_LEVEL} ${cmd_line_args}) endif() - set(absolute_res_files) - foreach(res_file ${US_RESOURCE_FILES}) - set(res_file "${US_RESOURCE_ROOT_DIR}/${res_file}") - if(IS_DIRECTORY ${res_file}) - message(SEND_ERROR "A resource cannot be a directory: ${res_file}") - endif() - if(NOT EXISTS ${res_file}) - message(SEND_ERROR "Resource does not exists: ${res_file}") - endif() - get_filename_component(res_file "${res_file}" REALPATH) - file(TO_NATIVE_PATH "${res_file}" res_file) - list(APPEND absolute_res_files ${res_file}) - endforeach() + if(US_RESOURCE_COMPRESSION_THRESHOLD) + set(cmd_line_args -t ${US_RESOURCE_COMPRESSION_THRESHOLD} ${cmd_line_args}) + endif() if(US_RESOURCE_LIBRARY_NAME) set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_LIBRARY_NAME}_resources.cpp") set(us_lib_name ${US_RESOURCE_LIBRARY_NAME}) else() set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_EXECUTABLE_NAME}_resources.cpp") set(us_lib_name "\"\"") endif() set(resource_compiler ${CppMicroServices_RCC_EXECUTABLE}) if(TARGET ${CppMicroServices_RCC_EXECUTABLE_NAME}) set(resource_compiler ${CppMicroServices_RCC_EXECUTABLE_NAME}) endif() add_custom_command( OUTPUT ${us_cpp_resource_file} - COMMAND ${resource_compiler} "${us_lib_name}" ${us_cpp_resource_file} ${absolute_res_files} - WORKING_DIRECTORY ${US_RESOURCE_ROOT_DIR} - DEPENDS ${absolute_res_files} + COMMAND ${resource_compiler} "${us_lib_name}" ${us_cpp_resource_file} ${cmd_line_args} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${absolute_res_files} ${resource_compiler} COMMENT "Generating embedded resource file ${us_cpp_resource_name}" ) set(${src_var} "${${src_var}};${us_cpp_resource_file}" PARENT_SCOPE) endfunction() diff --git a/Core/Code/CppMicroServices/CMakeLists.txt b/Core/Code/CppMicroServices/CMakeLists.txt index be5a542de2..534a6a3b65 100644 --- a/Core/Code/CppMicroServices/CMakeLists.txt +++ b/Core/Code/CppMicroServices/CMakeLists.txt @@ -1,358 +1,359 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 0) set(${PROJECT_NAME}_MINOR_VERSION 99) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) cmake_minimum_required(VERSION 2.8) #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(MacroParseArguments) include(CheckCXXSourceCompiles) include(usFunctionCheckCompilerFlags) include(usFunctionEmbedResources) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() #----------------------------------------------------------------------------- # 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() #----------------------------------------------------------------------------- # CMake options #----------------------------------------------------------------------------- function(us_cache_var _var_name _var_default _var_type _var_help) set(_advanced 0) set(_force) foreach(_argn ${ARGN}) if(_argn STREQUAL ADVANCED) set(_advanced 1) elseif(_argn STREQUAL FORCE) set(_force FORCE) endif() endforeach() if(US_IS_EMBEDDED) if(NOT DEFINED ${_var_name} OR _force) set(${_var_name} ${_var_default} PARENT_SCOPE) endif() else() set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) if(_advanced) mark_as_advanced(${_var_name}) endif() endif() endfunction() # Determine if we are being build inside a larger project if(NOT DEFINED US_IS_EMBEDDED) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(US_IS_EMBEDDED 0) else() set(US_IS_EMBEDDED 1) set(CppMicroServices_EXPORTS 1) endif() endif() us_cache_var(US_ENABLE_AUTOLOADING_SUPPORT OFF BOOL "Enable module auto-loading support") us_cache_var(US_ENABLE_SERVICE_FACTORY_SUPPORT ON BOOL "Enable Service Factory support" ADVANCED) us_cache_var(US_ENABLE_THREADING_SUPPORT OFF BOOL "Enable threading support") us_cache_var(US_ENABLE_DEBUG_OUTPUT OFF BOOL "Enable debug messages" ADVANCED) +us_cache_var(US_ENABLE_RESOURCE_COMPRESSION ON BOOL "Enable resource compression" ADVANCED) us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") if(MSVC10 OR MSVC11) # Visual Studio 2010 and newer have support for C++11 enabled by default set(US_USE_C++11 1) else() us_cache_var(US_USE_C++11 OFF BOOL "Enable the use of C++11 features" ADVANCED) endif() us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ micro services entities") us_cache_var(US_HEADER_PREFIX "" STRING "The file name prefix for the public C++ micro services header files") us_cache_var(US_BASECLASS_NAME "" STRING "The fully-qualified name of the base class") if(US_ENABLE_SERVICE_FACTORY_SUPPORT) us_cache_var(US_BASECLASS_PACKAGE "" STRING "The name of the package providing the base class definition" ADVANCED) set(bc_inc_d_doc "A list of include directories containing the header files for the base class") us_cache_var(US_BASECLASS_INCLUDE_DIRS "" STRING "${bc_inc_d_doc}" ADVANCED) set(bc_lib_d_doc "A list of library directories for the base class") us_cache_var(US_BASECLASS_LIBRARY_DIRS "" STRING "${bc_lib_d_doc}" ADVANCED) set(bc_lib_doc "A list of libraries needed for the base class") us_cache_var(US_BASECLASS_LIBRARIES "" STRING "${bc_lib_doc}" ADVANCED) us_cache_var(US_BASECLASS_HEADER "" STRING "The name of the header file containing the base class declaration" ADVANCED) endif() set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) # Sanity checks if(US_ENABLE_SERVICE_FACTORY_SUPPORT OR US_BUILD_TESTING) if(US_BASECLASS_PACKAGE) find_package(${US_BASECLASS_PACKAGE} REQUIRED) # Try to get the include dirs foreach(_suffix DIRECTORIES DIRS DIRECTORY DIR) if(${US_BASECLASS_PACKAGE}_INCLUDE_${_suffix} AND NOT US_BASECLASS_INCLUDE_DIRS) us_cache_var(US_BASECLASS_INCLUDE_DIRS "${${US_BASECLASS_PACKAGE}_INCLUDE_${_suffix}}" STRING "${bc_inc_d_doc}" FORCE) break() endif() endforeach() # Try to get the library dirs foreach(_suffix DIRECTORIES DIRS DIRECTORY DIR) if(${US_BASECLASS_PACKAGE}_LIBRARY_${_suffix} AND NOT US_BASECLASS_LIBRARY_DIRS) us_cache_var(US_BASECLASS_LIBRARY_DIRS "${${US_BASECLASS_PACKAGE}_LIBRARY_${_suffix}}" STRING "${bc_lib_d_doc}" FORCE) break() endif() endforeach() # Try to get the libraries foreach(_suffix LIBRARIES LIBS LIBRARY LIB) if(${US_BASECLASS_PACKAGE}_${_suffix} AND NOT US_BASECLASS_LIBRARIES) us_cache_var(US_BASECLASS_LIBRARIES "${${US_BASECLASS_PACKAGE}_${_suffix}}" STRING "${bc_lib_doc}" FORCE) break() endif() endforeach() if(NOT US_BASECLASS_NAME) message(FATAL_ERROR "US_BASECLASS_NAME not set") elseif(NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_BASECLASS_HEADER not set") endif() endif() if(US_ENABLE_SERVICE_FACTORY_SUPPORT AND US_BASECLASS_NAME AND NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_ENABLE_SERVICE_FACTORY_SUPPORT requires a US_BASECLASS_HEADER value") endif() endif() set(_us_baseclass_default 0) if(NOT US_BASECLASS_NAME) message(WARNING "Using build in base class \"::${US_NAMESPACE}::Base\"") set(_us_baseclass_default 1) set(US_BASECLASS_NAME "${US_NAMESPACE}::Base") set(US_BASECLASS_HEADER "usBase.h") endif() if(US_BUILD_TESTING AND US_BASECLASS_NAME AND NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_BUILD_TESTING requires a US_BASECLASS_HEADER value") endif() set(US_BASECLASS_INCLUDE "#include <${US_BASECLASS_HEADER}>") string(REPLACE "::" ";" _bc_token "${US_BASECLASS_NAME}") list(GET _bc_token -1 _bc_name) list(REMOVE_AT _bc_token -1) set(US_BASECLASS_FORWARD_DECLARATION "") foreach(_namespace_tok ${_bc_token}) if(_namespace_tok) set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}namespace ${_namespace_tok} { ") endif() endforeach() set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}class ${_bc_name}; ") foreach(_namespace_tok ${_bc_token}) if(_namespace_tok) set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}}") endif() endforeach() #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- set(US_C_FLAGS "${COVERAGE_C_FLAGS} ${ADDITIONAL_C_FLAGS}") set(US_CXX_FLAGS "${COVERAGE_CXX_FLAGS} ${ADDITIONAL_CXX_FLAGS}") # This is used as a preprocessor define set(US_USE_CXX11 ${US_USE_C++11}) # Set C++ compiler flags if(NOT MSVC) foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option -D_FORTIFY_SOURCE=2) usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) endforeach() if(US_USE_C++11) usFunctionCheckCompilerFlags("-std=c++0x" US_CXX_FLAGS) endif() endif() if(CMAKE_COMPILER_IS_GNUCXX) usFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) # With older versions of gcc the flag -fstack-protector-all requires an extra dependency to libssp.so. # If the gcc version is lower than 4.4.0 and the build type is Release let's not include the flag. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) usFunctionCheckCompilerFlags("-fstack-protector-all" US_CXX_FLAGS) endif() if(MINGW) # suppress warnings about auto imported symbols set(US_CXX_FLAGS "-Wl,--enable-auto-import ${US_CXX_FLAGS}") # we need to define a Windows version set(US_CXX_FLAGS "-D_WIN32_WINNT=0x0500 ${US_CXX_FLAGS}") else() # Enable visibility support if(NOT ${GCC_VERSION} VERSION_LESS "4.5") usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" US_CXX_FLAGS) endif() endif() elseif(MSVC) set(US_CXX_FLAGS "/MP /wd4996 ${US_CXX_FLAGS}") endif() if(NOT US_IS_EMBEDDED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") endif() #----------------------------------------------------------------------------- # US Link Flags #----------------------------------------------------------------------------- set(US_LINK_FLAGS ) if(NOT MSVC) foreach(_linkflag -Wl,--no-undefined) set(_add_flag) usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) if(_add_flag) set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") endif() endforeach() endif() #----------------------------------------------------------------------------- # US Header Checks #----------------------------------------------------------------------------- include(CheckIncludeFile) CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT) #----------------------------------------------------------------------------- # US include dirs and libraries #----------------------------------------------------------------------------- set(US_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include ) set(US_INTERNAL_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src/util ${CMAKE_CURRENT_SOURCE_DIR}/src/service ${CMAKE_CURRENT_SOURCE_DIR}/src/module ) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_INTERNAL_INCLUDE_DIRS ${US_BASECLASS_INCLUDE_DIRS}) endif() # link libraries for third party libs if(US_IS_EMBEDDED) set(US_LINK_LIBRARIES ${US_EMBEDDING_LIBRARY}) else() set(US_LINK_LIBRARIES ${PROJECT_NAME}) endif() # link libraries for the CppMicroServices lib set(_link_libraries ) if(UNIX) list(APPEND _link_libraries dl) endif() list(APPEND US_LINK_LIBRARIES ${_link_libraries}) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_LINK_LIBRARIES ${US_BASECLASS_LIBRARIES}) endif() set(US_LINK_DIRS ) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_LINK_DIRS ${US_BASECLASS_LIBRARY_DIRS}) endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- set(us_config_h_file "${PROJECT_BINARY_DIR}/include/usConfig.h") configure_file(usConfig.h.in ${us_config_h_file}) set(US_RCC_EXECUTABLE_NAME usResourceCompiler) set(CppMicroServices_RCC_EXECUTABLE_NAME ${US_RCC_EXECUTABLE_NAME}) set(US_RCC_EXECUTABLE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${US_RCC_EXECUTABLE_NAME}") set(CppMicroServices_RCC_EXECUTABLE ${US_RCC_EXECUTABLE}) add_subdirectory(tools) add_subdirectory(src) #----------------------------------------------------------------------------- # US testing #----------------------------------------------------------------------------- if(US_BUILD_TESTING) enable_testing() add_subdirectory(test) endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(documentation) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- configure_file(${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY) diff --git a/Core/Code/CppMicroServices/documentation/doxygen/MicroServices_Resources.md b/Core/Code/CppMicroServices/documentation/doxygen/MicroServices_Resources.md index 2c69fed77b..da80b20349 100644 --- a/Core/Code/CppMicroServices/documentation/doxygen/MicroServices_Resources.md +++ b/Core/Code/CppMicroServices/documentation/doxygen/MicroServices_Resources.md @@ -1,54 +1,56 @@ The Resources System {#MicroServices_Resources} ==================== The C++ Micro Services library provides a generic resources system to embed arbitrary files into a module's shared library (the current size limitation is based on the largest source code file size your compiler can handle). The following features are supported: * Embed arbitrary data into shared or static modules or executables. + * Data is embedded in a compressed format if the size reduction exceeds a + configurable threshold. * Resources are accessed via a Module instance, providing individual resource lookup and access for each module. * Resources are managed in a tree hierarchy, modeling the original child - parent relationship on the file-system. * The ModuleResource class provides a high-level API for accessing resource information and traversing the resource tree. * The ModuleResourceStream class provides an STL input stream derived class for the seamless usage of embedded resource data in third-party libraries. Embedding Resources in a %Module ------------------------------- Resources are embedded by compiling a source file generated by the `usResourceCompiler` executable into a module's shared or static library (or into an executable). If you are using CMake, consider using the provided `usFunctionEmbedResources` CMake macro which handles the invocation of the `usResourceCompiler` executable and sets up the correct file dependencies. Accessing Resources at Runtime ------------------------------ Each module provides access to its embedded resources via the Module class which provides methods returning ModuleResource objects. The ModuleResourceStream class provides a std::istream compatible object to access the resource contents. The following example shows how to retrieve a resource from each currently loaded module whose path is specified by a module property: \snippet uServices-resources/main.cpp 2 This example could be enhanced to dynamically react to modules being loaded and unloaded, making use of the popular "extender pattern" from OSGi. Limitations ----------- Currently, the system has the following limitations: * At most one file generated by the `usResourceCompiler` executable can be compiled into a module's shared library (you can work around this limitation by creating static modules and importing them). * The size of embedded resources is limited by the file size your compiler can handle. However, the file size is the sum of the size of all resources embedded into a module plus a small overhead. diff --git a/Core/Code/CppMicroServices/documentation/doxygen/standalone/BuildInstructions.md b/Core/Code/CppMicroServices/documentation/doxygen/standalone/BuildInstructions.md index c904ee8165..949489d93b 100644 --- a/Core/Code/CppMicroServices/documentation/doxygen/standalone/BuildInstructions.md +++ b/Core/Code/CppMicroServices/documentation/doxygen/standalone/BuildInstructions.md @@ -1,80 +1,83 @@ Build Instructions {#BuildInstructions} ================== The C++ Micro Services library provides [CMake][cmake] build scripts which allow the generation of platform and IDE specific project files. The library should compile on many different platforms. Below is a list of tested compiler/OS combinations: - GCC 4.5 (Ubuntu 11.04 and MacOS X 10.6) - Visual Studio 2008 and 2010 - Clang 3.0 (Ubuntu 11.04 and MacOS X 10.6) Prerequisites ------------- - [CMake][cmake] 2.8 (Visual Studio 2010 users should use the latest CMake version available) Configuring the Build --------------------- When building the C++ Micro Services library, you have a few configuration options at hand. ### General build options - **US_BUILD_SHARED_LIBS** Specify if the library should be build shared or static. See \ref MicroServices_StaticModules for detailed information about static CppMicroServices modules. - **US_BUILD_TESTING** Build unit tests and code snippets. - **US_ENABLE_AUTOLOADING_SUPPORT** Enable auto-loading of modules located in special sup-directories. See \ref MicroServices_AutoLoading for detailed information about this feature. - **US_ENABLE_THREADING_SUPPORT** Enable the use of synchronization primitives (atomics and pthread mutexes or Windows primitives) to make the API thread-safe. If you are application is not multi-threaded, turn this option OFF to get maximum performance. - **US_USE_C++11 (advanced)** Enable the usage of C++11 constructs +- **US_ENABLE_RESOURCE_COMPRESSION** + Enable compression of embedded resources. See \ref MicroServices_Resources for detailed information + about the resource system. ### Customizing naming conventions - **US_NAMESPACE** The default namespace is `us` but you may override this at will. - **US_HEADER_PREFIX** By default, all public headers have a "us" prefix. You may specify an arbitrary prefix to match your naming conventions. The above options are mainly useful when embedding the C++ Micro Services source code in your own library and you want to make it look like native source code. ### Configure the service base class All service implementations must inherit from the same base class. The C++ Micro Services library provides a trivial class called `us::Base` for that purpose. However, most applications already have a special base class and you can configure the C++ Micro Services library to use that class. - **US_BASECLASS_NAME** The fully-qualified name of the base class, e.g. `my::OwnBaseClass`. If you don't need support for service factories (see below) and don't want to enable US_BUILD_TESTING, this is all you need. - **US_ENABLE_SERVICE_FACTORY_SUPPORT (advanced)** If you want support for service factories (they allow the customization of service objects for individual modules, see OSGi Service Platform Core Specification Release 4, Version 4.3, Section 5.6), switch this option to ON. If you also provided a custom US_BASECLASS_NAME, you need to set the US_BASECLASS_HEADER variable. - **US_BASECLASS_HEADER (advanced)** The name of the header file containing the declaration for the base class specified in US_BASECLASS_NAME, e.g. `myOwnBaseClass.h`. You will also have to set US_BASECLASS_PACKAGE or US_BASECLASS_INCLUDE_DIRS and US_BASECLASS_LIBRARIES. - **US_BASECLASS_PACKAGE (advanced)** If your specified a custom base class from a library which can be found via a CMake `find_package` command, enter the package name here. Most of the time, this will correctly set the values for US_BASECLASS_INCLUDE_DIRS, US_BASECLASS_LIBRARIES, and US_BASECLASS_LIBRARY_DIRS. - **US_BASECLASS_INCLUDE_DIRS (advanced)** A list of include dirs needed to include the base class header file as specified in US_BASECLASS_HEADER. - **US_BASECLASS_LIBRARIES (advanced)** A list of libraries to link the C++ Micro Services library against for resolving symbols needed for a custom base class. - **US_BASECLASS_LIBRARY_DIRS (advanced)** A list of directories to look for the libraries specified in US_BASECLASS_LIBRARIES [cmake]: http://www.cmake.org diff --git a/Core/Code/CppMicroServices/src/CMakeLists.txt b/Core/Code/CppMicroServices/src/CMakeLists.txt index 12959997e7..45a9814854 100644 --- a/Core/Code/CppMicroServices/src/CMakeLists.txt +++ b/Core/Code/CppMicroServices/src/CMakeLists.txt @@ -1,181 +1,184 @@ #----------------------------------------------------------------------------- # US source files #----------------------------------------------------------------------------- set(_srcs util/usAny.cpp + util/usUncompressResourceData.c + util/usUncompressResourceData.cpp util/usThreads.cpp util/usUtils.cpp service/usLDAPExpr.cpp service/usLDAPFilter.cpp service/usServiceException.cpp service/usServiceEvent.cpp service/usServiceListenerEntry.cpp service/usServiceListenerEntry_p.h service/usServiceListeners.cpp service/usServiceListeners_p.h service/usServiceProperties.cpp service/usServiceReference.cpp service/usServiceReferencePrivate.cpp service/usServiceRegistration.cpp service/usServiceRegistrationPrivate.cpp service/usServiceRegistry.cpp service/usServiceRegistry_p.h module/usCoreModuleContext_p.h module/usCoreModuleContext.cpp module/usModuleContext.cpp module/usModule.cpp module/usModuleEvent.cpp module/usModuleInfo.cpp module/usModulePrivate.cpp module/usModuleRegistry.cpp module/usModuleResource.cpp module/usModuleResourceBuffer.cpp module/usModuleResourceStream.cpp module/usModuleResourceTree.cpp module/usModuleSettings.cpp module/usModuleUtils.cpp module/usModuleVersion.cpp ) set(_private_headers util/usAtomicInt_p.h util/usFunctor_p.h util/usStaticInit_p.h util/usThreads_p.h util/usUtils_p.h util/dirent_win32_p.h util/stdint_p.h util/stdint_vc_p.h service/usServiceTracker.tpp service/usServiceTrackerPrivate.h service/usServiceTrackerPrivate.tpp service/usTrackedService_p.h service/usTrackedServiceListener_p.h service/usTrackedService.tpp module/usModuleAbstractTracked_p.h module/usModuleAbstractTracked.tpp module/usModuleResourceBuffer_p.h module/usModuleResourceTree_p.h module/usModuleUtils_p.h ) set(_public_headers util/usAny.h util/usSharedData.h + util/usUncompressResourceData.h service/usLDAPFilter.h service/usServiceEvent.h service/usServiceException.h service/usServiceInterface.h service/usServiceProperties.h service/usServiceReference.h service/usServiceRegistration.h service/usServiceTracker.h service/usServiceTrackerCustomizer.h module/usGetModuleContext.h module/usModule.h module/usModuleActivator.h module/usModuleContext.h module/usModuleEvent.h module/usModuleImport.h module/usModuleInfo.h module/usModuleInitialization.h module/usModuleRegistry.h module/usModuleResource.h module/usModuleResourceStream.h module/usModuleSettings.h module/usModuleVersion.h ) if(_us_baseclass_default) list(APPEND _public_headers util/usBase.h) endif() if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND _public_headers service/usServiceFactory.h) endif() if(US_IS_EMBEDDED) set(US_SOURCES ) get_filename_component(_path_prefix "${PROJECT_SOURCE_DIR}" NAME) set(_path_prefix "${_path_prefix}/src") foreach(_src ${_srcs} ${_public_headers} ${_private_headers}) list(APPEND US_SOURCES ${_path_prefix}/${_src}) endforeach() set(US_SOURCES ${US_SOURCES} PARENT_SCOPE) endif() #----------------------------------------------------------------------------- # Create library (only if not in embedded mode) #----------------------------------------------------------------------------- if(NOT US_IS_EMBEDDED) include_directories(${US_INTERNAL_INCLUDE_DIRS}) if(US_LINK_DIRS) link_directories(${US_LINK_DIRS}) endif() usFunctionGenerateModuleInit(_srcs NAME ${PROJECT_NAME} VERSION "0.9.0") add_library(${PROJECT_NAME} ${_srcs} ${_public_headers} ${_private_headers} ${us_config_h_file}) if(NOT US_IS_EMBEDDED AND US_LINK_FLAGS) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "${US_LINK_FLAGS}") endif() set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY COMPILE_DEFINITIONS US_FORCE_MODULE_INIT) set_property(TARGET ${PROJECT_NAME} PROPERTY FRAMEWORK 1) if(US_LINK_LIBRARIES) - target_link_libraries(${PROJECT_NAME} ${US_LINK_LIBRARIES}) + target_link_libraries(${PROJECT_NAME} ${_link_libraries}) endif() endif() #----------------------------------------------------------------------------- # Configure public header wrappers #----------------------------------------------------------------------------- set(US_PUBLIC_HEADERS ${_public_headers}) if(US_HEADER_PREFIX) set(US_PUBLIC_HEADERS ) foreach(_public_header ${_public_headers}) get_filename_component(_public_header_basename ${_public_header} NAME_WE) set(_us_public_header ${_public_header_basename}.h) string(SUBSTRING "${_public_header_basename}" 2 -1 _public_header_basename) set(_header_wrapper "${PROJECT_BINARY_DIR}/include/${US_HEADER_PREFIX}${_public_header_basename}.h") configure_file(${PROJECT_SOURCE_DIR}/CMake/usPublicHeaderWrapper.h.in ${_header_wrapper} @ONLY) list(APPEND US_PUBLIC_HEADERS ${_header_wrapper}) endforeach() endif() foreach(_header ${_public_headers} ${_private_headers}) get_filename_component(_header_name "${_header}" NAME) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${_header} "${PROJECT_BINARY_DIR}/include/${_header_name}") endforeach() if(NOT US_IS_EMBEDDED) set_property(TARGET ${PROJECT_NAME} PROPERTY PUBLIC_HEADER ${US_PUBLIC_HEADERS}) set_property(TARGET ${PROJECT_NAME} PROPERTY PRIVATE_HEADER ${_private_headers} ${us_config_h_file}) else() set(US_PUBLIC_HEADERS ${US_PUBLIC_HEADERS} PARENT_SCOPE) set(US_PRIVATE_HEADERS ${US_PRIVATE_HEADERS} PARENT_SCOPE) endif() #----------------------------------------------------------------------------- # Install support (only if not in embedded mode) #----------------------------------------------------------------------------- if(NOT US_IS_EMBEDDED) install(TARGETS ${PROJECT_NAME} FRAMEWORK DESTINATION . RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib PUBLIC_HEADER DESTINATION include PRIVATE_HEADER DESTINATION include) endif() diff --git a/Core/Code/CppMicroServices/src/module/usModuleResource.cpp b/Core/Code/CppMicroServices/src/module/usModuleResource.cpp index 4af82ea877..55215a0bda 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResource.cpp +++ b/Core/Code/CppMicroServices/src/module/usModuleResource.cpp @@ -1,262 +1,271 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usModuleResource.h" #include "usAtomicInt_p.h" #include "usModuleResourceTree_p.h" #include US_BEGIN_NAMESPACE class ModuleResourcePrivate { public: ModuleResourcePrivate() : associatedResourceTree(NULL) , node(-1) , size(0) , data(NULL) , isFile(false) + , isCompressed(false) , ref(1) {} std::string fileName; std::string path; std::string filePath; std::vector resourceTrees; const ModuleResourceTree* associatedResourceTree; int node; int32_t size; const unsigned char* data; + unsigned char* uncompressedData; mutable std::vector children; bool isFile; + bool isCompressed; /** * Reference count for implicitly shared private implementation. */ AtomicInt ref; }; ModuleResource::ModuleResource() : d(new ModuleResourcePrivate) { } ModuleResource::ModuleResource(const ModuleResource &resource) : d(resource.d) { d->ref.Ref(); } ModuleResource::ModuleResource(const std::string& _file, ModuleResourceTree* associatedResourceTree, const std::vector& resourceTrees) : d(new ModuleResourcePrivate) { d->resourceTrees = resourceTrees; d->associatedResourceTree = associatedResourceTree; std::string file = _file; if (file.empty()) file = "/"; if (file[0] != '/') file = std::string("/") + file; std::size_t index = file.find_last_of('/'); if (index < file.size()-1) { d->fileName = file.substr(index+1); } std::string rawPath = file.substr(0,index+1); // remove duplicate / std::string::value_type lastChar = 0; for (std::size_t i = 0; i < rawPath.size(); ++i) { if (rawPath[i] == '/' && lastChar == '/') { continue; } lastChar = rawPath[i]; d->path.push_back(lastChar); } d->filePath = d->path + d->fileName; d->node = d->associatedResourceTree->FindNode(GetResourcePath()); if (d->node != -1) { - d->isFile = !associatedResourceTree->IsDir(d->node); + d->isFile = !d->associatedResourceTree->IsDir(d->node); if (d->isFile) { d->data = d->associatedResourceTree->GetData(d->node, &d->size); + d->isCompressed = d->associatedResourceTree->IsCompressed(d->node); } } } ModuleResource::~ModuleResource() { if (!d->ref.Deref()) delete d; } ModuleResource& ModuleResource::operator =(const ModuleResource& resource) { ModuleResourcePrivate* curr_d = d; d = resource.d; d->ref.Ref(); if (!curr_d->ref.Deref()) delete curr_d; return *this; } bool ModuleResource::operator <(const ModuleResource& resource) const { return this->GetResourcePath() < resource.GetResourcePath(); } bool ModuleResource::operator ==(const ModuleResource& resource) const { return d->associatedResourceTree == resource.d->associatedResourceTree && this->GetResourcePath() == resource.GetResourcePath(); } bool ModuleResource::operator !=(const ModuleResource &resource) const { return !(*this == resource); } bool ModuleResource::IsValid() const { return d->associatedResourceTree && d->associatedResourceTree->IsValid() && d->node > -1; } +bool ModuleResource::IsCompressed() const +{ + return d->isCompressed; +} + ModuleResource::operator bool() const { return IsValid(); } std::string ModuleResource::GetName() const { return d->fileName; } std::string ModuleResource::GetPath() const { return d->path; } std::string ModuleResource::GetResourcePath() const { return d->filePath; } std::string ModuleResource::GetBaseName() const { return d->fileName.substr(0, d->fileName.find_first_of('.')); } std::string ModuleResource::GetCompleteBaseName() const { return d->fileName.substr(0, d->fileName.find_last_of('.')); } std::string ModuleResource::GetSuffix() const { std::size_t index = d->fileName.find_last_of('.'); return index < d->fileName.size()-1 ? d->fileName.substr(index+1) : std::string(""); } std::string ModuleResource::GetCompleteSuffix() const { std::size_t index = d->fileName.find_first_of('.'); return index < d->fileName.size()-1 ? d->fileName.substr(index+1) : std::string(""); } bool ModuleResource::IsDir() const { return !d->isFile; } bool ModuleResource::IsFile() const { return d->isFile; } std::vector ModuleResource::GetChildren() const { if (d->isFile || !IsValid()) return d->children; if (!d->children.empty()) return d->children; bool indexPastAssociatedResTree = false; for (std::size_t i = 0; i < d->resourceTrees.size(); ++i) { if (d->resourceTrees[i] == d->associatedResourceTree) { indexPastAssociatedResTree = true; d->associatedResourceTree->GetChildren(d->node, d->children); } else if (indexPastAssociatedResTree) { int nodeIndex = d->resourceTrees[i]->FindNode(GetPath()); if (nodeIndex > -1) { d->resourceTrees[i]->GetChildren(d->node, d->children); } } } return d->children; } int ModuleResource::GetSize() const { return d->size; } const unsigned char* ModuleResource::GetData() const { if (!IsValid()) return NULL; return d->data; } std::size_t ModuleResource::Hash() const { using namespace US_HASH_FUNCTION_NAMESPACE; return US_HASH_FUNCTION(std::string, this->GetResourcePath()); } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ModuleResource& resource) { return os << resource.GetResourcePath(); } diff --git a/Core/Code/CppMicroServices/src/module/usModuleResource.h b/Core/Code/CppMicroServices/src/module/usModuleResource.h index 1bcf8a0657..9c6f4e9ec9 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResource.h +++ b/Core/Code/CppMicroServices/src/module/usModuleResource.h @@ -1,293 +1,304 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USMODULERESOURCE_H #define USMODULERESOURCE_H #include #include #include US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class ModuleResourcePrivate; class ModuleResourceTree; /** * \ingroup MicroServices * * Represents a resource (text file, image, etc.) embedded in a CppMicroServices module. * * A \c %ModuleResource object provides information about a resource (external file) which * was embedded into this module's shared library. \c %ModuleResource objects can be obtained * be calling Module#GetResource or Module#FindResources. * * Example code for retreiving a resource object and reading its contents: * \snippet uServices-resources/main.cpp 1 * * %ModuleResource objects have value semantics and copies are very inexpensive. * * \see ModuleResourceStream * \see \ref MicroServices_Resources */ class US_EXPORT ModuleResource { public: /** * Creates in invalid %ModuleResource object. */ ModuleResource(); /** * Copy constructor. * @param resource The object to be copied. */ ModuleResource(const ModuleResource& resource); ~ModuleResource(); /** * Assignment operator. * * @param resource The %ModuleResource object which is assigned to this instance. * @return A reference to this %ModuleResource instance. */ ModuleResource& operator=(const ModuleResource& resource); /** * A less then operator using the full resource path as returned by * GetResourcePath() to define the ordering. * * @param resource The object to which this %ModuleResource object is compared to. * @return \c true if this %ModuleResource object is less then \c resource, * \c false otherwise. */ bool operator<(const ModuleResource& resource) const; /** * Equality operator for %ModuleResource objects. * * @param resource The object for testing equality. * @return \c true if this %ModuleResource object is equal to \c resource, i.e. * they are coming from the same module (shared or static) and have an equal * resource path, \c false otherwise. */ bool operator==(const ModuleResource& resource) const; /** * Inequality operator for %ModuleResource objects. * * @param resource The object for testing inequality. * @return The result of !(*this == resource). */ bool operator!=(const ModuleResource& resource) const; /** * Tests this %ModuleResource object for validity. * * Invalid %ModuleResource objects are created by the default constructor or * can be returned by the Module class if the resource path is not found. If a * module from which %ModuleResource objects have been obtained is un-loaded, * these objects become invalid. * * @return \c true if this %ModuleReource object is valid and can safely be used, * \c false otherwise. */ bool IsValid() const; + /** + * Returns \c true if the resource represents a file and the resource data + * is in a compressed format, \c false otherwise. + * + * @return \c true if the resource data is compressed, \c false otherwise. + */ + bool IsCompressed() const; + /** * Boolean conversion operator using IsValid(). */ operator bool() const; /** * Returns the name of the resource, excluding the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string name = resource.GetName(); // name = "archive.tar.gz" * \endcode * * @return The resource name. * @see GetPath(), GetResourcePath() */ std::string GetName() const; /** * Returns the resource's path, without the file name. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string path = resource.GetPath(); // path = "/data" * \endcode * * @return The resource path without the name. * @see GetResourcePath(), GetName() and IsDir() */ std::string GetPath() const; /** * Returns the resource name including the path. * * @return The resource path include the name. * @see GetPath(), GetName() and IsDir() */ std::string GetResourcePath() const; /** * Returns the base name of the resource without the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string base = resource.GetBaseName(); // base = "archive" * \endcode * * @return The resource base name. * @see GetName(), GetSuffix(), GetCompleteSuffix() and GetCompleteBaseName() */ std::string GetBaseName() const; /** * Returns the complete base name of the resource without the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string base = resource.GetCompleteBaseName(); // base = "archive.tar" * \endcode * * @return The resource's complete base name. * @see GetName(), GetSuffix(), GetCompleteSuffix(), and GetBaseName() */ std::string GetCompleteBaseName() const; /** * Returns the suffix of the resource. * * The suffix consists of all characters in the resource name after (but not * including) the last '.'. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string suffix = resource.GetSuffix(); // suffix = "gz" * \endcode * * @return The resource name suffix. * @see GetName(), GetCompleteSuffix(), GetBaseName() and GetCompleteBaseName() */ std::string GetSuffix() const; /** * Returns the complete suffix of the resource. * * The suffix consists of all characters in the resource name after (but not * including) the first '.'. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string suffix = resource.GetCompleteSuffix(); // suffix = "tar.gz" * \endcode * * @return The resource name suffix. * @see GetName(), GetSuffix(), GetBaseName(), and GetCompleteBaseName() */ std::string GetCompleteSuffix() const; /** - * Returns \c true if this %ModuleResource object points to a directory. + * Returns \c true if this %ModuleResource object points to a directory and thus + * may have child resources. * * @return \c true if this object points to a directory, \c false otherwise. */ bool IsDir() const; /** * Returns \c true if this %ModuleResource object points to a file resource. * * @return \c true if this object points to an embedded file, \c false otherwise. */ bool IsFile() const; /** * Returns a list of resource names which are children of this object. * * The returned names are relative to the path of this %ModuleResource object and * may contain duplicates in case of modules which are statically linked into the * module from which this object was retreived. * * @return A list of child resource names. */ std::vector GetChildren() const; /** * Returns the size of the raw embedded data for this %ModuleResource object. * * @return The resource data size. */ int GetSize() const; /** * Returns a data pointer pointing to the raw data of this %ModuleResource object. + * If the resource is compressed the data returned is compressed and UncompressResourceData() + * must be used to access the data. If the resource represents a directory \c 0 is returned. * - * @return A raw pointer to the embedded data. + * @return A raw pointer to the embedded data, or \c 0 if the resource is not a file resource. */ const unsigned char* GetData() const; private: ModuleResource(const std::string& file, ModuleResourceTree* resourceTree, const std::vector& resourceTrees); friend class Module; US_HASH_FUNCTION_FRIEND(ModuleResource); std::size_t Hash() const; ModuleResourcePrivate* d; }; US_END_NAMESPACE US_MSVC_POP_WARNING /** * \ingroup MicroServices */ US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ModuleResource)& resource); US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ModuleResource)) return arg.Hash(); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USMODULERESOURCE_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp index 3b76d4aa9e..214ef231b8 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp @@ -1,275 +1,305 @@ /*=================================================================== BlueBerry Platform 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 "usModuleResourceBuffer_p.h" +#include "usUncompressResourceData.h" #include "stdint_p.h" #include #include #ifdef US_PLATFORM_WINDOWS #define DATA_NEEDS_NEWLINE_CONVERSION 1 #undef REMOVE_LAST_NEWLINE_IN_TEXT_MODE #else #undef DATA_NEEDS_NEWLINE_CONVERSION #define REMOVE_LAST_NEWLINE_IN_TEXT_MODE 1 #endif US_BEGIN_NAMESPACE static const std::size_t BUFFER_SIZE = 1024; class ModuleResourceBufferPrivate { public: ModuleResourceBufferPrivate(const char* begin, std::size_t size, std::ios_base::openmode mode) : begin(begin) , end(begin + size) , current(begin) , mode(mode) + #ifdef US_ENABLE_RESOURCE_COMPRESSION + , uncompressedData(NULL) + #endif #ifdef DATA_NEEDS_NEWLINE_CONVERSION , pos(0) #endif { } + ~ModuleResourceBufferPrivate() + { +#ifdef US_ENABLE_RESOURCE_COMPRESSION + delete[] uncompressedData; +#endif + } + const char* const begin; const char* const end; const char* current; const std::ios_base::openmode mode; +#ifdef US_ENABLE_RESOURCE_COMPRESSION + const unsigned char* uncompressedData; +#endif + #ifdef DATA_NEEDS_NEWLINE_CONVERSION // records the stream position ignoring CR characters std::streambuf::pos_type pos; #endif }; ModuleResourceBuffer::ModuleResourceBuffer(const unsigned char* data, std::size_t _size, - std::ios_base::openmode mode) + std::ios_base::openmode mode, bool compressed) : d(NULL) { assert(_size < static_cast(std::numeric_limits::max())); // assert(data != NULL); + if (compressed && _size) + { +#ifdef US_ENABLE_RESOURCE_COMPRESSION + data = UncompressResourceData(data, _size, &_size); +#else + assert(!"CppMicroServices built without support for resource compression"); +#endif + } + const char* begin = reinterpret_cast(data); std::size_t size = _size; #ifdef DATA_NEEDS_NEWLINE_CONVERSION if (data != NULL && !(mode & std::ios_base::binary) && begin[0] == '\r') { ++begin; --size; } #endif #ifdef REMOVE_LAST_NEWLINE_IN_TEXT_MODE - if(data != NULL && !(mode & std::ios_base::binary) && begin[size-1] == '\n') + if (data != NULL && !(mode & std::ios_base::binary) && begin[size-1] == '\n') { --size; } #endif d = new ModuleResourceBufferPrivate(begin, size, mode); +#ifdef US_ENABLE_RESOURCE_COMPRESSION + if (compressed) + { + d->uncompressedData = data; + } +#endif } ModuleResourceBuffer::~ModuleResourceBuffer() { delete d; } ModuleResourceBuffer::int_type ModuleResourceBuffer::underflow() { if (d->current == d->end) return traits_type::eof(); #ifdef DATA_NEEDS_NEWLINE_CONVERSION char c = *d->current; if (!(d->mode & std::ios_base::binary)) { if (c == '\r') { if (d->current + 1 == d->end) { return traits_type::eof(); } c = d->current[1]; } } return traits_type::to_int_type(c); #else return traits_type::to_int_type(*d->current); #endif } ModuleResourceBuffer::int_type ModuleResourceBuffer::uflow() { if (d->current == d->end) return traits_type::eof(); #ifdef DATA_NEEDS_NEWLINE_CONVERSION char c = *d->current++; if (!(d->mode & std::ios_base::binary)) { if (c == '\r') { if (d->current == d->end) { return traits_type::eof(); } c = *d->current++; } } return traits_type::to_int_type(c); #else return traits_type::to_int_type(*d->current++); #endif } ModuleResourceBuffer::int_type ModuleResourceBuffer::pbackfail(int_type ch) { int backOffset = -1; #ifdef DATA_NEEDS_NEWLINE_CONVERSION if (!(d->mode & std::ios_base::binary)) { while ((d->current - backOffset) >= d->begin && d->current[backOffset] == '\r') { --backOffset; } // d->begin always points to a character != '\r' } #endif if (d->current == d->begin || (ch != traits_type::eof() && ch != d->current[backOffset])) { return traits_type::eof(); } d->current += backOffset; return traits_type::to_int_type(*d->current); } std::streamsize ModuleResourceBuffer::showmanyc() { assert(d->current <= d->end); #ifdef DATA_NEEDS_NEWLINE_CONVERSION std::streamsize ssize = 0; std::size_t chunkSize = d->end - d->current; for (std::size_t i = 0; i < chunkSize; ++i) { if (d->current[i] != '\r') { ++ssize; } } return ssize; #else return d->end - d->current; #endif } std::streambuf::pos_type ModuleResourceBuffer::seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*which*/) { #ifdef DATA_NEEDS_NEWLINE_CONVERSION std::streambuf::off_type step = 1; if (way == std::ios_base::beg) { d->current = d->begin; } else if (way == std::ios_base::end) { d->current = d->end; step = -1; } if (!(d->mode & std::ios_base::binary)) { if (way == std::ios_base::beg) { d->pos = 0; } else if (way == std::ios_base::end) { d->current -= 1; } std::streambuf::off_type i = 0; // scan through off amount of characters excluding '\r' while (i != off) { if (*d->current != '\r') { i += step; d->pos += step; } d->current += step; } // adjust the position in case of a "backwards" seek if (way == std::ios_base::end) { // fix pointer from previous while loop d->current += 1; d->pos = 0; i = 0; const std::streampos currInternalPos = d->current - d->begin; while (i != currInternalPos) { if (d->begin[i] != '\r') { d->pos += 1; } ++i; } } } else { d->current += off; d->pos = d->current - d->begin; } return d->pos; #else if (way == std::ios_base::beg) { d->current = d->begin + off; return off; } else if (way == std::ios_base::cur) { d->current += off; return d->current - d->begin; } else { d->current = d->end + off; return d->current - d->begin; } #endif } std::streambuf::pos_type ModuleResourceBuffer::seekpos(std::streambuf::pos_type sp, std::ios_base::openmode /*which*/) { return this->seekoff(sp, std::ios_base::beg); } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer_p.h b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer_p.h index 8432a5ab23..95797022d4 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer_p.h +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer_p.h @@ -1,63 +1,63 @@ /*=================================================================== BlueBerry Platform 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 USMODULERESOURCEBUFFER_P_H #define USMODULERESOURCEBUFFER_P_H #include #include US_BEGIN_NAMESPACE class ModuleResourceBufferPrivate; class US_EXPORT ModuleResourceBuffer: public std::streambuf { public: explicit ModuleResourceBuffer(const unsigned char* data, std::size_t size, - std::ios_base::openmode mode); + std::ios_base::openmode mode, bool compressed); ~ModuleResourceBuffer(); private: int_type underflow(); int_type uflow(); int_type pbackfail(int_type ch); std::streamsize showmanyc(); pos_type seekoff (off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out); pos_type seekpos (pos_type sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out); // purposely not implemented ModuleResourceBuffer(const ModuleResourceBuffer&); ModuleResourceBuffer& operator=(const ModuleResourceBuffer&); private: ModuleResourceBufferPrivate* d; }; US_END_NAMESPACE #endif // USMODULERESOURCEBUFFER_P_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceStream.cpp b/Core/Code/CppMicroServices/src/module/usModuleResourceStream.cpp index bcb81ad59c..fd6fa8a448 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResourceStream.cpp +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceStream.cpp @@ -1,34 +1,35 @@ /*=================================================================== BlueBerry Platform 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 "usModuleResourceStream.h" #include "usModuleResource.h" // 'this' used in base member initializer list US_MSVC_PUSH_DISABLE_WARNING(4355) US_BEGIN_NAMESPACE ModuleResourceStream::ModuleResourceStream(const ModuleResource& resource, std::ios_base::openmode mode) - : ModuleResourceBuffer(resource.GetData(), resource.GetSize(), mode | std::ios_base::in) + : ModuleResourceBuffer(resource.GetData(), resource.GetSize(), mode | std::ios_base::in, + resource.IsCompressed()) , std::istream(this) { } US_END_NAMESPACE US_MSVC_POP_WARNING diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceTree_p.h b/Core/Code/CppMicroServices/src/module/usModuleResourceTree_p.h index 9ebfb44cc3..038e3434ed 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResourceTree_p.h +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceTree_p.h @@ -1,96 +1,98 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USMODULERESOURCETREE_H #define USMODULERESOURCETREE_H #include #include "usModuleInfo.h" #include "stdint_p.h" #include US_BEGIN_NAMESPACE struct ModuleInfo; /* * This class represents the triple of data pointers * (us_resource_data, us_resource_name, us_resource_tree) generate by * the resource compiler. * * Each module owns zero or one such triple but in case of a statically * linked (imported) module, the resource trees are "merged" together. */ class ModuleResourceTree { private: enum Flags { - Directory = 0x01 + Directory = 0x01, + Compressed = 0x02 }; bool isValid; const unsigned char *tree, *names, *payloads; // Returns the offset in the us_resource_tree array for a given node index inline int FindOffset(int node) const { return node * 14; } // sizeof each tree element std::string GetName(int node) const; short GetFlags(int node) const; void FindNodes(std::vector& result, const std::string& path, const int rootNode, const std::string& filePattern, bool recurse); uint32_t GetHash(int node) const; bool Matches(const std::string& name, const std::string& filePattern); public: ModuleResourceTree(ModuleInfo::ModuleResourceData resourceTree, ModuleInfo::ModuleResourceData resourceNames, ModuleInfo::ModuleResourceData resourceData); bool IsValid() const; void Invalidate(); // Returns an index enumerating the info entries in the us_resource_tree array for // the given resource path. int FindNode(const std::string& path) const; void FindNodes(const std::string& path, const std::string& filePattern, bool recurse, std::vector& result); - inline bool IsDir(int node) const { return GetFlags(node) & Directory; } + inline bool IsCompressed(int node) const {return GetFlags(node) & Compressed ? true : false; } + inline bool IsDir(int node) const { return GetFlags(node) & Directory ? true : false; } const unsigned char* GetData(int node, int32_t *size) const; void GetChildren(int node, std::vector& children) const; }; US_END_NAMESPACE #endif // USMODULERESOURCETREE_H diff --git a/Core/Code/CppMicroServices/src/service/usServiceEvent.h b/Core/Code/CppMicroServices/src/service/usServiceEvent.h index d1047b5fab..1d181deed2 100644 --- a/Core/Code/CppMicroServices/src/service/usServiceEvent.h +++ b/Core/Code/CppMicroServices/src/service/usServiceEvent.h @@ -1,179 +1,191 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USSERVICEEVENT_H #define USSERVICEEVENT_H +#ifdef REGISTERED +#ifdef _WIN32 +#error The REGISTERED preprocessor define clashes with the ServiceEvent::REGISTERED\ + enum type. Try to reorder your includes, compile with WIN32_LEAN_AND_MEAN, or undef\ + the REGISTERED macro befor including this header. +#else +#error The REGISTERED preprocessor define clashes with the ServiceEvent::REGISTERED\ + enum type. Try to reorder your includes or undef the REGISTERED macro befor including\ + this header. +#endif +#endif + #include "usSharedData.h" #include "usServiceReference.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4251) #endif US_BEGIN_NAMESPACE class ServiceEventData; /** * \ingroup MicroServices * * An event from the Micro Services framework describing a service lifecycle change. *

* ServiceEvent objects are delivered to * listeners connected via ModuleContext::AddServiceListener() when a * change occurs in this service's lifecycle. A type code is used to identify * the event type for future extendability. */ class US_EXPORT ServiceEvent { SharedDataPointer d; public: enum Type { /** * This service has been registered. *

* This event is delivered after the service * has been registered with the framework. * * @see ModuleContext#RegisterService() */ REGISTERED = 0x00000001, /** * The properties of a registered service have been modified. *

* This event is delivered after the service * properties have been modified. * * @see ServiceRegistration#SetProperties */ MODIFIED = 0x00000002, /** * This service is in the process of being unregistered. *

* This event is delivered before the service * has completed unregistering. * *

* If a module is using a service that is UNREGISTERING, the * module should release its use of the service when it receives this event. * If the module does not release its use of the service when it receives * this event, the framework will automatically release the module's use of * the service while completing the service unregistration operation. * * @see ServiceRegistration#Unregister * @see ModuleContext#UngetService */ UNREGISTERING = 0x00000004, /** * The properties of a registered service have been modified and the new * properties no longer match the listener's filter. *

* This event is delivered after the service * properties have been modified. This event is only delivered to listeners * which were added with a non-empty filter where the filter * matched the service properties prior to the modification but the filter * does not match the modified service properties. * * @see ServiceRegistration#SetProperties */ MODIFIED_ENDMATCH = 0x00000008 }; /** * Creates an invalid instance. */ ServiceEvent(); ~ServiceEvent(); /** * Can be used to check if this ServiceEvent instance is valid, * or if it has been constructed using the default constructor. * * @return true if this event object is valid, * false otherwise. */ bool IsNull() const; /** * Creates a new service event object. * * @param type The event type. * @param reference A ServiceReference object to the service * that had a lifecycle change. */ ServiceEvent(Type type, const ServiceReference& reference); ServiceEvent(const ServiceEvent& other); ServiceEvent& operator=(const ServiceEvent& other); /** * Returns a reference to the service that had a change occur in its * lifecycle. *

* This reference is the source of the event. * * @return Reference to the service that had a lifecycle change. */ ServiceReference GetServiceReference() const; /** * Returns the type of event. The event type values are: *

    *
  • {@link #REGISTERED}
  • *
  • {@link #MODIFIED}
  • *
  • {@link #MODIFIED_ENDMATCH}
  • *
  • {@link #UNREGISTERING}
  • *
* * @return Type of service lifecycle change. */ Type GetType() const; }; US_END_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif /** * \ingroup MicroServices * @{ */ US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceEvent::Type)& type); US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceEvent)& event); /** @}*/ #endif // USSERVICEEVENT_H diff --git a/Core/Code/CppMicroServices/src/util/tinfl.c b/Core/Code/CppMicroServices/src/util/tinfl.c new file mode 100644 index 0000000000..a17a156b6c --- /dev/null +++ b/Core/Code/CppMicroServices/src/util/tinfl.c @@ -0,0 +1,592 @@ +/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c) + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated May 20, 2011 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers. +*/ +#ifndef TINFL_HEADER_INCLUDED +#define TINFL_HEADER_INCLUDED + +#include + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef unsigned long long mz_uint64; + +#if defined(_M_IX86) || defined(_M_X64) +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif + +#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +// Works around MSVC's spammy "warning C4127: conditional expression is constant" message. +#ifdef _MSC_VER + #define MZ_MACRO_END while (0, 0) +#else + #define MZ_MACRO_END while (0) +#endif + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum +{ + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum +{ + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS + #define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#endif // #ifdef TINFL_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef TINFL_HEADER_FILE_ONLY + +#include + +// MZ_MALLOC, etc. are only used by the optional high-level helper functions. +#ifdef MINIZ_NO_MALLOC + #define MZ_MALLOC(x) NULL + #define MZ_FREE(x) x, ((void)0) + #define MZ_REALLOC(p, x) NULL +#else + #define MZ_MALLOC(x) malloc(x) + #define MZ_FREE(x) free(x) + #define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) + #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else + #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) + #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for ( ; ; ) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a +// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ + } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read +// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully +// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ + int temp; mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ + } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; + static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + + num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; + r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; + cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) + { + mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) + { + mz_uint8 *pSrc; + for ( ; ; ) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } +#else + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + bit_buf >>= code_len; num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +#endif // #ifndef TINFL_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ diff --git a/Core/Code/CppMicroServices/src/util/usUncompressResourceData.c b/Core/Code/CppMicroServices/src/util/usUncompressResourceData.c new file mode 100644 index 0000000000..310491ed82 --- /dev/null +++ b/Core/Code/CppMicroServices/src/util/usUncompressResourceData.c @@ -0,0 +1,59 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + + +#include "tinfl.c" + +#include + +static char us_uncompress_error_msg[256]; + +const char* us_uncompress_resource_error() +{ + return us_uncompress_error_msg; +} + +void us_uncompress_resource_data(const unsigned char* data, size_t size, + unsigned char* uncompressedData, size_t uncompressedSize) +{ + size_t bytesWritten = 0; + + memset(us_uncompress_error_msg, 0, sizeof(us_uncompress_error_msg)); + + if (data == NULL) + { + return; + } + + if (uncompressedData == NULL) + { + sprintf(us_uncompress_error_msg, "us_uncompress_resource_data: Buffer for uncomcpressing data is NULL"); + return; + } + + bytesWritten = tinfl_decompress_mem_to_mem(uncompressedData, uncompressedSize, + data, size, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if (bytesWritten != uncompressedSize) + { + sprintf(us_uncompress_error_msg, "us_uncompress_resource_data: tinfl_decompress_mem_to_mem failed"); + } +} diff --git a/Core/Code/CppMicroServices/src/util/usUncompressResourceData.cpp b/Core/Code/CppMicroServices/src/util/usUncompressResourceData.cpp new file mode 100644 index 0000000000..dbc383145d --- /dev/null +++ b/Core/Code/CppMicroServices/src/util/usUncompressResourceData.cpp @@ -0,0 +1,86 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + +#include "usUncompressResourceData.h" + +#ifdef US_ENABLE_RESOURCE_COMPRESSION +#include "usUtils_p.h" + +extern "C" { +const char* us_uncompress_resource_error(); +void us_uncompress_resource_data(const unsigned char*, size_t, unsigned char*, size_t); +} + +US_BEGIN_NAMESPACE + +unsigned char* UncompressResourceData(const unsigned char* data, std::size_t size, + std::size_t* uncompressedSize) +{ + if (size <= 4) + { + if (size < 4 || (data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 0)) + { + US_WARN << "UncompressResourceData: Input data is corrupted"; + return NULL; + } + } + std::size_t expectedSize = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + try + { + unsigned char* uncompressedData = new unsigned char[expectedSize]; + us_uncompress_resource_data(data+4, size-4, uncompressedData, expectedSize); + if (us_uncompress_resource_error()[0] != 0) + { + US_WARN << us_uncompress_resource_error(); + delete[] uncompressedData; + return NULL; + } + + if (uncompressedSize != NULL) + { + *uncompressedSize = expectedSize; + } + + return uncompressedData; + } + catch (const std::bad_alloc&) + { + US_WARN << "UncompressResourceData: Could not allocate enough memory for uncompressing resource data"; + return NULL; + } + + return NULL; +} + +US_END_NAMESPACE + +#else + +US_BEGIN_NAMESPACE + +unsigned char* UncompressResourceData(const unsigned char*, std::size_t, std::size_t*) +{ + return 0; +} + +US_END_NAMESPACE + +#endif // US_ENABLE_RESOURCE_COMPRESSION diff --git a/Core/Code/CppMicroServices/src/util/usUncompressResourceData.h b/Core/Code/CppMicroServices/src/util/usUncompressResourceData.h new file mode 100644 index 0000000000..a3e82f3679 --- /dev/null +++ b/Core/Code/CppMicroServices/src/util/usUncompressResourceData.h @@ -0,0 +1,33 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + +#ifndef USUNCOMPRESSRESOURCEDATA_H +#define USUNCOMPRESSRESOURCEDATA_H + +#include "usConfig.h" + +US_BEGIN_NAMESPACE + +US_EXPORT unsigned char* UncompressResourceData(const unsigned char* data, std::size_t size, std::size_t* uncompressedSize); + +US_END_NAMESPACE + +#endif // USUNCOMPRESSRESOURCEDATA_H diff --git a/Core/Code/CppMicroServices/test/modules/libRWithResources/CMakeLists.txt b/Core/Code/CppMicroServices/test/modules/libRWithResources/CMakeLists.txt index 2b4880e3ca..c39359ab09 100644 --- a/Core/Code/CppMicroServices/test/modules/libRWithResources/CMakeLists.txt +++ b/Core/Code/CppMicroServices/test/modules/libRWithResources/CMakeLists.txt @@ -1,13 +1,14 @@ set(resource_files + icons/compressable.bmp icons/cppmicroservices.png icons/readme.txt foo.txt special_chars.dummy.txt test.xml ) usFunctionCreateTestModuleWithResources(TestModuleR SOURCES usTestModuleR.cpp RESOURCES ${resource_files}) diff --git a/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/compressable.bmp b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/compressable.bmp new file mode 100644 index 0000000000..96c6caba90 Binary files /dev/null and b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/compressable.bmp differ diff --git a/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp b/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp index cab32d6be6..4185701c8a 100644 --- a/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp +++ b/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp @@ -1,485 +1,534 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include #include #include "usTestUtilSharedLibrary.h" #include "usTestingMacros.h" #include #include US_USE_NAMESPACE namespace { void checkResourceInfo(const ModuleResource& res, const std::string& path, const std::string& baseName, const std::string& completeBaseName, const std::string& suffix, const std::string& completeSuffix, - int size, bool children = false) + int size, bool children = false, bool compressed = false) { US_TEST_CONDITION_REQUIRED(res.IsValid(), "Valid resource") US_TEST_CONDITION(res.GetBaseName() == baseName, "GetBaseName()") US_TEST_CONDITION(res.GetChildren().empty() == !children, "No children") US_TEST_CONDITION(res.GetCompleteBaseName() == completeBaseName, "GetCompleteBaseName()") US_TEST_CONDITION(res.GetName() == completeBaseName + "." + suffix, "GetName()") US_TEST_CONDITION(res.GetResourcePath() == path + completeBaseName + "." + suffix, "GetResourcePath()") US_TEST_CONDITION(res.GetPath() == path, "GetPath()") US_TEST_CONDITION(res.GetSize() == size, "Data size") US_TEST_CONDITION(res.GetSuffix() == suffix, "Suffix") US_TEST_CONDITION(res.GetCompleteSuffix() == completeSuffix, "Complete suffix") + US_TEST_CONDITION(res.IsCompressed() == compressed, "Compression flag") } void testTextResource(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 16, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 13, false); const std::streampos ssize(12); const std::string fileData = "foo and\nbar\n"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); rs.clear(); rs.seekg(0); US_TEST_CONDITION_REQUIRED(rs.tellg() == std::streampos(0), "Move to start") US_TEST_CONDITION_REQUIRED(rs.good(), "Start re-reading"); std::vector lines; std::string line; while (std::getline(rs, line)) { lines.push_back(line); } US_TEST_CONDITION_REQUIRED(lines.size() > 1, "Number of lines") US_TEST_CONDITION(lines[0] == "foo and", "Check first line") US_TEST_CONDITION(lines[1] == "bar", "Check second line") } void testTextResourceAsBinary(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 16, false); const std::streampos ssize(16); const std::string fileData = "foo and\r\nbar\r\n\r\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 13, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #endif ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } #ifdef US_BUILD_SHARED_LIBS void testInvalidResource(Module* module) { ModuleResource res = module->GetResource("invalid"); US_TEST_CONDITION_REQUIRED(res.IsValid() == false, "Check invalid resource") US_TEST_CONDITION(res.GetName().empty(), "Check empty name") US_TEST_CONDITION(res.GetPath().empty(), "Check empty path") US_TEST_CONDITION(res.GetResourcePath().empty(), "Check empty resource path") US_TEST_CONDITION(res.GetBaseName().empty(), "Check empty base name") US_TEST_CONDITION(res.GetCompleteBaseName().empty(), "Check empty complete base name") US_TEST_CONDITION(res.GetSuffix().empty(), "Check empty suffix") US_TEST_CONDITION(res.GetChildren().empty(), "Check empty children") US_TEST_CONDITION(res.GetSize() == 0, "Check zero size") US_TEST_CONDITION(res.GetData() == NULL, "Check NULL data") ModuleResourceStream rs(res); US_TEST_CONDITION(rs.good() == true, "Check invalid resource stream") rs.ignore(); US_TEST_CONDITION(rs.good() == false, "Check invalid resource stream") US_TEST_CONDITION(rs.eof() == true, "Check invalid resource stream") } #endif void testSpecialCharacters(Module* module) { ModuleResource res = module->GetResource("special_chars.dummy.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", "dummy.txt", 56, false); const std::streampos ssize(54); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)\n"; #else checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", "dummy.txt", 54, false); const std::streampos ssize(53); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios_base::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios_base::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } void testBinaryResource(Module* module) { ModuleResource res = module->GetResource("/icons/cppmicroservices.png"); checkResourceInfo(res, "/icons/", "cppmicroservices", "cppmicroservices", "png", "png", 2424, false); ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios_base::end); std::streampos resLength = rs.tellg(); rs.seekg(0); std::ifstream png(CppMicroServices_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/cppmicroservices.png", std::ifstream::in | std::ifstream::binary); US_TEST_CONDITION_REQUIRED(png.is_open(), "Open reference file") png.seekg(0, std::ios_base::end); std::streampos pngLength = png.tellg(); png.seekg(0); - US_TEST_CONDITION(resLength = res.GetSize(), "Check resource size") + US_TEST_CONDITION(res.GetSize() == resLength, "Check resource size") US_TEST_CONDITION_REQUIRED(resLength == pngLength, "Compare sizes") char c1 = 0; char c2 = 0; bool isEqual = true; int count = 0; while (png.get(c1) && rs.get(c2)) { ++count; if (c1 != c2) { isEqual = false; break; } } US_TEST_CONDITION_REQUIRED(count == pngLength, "Check if everything was read"); US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); US_TEST_CONDITION(png.eof(), "EOF check"); } +#ifdef US_ENABLE_RESOURCE_COMPRESSION +void testCompressedResource(Module* module) +{ + ModuleResource res = module->GetResource("/icons/compressable.bmp"); + checkResourceInfo(res, "/icons/", "compressable", "compressable", "bmp", "bmp", 411, false, true); + + ModuleResourceStream rs(res, std::ios_base::binary); + rs.seekg(0, std::ios_base::end); + std::streampos resLength = rs.tellg(); + rs.seekg(0); + + std::ifstream bmp(CppMicroServices_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/compressable.bmp", + std::ifstream::in | std::ifstream::binary); + + US_TEST_CONDITION_REQUIRED(bmp.is_open(), "Open reference file") + + bmp.seekg(0, std::ios_base::end); + std::streampos bmpLength = bmp.tellg(); + bmp.seekg(0); + US_TEST_CONDITION(300122 == resLength, "Check resource size") + US_TEST_CONDITION_REQUIRED(resLength == bmpLength, "Compare sizes") + + char c1 = 0; + char c2 = 0; + bool isEqual = true; + int count = 0; + while (bmp.get(c1) && rs.get(c2)) + { + ++count; + if (c1 != c2) + { + isEqual = false; + break; + } + } + + US_TEST_CONDITION_REQUIRED(count == bmpLength, "Check if everything was read"); + US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); + US_TEST_CONDITION(bmp.eof(), "EOF check"); +} +#endif + struct ResourceComparator { bool operator()(const ModuleResource& mr1, const ModuleResource& mr2) const { return mr1 < mr2; } }; #ifdef US_BUILD_SHARED_LIBS void testResourceTree(Module* module) { ModuleResource res = module->GetResource(""); US_TEST_CONDITION(res.GetResourcePath() == "/", "Check root file path") US_TEST_CONDITION(res.IsDir() == true, "Check type") std::vector children = res.GetChildren(); std::sort(children.begin(), children.end()); US_TEST_CONDITION_REQUIRED(children.size() == 4, "Check child count") US_TEST_CONDITION(children[0] == "foo.txt", "Check child name") US_TEST_CONDITION(children[1] == "icons", "Check child name") US_TEST_CONDITION(children[2] == "special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(children[3] == "test.xml", "Check child name") ModuleResource readme = module->GetResource("/icons/readme.txt"); US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") ModuleResource icons = module->GetResource("icons"); US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") children = icons.GetChildren(); - US_TEST_CONDITION_REQUIRED(children.size() == 2, "Check icons child count") + US_TEST_CONDITION_REQUIRED(children.size() == 3, "Check icons child count") std::sort(children.begin(), children.end()); - US_TEST_CONDITION(children[0] == "cppmicroservices.png", "Check child name") - US_TEST_CONDITION(children[1] == "readme.txt", "Check child name") + US_TEST_CONDITION(children[0] == "compressable.bmp", "Check child name") + US_TEST_CONDITION(children[1] == "cppmicroservices.png", "Check child name") + US_TEST_CONDITION(children[2] == "readme.txt", "Check child name") ResourceComparator resourceComparator; // find all .txt files std::vector nodes = module->FindResources("", "*.txt", false); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 2, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") nodes = module->FindResources("", "*.txt", true); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 3, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/icons/readme.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") // find all resources nodes = module->FindResources("", "", true); - US_TEST_CONDITION(nodes.size() == 5, "Total resource number") + US_TEST_CONDITION(nodes.size() == 6, "Total resource number") nodes = module->FindResources("", "**", true); - US_TEST_CONDITION(nodes.size() == 5, "Total resource number") + US_TEST_CONDITION(nodes.size() == 6, "Total resource number") // test pattern matching nodes.clear(); nodes = module->FindResources("/icons", "*micro*.png", false); US_TEST_CONDITION(nodes.size() == 1 && nodes[0].GetResourcePath() == "/icons/cppmicroservices.png", "Check file pattern matches") nodes.clear(); nodes = module->FindResources("", "*.txt", true); US_TEST_CONDITION(nodes.size() == 3, "Check recursive pattern matches") } #else void testResourceTree(Module* module) { ModuleResource res = module->GetResource(""); US_TEST_CONDITION(res.GetResourcePath() == "/", "Check root file path") US_TEST_CONDITION(res.IsDir() == true, "Check type") std::vector children = res.GetChildren(); std::sort(children.begin(), children.end()); US_TEST_CONDITION_REQUIRED(children.size() == 8, "Check child count") US_TEST_CONDITION(children[0] == "dynamic.txt", "Check dynamic.txt child name") US_TEST_CONDITION(children[1] == "foo.txt", "Check foo.txt child name") US_TEST_CONDITION(children[2] == "icons", "Check icons child name") US_TEST_CONDITION(children[3] == "res.txt", "Check res.txt child name") US_TEST_CONDITION(children[4] == "res.txt", "Check res.txt child name") US_TEST_CONDITION(children[5] == "special_chars.dummy.txt", "Check special_chars.dummy.txt child name") US_TEST_CONDITION(children[6] == "static.txt", "Check static.txt child name") US_TEST_CONDITION(children[7] == "test.xml", "Check test.xml child name") ModuleResource readme = module->GetResource("/icons/readme.txt"); US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") ModuleResource icons = module->GetResource("icons"); US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") children = icons.GetChildren(); - US_TEST_CONDITION_REQUIRED(children.size() == 2, "Check icons child count") + US_TEST_CONDITION_REQUIRED(children.size() == 3, "Check icons child count") std::sort(children.begin(), children.end()); - US_TEST_CONDITION(children[0] == "cppmicroservices.png", "Check child name") - US_TEST_CONDITION(children[1] == "readme.txt", "Check child name") + US_TEST_CONDITION(children[0] == "compressable.bmp", "Check child name") + US_TEST_CONDITION(children[1] == "cppmicroservices.png", "Check child name") + US_TEST_CONDITION(children[2] == "readme.txt", "Check child name") ResourceComparator resourceComparator; // find all .txt files std::vector nodes = module->FindResources("", "*.txt", false); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 6, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/dynamic.txt", "Check dynamic.txt child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/res.txt", "Check res.txt child name") US_TEST_CONDITION(nodes[3].GetResourcePath() == "/res.txt", "Check res.txt child name") US_TEST_CONDITION(nodes[4].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(nodes[5].GetResourcePath() == "/static.txt", "Check static.txt child name") nodes = module->FindResources("", "*.txt", true); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 7, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/dynamic.txt", "Check dynamic.txt child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/icons/readme.txt", "Check child name") US_TEST_CONDITION(nodes[3].GetResourcePath() == "/res.txt", "Check res.txt child name") US_TEST_CONDITION(nodes[4].GetResourcePath() == "/res.txt", "Check res.txt child name") US_TEST_CONDITION(nodes[5].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(nodes[6].GetResourcePath() == "/static.txt", "Check static.txt child name") // find all resources nodes = module->FindResources("", "", true); - US_TEST_CONDITION(nodes.size() == 9, "Total resource number") + US_TEST_CONDITION(nodes.size() == 10, "Total resource number") nodes = module->FindResources("", "**", true); - US_TEST_CONDITION(nodes.size() == 9, "Total resource number") + US_TEST_CONDITION(nodes.size() == 10, "Total resource number") // test pattern matching nodes.clear(); nodes = module->FindResources("/icons", "*micro*.png", false); US_TEST_CONDITION(nodes.size() == 1 && nodes[0].GetResourcePath() == "/icons/cppmicroservices.png", "Check file pattern matches") nodes.clear(); nodes = module->FindResources("", "*.txt", true); US_TEST_CONDITION(nodes.size() == 7, "Check recursive pattern matches") } #endif void testResourceOperators(Module* module) { ModuleResource invalid = module->GetResource("invalid"); ModuleResource foo = module->GetResource("foo.txt"); US_TEST_CONDITION_REQUIRED(foo.IsValid() && foo, "Check valid resource") ModuleResource foo2(foo); US_TEST_CONDITION(foo == foo, "Check equality operator") US_TEST_CONDITION(foo == foo2, "Check copy constructor and equality operator") US_TEST_CONDITION(foo != invalid, "Check inequality with invalid resource") ModuleResource xml = module->GetResource("/test.xml"); US_TEST_CONDITION_REQUIRED(xml.IsValid() && xml, "Check valid resource") US_TEST_CONDITION(foo != xml, "Check inequality") US_TEST_CONDITION(foo < xml, "Check operator<") // check operator< by using a set std::set resources; resources.insert(foo); resources.insert(foo); resources.insert(xml); US_TEST_CONDITION(resources.size() == 2, "Check operator< with set") // check hash function specialization US_UNORDERED_SET_TYPE resources2; resources2.insert(foo); resources2.insert(foo); resources2.insert(xml); US_TEST_CONDITION(resources2.size() == 2, "Check operator< with unordered set") // check operator<< std::ostringstream oss; oss << foo; US_TEST_CONDITION(oss.str() == foo.GetResourcePath(), "Check operator<<") } #ifdef US_BUILD_SHARED_LIBS void testResourceFromExecutable(Module* module) { ModuleResource resource = module->GetResource("usTestResource.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid executable resource") std::string line; ModuleResourceStream rs(resource); std::getline(rs, line); US_TEST_CONDITION(line == "meant to be compiled into the test driver", "Check executable resource content") } #endif } // end unnamed namespace int usModuleResourceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleResourceTest"); ModuleContext* mc = GetModuleContext(); assert(mc); #ifdef US_BUILD_SHARED_LIBS SharedLibraryHandle libR("TestModuleR"); try { libR.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } Module* moduleR = ModuleRegistry::GetModule("TestModuleR Module"); US_TEST_CONDITION_REQUIRED(moduleR != NULL, "Test for existing module TestModuleR") US_TEST_CONDITION(moduleR->GetName() == "TestModuleR Module", "Test module name") testInvalidResource(moduleR); testResourceFromExecutable(mc->GetModule()); #else Module* moduleR = mc->GetModule(); US_TEST_CONDITION_REQUIRED(moduleR != NULL, "Test for existing module 0") US_TEST_CONDITION(moduleR->GetName() == "CppMicroServices", "Test module name") #endif testResourceTree(moduleR); testResourceOperators(moduleR); testTextResource(moduleR); testTextResourceAsBinary(moduleR); testSpecialCharacters(moduleR); testBinaryResource(moduleR); +#ifdef US_ENABLE_RESOURCE_COMPRESSION + testCompressedResource(moduleR); +#endif + #ifdef US_BUILD_SHARED_LIBS ModuleResource foo = moduleR->GetResource("foo.txt"); US_TEST_CONDITION(foo.IsValid() == true, "Valid resource") libR.Unload(); US_TEST_CONDITION(foo.IsValid() == false, "Invalidated resource") US_TEST_CONDITION(foo.GetData() == NULL, "NULL data") #endif US_TEST_END() } diff --git a/Core/Code/CppMicroServices/test/usTestUtilSharedLibrary.cpp b/Core/Code/CppMicroServices/test/usTestUtilSharedLibrary.cpp index 199aca0313..68be2b5a4c 100644 --- a/Core/Code/CppMicroServices/test/usTestUtilSharedLibrary.cpp +++ b/Core/Code/CppMicroServices/test/usTestUtilSharedLibrary.cpp @@ -1,141 +1,143 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usTestUtilSharedLibrary.h" #include #include #include #include #include #if defined(US_PLATFORM_POSIX) #include #elif defined(US_PLATFORM_WINDOWS) - #define WIN32_LEAN_AND_MEAN + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif #include #include #else #error Unsupported platform #endif US_BEGIN_NAMESPACE SharedLibraryHandle::SharedLibraryHandle() : m_Handle(0) {} SharedLibraryHandle::SharedLibraryHandle(const std::string& name) : m_Name(name), m_Handle(0) {} SharedLibraryHandle::~SharedLibraryHandle() {} void SharedLibraryHandle::Load() { Load(m_Name); } void SharedLibraryHandle::Load(const std::string& name) { #ifdef US_BUILD_SHARED_LIBS if (m_Handle) throw std::logic_error(std::string("Library already loaded: ") + name); std::string libPath = GetAbsolutePath(name); #ifdef US_PLATFORM_POSIX m_Handle = dlopen(libPath.c_str(), RTLD_LAZY | RTLD_GLOBAL); if (!m_Handle) { const char* err = dlerror(); throw std::runtime_error(err ? std::string(err) : libPath); } #else m_Handle = LoadLibrary(libPath.c_str()); if (!m_Handle) { std::string errMsg = "Loading "; errMsg.append(libPath).append("failed with error: ").append(GetLastErrorStr()); throw std::runtime_error(errMsg); } #endif #endif m_Name = name; } void SharedLibraryHandle::Unload() { #ifdef US_BUILD_SHARED_LIBS if (m_Handle) { #ifdef US_PLATFORM_POSIX dlclose(m_Handle); #else FreeLibrary((HMODULE)m_Handle); #endif m_Handle = 0; } #endif } std::string SharedLibraryHandle::GetAbsolutePath(const std::string& name) { return GetLibraryPath() + "/" + Prefix() + name + Suffix(); } std::string SharedLibraryHandle::GetAbsolutePath() { return GetLibraryPath() + "/" + Prefix() + m_Name + Suffix(); } std::string SharedLibraryHandle::GetLibraryPath() { #ifdef US_PLATFORM_WINDOWS return std::string(US_RUNTIME_OUTPUT_DIRECTORY); #else return std::string(US_LIBRARY_OUTPUT_DIRECTORY); #endif } std::string SharedLibraryHandle::Suffix() { #ifdef US_PLATFORM_WINDOWS return ".dll"; #elif defined(US_PLATFORM_APPLE) return ".dylib"; #else return ".so"; #endif } std::string SharedLibraryHandle::Prefix() { #if defined(US_PLATFORM_POSIX) return "lib"; #else return ""; #endif } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/tools/CMakeLists.txt b/Core/Code/CppMicroServices/tools/CMakeLists.txt index daa64f269d..066a9f5207 100644 --- a/Core/Code/CppMicroServices/tools/CMakeLists.txt +++ b/Core/Code/CppMicroServices/tools/CMakeLists.txt @@ -1,6 +1,14 @@ include_directories(${US_INCLUDE_DIRS}) add_definitions(-DUS_RCC_EXECUTABLE_NAME=\"${US_RCC_EXECUTABLE_NAME}\") -add_executable(${US_RCC_EXECUTABLE_NAME} usResourceCompiler.cpp) +set(srcs usResourceCompiler.cpp) +if(US_ENABLE_RESOURCE_COMPRESSION) + list(APPEND srcs usResourceCompressor.c) +endif() + +add_executable(${US_RCC_EXECUTABLE_NAME} ${srcs}) +if(WIN32) + target_link_libraries(${US_RCC_EXECUTABLE_NAME} Shlwapi) +endif() diff --git a/Core/Code/CppMicroServices/tools/miniz.c b/Core/Code/CppMicroServices/tools/miniz.c new file mode 100644 index 0000000000..39a1752410 --- /dev/null +++ b/Core/Code/CppMicroServices/tools/miniz.c @@ -0,0 +1,4766 @@ +/* miniz.c v1.14 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated May 20, 2012 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Change History + 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). + 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. + Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. + Eliminated a bunch of warnings when compiling with GCC 32-bit/64. + Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly + "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). + Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. + Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. + Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. + Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) + Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). + 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. + level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. + 5/28/11 v1.11 - Added statement from unlicense.org + 5/27/11 v1.10 - Substantial compressor optimizations: + Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a + Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). + Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. + Refactored the compression code for better readability and maintainability. + Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large + drop in throughput on some files). + 5/15/11 v1.09 - Initial stable release. + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 +*/ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +#include + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +// Defines to completely disable specific portions of miniz.c: +// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. + +// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. +//#define MINIZ_NO_STDIO + +// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or +// get/set file times. +//#define MINIZ_NO_TIME + +// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. +//#define MINIZ_NO_ARCHIVE_APIS + +// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. +//#define MINIZ_NO_ARCHIVE_WRITING_APIS + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. +//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc +// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user +// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. +//#define MINIZ_NO_MALLOC + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API Definitions. + +// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! +typedef unsigned long mz_ulong; + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +#define MZ_ADLER32_INIT (1) +// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +// Compression strategies. +enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; + +// Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + +#define MZ_VERSION "9.1.14" +#define MZ_VERNUM 0x91E0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 14 +#define MZ_VER_SUBREVISION 0 + +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). +enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; + +// Return status codes. MZ_PARAM_ERROR is non-standard. +enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; + +// Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +// Compression/decompression stream struct. +typedef struct mz_stream_s +{ + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used +} mz_stream; + +typedef mz_stream *mz_streamp; + +// Returns the version string of miniz.c. +const char *mz_version(void); + +// mz_deflateInit() initializes a compressor with default options: +// Parameters: +// pStream must point to an initialized mz_stream struct. +// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. +// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. +// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if the input parameters are bogus. +// MZ_MEM_ERROR on out of memory. +int mz_deflateInit(mz_streamp pStream, int level); + +// mz_deflateInit2() is like mz_deflate(), except with more control: +// Additional parameters: +// method must be MZ_DEFLATED +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) +// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +int mz_deflateReset(mz_streamp pStream); + +// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. +// Return values: +// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). +// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) +int mz_deflate(mz_streamp pStream, int flush); + +// mz_deflateEnd() deinitializes a compressor: +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +int mz_deflateEnd(mz_streamp pStream); + +// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +// Single-call compression functions mz_compress() and mz_compress2(): +// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). +mz_ulong mz_compressBound(mz_ulong source_len); + +// Initializes a decompressor. +int mz_inflateInit(mz_streamp pStream); + +// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. +// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). +// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. +// Return values: +// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_DATA_ERROR if the deflate stream is invalid. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again +// with more input data, or with more room in the output buffer (except when using single call decompression, described above). +int mz_inflate(mz_streamp pStream, int flush); + +// Deinitializes a decompressor. +int mz_inflateEnd(mz_streamp pStream); + +// Single-call decompression. +// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + +// Returns a string description of the specified error code, or NULL if the error code is invalid. +const char *mz_error(int err); + +// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + typedef unsigned char Byte; + typedef unsigned int uInt; + typedef mz_ulong uLong; + typedef Byte Bytef; + typedef uInt uIntf; + typedef char charf; + typedef int intf; + typedef void *voidpf; + typedef uLong uLongf; + typedef void *voidp; + typedef void *const voidpc; + #define Z_NULL 0 + #define Z_NO_FLUSH MZ_NO_FLUSH + #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH + #define Z_SYNC_FLUSH MZ_SYNC_FLUSH + #define Z_FULL_FLUSH MZ_FULL_FLUSH + #define Z_FINISH MZ_FINISH + #define Z_BLOCK MZ_BLOCK + #define Z_OK MZ_OK + #define Z_STREAM_END MZ_STREAM_END + #define Z_NEED_DICT MZ_NEED_DICT + #define Z_ERRNO MZ_ERRNO + #define Z_STREAM_ERROR MZ_STREAM_ERROR + #define Z_DATA_ERROR MZ_DATA_ERROR + #define Z_MEM_ERROR MZ_MEM_ERROR + #define Z_BUF_ERROR MZ_BUF_ERROR + #define Z_VERSION_ERROR MZ_VERSION_ERROR + #define Z_PARAM_ERROR MZ_PARAM_ERROR + #define Z_NO_COMPRESSION MZ_NO_COMPRESSION + #define Z_BEST_SPEED MZ_BEST_SPEED + #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION + #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION + #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY + #define Z_FILTERED MZ_FILTERED + #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY + #define Z_RLE MZ_RLE + #define Z_FIXED MZ_FIXED + #define Z_DEFLATED MZ_DEFLATED + #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS + #define alloc_func mz_alloc_func + #define free_func mz_free_func + #define internal_state mz_internal_state + #define z_stream mz_stream + #define deflateInit mz_deflateInit + #define deflateInit2 mz_deflateInit2 + #define deflateReset mz_deflateReset + #define deflate mz_deflate + #define deflateEnd mz_deflateEnd + #define deflateBound mz_deflateBound + #define compress mz_compress + #define compress2 mz_compress2 + #define compressBound mz_compressBound + #define inflateInit mz_inflateInit + #define inflateInit2 mz_inflateInit2 + #define inflate mz_inflate + #define inflateEnd mz_inflateEnd + #define uncompress mz_uncompress + #define crc32 mz_crc32 + #define adler32 mz_adler32 + #define MAX_WBITS 15 + #define MAX_MEM_LEVEL 9 + #define zError mz_error + #define ZLIB_VERSION MZ_VERSION + #define ZLIB_VERNUM MZ_VERNUM + #define ZLIB_VER_MAJOR MZ_VER_MAJOR + #define ZLIB_VER_MINOR MZ_VER_MINOR + #define ZLIB_VER_REVISION MZ_VER_REVISION + #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION + #define zlibVersion mz_version + #define zlib_version mz_version() +#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Types and macros + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +// Works around MSVC's spammy "warning C4127: conditional expression is constant" message. +#ifdef _MSC_VER + #define MZ_MACRO_END while (0, 0) +#else + #define MZ_MACRO_END while (0) +#endif + +// ------------------- ZIP archive reading/writing + +#ifndef MINIZ_NO_ARCHIVE_APIS + +enum +{ + MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 +}; + +typedef struct +{ + mz_uint32 m_file_index; + mz_uint32 m_central_dir_ofs; + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; +#ifndef MINIZ_NO_TIME + time_t m_time; +#endif + mz_uint32 m_crc32; + mz_uint64 m_comp_size; + mz_uint64 m_uncomp_size; + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + mz_uint64 m_local_header_ofs; + mz_uint32 m_comment_size; + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum +{ + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef struct +{ + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; + + mz_uint m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef enum +{ + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 +} mz_zip_flags; + +// ZIP archive reading + +// Inits a ZIP archive reader. +// These functions read and validate the archive's central directory. +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +#endif + +// Returns the total number of files in the archive. +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +// Returns detailed information about an archive file entry. +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +// Determines if an archive file entry is a directory entry. +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +// Retrieves the filename of an archive file entry. +// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +// Attempts to locates a file in the archive's central directory. +// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH +// Returns -1 if the file cannot be found. +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + +// Extracts a archive file to a memory buffer using no memory allocation. +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +// Extracts a archive file to a memory buffer. +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +// Extracts a archive file to a dynamically allocated heap buffer. +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +// Extracts a archive file using a callback function to output the file's data. +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +// Extracts a archive file to a disk file and sets its last accessed and modified times. +// This function only extracts files, not archive directory records. +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); +#endif + +// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. +mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +// ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +// Inits a ZIP archive writer. +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +#endif + +// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. +// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. +// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). +// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. +// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before +// the archive is finalized the file's central directory will be hosed. +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); + +// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. +// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +#ifndef MINIZ_NO_STDIO +// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +#endif + +// Adds a file to an archive by fully cloning the data from another archive. +// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); + +// Finalizes the archive by writing the central directory records followed by the end of central directory record. +// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). +// An archive must be manually finalized by calling this function for it to be valid. +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); + +// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. +// Note for the archive to be valid, it must have been finalized before ending. +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +// Misc. high-level helper functions: + +// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +// Reads a single file from an archive into a heap block. +// Returns NULL on failure. +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +// ------------------- Low-level Decompression API Definitions + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum +{ + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum +{ + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS + #define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +// ------------------- Low-level Compression API Definitions + +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + +// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): +// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). +enum +{ + TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. +// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. +// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). +// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) +// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. +// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +// High level compression functions: +// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of source block to compress. +// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. +// Returns 0 on failure. +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// Compresses an image to a compressed PNG file in memory. +// On entry: +// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pLen_out will be set to the size of the PNG image file. +// The caller must free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); + +// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; + +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY +enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#else +enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#endif + +// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. +typedef enum +{ + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1, +} tdefl_status; + +// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums +typedef enum +{ + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +// tdefl's compression state structure. +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +// Initializes the compressor. +// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. +// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. +// If pBut_buf_func is NULL the user should always call the tdefl_compress() API. +// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. +// tdefl_compress_buffer() always consumes the entire input buffer. +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. +#ifndef MINIZ_NO_ZLIB_APIS +// Create tdefl_compress() flags given zlib-style compression parameters. +// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) +// window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); +#endif // #ifndef MINIZ_NO_ZLIB_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; + +#include +#include + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC + #define MZ_MALLOC(x) NULL + #define MZ_FREE(x) (void)x, ((void)0) + #define MZ_REALLOC(p, x) NULL +#else + #define MZ_MALLOC(x) malloc(x) + #define MZ_FREE(x) free(x) + #define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) + #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else + #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) + #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#ifdef _MSC_VER + #define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define MZ_FORCEINLINE __attribute__((__always_inline__)) +#else + #define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +// ------------------- zlib-style API's + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + return (s2 << 16) + s1; +} + +// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +{ + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) return MZ_CRC32_INIT; + crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } + return ~crcu32; +} + +#ifndef MINIZ_NO_ZLIB_APIS + +static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } +static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } +static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } + +const char *mz_version(void) +{ + return MZ_VERSION; +} + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; + for ( ; ; ) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +{ + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) +{ + return mz_deflateBound(NULL, source_len); +} + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state* pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + + pState = (inflate_state*)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for ( ; ; ) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. + else if (flush == MZ_FINISH) + { + // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) +{ + static struct { int m_err; const char *m_pDesc; } s_error_descs[] = + { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, + { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif //MINIZ_NO_ZLIB_APIS + +// ------------------- Low-level Decompression (completely independent from all compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for ( ; ; ) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a +// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ + } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read +// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully +// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ + int temp; mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ + } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; + static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + + num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; + r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; + cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) + { + mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) + { + mz_uint8 *pSrc; + for ( ; ; ) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } +#else + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + bit_buf >>= code_len; num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +// ------------------- Low-level Compression (independent from all decompression API's) + +// Purposely making these tables static for faster init and thread safety. +static const mz_uint16 s_tdefl_len_sym[256] = { + 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, + 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, + 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, + 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, + 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, + 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, + 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, + 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; + +static const mz_uint8 s_tdefl_len_extra[256] = { + 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7 }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, + 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; + +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. +typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; +static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32* pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } + for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } + } + return pCur_syms; +} + +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } + A[0].m_key += A[1].m_key; root = 0; leaf = 2; + for (next=1; next < n-1; next++) + { + if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; + avbl = 1; used = dpth = 0; root = n-2; next = n-1; + while (avbl>0) + { + while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } + while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } + avbl = 2*used; dpth++; used = 0; + } +} + +// Limits canonical Huffman code table's max code size. +enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; mz_uint32 total = 0; if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) do { \ + mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ +} MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ +} rle_repeat_count = 0; } } + +#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ +} rle_z_count = 0; } } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) *p++ = 8; + for ( ; i <= 255; ++i) *p++ = 9; + for ( ; i <= 279; ++i) *p++ = 7; + for ( ; i <= 287; ++i) *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64*)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. + if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) + { + mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } + } + else + { + mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + if (!probe_len) + { + *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; + if (probe_len > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; + c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; + + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + // Simple lazy/greedy parsing state machine. + len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output buffer. + if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) + { + int n; + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +{ + MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; + d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +{ + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; + pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); return succeeded; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +{ + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; + do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); + pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; + p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; + } + memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; + *pOut_len = out_buf.m_size; return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) return 0; + out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; + return out_buf.m_size; +} + +#ifndef MINIZ_NO_ZLIB_APIS +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} +#endif //MINIZ_NO_ZLIB_APIS + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) +#endif + +// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at +// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +{ + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; + if (!pComp) return NULL; + MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } + // write dummy header + for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + // compress image data + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + y * bpl, bpl, TDEFL_NO_FLUSH); } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + // write real header + *pLen_out = out_buf.m_size-41; + { + mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,"\0\0\04\02\06"[num_chans],0,0,0,0,0,0,0, + (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; + c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; +} + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +// ------------------- .ZIP archive reading + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef MINIZ_NO_STDIO + #define MZ_FILE void * +#else + #include + #include + #if defined(_MSC_VER) || defined(__MINGW64__) + #include + #define MZ_FILE FILE + #define MZ_FOPEN fopen + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 _ftelli64 + #define MZ_FSEEK64 _fseeki64 + #define MZ_FILE_STAT_STRUCT _stat + #define MZ_FILE_STAT _stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN freopen + #define MZ_DELETE_FILE remove + #elif defined(__MINGW32__) + #include + #define MZ_FILE FILE + #define MZ_FOPEN fopen + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 ftello64 + #define MZ_FSEEK64 fseeko64 + #define MZ_FILE_STAT_STRUCT _stat + #define MZ_FILE_STAT _stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN freopen + #define MZ_DELETE_FILE remove + #else + #include + #define MZ_FILE FILE + #define MZ_FOPEN fopen + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 ftello + #define MZ_FSEEK64 fseeko + #define MZ_FILE_STAT_STRUCT stat + #define MZ_FILE_STAT stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN freopen + #define MZ_DELETE_FILE remove + #endif // #ifdef _MSC_VER +#endif // #ifdef MINIZ_NO_STDIO + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +// Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. +enum +{ + // ZIP archive identifiers and record sizes + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + // Central directory header record offsets + MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + // Local directory header offsets + MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + // End of central directory offsets + MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, +}; + +typedef struct +{ + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag +{ + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + MZ_FILE *m_pFile; + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +{ + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +{ + void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; + if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; + pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +{ + if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +{ + if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +{ + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +{ + size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; + memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ + struct tm *tm = localtime(&time); + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif + +#ifndef MINIZ_NO_STDIO +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef MINIZ_NO_TIME + (void)pFilename; *pDOS_date = *pDOS_time = 0; +#else + struct MZ_FILE_STAT_STRUCT file_stat; if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); +#endif // #ifdef MINIZ_NO_TIME + return MZ_TRUE; +} + +static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) +{ +#ifndef MINIZ_NO_TIME + struct utimbuf t; t.actime = access_time; t.modtime = modified_time; + return !utime(pFilename, &t); +#else + pFilename, access_time, modified_time; + return MZ_TRUE; +#endif // #ifndef MINIZ_NO_TIME +} +#endif + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) +{ + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END + +// Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) +static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + int start = (size - 2) >> 1, end; + while (start >= 0) + { + int child, root = start; + for ( ; ; ) + { + if ((child = (root << 1) + 1) >= size) + break; + child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; + } + start--; + } + + end = size - 1; + while (end > 0) + { + int child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for ( ; ; ) + { + if ((child = (root << 1) + 1) >= end) + break; + child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) +{ + mz_uint cdir_size, num_this_disk, cdir_disk_index; + mz_uint64 cdir_ofs; + mz_int64 cur_file_ofs; + const mz_uint8 *p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + // Find the end of central directory record by scanning the file from the end towards the beginning. + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for ( ; ; ) + { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + for (i = n - 4; i >= 0; --i) + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) + break; + if (i >= 0) + { + cur_file_ofs += i; + break; + } + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return MZ_FALSE; + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + // Read and verify the end of central directory record. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) + return MZ_FALSE; + + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + return MZ_FALSE; + + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return MZ_FALSE; + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) + { + mz_uint i, n; + // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + return MZ_FALSE; + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + return MZ_FALSE; + + // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) + { + mz_uint total_header_size, comp_size, decomp_size, disk_index; + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return MZ_FALSE; + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) + return MZ_FALSE; + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index != num_this_disk) && (disk_index != 1)) + return MZ_FALSE; + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return MZ_FALSE; + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + return MZ_FALSE; + n -= total_header_size; p += total_header_size; + } + } + + if ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) +{ + if ((!pZip) || (!pZip->m_pRead)) + return MZ_FALSE; + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + pZip->m_archive_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) +{ + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pMem = (void *)pMem; + pZip->m_pState->m_mem_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +{ + mz_uint64 file_size; + MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) + return MZ_FALSE; + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + return MZ_FALSE; + file_size = MZ_FTELL64(pFile); + if (!mz_zip_reader_init_internal(pZip, flags)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_total_files : 0; +} + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +{ + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + return MZ_FALSE; + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & 1); +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint filename_len, internal_attr, external_attr; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + return MZ_FALSE; + + internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((!internal_attr) && ((external_attr & 0x10) != 0)) + return MZ_TRUE; + + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) + { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + return MZ_FALSE; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if ((!p) || (!pStat)) + return MZ_FALSE; + + // Unpack the central directory record. + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + // Copy as much of the filename and comment as possible. + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; + + return MZ_TRUE; +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) + { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +{ + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) + return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) + return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + int l = 0, h = size - 1; + while (l <= h) + { + int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) + return file_index; + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + return -1; +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +{ + mz_uint file_index; size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return -1; + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_p)) + return mz_zip_reader_locate_file_binary_search(pZip, pName); + name_len = strlen(pName); if (name_len > 0xFFFF) return -1; + comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; + for (file_index = 0; file_index < pZip->m_total_files; file_index++) + { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) + continue; + if (comment_len) + { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) + { + int ofs = filename_len - 1; + do + { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) + return file_index; + } + return -1; +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((buf_size) && (!pBuf)) + return MZ_FALSE; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if (!file_stat.m_comp_size) + return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) + return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Ensure supplied output buffer is large enough. + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + return MZ_FALSE; + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + } + + // Decompress the file either directly from memory or from a file input buffer. + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) + { + // Read directly from the archive in memory. + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else if (pUser_read_buf) + { + // Use a user provided read buffer. + if (!user_read_buf_size) + return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_uncomp_size; + } + else + { + // Temporarily allocate a read buffer. + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#endif + return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do + { + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) + { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +{ + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + void *pBuf; + + if (pSize) + *pSize = 0; + if (!p) + return NULL; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#endif + return NULL; + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + return NULL; + + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + { + if (pSize) *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; void *pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if (!file_stat.m_comp_size) + return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) + return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + // Decompress the file either directly from memory or from a file input buffer. + if (pZip->m_pState->m_pMem) + { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pState->m_pMem) + { +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) +#endif + return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + status = TINFL_STATUS_FAILED; + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + while (comp_remaining) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } + else + { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + status = TINFL_STATUS_FAILED; + else + { + do + { + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) + { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) + { + status = TINFL_STATUS_FAILED; + break; + } + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) + { + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if (!pZip->m_pState->m_pMem) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + if (pWrite_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +{ + (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +{ + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) + return MZ_FALSE; + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + if (MZ_FCLOSE(pFile) == EOF) + return MZ_FALSE; +#ifndef MINIZ_NO_TIME + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + return status; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + + if (pZip->m_pState) + { + mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} +#endif + +// ------------------- .ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } +static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +{ + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (pZip->m_file_offset_alignment) + { + // Ensure user specified file offset alignment is a power of 2. + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return MZ_FALSE; + } + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; +} + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); +#ifdef _MSC_VER + if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#else + if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#endif + return 0; + if (new_size > pState->m_mem_capacity) + { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + return 0; + pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +{ + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) + return MZ_FALSE; + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) + { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +{ + MZ_FILE *pFile; + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) + return MZ_FALSE; + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_pFile = pFile; + if (size_to_reserve_at_beginning) + { + mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); + do + { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + cur_ofs += n; size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +{ + mz_zip_internal_state *pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + // No sense in trying to write to an archive that's already at the support max size + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if (pState->m_pFile) + { +#ifdef MINIZ_NO_STDIO + pFilename; return MZ_FALSE; +#else + // Archive is being read from stdio - try to reopen as writable. + if (pZip->m_pIO_opaque != pZip) + return MZ_FALSE; + if (!pFilename) + return MZ_FALSE; + pZip->m_pWrite = mz_zip_file_write_func; + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. + mz_zip_reader_end(pZip); + return MZ_FALSE; + } +#endif // #ifdef MINIZ_NO_STDIO + } + else if (pState->m_pMem) + { + // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. + if (pZip->m_pIO_opaque != pZip) + return MZ_FALSE; + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + } + // Archive is being read via a user provided read function - make sure the user has specified a write function too. + else if (!pZip->m_pWrite) + return MZ_FALSE; + + // Start writing new files at the archive's current central directory location. + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_central_directory_file_ofs = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +{ + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +} + +typedef struct +{ + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) +{ + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + return MZ_FALSE; + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + // No zip64 support yet + if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) + return MZ_FALSE; + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) + { + // Try to push the central directory array back into its original state. + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +{ + // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. + if (*pArchive_name == '/') + return MZ_FALSE; + while (*pArchive_name) + { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) + return MZ_FALSE; + pArchive_name++; + } + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +{ + mz_uint32 n; + if (!pZip->m_file_offset_alignment) + return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +{ + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) + { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return MZ_FALSE; + cur_file_ofs += s; n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +{ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return MZ_FALSE; + // No zip64 support yet + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + +#ifndef MINIZ_NO_TIME + { + time_t cur_time; time(&cur_time); + mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif // #ifndef MINIZ_NO_TIME + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) + return MZ_FALSE; + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) + { + // Set DOS Subdirectory attribute bit. + ext_attributes |= 0x10; + // Subdirectories cannot contain data. + if ((buf_size) || (uncomp_size)) + return MZ_FALSE; + } + + // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return MZ_FALSE; + + if ((!store_data_uncompressed) && (buf_size)) + { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return MZ_FALSE; + } + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) + { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + if (store_data_uncompressed) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + method = MZ_DEFLATED; + } + else if (buf_size) + { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + MZ_FILE *pSrc_file = NULL; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) + return MZ_FALSE; + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return MZ_FALSE; + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + if (uncomp_size > 0xFFFFFFFF) + { + // No zip64 support yet + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (uncomp_size <= 3) + level = 0; + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) + return MZ_FALSE; + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (uncomp_size) + { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + if (!level) + { + while (uncomp_remaining) + { + mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } + else + { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + for ( ; ; ) + { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) + break; + + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + + status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) + { + result = MZ_TRUE; + break; + } + else if (status != TDEFL_STATUS_OKAY) + break; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + MZ_FCLOSE(pSrc_file); pSrc_file = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) +{ + mz_uint n, bit_flags, num_alignment_padding_bytes; + mz_uint64 comp_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; const mz_uint8 *pSrc_central_header; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) + return MZ_FALSE; + pState = pZip->m_pState; + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + return MZ_FALSE; + cur_dst_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) + return MZ_FALSE; + + while (comp_bytes_remaining) + { + n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_dst_file_ofs += n; + + comp_bytes_remaining -= n; + } + + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) + { + // Copy data descriptor + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + // no zip64 support yet + if (cur_dst_file_ofs > 0xFFFFFFFF) + return MZ_FALSE; + + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; + + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + if (pState->m_central_dir.m_size > 0xFFFFFFFF) + return MZ_FALSE; + n = (mz_uint32)pState->m_central_dir.m_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + + pState = pZip->m_pState; + + // no zip64 support yet + if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) + { + // Write central directory + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) + return MZ_FALSE; + pZip->m_archive_size += central_dir_size; + } + + // Write end of central directory record + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) + return MZ_FALSE; +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) + return MZ_FALSE; +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_archive_size += sizeof(hdr); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) +{ + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) + return MZ_FALSE; + if (pZip->m_pWrite != mz_zip_heap_write_func) + return MZ_FALSE; + if (!mz_zip_writer_finalize_archive(pZip)) + return MZ_FALSE; + + *pBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + return MZ_FALSE; + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + MZ_CLEAR_OBJ(zip_archive); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) + { + // Create a new archive. + if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) + return MZ_FALSE; + created_new_archive = MZ_TRUE; + } + else + { + // Append to an existing archive. + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return MZ_FALSE; + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) + { + mz_zip_reader_end(&zip_archive); + return MZ_FALSE; + } + } + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) + if (!mz_zip_writer_finalize_archive(&zip_archive)) + status = MZ_FALSE; + if (!mz_zip_writer_end(&zip_archive)) + status = MZ_FALSE; + if ((!status) && (created_new_archive)) + { + // It's a new archive and something went wrong, so just delete it. + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + return status; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +{ + int file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) + *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) + return NULL; + + MZ_CLEAR_OBJ(zip_archive); + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return NULL; + + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + + mz_zip_reader_end(&zip_archive); + return p; +} + +#endif // #ifndef MINIZ_NO_STDIO + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ diff --git a/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp b/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp index 391a7adb86..443cd9c46f 100644 --- a/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp +++ b/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp @@ -1,668 +1,827 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usConfig.h" #include #include #include #include #include +#include #include #include #include #include #include "stdint_p.h" #include "usConfig.h" +#ifdef US_ENABLE_RESOURCE_COMPRESSION +extern "C" { +const char* us_resource_compressor_error(); +unsigned char* us_resource_compressor(FILE*, long, int level, long* out_size); +} +#endif // US_ENABLE_RESOURCE_COMPRESSION + #ifdef US_PLATFORM_WINDOWS static const char DIR_SEP = '\\'; #else static const char DIR_SEP = '/'; #endif class ResourceWriter; class Resource { public: enum Flags { NoFlags = 0x00, - Directory = 0x01 + Directory = 0x01, + Compressed = 0x02 }; Resource(const std::string& name, const std::string& path = std::string(), unsigned int flags = NoFlags); ~Resource(); std::string GetResourcePath() const; int64_t WriteName(ResourceWriter& writer, int64_t offset); void WriteTreeInfo(ResourceWriter& writer); int64_t WritePayload(ResourceWriter& writer, int64_t offset, std::string* errorMessage); std::string name; std::string path; unsigned int flags; Resource* parent; std::map children; std::map sortedChildren; int64_t nameOffset; int64_t dataOffset; int64_t childOffset; }; class ResourceWriter { public: - ResourceWriter(const std::string& fileName, const std::string& libName); + ResourceWriter(const std::string& fileName, const std::string& libName, + int compressionLevel, int compressionThreshold); ~ResourceWriter(); bool AddFiles(const std::vector& files, const std::string& basePath); bool Write(); private: friend class Resource; bool AddFile(const std::string& alias, const Resource& file); bool WriteHeader(); bool WritePayloads(); bool WriteNames(); bool WriteDataTree(); bool WriteRegistrationCode(); void WriteString(const std::string& str); void WriteChar(char c); void WriteHex(uint8_t tmp); void WriteNumber2(uint16_t number); void WriteNumber4(uint32_t number); std::ofstream out; std::vector files; std::string libName; std::string fileName; + int compressionLevel; + int compressionThreshold; + Resource* root; }; Resource::Resource(const std::string& name, const std::string& path, unsigned int flags) : name(name) , path(path) , flags(flags) , parent(NULL) , nameOffset(0) , dataOffset(0) , childOffset(0) { } Resource::~Resource() { for (std::map::iterator i = children.begin(); i != children.end(); ++i) { delete i->second; } } std::string Resource::GetResourcePath() const { std::string resource = name; for (Resource* p = parent; p; p = p->parent) { resource = resource.insert(0, p->name + '/'); } return resource; } int64_t Resource::WriteName(ResourceWriter& writer, int64_t offset) { // capture the offset nameOffset = offset; // write the resource name as a comment writer.WriteString(" // "); writer.WriteString(name); writer.WriteString("\n "); // write the length of the name writer.WriteNumber2(static_cast(name.size())); writer.WriteString("\n "); offset += 2; // write the hash value writer.WriteNumber4(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, name))); writer.WriteString("\n "); offset += 4; // write the name itself for (std::size_t i = 0; i < name.length(); ++i) { writer.WriteHex(name[i]); if (i != 0 && i % 32 == 0) writer.WriteString("\n "); } offset += name.length(); // done writer.WriteString("\n "); return offset; } void Resource::WriteTreeInfo(ResourceWriter& writer) { // write the resource path as a comment writer.WriteString(" // "); writer.WriteString(GetResourcePath()); writer.WriteString("\n "); if (flags & Directory) { // name offset (in the us_resource_name array) writer.WriteNumber4(static_cast(nameOffset)); // flags writer.WriteNumber2(flags); // child count writer.WriteNumber4(static_cast(children.size())); // first child offset (in the us_resource_tree array) writer.WriteNumber4(static_cast(childOffset)); } else { // name offset writer.WriteNumber4(static_cast(nameOffset)); // flags writer.WriteNumber2(flags); // padding (not used) writer.WriteNumber4(0); // data offset writer.WriteNumber4(static_cast(dataOffset)); } writer.WriteChar('\n'); } int64_t Resource::WritePayload(ResourceWriter& writer, int64_t offset, std::string* errorMessage) { // capture the offset dataOffset = offset; // open the resource file on the file system - std::ifstream file(path.c_str(), std::ifstream::in | std::ifstream::binary); + FILE* file = fopen(path.c_str(), "rb"); if (!file) { *errorMessage = "File could not be opened: " + path; return 0; } + // get the file size + fseek(file, 0, SEEK_END); + const long fileSize = ftell(file); + fseek(file, 0, SEEK_SET); + + unsigned char* fileBuffer = NULL; + long fileBufferSize = 0; + +#ifdef US_ENABLE_RESOURCE_COMPRESSION + // try compression + if (writer.compressionLevel != 0 && fileSize != 0) + { + long compressedSize = 0; + unsigned char* compressedBuffer = us_resource_compressor(file, fileSize, writer.compressionLevel, &compressedSize); + if (compressedBuffer == NULL) + { + *errorMessage = us_resource_compressor_error(); + return 0; + } + + int compressRatio = static_cast((100.0 * (fileSize - compressedSize)) / fileSize); + if (compressRatio >= writer.compressionThreshold) + { + fileBuffer = compressedBuffer; + fileBufferSize = compressedSize; + flags |= Compressed; + } + else + { + free(compressedBuffer); + } + } + + if (!(flags & Compressed)) +#endif // US_ENABLE_RESOURCE_COMPRESSION + { + fileBuffer = static_cast(malloc(sizeof(unsigned char)*fileSize)); + if (fileBuffer == NULL) + { + *errorMessage = "Could not allocate memory buffer for resource file " + path; + return 0; + } + if (fseek(file, 0, SEEK_SET) != 0) + { + free(fileBuffer); + *errorMessage = "Could not set stream position for resource file " + path; + return 0; + } + if (fread(fileBuffer, 1, fileSize, file) != static_cast(fileSize)) + { + free(fileBuffer); + *errorMessage = "Error reading resource file " + path; + return 0; + } + fileBufferSize = fileSize; + } + + if (fclose(file)) + { + *errorMessage = "Error closing resource file " + path; + free(fileBuffer); + return 0; + } + // write the full path of the resource in the file system as a comment writer.WriteString(" // "); writer.WriteString(path); writer.WriteString("\n "); // write the length - file.seekg(0, std::ifstream::end); - std::ifstream::pos_type size = file.tellg(); - file.seekg(0); - writer.WriteNumber4(static_cast(size)); + writer.WriteNumber4(static_cast(fileBufferSize)); writer.WriteString("\n "); offset += 4; // write the actual payload int charsLeft = 16; - char c = 0; - while (file.get(c)) + for (long i = 0; i < fileBufferSize; ++i) { --charsLeft; - writer.WriteHex(static_cast(c)); + writer.WriteHex(static_cast(fileBuffer[i])); if (charsLeft == 0) { writer.WriteString("\n "); charsLeft = 16; } } - offset += size; + offset += fileBufferSize; + + free(fileBuffer); // done writer.WriteString("\n "); return offset; } -ResourceWriter::ResourceWriter(const std::string& fileName, const std::string& libName) +ResourceWriter::ResourceWriter(const std::string& fileName, const std::string& libName, + int compressionLevel, int compressionThreshold) : libName(libName) , fileName(fileName) + , compressionLevel(compressionLevel) + , compressionThreshold(compressionThreshold) , root(NULL) { out.exceptions(std::ofstream::goodbit); out.open(fileName.c_str()); } ResourceWriter::~ResourceWriter() { delete root; } bool ResourceWriter::AddFiles(const std::vector& files, const std::string& basePath) { bool success = true; for (std::size_t i = 0; i < files.size(); ++i) { const std::string& file = files[i]; if (file.size() <= basePath.size() || file.substr(0, basePath.size()) != basePath) { std::cerr << "File " << file << " is not an absolute path starting with " << basePath << std::endl; success = false; } else { const std::string relativePath = file.substr(basePath.size()); std::string name = relativePath; std::size_t index = relativePath.find_last_of(DIR_SEP); if (index != std::string::npos) { name = relativePath.substr(index+1); } success &= AddFile(relativePath, Resource(name, file)); } } return success; } bool ResourceWriter::Write() { if (!WriteHeader()) { std::cerr << "Could not write header." << std::endl; return false; } if (!WritePayloads()) { std::cerr << "Could not write data blobs." << std::endl; return false; } if (!WriteNames()) { std::cerr << "Could not write file names." << std::endl; return false; } if (!WriteDataTree()) { std::cerr << "Could not write data tree." << std::endl; return false; } if (!WriteRegistrationCode()) { std::cerr << "Could not write footer" << std::endl; return false; } return true; } bool ResourceWriter::AddFile(const std::string& alias, const Resource& file) { std::ifstream in(file.path.c_str(), std::ifstream::in | std::ifstream::binary); if (!in) { std::cerr << "File could not be opened: " << file.path << std::endl; return false; } in.seekg(0, std::ifstream::end); std::ifstream::pos_type size = in.tellg(); in.close(); if (size > 0xffffffff) { std::cerr << "File too big: " << file.path << std::endl; return false; } if (!root) { root = new Resource(std::string(), std::string(), Resource::Directory); } Resource* parent = root; std::stringstream ss(alias); std::vector nodes; { std::string node; while (std::getline(ss, node, DIR_SEP)) { if (node.empty()) continue; nodes.push_back(node); } } for(std::size_t i = 0; i < nodes.size()-1; ++i) { const std::string& node = nodes[i]; if (parent->children.find(node) == parent->children.end()) { Resource* s = new Resource(node, std::string(), Resource::Directory); s->parent = parent; parent->children.insert(std::make_pair(node, s)); parent->sortedChildren.insert(std::make_pair(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, node)), s)); parent = s; } else { parent = parent->children[node]; } } const std::string filename = nodes.back(); Resource* s = new Resource(file); s->parent = parent; parent->children.insert(std::make_pair(filename, s)); parent->sortedChildren.insert(std::make_pair(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, filename)), s)); return true; } bool ResourceWriter::WriteHeader() { std::stringstream ss; std::time_t now = time(0); ss << std::ctime(&now); WriteString("/*=============================================================================\n"); WriteString(" Resource object code\n"); WriteString("\n"); WriteString(" Created: "); WriteString(ss.str()); WriteString(" by: The Resource Compiler for CppMicroServices version "); WriteString(CppMicroServices_VERSION_STR); WriteString("\n\n"); WriteString(" WARNING! All changes made in this file will be lost!\n"); WriteString( "=============================================================================*/\n\n"); WriteString("#include \n"); WriteString("#include \n\n"); return true; } bool ResourceWriter::WritePayloads() { if (!root) return false; WriteString("static const unsigned char us_resource_data[] = {\n"); std::stack pending; pending.push(root); int64_t offset = 0; std::string errorMessage; while (!pending.empty()) { Resource* file = pending.top(); pending.pop(); for (std::map::iterator i = file->children.begin(); i != file->children.end(); ++i) { Resource* child = i->second; if (child->flags & Resource::Directory) { pending.push(child); } else { offset = child->WritePayload(*this, offset, &errorMessage); if (offset == 0) { std::cerr << errorMessage << std::endl; + return false; } } } } WriteString("\n};\n\n"); return true; } bool ResourceWriter::WriteNames() { if (!root) return false; WriteString("static const unsigned char us_resource_name[] = {\n"); std::map names; std::stack pending; pending.push(root); int64_t offset = 0; while (!pending.empty()) { Resource* file = pending.top(); pending.pop(); for (std::map::iterator it = file->children.begin(); it != file->children.end(); ++it) { Resource* child = it->second; if (child->flags & Resource::Directory) { pending.push(child); } if (names.find(child->name) != names.end()) { child->nameOffset = names[child->name]; } else { names.insert(std::make_pair(child->name, offset)); offset = child->WriteName(*this, offset); } } } WriteString("\n};\n\n"); return true; } bool ResourceWriter::WriteDataTree() { if (!root) return false; WriteString("static const unsigned char us_resource_tree[] = {\n"); std::stack pending; // calculate the child offsets in the us_resource_tree array pending.push(root); int offset = 1; while (!pending.empty()) { Resource* file = pending.top(); pending.pop(); file->childOffset = offset; // calculate the offset now for (std::map::iterator i = file->sortedChildren.begin(); i != file->sortedChildren.end(); ++i) { Resource* child = i->second; ++offset; if (child->flags & Resource::Directory) { pending.push(child); } } } // write the tree structure pending.push(root); root->WriteTreeInfo(*this); while (!pending.empty()) { Resource *file = pending.top(); pending.pop(); // write the actual data now for (std::map::iterator i = file->sortedChildren.begin(); i != file->sortedChildren.end(); ++i) { Resource *child = i->second; child->WriteTreeInfo(*this); if (child->flags & Resource::Directory) { pending.push(child); } } } WriteString("\n};\n\n"); return true; } bool ResourceWriter::WriteRegistrationCode() { WriteString("US_BEGIN_NAMESPACE\n\n"); WriteString("extern US_EXPORT bool RegisterResourceData(int, ModuleInfo*, ModuleInfo::ModuleResourceData, ModuleInfo::ModuleResourceData, ModuleInfo::ModuleResourceData);\n\n"); WriteString("US_END_NAMESPACE\n\n"); WriteString(std::string("extern \"C\" US_ABI_EXPORT int _us_init_resources_") + libName + "(US_PREPEND_NAMESPACE(ModuleInfo)* moduleInfo)\n"); WriteString("{\n"); WriteString(" US_PREPEND_NAMESPACE(RegisterResourceData)(0x01, moduleInfo, us_resource_tree, us_resource_name, us_resource_data);\n"); WriteString(" return 1;\n"); WriteString("}\n"); return true; } void ResourceWriter::WriteString(const std::string& str) { out << str; } void ResourceWriter::WriteChar(char c) { out << c; } void ResourceWriter::WriteHex(uint8_t tmp) { const char* const digits = "0123456789abcdef"; WriteChar('0'); WriteChar('x'); if (tmp < 16) { WriteChar(digits[tmp]); } else { WriteChar(digits[tmp >> 4]); WriteChar(digits[tmp & 0xf]); } WriteChar(','); } void ResourceWriter::WriteNumber2(uint16_t number) { WriteHex(number >> 8); WriteHex(static_cast(number)); } void ResourceWriter::WriteNumber4(uint32_t number) { WriteHex(number >> 24); WriteHex(number >> 16); WriteHex(number >> 8); WriteHex(number); } #ifdef US_PLATFORM_POSIX #include std::string GetCurrentDir() { char currDir[512]; if (!getcwd(currDir, sizeof(currDir))) { std::cerr << "Getting the current directory failed." << std::endl; exit(EXIT_FAILURE); } return std::string(currDir); } + +bool IsAbsolutePath(const std::string& path) +{ + return path.find_first_of('/') == 0; +} #else #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include +#include std::string GetCurrentDir() { TCHAR currDir[512]; DWORD dwRet; dwRet = GetCurrentDirectory(sizeof(currDir), currDir); if( dwRet == 0 || dwRet > 512) { std::cerr << "Getting the current directory failed." << std::endl; exit(EXIT_FAILURE); } return std::string(currDir); } + +bool IsAbsolutePath(const std::string& path) +{ + return !PathIsRelative(path.c_str()); +} #endif int main(int argc, char** argv) { if (argc < 4) { std::cout << US_RCC_EXECUTABLE_NAME " - A resource compiler for C++ Micro Services modules\n" "\n" - "Usage: " US_RCC_EXECUTABLE_NAME " LIBNAME OUTPUT INPUT [INPUT]...\n" - "Convert all INPUT files into hex code embedded in C funtions written to OUTPUT.\n"; + "Usage: " US_RCC_EXECUTABLE_NAME " LIBNAME OUTPUT INPUT... " + "[-c COMPRESSION_LEVEL] [-t COMPRESSION_THRESHOLD] [-d ROOT_DIR INPUT...]...\n\n" + "Convert all INPUT files into hex code written to OUTPUT.\n" + "\n" + " LIBNAME The modules library name as it is specified in the US_INITIALIZE_MODULE macro\n" + " OUTPUT Absolute path for the generated source file\n" + " INPUT Path to the resource file, relative to the current working directory or" + " the preceeding ROOT_DIR argument\n" + " -c The Zip compression level (0-9) or -1 [defaults to -1, the default level]\n" + " -t Size reduction threshold (0-100) to trigger compression [defaults to 30]\n" + " -d Absolute path to a directory containing resource files. All following INPUT" + " files must be relative to this root path\n"; exit(EXIT_SUCCESS); } std::string libName(argv[1]); std::string fileName(argv[2]); - std::vector inputFiles; + // default zlib compression level + int compressionLevel = -1; + + // use compressed data if 30% reduction or better + int compressionThreshold = 30; + std::map > inputFiles; + inputFiles.insert(std::make_pair(GetCurrentDir(), std::vector())); + + std::vector* currFiles = &inputFiles.begin()->second; + std::string currRootDir = inputFiles.begin()->first; for (int i = 3; i < argc; i++) { - inputFiles.push_back(argv[i]); + if (std::strcmp(argv[i], "-d") == 0) + { + if (i == argc-1) + { + std::cerr << "No argument after -d given." << std::endl; + exit(EXIT_FAILURE); + } + currRootDir = argv[++i]; + inputFiles.insert(std::make_pair(currRootDir, std::vector())); + currFiles = &inputFiles[currRootDir]; + } + else if(std::strcmp(argv[i], "-c") == 0) + { + if (i == argc-1) + { + std::cerr << "No argument after -c given." << std::endl; + exit(EXIT_FAILURE); + } + compressionLevel = atoi(argv[++i]); + if (compressionLevel < -1 || compressionLevel > 10) + { + compressionLevel = -1; + } + } + else if(std::strcmp(argv[i], "-t") == 0) + { + if (i == argc-1) + { + std::cerr << "No argument after -t given." << std::endl; + exit(EXIT_FAILURE); + } + compressionThreshold = atoi(argv[++i]); + } + else + { + const std::string inputFile = argv[i]; + if (IsAbsolutePath(inputFile)) + { + currFiles->push_back(inputFile); + } + else + { + currFiles->push_back(currRootDir + DIR_SEP + inputFile); + } + } } - ResourceWriter writer(fileName, libName); - if (!writer.AddFiles(inputFiles, GetCurrentDir())) + ResourceWriter writer(fileName, libName, compressionLevel, compressionThreshold); + for(std::map >::iterator i = inputFiles.begin(); + i != inputFiles.end(); ++i) { - return EXIT_FAILURE; + if (i->second.empty()) continue; + + if (!writer.AddFiles(i->second, i->first)) + { + return EXIT_FAILURE; + } } return writer.Write() ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/Core/Code/CppMicroServices/tools/usResourceCompressor.c b/Core/Code/CppMicroServices/tools/usResourceCompressor.c new file mode 100644 index 0000000000..31e0ec28d6 --- /dev/null +++ b/Core/Code/CppMicroServices/tools/usResourceCompressor.c @@ -0,0 +1,141 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + +#define MINIZ_NO_TIME +#define MINIZ_NO_ARCHIVE_APIS +#include "miniz.c" + +#include +#include + +typedef unsigned char uint8; +typedef unsigned int uint; + +#define COMPRESS_MSG_BUFFER_SIZE 1024 +static char us_compress_error[COMPRESS_MSG_BUFFER_SIZE]; + +#define my_max(a,b) (((a) > (b)) ? (a) : (b)) +#define my_min(a,b) (((a) < (b)) ? (a) : (b)) + +#define BUF_SIZE (1024 * 1024) +static uint8 s_inbuf[BUF_SIZE]; + + +const char* us_resource_compressor_error() +{ + return us_compress_error; +} + +unsigned char* us_resource_compressor(FILE* pInfile, long file_loc, int level, long* out_size) +{ + const uint infile_size = (uint)file_loc; + z_stream stream; + uint infile_remaining = infile_size; + long bytes_written = 0; + unsigned char* s_outbuf = NULL; + + memset(us_compress_error, 0, COMPRESS_MSG_BUFFER_SIZE); + + if (file_loc < 0 || file_loc > INT_MAX) + { + sprintf(us_compress_error, "Resource too large to be processed."); + return NULL; + } + + s_outbuf = (unsigned char*)malloc(sizeof(unsigned char)*(infile_size+4)); + if (s_outbuf == NULL) + { + sprintf(us_compress_error, "Failed to allocate %d bytes for compression buffer.", infile_size); + return NULL; + } + + // Init the z_stream + memset(&stream, 0, sizeof(stream)); + stream.next_in = s_inbuf; + stream.avail_in = 0; + stream.next_out = s_outbuf+4; + stream.avail_out = infile_size; + + // Compression. + if (deflateInit2(&stream, level, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY) != Z_OK) + { + sprintf(us_compress_error, "deflateInit() failed."); + free(s_outbuf); + return NULL; + } + + // Write the uncompressed file size in the first four bytes + s_outbuf[0] = (unsigned char)((file_loc & 0xff000000) >> 24); + s_outbuf[1] = (unsigned char)((file_loc & 0x00ff0000) >> 16); + s_outbuf[2] = (unsigned char)((file_loc & 0x0000ff00) >> 8); + s_outbuf[3] = (unsigned char)(file_loc & 0x000000ff); + + bytes_written = 4; + for ( ; ; ) + { + int status; + if (!stream.avail_in) + { + // Input buffer is empty, so read more bytes from input file. + uint n = my_min(BUF_SIZE, infile_remaining); + + if (fread(s_inbuf, 1, n, pInfile) != n) + { + sprintf(us_compress_error, "Failed reading from input file."); + free(s_outbuf); + return NULL; + } + + stream.next_in = s_inbuf; + stream.avail_in = n; + + infile_remaining -= n; + } + + status = deflate(&stream, infile_remaining ? Z_NO_FLUSH : Z_FINISH); + + if ((status == Z_STREAM_END) || (!stream.avail_out)) + { + // Output buffer is full, or compression is done. + bytes_written += infile_size - stream.avail_out; + break; + } + else if (status != Z_OK) + { + sprintf(us_compress_error, "deflate() failed with status %i.", status); + free(s_outbuf); + return NULL; + } + } + + if (deflateEnd(&stream) != Z_OK) + { + sprintf(us_compress_error, "deflateEnd() failed."); + free(s_outbuf); + return NULL; + } + + if (out_size != NULL) + { + *out_size = bytes_written; + } + return s_outbuf; +} diff --git a/Core/Code/CppMicroServices/usConfig.h.in b/Core/Code/CppMicroServices/usConfig.h.in index 97ab1a3d43..9489a2ccc3 100644 --- a/Core/Code/CppMicroServices/usConfig.h.in +++ b/Core/Code/CppMicroServices/usConfig.h.in @@ -1,251 +1,252 @@ /* USCONFIG.h this file is generated. Do not change! */ #ifndef USCONFIG_H #define USCONFIG_H #cmakedefine US_BUILD_SHARED_LIBS #cmakedefine CppMicroServices_EXPORTS #cmakedefine US_ENABLE_AUTOLOADING_SUPPORT #cmakedefine US_ENABLE_THREADING_SUPPORT #cmakedefine US_ENABLE_SERVICE_FACTORY_SUPPORT +#cmakedefine US_ENABLE_RESOURCE_COMPRESSION #cmakedefine US_USE_CXX11 ///------------------------------------------------------------------- // Version information //------------------------------------------------------------------- #define CppMicroServices_VERSION_MAJOR @CppMicroServices_VERSION_MAJOR@ #define CppMicroServices_VERSION_MINOR @CppMicroServices_VERSION_MINOR@ #define CppMicroServices_VERSION_PATH @CppMicroServices_VERSION_PATCH@ #define CppMicroServices_VERSION @CppMicroServices_VERSION@ #define CppMicroServices_VERSION_STR "@CppMicroServices_VERSION@" ///------------------------------------------------------------------- // Macros used by the unit tests //------------------------------------------------------------------- #define CppMicroServices_SOURCE_DIR "@CppMicroServices_SOURCE_DIR@" ///------------------------------------------------------------------- // Macros for import/export declarations //------------------------------------------------------------------- #if defined(WIN32) #define US_ABI_EXPORT __declspec(dllexport) #define US_ABI_IMPORT __declspec(dllimport) #define US_ABI_LOCAL #else #if __GNUC__ >= 4 #define US_ABI_EXPORT __attribute__ ((visibility ("default"))) #define US_ABI_IMPORT __attribute__ ((visibility ("default"))) #define US_ABI_LOCAL __attribute__ ((visibility ("hidden"))) #else #define US_ABI_EXPORT #define US_ABI_IMPORT #define US_ABI_LOCAL #endif #endif #ifdef US_BUILD_SHARED_LIBS // We are building a shared lib #ifdef CppMicroServices_EXPORTS #define US_EXPORT US_ABI_EXPORT #else #define US_EXPORT US_ABI_IMPORT #endif #else // We are building a static lib #if __GNUC__ >= 4 // Don't hide RTTI symbols of definitions in the C++ Micro Services // headers that are included in DSOs with hidden visibility #define US_EXPORT US_ABI_EXPORT #else #define US_EXPORT #endif #endif //------------------------------------------------------------------- // Namespace customization //------------------------------------------------------------------- #define US_NAMESPACE @US_NAMESPACE@ #ifndef US_NAMESPACE /* user namespace */ # define US_PREPEND_NAMESPACE(name) ::name # define US_USE_NAMESPACE # define US_BEGIN_NAMESPACE # define US_END_NAMESPACE # define US_FORWARD_DECLARE_CLASS(name) class name; # define US_FORWARD_DECLARE_STRUCT(name) struct name; #else /* user namespace */ # define US_PREPEND_NAMESPACE(name) ::US_NAMESPACE::name # define US_USE_NAMESPACE using namespace ::US_NAMESPACE; # define US_BEGIN_NAMESPACE namespace US_NAMESPACE { # define US_END_NAMESPACE } # define US_FORWARD_DECLARE_CLASS(name) \ US_BEGIN_NAMESPACE class name; US_END_NAMESPACE # define US_FORWARD_DECLARE_STRUCT(name) \ US_BEGIN_NAMESPACE struct name; US_END_NAMESPACE namespace US_NAMESPACE {} #endif /* user namespace */ #define US_BASECLASS_NAME @US_BASECLASS_NAME@ #define US_BASECLASS_HEADER <@US_BASECLASS_HEADER@> // base class forward declaration @US_BASECLASS_FORWARD_DECLARATION@ //------------------------------------------------------------------- // Platform defines //------------------------------------------------------------------- #if defined(__APPLE__) #define US_PLATFORM_APPLE #endif #if defined(__linux__) #define US_PLATFORM_LINUX #endif #if defined(_WIN32) || defined(_WIN64) #define US_PLATFORM_WINDOWS #else #define US_PLATFORM_POSIX #endif //------------------------------------------------------------------- // Macros for suppressing warnings //------------------------------------------------------------------- #ifdef _MSC_VER #define US_MSVC_PUSH_DISABLE_WARNING(wn) \ __pragma(warning(push)) \ __pragma(warning(disable:wn)) #define US_MSVC_POP_WARNING \ __pragma(warning(pop)) #define US_MSVC_DISABLE_WARNING(wn) \ __pragma(warning(disable:wn)) #else #define US_MSVC_PUSH_DISABLE_WARNING(wn) #define US_MSVC_POP_WARNING #define US_MSVC_DISABLE_WARNING(wn) #endif // Do not warn about the usage of deprecated unsafe functions US_MSVC_DISABLE_WARNING(4996) //------------------------------------------------------------------- // Debuging & Logging //------------------------------------------------------------------- #cmakedefine US_ENABLE_DEBUG_OUTPUT US_BEGIN_NAMESPACE enum MsgType { DebugMsg = 0, InfoMsg = 1, WarningMsg = 2, ErrorMsg = 3 }; typedef void (*MsgHandler)(MsgType, const char *); US_EXPORT MsgHandler installMsgHandler(MsgHandler); US_END_NAMESPACE //------------------------------------------------------------------- // Hash Container //------------------------------------------------------------------- #ifdef US_USE_CXX11 #include #include #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ struct hash : std::unary_function { \ std::size_t operator()(const type& arg) const { #define US_HASH_FUNCTION_END } }; #define US_HASH_FUNCTION(type, arg) hash()(arg) #if defined(US_PLATFORM_WINDOWS) && (_MSC_VER < 1700) #define US_HASH_FUNCTION_FRIEND(type) friend class ::std::hash #else #define US_HASH_FUNCTION_FRIEND(type) friend struct ::std::hash #endif #define US_UNORDERED_MAP_TYPE ::std::unordered_map #define US_UNORDERED_SET_TYPE ::std::unordered_set #define US_HASH_FUNCTION_NAMESPACE ::std #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { #define US_HASH_FUNCTION_NAMESPACE_END } #elif defined(__GNUC__) #include #include #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ struct hash : std::unary_function { \ std::size_t operator()(const type& arg) const { #define US_HASH_FUNCTION_END } }; #define US_HASH_FUNCTION(type, arg) hash()(arg) #define US_HASH_FUNCTION_FRIEND(type) friend struct ::std::tr1::hash #define US_UNORDERED_MAP_TYPE ::std::tr1::unordered_map #define US_UNORDERED_SET_TYPE ::std::tr1::unordered_set #define US_HASH_FUNCTION_NAMESPACE ::std::tr1 #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { namespace tr1 { #define US_HASH_FUNCTION_NAMESPACE_END }} #elif _MSC_VER <= 1500 // Visual Studio 2008 and lower #include #include #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ inline std::size_t hash_value(const type& arg) { #define US_HASH_FUNCTION_END } #define US_HASH_FUNCTION(type, arg) hash_value(arg) #define US_HASH_FUNCTION_FRIEND(type) friend std::size_t stdext::hash_value(const type&) #define US_UNORDERED_MAP_TYPE ::stdext::hash_map #define US_UNORDERED_SET_TYPE ::stdext::hash_set #define US_HASH_FUNCTION_NAMESPACE ::stdext #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace stdext { #define US_HASH_FUNCTION_NAMESPACE_END } #endif //------------------------------------------------------------------- // Threading Configuration //------------------------------------------------------------------- #ifdef US_ENABLE_THREADING_SUPPORT #define US_DEFAULT_THREADING US_PREPEND_NAMESPACE(MultiThreaded) #else #define US_DEFAULT_THREADING US_PREPEND_NAMESPACE(SingleThreaded) #endif //------------------------------------------------------------------- // Header Availability //------------------------------------------------------------------- #cmakedefine HAVE_STDINT #endif // USCONFIG_H diff --git a/Core/Code/DataManagement/mitkBaseData.h b/Core/Code/DataManagement/mitkBaseData.h index cf003d8da0..73ff102752 100644 --- a/Core/Code/DataManagement/mitkBaseData.h +++ b/Core/Code/DataManagement/mitkBaseData.h @@ -1,388 +1,388 @@ /*=================================================================== 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 BASEDATA_H_HEADER_INCLUDED_C1EBB6FA #define BASEDATA_H_HEADER_INCLUDED_C1EBB6FA #include #include "mitkBaseProcess.h" #include "mitkTimeSlicedGeometry.h" #include #include "mitkOperationActor.h" #include "mitkPropertyList.h" namespace mitk { //class BaseProcess; //##Documentation //## @brief Base of all data objects //## //## Base of all data objects, e.g., images, contours, surfaces etc. Inherits //## from itk::DataObject and thus can be included in a pipeline. //## Inherits also from OperationActor and can be used as a destination for Undo //## @ingroup Data class MITK_CORE_EXPORT BaseData : public itk::DataObject, public OperationActor { public: - mitkClassMacro(BaseData,itk::DataObject); + mitkClassMacro(BaseData,itk::DataObject) //##Documentation //## @brief Return the TimeSlicedGeometry of the data as const pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. const mitk::TimeSlicedGeometry* GetTimeSlicedGeometry() const { return m_TimeSlicedGeometry.GetPointer(); } //##Documentation //## @brief Return the TimeSlicedGeometry of the data as pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. mitk::TimeSlicedGeometry* GetTimeSlicedGeometry() { return m_TimeSlicedGeometry.GetPointer(); } //##Documentation //## @brief Return the Geometry3D of the data. //## //## The method does not simply return the value of the m_TimeSlicedGeometry //## member. Before doing this, it makes sure that the TimeSlicedGeometry //## is up-to-date (by setting the update extent to largest possible and //## calling UpdateOutputInformation). const mitk::TimeSlicedGeometry* GetUpdatedTimeSlicedGeometry(); //##Documentation //## @brief Expands the TimeSlicedGeometry to a number of TimeSteps. //## //## The method expands the TimeSlicedGeometry to the given number of TimeSteps, //## filling newly created elements with empty geometries. Sub-classes should override //## this method to handle the elongation of their data vectors, too. //## Note that a shrinking is neither possible nor intended. virtual void Expand( unsigned int timeSteps ); //##Documentation //## @brief Return the Geometry3D of the data at time \a t. //## //## The method does not simply return //## m_TimeSlicedGeometry->GetGeometry(t). //## Before doing this, it makes sure that the Geometry3D is up-to-date //## (by setting the update extent appropriately and calling //## UpdateOutputInformation). //## //## @todo Appropriate setting of the update extent is missing. const mitk::Geometry3D* GetUpdatedGeometry(int t=0); //##Documentation //## @brief Return the geometry, which is a TimeSlicedGeometry, of the data //## as non-const pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. mitk::Geometry3D* GetGeometry(int t=0) const { if(m_TimeSlicedGeometry.IsNull()) return NULL; return m_TimeSlicedGeometry->GetGeometry3D(t); } //##Documentation //## @brief Helps to deal with the weak-pointer-problem. virtual void UnRegister() const; //##Documentation //## @brief for internal use only. Helps to deal with the //## weak-pointer-problem. virtual int GetExternalReferenceCount() const; //##Documentation //## @brief Update the information for this BaseData (the geometry in particular) //## so that it can be used as an output of a BaseProcess. //## //## This method is used in the pipeline mechanism to propagate information and //## initialize the meta data associated with a BaseData. Any implementation //## of this method in a derived class is assumed to call its source's //## BaseProcess::UpdateOutputInformation() which determines modified //## times, LargestPossibleRegions, and any extra meta data like spacing, //## origin, etc. Default implementation simply call's it's source's //## UpdateOutputInformation(). //## \note Implementations of this methods in derived classes must take care //## that the geometry is updated by calling //## GetTimeSlicedGeometry()->UpdateInformation() //## \em after calling its source's BaseProcess::UpdateOutputInformation(). void UpdateOutputInformation(); //##Documentation //## @brief Set the RequestedRegion to the LargestPossibleRegion. //## //## This forces a filter to produce all of the output in one execution //## (i.e. not streaming) on the next call to Update(). void SetRequestedRegionToLargestPossibleRegion()=0; //##Documentation //## @brief Determine whether the RequestedRegion is outside of the BufferedRegion. //## //## This method returns true if the RequestedRegion //## is outside the BufferedRegion (true if at least one pixel is //## outside). This is used by the pipeline mechanism to determine //## whether a filter needs to re-execute in order to satisfy the //## current request. If the current RequestedRegion is already //## inside the BufferedRegion from the previous execution (and the //## current filter is up to date), then a given filter does not need //## to re-execute bool RequestedRegionIsOutsideOfTheBufferedRegion()=0; //##Documentation //## @brief Verify that the RequestedRegion is within the LargestPossibleRegion. //## //## If the RequestedRegion is not within the LargestPossibleRegion, //## then the filter cannot possibly satisfy the request. This method //## returns true if the request can be satisfied (even if it will be //## necessary to process the entire LargestPossibleRegion) and //## returns false otherwise. This method is used by //## PropagateRequestedRegion(). PropagateRequestedRegion() throws a //## InvalidRequestedRegionError exception if the requested region is //## not within the LargestPossibleRegion. virtual bool VerifyRequestedRegion() = 0; //##Documentation //## @brief Copy information from the specified data set. //## //## This method is part of the pipeline execution model. By default, a //## BaseProcess will copy meta-data from the first input to all of its //## outputs. See ProcessObject::GenerateOutputInformation(). Each //## subclass of DataObject is responsible for being able to copy //## whatever meta-data it needs from another DataObject. //## The default implementation of this method copies the time sliced geometry //## and the property list of an object. If a subclass overrides this //## method, it should always call its superclass' version. void CopyInformation(const itk::DataObject* data); //##Documentation //## @brief Check whether the data has been initialized, i.e., //## at least the Geometry and other header data has been set //## //## \warning Set to \a true by default for compatibility reasons. //## Set m_Initialized=false in constructors of sub-classes that //## support distinction between initialized and uninitialized state. virtual bool IsInitialized() const; //##Documentation //## @brief Calls ClearData() and InitializeEmpty(); //## \warning Only use in subclasses that reimplemented these methods. //## Just calling Clear from BaseData will reset an object to a not initialized, //## invalid state. virtual void Clear(); //##Documentation //## @brief Check whether object contains data (at //## a specified time), e.g., a set of points may be empty //## //## \warning Returns IsInitialized()==false by default for //## compatibility reasons. Override in sub-classes that //## support distinction between empty/non-empty state. virtual bool IsEmptyTimeStep(unsigned int t) const; //##Documentation //## @brief Check whether object contains data (at //## least at one point in time), e.g., a set of points //## may be empty //## //## \warning Returns IsInitialized()==false by default for //## compatibility reasons. Override in sub-classes that //## support distinction between empty/non-empty state. virtual bool IsEmpty() const; //##Documentation //## @brief Set the requested region from this data object to match the requested //## region of the data object passed in as a parameter. //## //## This method is implemented in the concrete subclasses of BaseData. void SetRequestedRegion(itk::DataObject *data)=0; //##Documentation //##@brief overwrite if the Data can be called by an Interactor (StateMachine). //## //## Empty by default. Overwrite and implement all the necessary operations here //## and get the necessary information from the parameter operation. void ExecuteOperation(Operation* operation); //##Documentation //## @brief Set the Geometry3D of the data, which will be referenced (not copied!). //## Assumes the data object has only 1 time step ( is a 3D object ). //## //## For convenience (and historic) reasons, it is also possible to set a complete //## mitk::TimeSlicedGeometry*, which will be referenced (not copied!). //## //## @warning This method will normally be called internally by the sub-class of BaseData //## during initialization. //## \sa SetClonedGeometry virtual void SetGeometry(Geometry3D* aGeometry3D); //##Documentation //## @brief Set a clone of the provided geometry as Geometry3D of the data. //## Assumes the data object has only 1 time step ( is a 3D object ) //## //## \sa SetGeometry virtual void SetClonedGeometry(const Geometry3D* aGeometry3D); //##Documentation //## @brief Set a clone of the provided geometry as Geometry3D of a given time step. //## //## \sa SetGeometry virtual void SetClonedGeometry(const Geometry3D* aGeometry3D, unsigned int time); //##Documentation //## @brief Get the data's property list //## @sa GetProperty //## @sa m_PropertyList mitk::PropertyList::Pointer GetPropertyList() const; //##Documentation //## @brief Set the data's property list //## @sa SetProperty //## @sa m_PropertyList void SetPropertyList(PropertyList* propertyList); //##Documentation //## @brief Get the property (instance of BaseProperty) with key @a propertyKey from the PropertyList, //## and set it to this, respectively; //## @sa GetPropertyList //## @sa m_PropertyList //## @sa m_MapOfPropertyLists mitk::BaseProperty::Pointer GetProperty(const char *propertyKey) const; void SetProperty(const char *propertyKey, BaseProperty* property); //##Documentation //## @brief Convenience method for setting the origin of //## the Geometry3D instances of all time steps //## //## \warning Geometries contained in the Geometry3D will //## \em not be changed, e.g. in case the Geometry3D is a //## SlicedGeometry3D the origin will \em not be propagated //## to the contained slices. The sub-class SlicedData //## does this for the case that the SlicedGeometry3D is //## evenly spaced. virtual void SetOrigin(const Point3D& origin); /** \brief Get the process object that generated this data object. * * If there is no process object, then the data object has * been disconnected from the pipeline, or the data object * was created manually. (Note: we cannot use the GetObjectMacro() * defined in itkMacro because the mutual dependency of * DataObject and ProcessObject causes compile problems. Also, * a forward reference smart pointer is returned, not a smart pointer, * because of the circular dependency between the process and data object.) * * GetSource() returns a SmartPointer and not a WeakPointer * because it is assumed the code calling GetSource() wants to hold a * long term reference to the source. */ itk::SmartPointer GetSource() const; //##Documentation //## @brief Get the number of time steps from the Timeslicedgeometry //## As the base data has not a data vector given by itself, the number //## of time steps is defined over the time sliced geometry. In sub classes, //## a better implementation could be over the length of the data vector. unsigned int GetTimeSteps() const { return m_TimeSlicedGeometry->GetTimeSteps(); - }; + } //##Documentation //## @brief Get the modified time of the last change of the contents //## this data object or its geometry. virtual unsigned long GetMTime() const; protected: BaseData(); BaseData(const BaseData &other); ~BaseData(); //##Documentation //## @brief Initialize the TimeSlicedGeometry for a number of time steps. //## The TimeSlicedGeometry is initialized empty and evenly timed. //## In many cases it will be necessary to overwrite this in sub-classes. virtual void InitializeTimeSlicedGeometry( unsigned int timeSteps = 1 ); //##Documentation //## @brief reset to non-initialized state, release memory virtual void ClearData(); //##Documentation //## @brief Pure virtual; Must be used in subclasses to get a data object to a //## valid state. Should at least create one empty object and call //## Superclass::InitializeTimeSlicedGeometry() to ensure an existing valid geometry - virtual void InitializeEmpty(){}; + virtual void InitializeEmpty(){} virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; bool m_RequestedRegionInitialized; bool m_LastRequestedRegionWasOutsideOfTheBufferedRegion; mutable itk::SmartPointer m_SmartSourcePointer; mutable unsigned int m_SourceOutputIndexDuplicate; //##Documentation //## @brief for internal use only. Helps to deal with the //## weak-pointer-problem. virtual void ConnectSource(itk::ProcessObject *arg, unsigned int idx) const; bool m_Initialized; private: //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable bool m_Unregistering; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable bool m_CalculatingExternalReferenceCount; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable int m_ExternalReferenceCount; //##Documentation //## @brief PropertyList, f.e. to hold pic-tags, tracking-data,.. //## PropertyList::Pointer m_PropertyList; TimeSlicedGeometry::Pointer m_TimeSlicedGeometry; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. friend class mitk::BaseProcess; }; } // namespace mitk #endif /* BASEDATA_H_HEADER_INCLUDED_C1EBB6FA */ diff --git a/Core/Code/DataManagement/mitkImageAccessorBase.cpp b/Core/Code/DataManagement/mitkImageAccessorBase.cpp index cc678aaddb..c08a6d709f 100644 --- a/Core/Code/DataManagement/mitkImageAccessorBase.cpp +++ b/Core/Code/DataManagement/mitkImageAccessorBase.cpp @@ -1,187 +1,177 @@ /*=================================================================== 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 "mitkImageAccessorBase.h" #include "mitkImage.h" -itk::ThreadProcessIDType mitk::CurrentThreadHandle() +mitk::ImageAccessorBase::ThreadIDType mitk::ImageAccessorBase::CurrentThreadHandle() { #ifdef ITK_USE_SPROC - return GetCurrentThread(); + return GetCurrentThreadId(); #endif #ifdef ITK_USE_PTHREADS return pthread_self(); #endif #ifdef ITK_USE_WIN32_THREADS - return GetCurrentThread(); + return GetCurrentThreadId(); #endif } -bool mitk::CompareThreadHandles(itk::ThreadProcessIDType handle1, itk::ThreadProcessIDType handle2) +bool mitk::ImageAccessorBase::CompareThreadHandles(mitk::ImageAccessorBase::ThreadIDType handle1, mitk::ImageAccessorBase::ThreadIDType handle2) { - #ifdef ITK_USE_SPROC - return GetThreadId(handle1) == GetThreadId(handle2); - #endif - - #ifdef ITK_USE_WIN32_THREADS - return GetThreadId(handle1) == GetThreadId(handle2); - #endif - - #ifdef ITK_USE_PTHREADS - return handle1 == handle2; - #endif + return handle1 == handle2; } mitk::ImageAccessorBase::ImageAccessorBase( ImagePointer iP, ImageDataItem* imageDataItem, int OptionFlags ) : m_Image(iP), // imageDataItem(iDI), m_SubRegion(NULL), m_Options(OptionFlags), m_CoherentMemory(false) { - m_Thread = mitk::CurrentThreadHandle(); + m_Thread = CurrentThreadHandle(); // Initialize WaitLock m_WaitLock = new ImageAccessorWaitLock(); m_WaitLock->m_WaiterCount = 0; // Check validity of ImageAccessor // Is there an Image? /* if(!m_Image) { mitkThrow() << "Invalid ImageAccessor: No Image was specified in constructor of ImageAccessor"; } */ if(m_Image) { // Make sure, that the Image is initialized properly if(m_Image->m_Initialized==false) { if(m_Image->GetSource().IsNull()) mitkThrow() << "ImageAccessor: No image source is defined"; if(m_Image->GetSource()->Updating()==false) m_Image->GetSource()->UpdateOutputInformation(); } } // Investigate 4 cases of possible image parts/regions // Case 1: No ImageDataItem and no Subregion => Whole Image is accessed if(imageDataItem == NULL && m_SubRegion == NULL) { m_CoherentMemory = true; // Organize first image channel imageDataItem = m_Image->GetChannelData(); // Set memory area m_AddressBegin = imageDataItem->m_Data; m_AddressEnd = (unsigned char*) m_AddressBegin + imageDataItem->m_Size; } // Case 2: ImageDataItem but no Subregion if(imageDataItem && m_SubRegion == NULL) { m_CoherentMemory = true; // Set memory area m_AddressBegin = imageDataItem->m_Data; m_AddressEnd = (unsigned char*) m_AddressBegin + imageDataItem->m_Size; } // Case 3: No ImageDataItem but a SubRegion if(imageDataItem == NULL && m_SubRegion) { mitkThrow() << "Invalid ImageAccessor: The use of a SubRegion is not supported (yet)."; } // Case 4: ImageDataItem and SubRegion if(imageDataItem == NULL && m_SubRegion) { mitkThrow() << "Invalid ImageAccessor: The use of a SubRegion is not supported (yet)."; } } /** \brief Computes if there is an Overlap of the image part between this instantiation and another ImageAccessor object * \throws mitk::Exception if memory area is incoherent (not supported yet) */ bool mitk::ImageAccessorBase::Overlap(const ImageAccessorBase* iAB) { if(m_CoherentMemory) { if((iAB->m_AddressBegin >= m_AddressBegin && iAB->m_AddressBegin < m_AddressEnd) || (iAB->m_AddressEnd > m_AddressBegin && iAB->m_AddressEnd <= m_AddressEnd)) { return true; } if((m_AddressBegin >= iAB->m_AddressBegin && m_AddressBegin < iAB->m_AddressEnd) || (m_AddressEnd > iAB->m_AddressBegin && m_AddressEnd <= iAB->m_AddressEnd)) { return true; } } else { m_Image->m_ReadWriteLock.Unlock(); mitkThrow() << "ImageAccessor: incoherent memory area is not supported yet"; } return false; } /** \brief Uses the WaitLock to wait for another ImageAccessor*/ void mitk::ImageAccessorBase::WaitForReleaseOf(ImageAccessorWaitLock* wL) { wL->m_Mutex.Lock(); // Decrement wL->m_WaiterCount -= 1; // If there are no more waiting ImageAccessors, delete the Mutex // (Der Letzte macht das Licht aus!) if(wL->m_WaiterCount <= 0) { wL->m_Mutex.Unlock(); delete wL; } else { wL->m_Mutex.Unlock(); } } void mitk::ImageAccessorBase::PreventRecursiveMutexLock(mitk::ImageAccessorBase* iAB) { #ifdef MITK_USE_RECURSIVE_MUTEX_PREVENTION // Prevent deadlock - itk::ThreadProcessIDType id = mitk::CurrentThreadHandle(); - if(mitk::CompareThreadHandles(id,iAB->m_Thread)) { + ThreadIDType id = CurrentThreadHandle(); + if(CompareThreadHandles(id,iAB->m_Thread)) { m_Image->m_ReadWriteLock.Unlock(); mitkThrow() << "Prohibited image access: the requested image part is already in use and cannot be requested recursively!"; } #endif } diff --git a/Core/Code/DataManagement/mitkImageAccessorBase.h b/Core/Code/DataManagement/mitkImageAccessorBase.h index 5433a7dac6..f5da85cc07 100644 --- a/Core/Code/DataManagement/mitkImageAccessorBase.h +++ b/Core/Code/DataManagement/mitkImageAccessorBase.h @@ -1,157 +1,165 @@ /*=================================================================== 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 MITKIMAGEACCESSORBASE_H #define MITKIMAGEACCESSORBASE_H #include #include #include #include #include #include "mitkImageDataItem.h" namespace mitk { //##Documentation //## @brief The ImageAccessorBase class provides a lock mechanism for all inheriting image accessors. //## //## @ingroup Data class Image; typedef itk::SmartPointer ImagePointer; /** \brief This struct allows to make ImageAccessors wait for this particular ImageAccessor object*/ struct ImageAccessorWaitLock { /** \brief Holds the number of ImageAccessors, which are waiting until the represented ImageAccessor is released. */ unsigned int m_WaiterCount; /** \brief A mutex that allows other ImageAccessors to wait for the represented ImageAccessor. */ itk::SimpleFastMutexLock m_Mutex; }; - -/** \brief System dependend thread method, to prevent recursive mutex access */ -itk::ThreadProcessIDType MITK_CORE_EXPORT CurrentThreadHandle(); -/** \brief System dependend thread method, to prevent recursive mutex access */ -bool MITK_CORE_EXPORT CompareThreadHandles(itk::ThreadProcessIDType, itk::ThreadProcessIDType); - // Defs to assure dead lock prevention only in case of possible thread handling. #if defined(ITK_USE_SPROC) || defined(ITK_USE_PTHREADS) || defined(ITK_USE_WIN32_THREADS) #define MITK_USE_RECURSIVE_MUTEX_PREVENTION #endif class MITK_CORE_EXPORT ImageAccessorBase { friend class Image; friend class ImageReadAccessor; friend class ImageWriteAccessor; template friend class ImagePixelReadAccessor; template friend class ImagePixelWriteAccessor; public: /** \brief defines different flags for the ImageAccessor constructors */ enum Options { /** No specific Options ==> Default */ DefaultBehavior = 0, /** Defines if the Constructor waits for locked memory until it is released or not. If not, an exception is thrown.*/ ExceptionIfLocked = 1, /** Defines if requested Memory has to be coherent. If the parameter is true, it is possible that new Memory has to be allocated to arrange this desired condition. Consequently, this parameter can heavily affect computation time.*/ ForceCoherentMemory = 2 }; virtual ~ImageAccessorBase() { } protected: -// ImageAccessorBase() : -// m_CoherentMemory(false) -// { -// m_waitLock = new ImageAccessorWaitLock(); -// m_waitLock->m_WaiterCount = 0; -// } + // Define type of thread id +#ifdef ITK_USE_SPROC +typedef int ThreadIDType; +#endif + +#ifdef ITK_USE_WIN32_THREADS +typedef DWORD ThreadIDType; +#endif + +#ifdef ITK_USE_PTHREADS +typedef pthread_t ThreadIDType; +#endif /** \brief Checks validity of given parameters from inheriting classes and stores those parameters in member variables. */ ImageAccessorBase( ImagePointer iP, ImageDataItem* iDI = NULL, int OptionFlags = DefaultBehavior ); /** ImageAccessor has access to the image it belongs to. */ ImagePointer m_Image; /** Contains a SubRegion (always represented in maximal possible dimension) */ itk::ImageRegion<4>* m_SubRegion; /** Points to the beginning of the image part. */ void* m_AddressBegin; /** Contains the first address after the image part. */ void* m_AddressEnd; /** \brief Stores all extended properties of an ImageAccessor. * The different flags in mitk::ImageAccessorBase::Options can be unified by bitwise operations. */ int m_Options; /** Defines if the accessed image part lies coherently in memory */ bool m_CoherentMemory; /** \brief Pointer to a WaitLock struct, that allows other ImageAccessors to wait for this ImageAccessor */ ImageAccessorWaitLock* m_WaitLock; /** \brief Increments m_WaiterCount. A call of this method is prohibited unless the Mutex m_ReadWriteLock in the mitk::Image class is Locked. */ inline void Increment() { m_WaitLock->m_WaiterCount += 1; } /** \brief Computes if there is an Overlap of the image part between this instantiation and another ImageAccessor object * \throws mitk::Exception if memory area is incoherent (not supported yet) */ bool Overlap(const ImageAccessorBase* iAB); /** \brief Uses the WaitLock to wait for another ImageAccessor*/ void WaitForReleaseOf(ImageAccessorWaitLock* wL); - itk::ThreadProcessIDType m_Thread; + ThreadIDType m_Thread; /** \brief Prevents a recursive mutex lock by comparing thread ids of competing image accessors */ void PreventRecursiveMutexLock(ImageAccessorBase* iAB); + +private: + + /** \brief System dependend thread method, to prevent recursive mutex access */ + ThreadIDType CurrentThreadHandle(); + /** \brief System dependend thread method, to prevent recursive mutex access */ + inline bool CompareThreadHandles(ThreadIDType, ThreadIDType); + }; class MemoryIsLockedException : public Exception { public: mitkExceptionClassMacro(MemoryIsLockedException,Exception) }; } #endif diff --git a/Core/Code/DataManagement/mitkLevelWindowPreset.cpp b/Core/Code/DataManagement/mitkLevelWindowPreset.cpp index 332df9b090..06a4ead1ed 100644 --- a/Core/Code/DataManagement/mitkLevelWindowPreset.cpp +++ b/Core/Code/DataManagement/mitkLevelWindowPreset.cpp @@ -1,132 +1,144 @@ /*=================================================================== 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 "mitkLevelWindowPreset.h" -#include "mitkStandardFileLocations.h" #include +#include "mitkGetModuleContext.h" +#include "mitkModuleContext.h" +#include "mitkModule.h" +#include "mitkModuleResource.h" +#include "mitkModuleResourceStream.h" + namespace mitk { const std::string LevelWindowPreset::PRESET = "preset"; vtkStandardNewMacro(LevelWindowPreset); LevelWindowPreset::LevelWindowPreset() { } LevelWindowPreset::~LevelWindowPreset() { } bool LevelWindowPreset::LoadPreset() { - m_XmlFileName = mitk::StandardFileLocations::GetInstance()->FindFile("mitkLevelWindowPresets.xml", "Config"); + ModuleResource presetResource = GetModuleContext()->GetModule()->GetResource("mitkLevelWindowPresets.xml"); + if (!presetResource) return false; - if (!m_XmlFileName.empty()) - return LoadPreset(m_XmlFileName); - else + ModuleResourceStream presetStream(presetResource); + vtkXMLParser::SetStream(&presetStream); + if ( !vtkXMLParser::Parse() ) + { +#ifdef INTERDEBUG + MITK_INFO<<"LevelWindowPreset::LoadPreset xml file cannot parse!"<& LevelWindowPreset::getLevelPresets() { return m_Level; } std::map& LevelWindowPreset::getWindowPresets() { return m_Window; } void LevelWindowPreset::save() { //XMLWriter writer(m_XmlFileName.c_str()); //saveXML(writer); } void LevelWindowPreset::newPresets(std::map newLevel, std::map newWindow) { m_Level = newLevel; m_Window = newWindow; save(); } } diff --git a/Core/Code/DataManagement/mitkRenderingModeProperty.cpp b/Core/Code/DataManagement/mitkRenderingModeProperty.cpp new file mode 100644 index 0000000000..6766fedde9 --- /dev/null +++ b/Core/Code/DataManagement/mitkRenderingModeProperty.cpp @@ -0,0 +1,65 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkRenderingModeProperty.h" + + +mitk::RenderingModeProperty::RenderingModeProperty( ) +{ + this->AddRenderingModes(); + this->SetValue( LEVELWINDOW_COLOR ); +} + +mitk::RenderingModeProperty::RenderingModeProperty( const IdType& value ) +{ + this->AddRenderingModes(); + if ( IsValidEnumerationValue( value ) ) + { + this->SetValue( value ) ; + } + else + MITK_WARN << "Warning: invalid image rendering mode"; +} + +mitk::RenderingModeProperty::RenderingModeProperty( const std::string& value ) +{ + this->AddRenderingModes(); + if ( IsValidEnumerationValue( value ) ) + { + this->SetValue( value ); + } + else + MITK_WARN << "Invalid image rendering mode"; +} + +int mitk::RenderingModeProperty::GetRenderingMode() +{ + return static_cast( this->GetValueAsId() ); +} + +void mitk::RenderingModeProperty::AddRenderingModes() +{ + AddEnum( "LevelWindow_Color", LEVELWINDOW_COLOR ); + AddEnum( "LookupTable_LevelWindow_Color", LOOKUPTABLE_LEVELWINDOW_COLOR ); + AddEnum( "ColorTransferFunction_LevelWindow_Color", COLORTRANSFERFUNCTION_LEVELWINDOW_COLOR ); + AddEnum( "LookupTable_Color", LOOKUPTABLE_COLOR ); + AddEnum( "ColorTransferFunction_Color", COLORTRANSFERFUNCTION_COLOR ); +} + +bool mitk::RenderingModeProperty::AddEnum( const std::string& name, const IdType& id ) +{ + return Superclass::AddEnum( name, id ); +} diff --git a/Core/Code/DataManagement/mitkRenderingModeProperty.h b/Core/Code/DataManagement/mitkRenderingModeProperty.h new file mode 100644 index 0000000000..ac11f0ab16 --- /dev/null +++ b/Core/Code/DataManagement/mitkRenderingModeProperty.h @@ -0,0 +1,114 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef _MITK_RENDERING_MODE_PROPERTY__H_ +#define _MITK_RENDERING_MODE_PROPERTY__H_ + +#include "mitkEnumerationProperty.h" + +namespace mitk +{ + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4522) +#endif + +/** + * Encapsulates the enumeration for rendering modes. Valid values are: + * \li LEVELWINDOW_COLOR: Level window and color will be applied to the image. + * \li LOOKUPTABLE_LEVELWINDOW_COLOR: A lookup table, level window and color will be applied to the image. + * \li COLORTRANSFERFUNCTION_LEVELWINDOW_COLOR: A colortransferfunction, level window and color will be applied to the image. + * \li LOOKUPTABLE_COLOR: A lookup table and color will be applied to the image. + * \li COLORTRANSFERFUNCTION_COLOR: A colortransferfunction and color will be applied to the image. + * + * The order is given by the names (e.g. LOOKUPTABLE_COLOR applies first a lookup table and next a color). + * Currently, there is no GUI (in mitkWorkbench) support for controlling lookup tables or transfer functions. + * This has to be done by the programmer. Color and level window are controled by color widget and level window slider. + * Currently, the color is always applied. We do not set the color to white, if the user changes the mode. We assume + * that users who change the mode know that a previously set color will still be applied (on top of the mode). + */ + +class MITK_CORE_EXPORT RenderingModeProperty : public EnumerationProperty +{ +public: + + mitkClassMacro( RenderingModeProperty, EnumerationProperty ); + + itkNewMacro(RenderingModeProperty); + + mitkNewMacro1Param(RenderingModeProperty, const IdType&); + + mitkNewMacro1Param(RenderingModeProperty, const std::string&); + + enum ImageRenderingMode + { + LEVELWINDOW_COLOR = 0, + LOOKUPTABLE_LEVELWINDOW_COLOR = 1, + COLORTRANSFERFUNCTION_LEVELWINDOW_COLOR = 2, + LOOKUPTABLE_COLOR = 3, + COLORTRANSFERFUNCTION_COLOR = 4 + // Default = LEVELWINDOW_COLOR; + }; + + /** + * Returns the current rendering mode + */ + virtual int GetRenderingMode(); + + using BaseProperty::operator=; + + protected: + + /** Sets rendering type to default (VTK_RAY_CAST_COMPOSITE_FUNCTION). + */ + RenderingModeProperty( ); + + /** + * Constructor. Sets rendering type to the given value. + */ + RenderingModeProperty( const IdType& value ); + + /** + * Constructor. Sets rendering type to the given value. + */ + RenderingModeProperty( const std::string& value ); + + /** + * this function is overridden as protected, so that the user may not add + * additional invalid rendering types. + */ + virtual bool AddEnum( const std::string& name, const IdType& id ); + + /** + * Adds the default enumeration types. + */ + virtual void AddRenderingModes(); + +private: + + // purposely not implemented + RenderingModeProperty(const RenderingModeProperty&); + RenderingModeProperty& operator=(const RenderingModeProperty&); +}; + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +} // end of namespace mitk + +#endif diff --git a/Core/Code/DataManagement/mitkShaderProperty.cpp b/Core/Code/DataManagement/mitkShaderProperty.cpp index 28bfa885a8..e1d00c44e3 100644 --- a/Core/Code/DataManagement/mitkShaderProperty.cpp +++ b/Core/Code/DataManagement/mitkShaderProperty.cpp @@ -1,106 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "mitkShaderProperty.h" -#include "mitkShaderRepository.h" + +#include "mitkCoreServices.h" +#include "mitkIShaderRepository.h" #include #include mitk::ShaderProperty::ShaderProperty( ) { AddShaderTypes(); SetShader( (IdType)0 ); } mitk::ShaderProperty::ShaderProperty( const IdType& value ) { AddShaderTypes(); SetShader(value); } mitk::ShaderProperty::ShaderProperty( const std::string& value ) { AddShaderTypes(); SetShader(value); } void mitk::ShaderProperty::SetShader( const IdType& value ) { if ( IsValidEnumerationValue( value ) ) SetValue( value ); else SetValue( (IdType)0 ); } void mitk::ShaderProperty::SetShader( const std::string& value ) { if ( IsValidEnumerationValue( value ) ) SetValue( value ); else SetValue( (IdType)0 ); } mitk::EnumerationProperty::IdType mitk::ShaderProperty::GetShaderId() { return GetValueAsId(); } std::string mitk::ShaderProperty::GetShaderName() { return GetValueAsString(); } void mitk::ShaderProperty::AddShaderTypes() { AddEnum( "fixed" ); - std::list *l - = mitk::ShaderRepository::GetGlobalShaderRepository()->GetShaders(); + IShaderRepository* shaderRepo = CoreServices::GetShaderRepository(); + if (shaderRepo == NULL) return; + + std::list l = shaderRepo->GetShaders(); - std::list::const_iterator i = l->begin(); + std::list::const_iterator i = l.begin(); - while( i != l->end() ) + while( i != l.end() ) { - AddEnum( (*i)->name ); + AddEnum( (*i)->GetName() ); i++; } } bool mitk::ShaderProperty::AddEnum( const std::string& name ,const IdType& /*id*/) { Element e; e.name=name; bool success=Superclass::AddEnum( e.name, (IdType)shaderList.size() ); shaderList.push_back(e); return success; } bool mitk::ShaderProperty::Assign(const BaseProperty &property) { Superclass::Assign(property); this->shaderList = static_cast(property).shaderList; return true; } diff --git a/Core/Code/DataManagement/mitkTimeSlicedGeometry.h b/Core/Code/DataManagement/mitkTimeSlicedGeometry.h index 76eb5a6e47..1de4988cf4 100644 --- a/Core/Code/DataManagement/mitkTimeSlicedGeometry.h +++ b/Core/Code/DataManagement/mitkTimeSlicedGeometry.h @@ -1,181 +1,182 @@ /*=================================================================== 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 TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD #define TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD #include "mitkGeometry3D.h" namespace mitk { //##Documentation //## @brief Describes a geometry consisting of several geometries which //## exist at different times. //## //## The geometry contains m_TimeSteps geometries, which can be accessed //## using GetGeometry3D(int t). To convert between world-time in //## milliseconds and the integer timestep-number use MSToTimeStep. //## The hull (in space and time) of the TimeSlicedGeometry contains all //## contained geometries. //## @warning The hull (i.e., transform, bounding-box and //## time-bounds) is only guaranteed to be up-to-date after calling //## UpdateInformation(). //## //## TimeSlicedGeometry and the associated Geometry3Ds have to be //## initialized in the method GenerateOutputInformation() of BaseProcess (or //## CopyInformation/ UpdateOutputInformation of BaseData, if possible, e.g., //## by analyzing pic tags in Image) subclasses. See also //## itk::ProcessObject::GenerateOutputInformation(), //## itk::DataObject::CopyInformation() and //## itk::DataObject::UpdateOutputInformation(). //## //## @ingroup Geometry class MITK_CORE_EXPORT TimeSlicedGeometry : public Geometry3D { public: mitkClassMacro(TimeSlicedGeometry, Geometry3D); itkNewMacro(Self); //##Documentation //## @brief Re-calculate the hull of the contained geometries. //## //## The transforms, bounding-box and time-bounds of this //## geometry (stored in members of the super-class Geometry3D) //## are re-calculated from the contained geometries. void UpdateInformation(); //##Documentation //## @brief Get the number of time-steps itkGetConstMacro(TimeSteps, unsigned int); //##Documentation //## @brief Set/Get whether the TimeSlicedGeometry is evenly-timed (m_EvenlyTimed) //## //## If (a) we don't have a Geometry3D stored for the requested time, //## (b) m_EvenlyTimed is activated and (c) the first geometry (t=0) //## is set, then we clone the geometry and set the m_TimeBounds accordingly. //## \sa GetGeometry3D itkGetConstMacro(EvenlyTimed, bool); virtual void SetEvenlyTimed(bool on = true); //##Documentation //## @brief Set the Geometry3D for time @a t virtual bool SetGeometry3D(mitk::Geometry3D* geometry3D, int t); //##Documentation //## @brief When switching from an Image Geometry to a normal Geometry (and the other way around), you have to change the origin as well (See Geometry Documentation)! This function will change the "isImageGeometry" bool flag and changes the origin respectively. virtual void ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ); //##Documentation //## @brief Get the Geometry3D at time @a t virtual mitk::Geometry3D* GetGeometry3D(int t) const; //##Documentation //## @brief Test whether @a t is a valid time step virtual bool IsValidTime(int t) const; //##Documentation //## @brief Returns true if TimeSliceGeometry is valid virtual bool IsValid() const; //##Documentation //## @brief Convert time in ms to a time step virtual int MSToTimeStep(mitk::ScalarType time_in_ms) const; //##Documentation //## @brief Convert time step to time in ms virtual mitk::ScalarType TimeStepToMS(int timestep) const; //##Documentation //## @brief Convert time step in the reference TimeSlicedGeometry to time step //## in this TimeSlicedGeometry. virtual int TimeStepToTimeStep(const mitk::TimeSlicedGeometry *referenceGeometry, int t) const; //##Documentation //## @brief Completely initialize this instance as evenly-timed with //## \a timeSteps geometries of type Geometry3D, each initialized by //## Geometry3D::Initialize(). virtual void InitializeEvenlyTimed(unsigned int timeSteps); //##Documentation //## @brief Completely initialize this instance as evenly-timed with //## \a timeSteps geometries identical to the provided Geometry3D //## except for the time bounds virtual void InitializeEvenlyTimed(mitk::Geometry3D* geometry3D, unsigned int timeSteps); //##Documentation //## @brief Initialize this instance to contain \a timeSteps //## geometries, but without setting them yet virtual void InitializeEmpty(unsigned int timeSteps); //##Documentation //## @brief Expand the number of time steps contained //## to \a timeSteps. //## //## New, additional time steps will be initialized empty. //## Only enlargement of the time steps vector is intended and possible. virtual void ExpandToNumberOfTimeSteps( unsigned int timeSteps ); virtual void SetImageGeometry(const bool isAnImageGeometry); //##Documentation //## @brief Copy the m_TimeBounds of the geometries contained //## in timeslicedgeometry into the geometries contained in this //## TimeSlicedGeometry object. //## //## Useful for initialization of the TimeSlicedGeometry of the //## output in GenerateOutputInformation() methods of process objects, //## see for example BoundingObjectCutter::GenerateOutputInformation(). //## @param t start time index //## @param endtimeindex (endtimeindex) is the time index of //## the last geometry whose time-bounds are copied. If //## timeslicedgeometry or this TimeSlicedGeometry object does //## not contain enough geometries, endtimeindex is reduced //## appropriately. void CopyTimes(const mitk::TimeSlicedGeometry* timeslicedgeometry, unsigned int t=0, unsigned int endtimeindex = itk::NumericTraits::max()); //##Documentation //## @brief duplicates the geometry virtual AffineGeometryFrame3D::Pointer Clone() const; - TimeSlicedGeometry::Pointer CloneCopy() const; + // muellerm, 18.1.13, method not implemented + //TimeSlicedGeometry::Pointer CloneCopy() const; virtual void ExecuteOperation(Operation* operation); protected: TimeSlicedGeometry(); TimeSlicedGeometry(const TimeSlicedGeometry& other); virtual ~TimeSlicedGeometry(); virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; mutable std::vector m_Geometry3Ds; //##Documentation //## @brief Number of time steps unsigned int m_TimeSteps; //##Documentation //## @brief \a true in case the time steps have equal length bool m_EvenlyTimed; static const std::string EVENLY_TIMED; static const std::string TIME_STEPS; }; } // namespace mitk #endif /* TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD */ diff --git a/Core/Code/IO/mitkIOUtil.cpp b/Core/Code/IO/mitkIOUtil.cpp index 71eef6e604..37dc199f77 100644 --- a/Core/Code/IO/mitkIOUtil.cpp +++ b/Core/Code/IO/mitkIOUtil.cpp @@ -1,317 +1,317 @@ /*=================================================================== 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 "mitkIOUtil.h" #include "mitkDataNodeFactory.h" #include "mitkImageWriter.h" #include "mitkPointSetWriter.h" #include "mitkSurfaceVtkWriter.h" #include #include #include #include #include //ITK #include //VTK #include #include #include namespace mitk { const std::string IOUtil::DEFAULTIMAGEEXTENSION = ".nrrd"; const std::string IOUtil::DEFAULTSURFACEEXTENSION = ".stl"; const std::string IOUtil::DEFAULTPOINTSETEXTENSION = ".mps"; int IOUtil::LoadFiles(const std::vector &fileNames, DataStorage &ds) { // Get the set of registered mitk::IDataNodeReader services - ModuleContext* context = GetModuleContext(); + ModuleContext* context = mitk::GetModuleContext(); const std::list refs = context->GetServiceReferences(); std::vector services; services.reserve(refs.size()); for (std::list::const_iterator i = refs.begin(); i != refs.end(); ++i) { IDataNodeReader* s = context->GetService(*i); if (s != 0) { services.push_back(s); } } mitk::ProgressBar::GetInstance()->AddStepsToDo(2*fileNames.size()); // Iterate over all file names and use the IDataNodeReader services // to load them. int nodesRead = 0; for (std::vector::const_iterator i = fileNames.begin(); i != fileNames.end(); ++i) { for (std::vector::const_iterator readerIt = services.begin(); readerIt != services.end(); ++readerIt) { try { int n = (*readerIt)->Read(*i, ds); nodesRead += n; if (n > 0) break; } catch (const std::exception& e) { MITK_WARN << e.what(); } } mitk::ProgressBar::GetInstance()->Progress(2); } for (std::list::const_iterator i = refs.begin(); i != refs.end(); ++i) { context->UngetService(*i); } return nodesRead; } DataStorage::Pointer IOUtil::LoadFiles(const std::vector& fileNames) { mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); LoadFiles(fileNames, *ds); return ds.GetPointer(); } DataNode::Pointer IOUtil::LoadDataNode(const std::string path) { mitk::DataNodeFactory::Pointer reader = mitk::DataNodeFactory::New(); try { reader->SetFileName( path ); reader->Update(); if((reader->GetNumberOfOutputs()<1)) { MITK_ERROR << "Could not find data '" << path << "'"; mitkThrow() << "An exception occured during loading the file " << path << ". Exception says could not find data."; } mitk::DataNode::Pointer node = reader->GetOutput(0); if(node.IsNull()) { MITK_ERROR << "Could not find path: '" << path << "'" << " datanode is NULL" ; mitkThrow() << "An exception occured during loading the file " << path << ". Exception says datanode is NULL."; } return reader->GetOutput( 0 ); } catch ( itk::ExceptionObject & e ) { MITK_ERROR << "Exception occured during load data of '" << path << "': Exception: " << e.what(); mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: " << e.what(); } } Image::Pointer IOUtil::LoadImage(const std::string path) { mitk::DataNode::Pointer node = LoadDataNode(path); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if(image.IsNull()) { MITK_ERROR << "Image is NULL '" << path << "'"; mitkThrow() << "An exception occured during loading the image " << path << ". Exception says: Image is NULL."; } return image; } Surface::Pointer IOUtil::LoadSurface(const std::string path) { mitk::DataNode::Pointer node = LoadDataNode(path); mitk::Surface::Pointer surface = dynamic_cast(node->GetData()); if(surface.IsNull()) { MITK_ERROR << "Surface is NULL '" << path << "'"; mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: Surface is NULL."; } return surface; } PointSet::Pointer IOUtil::LoadPointSet(const std::string path) { mitk::DataNode::Pointer node = LoadDataNode(path); mitk::PointSet::Pointer pointset = dynamic_cast(node->GetData()); if(pointset.IsNull()) { MITK_ERROR << "PointSet is NULL '" << path << "'"; mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: Pointset is NULL."; } return pointset; } bool IOUtil::SaveImage(mitk::Image::Pointer image, const std::string path) { std::string dir = itksys::SystemTools::GetFilenamePath( path ); std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( path ); std::string extension = itksys::SystemTools::GetFilenameLastExtension( path ); std::string finalFileName = dir + "/" + baseFilename; mitk::ImageWriter::Pointer imageWriter = mitk::ImageWriter::New(); //check if an extension is given, else use the defaul extension if( extension == "" ) { MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName << DEFAULTIMAGEEXTENSION; extension = DEFAULTIMAGEEXTENSION; } // check if extension is suitable for writing image data if (!imageWriter->IsExtensionValid(extension)) { MITK_WARN << extension << " extension is unknown. Extension set to default: " << finalFileName << DEFAULTIMAGEEXTENSION; extension = DEFAULTIMAGEEXTENSION; } try { //write the data imageWriter->SetInput(image); imageWriter->SetFileName(finalFileName.c_str()); imageWriter->SetExtension(extension.c_str()); imageWriter->Write(); } catch ( std::exception& e ) { MITK_ERROR << " during attempt to write '" << finalFileName + extension << "' Exception says:"; MITK_ERROR << e.what(); mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); } return true; } bool IOUtil::SaveSurface(Surface::Pointer surface, const std::string path) { std::string dir = itksys::SystemTools::GetFilenamePath( path ); std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( path ); std::string extension = itksys::SystemTools::GetFilenameLastExtension( path ); std::string finalFileName = dir + "/" + baseFilename; if (extension == "") // if no extension has been set we use the default extension { MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName << DEFAULTSURFACEEXTENSION; extension = DEFAULTSURFACEEXTENSION; } try { finalFileName += extension; if(extension == ".stl" ) { mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); // check if surface actually consists of triangles; if not, the writer will not do anything; so, convert to triangles... vtkPolyData* polys = surface->GetVtkPolyData(); if( polys->GetNumberOfStrips() > 0 ) { vtkSmartPointer triangleFilter = vtkSmartPointer::New(); triangleFilter->SetInput(polys); triangleFilter->Update(); polys = triangleFilter->GetOutput(); polys->Register(NULL); surface->SetVtkPolyData(polys); } surfaceWriter->SetInput( surface ); surfaceWriter->SetFileName( finalFileName.c_str() ); surfaceWriter->GetVtkWriter()->SetFileTypeToBinary(); surfaceWriter->Write(); } else if(extension == ".vtp") { mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); surfaceWriter->SetInput( surface ); surfaceWriter->SetFileName( finalFileName.c_str() ); surfaceWriter->GetVtkWriter()->SetDataModeToBinary(); surfaceWriter->Write(); } else if(extension == ".vtk") { mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); surfaceWriter->SetInput( surface ); surfaceWriter->SetFileName( finalFileName.c_str() ); surfaceWriter->Write(); } else { // file extension not suitable for writing specified data type MITK_ERROR << "File extension is not suitable for writing'" << finalFileName; mitkThrow() << "An exception occured during writing the file " << finalFileName << ". File extension " << extension << " is not suitable for writing."; } } catch(std::exception& e) { MITK_ERROR << " during attempt to write '" << finalFileName << "' Exception says:"; MITK_ERROR << e.what(); mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); } return true; } bool IOUtil::SavePointSet(PointSet::Pointer pointset, const std::string path) { mitk::PointSetWriter::Pointer pointSetWriter = mitk::PointSetWriter::New(); std::string dir = itksys::SystemTools::GetFilenamePath( path ); std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( path ); std::string extension = itksys::SystemTools::GetFilenameLastExtension( path ); std::string finalFileName = dir + "/" + baseFilename; if (extension == "") // if no extension has been entered manually into the filename { MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName << DEFAULTPOINTSETEXTENSION; extension = DEFAULTPOINTSETEXTENSION; } // check if extension is valid if (!pointSetWriter->IsExtensionValid(extension)) { MITK_WARN << extension << " extension is unknown. Extension set to default: " << finalFileName << DEFAULTPOINTSETEXTENSION; extension = DEFAULTPOINTSETEXTENSION; } try { pointSetWriter->SetInput( pointset ); finalFileName += extension; pointSetWriter->SetFileName( finalFileName.c_str() ); pointSetWriter->Update(); } catch( std::exception& e ) { MITK_ERROR << " during attempt to write '" << finalFileName << "' Exception says:"; MITK_ERROR << e.what(); mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); } return true; } } diff --git a/Core/Code/Interactions/mitkDispatcher.cpp b/Core/Code/Interactions/mitkDispatcher.cpp index 4207d4dbca..a90637e3d8 100644 --- a/Core/Code/Interactions/mitkDispatcher.cpp +++ b/Core/Code/Interactions/mitkDispatcher.cpp @@ -1,233 +1,230 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDispatcher.h" #include "mitkInteractionEvent.h" #include "mitkInternalEvent.h" // MicroServices #include "mitkGetModuleContext.h" #include "mitkModule.h" #include "mitkModuleRegistry.h" #include "mitkInteractionEventObserver.h" mitk::Dispatcher::Dispatcher() : m_ProcessingMode(REGULAR) { m_EventObserverTracker = new mitk::ServiceTracker(GetModuleContext()); m_EventObserverTracker->Open(); } void mitk::Dispatcher::AddDataInteractor(const DataNode* dataNode) { RemoveDataInteractor(dataNode); RemoveOrphanedInteractors(); DataInteractor::Pointer dataInteractor = dataNode->GetDataInteractor(); if (dataInteractor.IsNotNull()) { m_Interactors.push_back(dataInteractor); } } /* * Note: One DataInteractor can only have one DataNode and vice versa, * BUT the m_Interactors list may contain another DataInteractor that is still connected to this DataNode, * in this case we have to remove >1 DataInteractor. (Some special case of switching DataNodes between DataInteractors and registering a * DataNode to a DataStorage after assigning it to an DataInteractor) */ void mitk::Dispatcher::RemoveDataInteractor(const DataNode* dataNode) { for (ListInteractorType::iterator it = m_Interactors.begin(); it != m_Interactors.end();) { if ((*it)->GetDataNode() == dataNode) { it = m_Interactors.erase(it); } else { ++it; } } } size_t mitk::Dispatcher::GetNumberOfInteractors() { return m_Interactors.size(); } mitk::Dispatcher::~Dispatcher() { m_EventObserverTracker->Close(); delete m_EventObserverTracker; } bool mitk::Dispatcher::ProcessEvent(InteractionEvent* event) { InteractionEvent::Pointer p = event; //MITK_INFO << event->GetEventClass(); bool eventIsHandled = false; /* Filter out and handle Internal Events separately */ InternalEvent* internalEvent = dynamic_cast(event); if (internalEvent != NULL) { eventIsHandled = HandleInternalEvent(internalEvent); // InternalEvents that are handled are not sent to the listeners if (eventIsHandled) { return true; } } switch (m_ProcessingMode) { case CONNECTEDMOUSEACTION: // finished connected mouse action if (p->GetEventClass() == "MouseReleaseEvent") { m_ProcessingMode = REGULAR; eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); } // give event to selected interactor if (eventIsHandled == false) { eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); } break; case GRABINPUT: eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); SetEventProcessingMode(m_SelectedInteractor); break; case PREFERINPUT: if (m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()) == true) { SetEventProcessingMode(m_SelectedInteractor); eventIsHandled = true; } break; case REGULAR: break; } // Standard behavior. Is executed in STANDARD mode and PREFERINPUT mode, if preferred interactor rejects event. if (m_ProcessingMode == REGULAR || (m_ProcessingMode == PREFERINPUT && eventIsHandled == false)) { m_Interactors.sort(cmp()); // sorts interactors by layer (descending); for (std::list::iterator it = m_Interactors.begin(); it != m_Interactors.end(); ++it) { // explicit copy of pointer because HandleEvent function causes the m_Interactors list to be updated, // which in turn invalidates the iterator. DataInteractor::Pointer dataInteractor = *it; if (dataInteractor->HandleEvent(event, dataInteractor->GetDataNode())) { // if an event is handled several properties are checked, in order to determine the processing mode of the dispatcher SetEventProcessingMode(dataInteractor); if (p->GetEventClass() == "MousePressEvent" && m_ProcessingMode == REGULAR) { m_SelectedInteractor = dataInteractor; m_ProcessingMode = CONNECTEDMOUSEACTION; } eventIsHandled = true; break; } } } /* Notify InteractionEventObserver */ std::list listEventObserver; m_EventObserverTracker->GetServiceReferences(listEventObserver); for (std::list::iterator it = listEventObserver.begin(); it != listEventObserver.end(); ++it) { - - Any patternName = it->GetProperty("org.mitk.statemachinepattern"); - - //if (!patternName.Empty() || patternName.ToString() == "") - //{ - InteractionEventObserver* interactionEventObserver = m_EventObserverTracker->GetService(*it); - if (interactionEventObserver != NULL) + InteractionEventObserver* interactionEventObserver = m_EventObserverTracker->GetService(*it); + if (interactionEventObserver != NULL) + { + if (interactionEventObserver->IsEnabled()) { interactionEventObserver->Notify(event, eventIsHandled); } - //} + } } // Process event queue if (!m_QueuedEvents.empty()) { InteractionEvent::Pointer e = m_QueuedEvents.front(); m_QueuedEvents.pop_front(); ProcessEvent(e); } return eventIsHandled; } /* * Checks if DataNodes associated with DataInteractors point back to them. * If not remove the DataInteractors. (This can happen when s.o. tries to set DataNodes to multiple DataInteractors) */ void mitk::Dispatcher::RemoveOrphanedInteractors() { for (ListInteractorType::iterator it = m_Interactors.begin(); it != m_Interactors.end();) { DataNode::Pointer dn = (*it)->GetDataNode(); if (dn.IsNull()) { it = m_Interactors.erase(it); } else { DataInteractor::Pointer interactor = dn->GetDataInteractor(); if (interactor != it->GetPointer()) { it = m_Interactors.erase(it); } else { ++it; } } } } void mitk::Dispatcher::QueueEvent(InteractionEvent* event) { m_QueuedEvents.push_back(event); } void mitk::Dispatcher::SetEventProcessingMode(DataInteractor::Pointer dataInteractor) { m_ProcessingMode = dataInteractor->GetMode(); if (dataInteractor->GetMode() != REGULAR) { m_SelectedInteractor = dataInteractor; } } bool mitk::Dispatcher::HandleInternalEvent(InternalEvent* internalEvent) { if (internalEvent->GetSignalName() == IntDeactivateMe && internalEvent->GetTargetInteractor() != NULL) { internalEvent->GetTargetInteractor()->GetDataNode()->SetDataInteractor(NULL); internalEvent->GetTargetInteractor()->SetDataNode(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return true; } return false; } diff --git a/Core/Code/Interactions/mitkInteractionEventConst.h b/Core/Code/Interactions/mitkInteractionEventConst.h index f332d73487..cc06f391fd 100644 --- a/Core/Code/Interactions/mitkInteractionEventConst.h +++ b/Core/Code/Interactions/mitkInteractionEventConst.h @@ -1,131 +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 MITKINTERACTEVENTCONST_H #define MITKINTERACTEVENTCONST_H //##Documentation //## @file mitkInteractionEventConst.h //## @brief Constants to describe Mouse Events and special Key Events. #include namespace mitk { //##ButtonState // Mouse/keyboard state values enum MouseButtons { NoButton = 0x0000, LeftMouseButton = 0x0001, RightMouseButton = 0x0002, MiddleMouseButton = 0x0004, }; enum ModifierKeys { NoKey = 0x0000, ShiftKey = 0x0100, ControlKey = 0x0200, AltKey = 0x0400 }; /* * Allow bitwise OR operation on enums. */ inline MouseButtons operator|(MouseButtons a, MouseButtons b) { return static_cast(static_cast(a) | static_cast(b)); } inline MouseButtons& operator|=(MouseButtons& a, MouseButtons& b) { a = static_cast(static_cast(a) | static_cast(b)); return a; } inline ModifierKeys operator|(ModifierKeys a, ModifierKeys b) { return static_cast(static_cast(a) | static_cast(b)); } inline ModifierKeys& operator|=(ModifierKeys& a, ModifierKeys& b) { a = static_cast(static_cast(a) | static_cast(b)); return a; } /** * KeyConstants Constants for special keys */ // Special Keys const std::string KeyEsc = "Escape"; const std::string KeyEnter = "Enter"; const std::string KeyReturn = "Return"; const std::string KeyDelete = "Delete"; const std::string KeyArrowUp = "ArrowUp"; const std::string KeyArrowDown = "ArrowDown"; const std::string KeyArrowLeft = "ArrowLeft"; const std::string KeyArrowRight = "ArrowRight"; const std::string KeyF1 = "F1"; const std::string KeyF2 = "F2"; const std::string KeyF3 = "F3"; const std::string KeyF4 = "F4"; const std::string KeyF5 = "F5"; const std::string KeyF6 = "F6"; const std::string KeyF7 = "F7"; const std::string KeyF8 = "F8"; const std::string KeyF9 = "F9"; const std::string KeyF10 = "F10"; const std::string KeyF11 = "F11"; const std::string KeyF12 = "F12"; const std::string KeyPos1 = "Pos1"; - const std::string KeyEend = "End"; + const std::string KeyEnd = "End"; const std::string KeyInsert = "Insert"; const std::string KeyPageUp = "PageUp"; const std::string KeyPageDown = "PageDown"; + const std::string KeySpace = "Space"; // End special keys // XML Tags const std::string xmlTagConfigRoot = "config"; const std::string xmlTagParam = "param"; const std::string xmlTagEventVariant = "event_variant"; const std::string xmlTagAttribute = "attribute"; // XML Param const std::string xmlParameterName = "name"; const std::string xmlParameterValue = "value"; const std::string xmlParameterEventVariant = "event_variant"; const std::string xmlParameterEventClass = "class"; // Event Description const std::string xmlEventPropertyModifier = "Modifiers"; const std::string xmlEventPropertyEventButton = "EventButton"; const std::string xmlEventPropertyButtonState = "ButtonState"; const std::string xmlEventPropertyKey = "Key"; const std::string xmlEventPropertyScrollDirection = "ScrollDirection"; const std::string xmlEventPropertySignalName = "SignalName"; // Predefined internal events/signals const std::string IntDeactivateMe = "DeactivateMe"; const std::string IntLeaveWidget = "LeaveWidget"; const std::string IntEnterWidget = "EnterWidget"; } //namespace mitk #endif //ifndef MITKINTERACTEVENTCONST_H diff --git a/Core/Code/Interactions/mitkMouseModeSwitcher.cpp b/Core/Code/Interactions/mitkMouseModeSwitcher.cpp index 2c8169dfb4..f7a5f24a4b 100644 --- a/Core/Code/Interactions/mitkMouseModeSwitcher.cpp +++ b/Core/Code/Interactions/mitkMouseModeSwitcher.cpp @@ -1,110 +1,113 @@ /*=================================================================== 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 "mitkMouseModeSwitcher.h" // us #include "mitkGetModuleContext.h" #include "mitkModule.h" #include "mitkModuleRegistry.h" #include "mitkInteractionEventObserver.h" mitk::MouseModeSwitcher::MouseModeSwitcher() : m_ActiveInteractionScheme(MITK), m_ActiveMouseMode(MousePointer), m_CurrentObserver(NULL) { this->InitializeListeners(); this->SetInteractionScheme(m_ActiveInteractionScheme); } mitk::MouseModeSwitcher::~MouseModeSwitcher() { m_ServiceRegistration.Unregister(); } void mitk::MouseModeSwitcher::InitializeListeners() { if (m_CurrentObserver.IsNull()) { m_CurrentObserver = mitk::DisplayInteractor::New(); m_CurrentObserver->LoadStateMachine("DisplayInteraction.xml"); m_CurrentObserver->LoadEventConfig("DisplayConfigMITK.xml"); // Register as listener via micro services + ServiceProperties props; + props["name"] = std::string("DisplayInteractor"); m_ServiceRegistration = GetModuleContext()->RegisterService( - m_CurrentObserver.GetPointer()); + m_CurrentObserver.GetPointer(),props); + } } void mitk::MouseModeSwitcher::SetInteractionScheme(InteractionScheme scheme) { switch (scheme) { case MITK: { m_CurrentObserver->LoadEventConfig("DisplayConfigMITK.xml"); } break; case PACS: { m_CurrentObserver->LoadEventConfig("DisplayConfigPACS.xml"); } break; } m_ActiveInteractionScheme = scheme; this->InvokeEvent(MouseModeChangedEvent()); } void mitk::MouseModeSwitcher::SelectMouseMode(MouseMode mode) { if (m_ActiveInteractionScheme != PACS) return; switch (mode) { case MousePointer: { m_CurrentObserver->LoadEventConfig("DisplayConfigPACS.xml"); break; } // case 0 case Scroll: { m_CurrentObserver->AddEventConfig("DisplayConfigPACSScroll.xml"); break; } case LevelWindow: { m_CurrentObserver->AddEventConfig("DisplayConfigPACSLevelWindow.xml"); break; } case Zoom: { m_CurrentObserver->AddEventConfig("DisplayConfigPACSZoom.xml"); break; } case Pan: { m_CurrentObserver->AddEventConfig("DisplayConfigPACSPan.xml"); break; } } // end switch (mode) m_ActiveMouseMode = mode; this->InvokeEvent(MouseModeChangedEvent()); } mitk::MouseModeSwitcher::MouseMode mitk::MouseModeSwitcher::GetCurrentMouseMode() const { return m_ActiveMouseMode; } diff --git a/Core/Code/Interfaces/mitkIShaderRepository.cpp b/Core/Code/Interfaces/mitkIShaderRepository.cpp new file mode 100644 index 0000000000..506e67be26 --- /dev/null +++ b/Core/Code/Interfaces/mitkIShaderRepository.cpp @@ -0,0 +1,75 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkIShaderRepository.h" + + +namespace mitk { + +IShaderRepository::~IShaderRepository() +{ +} + +struct IShaderRepository::ShaderPrivate +{ + ShaderPrivate() : id(-1) {} + + int id; + std::string name; + std::string materialXml; +}; + +IShaderRepository::Shader::Shader() + : d(new ShaderPrivate) +{ +} + +void IShaderRepository::Shader::SetId(int id) +{ + d->id = id; +} + +IShaderRepository::Shader::~Shader() +{ + delete d; +} + +int IShaderRepository::Shader::GetId() const +{ + return d->id; +} + +std::string IShaderRepository::Shader::GetName() const +{ + return d->name; +} + +std::string IShaderRepository::Shader::GetMaterialXml() const +{ + return d->materialXml; +} + +void IShaderRepository::Shader::SetName(const std::string& name) +{ + d->name = name; +} + +void IShaderRepository::Shader::SetMaterialXml(const std::string &xml) +{ + d->materialXml = xml; +} + +} diff --git a/Core/Code/Interfaces/mitkIShaderRepository.h b/Core/Code/Interfaces/mitkIShaderRepository.h new file mode 100644 index 0000000000..ffa16dfdc6 --- /dev/null +++ b/Core/Code/Interfaces/mitkIShaderRepository.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 MITKISHADERREPOSITORY_H +#define MITKISHADERREPOSITORY_H + +#include + +#include "mitkCommon.h" +#include "mitkServiceInterface.h" + +#include + +class vtkActor; + +namespace mitk { + +class DataNode; +class BaseRenderer; + +/** + * \brief Management class for vtkShader XML descriptions. + * + * Loads XML shader files from std::istream objects and adds default properties + * for each shader object (shader uniforms) to the specified mitk::DataNode. + * + * Additionally, it provides a utility function for applying properties for shaders + * in mappers. + */ +struct MITK_CORE_EXPORT IShaderRepository +{ + + struct ShaderPrivate; + + class MITK_CORE_EXPORT Shader : public itk::LightObject + { + + public: + + mitkClassMacro( Shader, itk::Object ) + itkFactorylessNewMacro( Self ) + + ~Shader(); + + int GetId() const; + std::string GetName() const; + std::string GetMaterialXml() const; + + protected: + + Shader(); + + void SetId(int id); + void SetName(const std::string& name); + void SetMaterialXml(const std::string& xml); + + private: + + // not implemented + Shader(const Shader&); + Shader& operator=(const Shader&); + + ShaderPrivate* d; + + }; + + virtual ~IShaderRepository(); + + virtual std::list GetShaders() const = 0; + + /** + * \brief Return the named shader. + * + * \param name The shader name. + * \return A Shader object. + * + * Names might not be unique. Use the shader id to uniquely identify a shader. + */ + virtual Shader::Pointer GetShader(const std::string& name) const = 0; + + /** + * \brief Return the shader identified by the given id. + * @param id The shader id. + * @return The shader object or null if the id is unknown. + */ + virtual Shader::Pointer GetShader(int id) const = 0; + + /** \brief Adds all parsed shader uniforms to property list of the given DataNode; + * used by mappers. + */ + virtual void AddDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, + bool overwrite) const = 0; + + /** \brief Applies shader and shader specific variables of the specified DataNode + * to the VTK object by updating the shader variables of its vtkProperty. + */ + virtual void ApplyProperties(mitk::DataNode* node, vtkActor* actor, + mitk::BaseRenderer* renderer, itk::TimeStamp& MTime) const = 0; + + /** \brief Loads a shader from a given file. Make sure that this stream is in the XML shader format. + * + * \return A unique id for the loaded shader which can be used to unload it. + */ + virtual int LoadShader(std::istream& stream, const std::string& name) = 0; + + /** + * \brief Unload a previously loaded shader. + * \param id The unique shader id returned by LoadShader. + * \return \c true if the shader id was found and the shader was successfully unloaded, + * \c false otherwise. + */ + virtual bool UnloadShader(int id) = 0; +}; + +} + +US_DECLARE_SERVICE_INTERFACE(mitk::IShaderRepository, "org.mitk.services.IShaderRepository/1.0") + +#endif // MITKISHADERREPOSITORY_H diff --git a/Core/Code/Interfaces/mitkInteractionEventObserver.cpp b/Core/Code/Interfaces/mitkInteractionEventObserver.cpp index 785f1ef263..cb98786e3f 100644 --- a/Core/Code/Interfaces/mitkInteractionEventObserver.cpp +++ b/Core/Code/Interfaces/mitkInteractionEventObserver.cpp @@ -1,22 +1,41 @@ /*=================================================================== 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 "mitkInteractionEventObserver.h" +mitk::InteractionEventObserver::InteractionEventObserver() : m_IsEnabled(true) +{ +} + mitk::InteractionEventObserver::~InteractionEventObserver() { } + +void mitk::InteractionEventObserver::Disable() +{ + m_IsEnabled = false; +} + +void mitk::InteractionEventObserver::Enable() +{ + m_IsEnabled = true; +} + +bool mitk::InteractionEventObserver::IsEnabled() +{ + return m_IsEnabled; +} diff --git a/Core/Code/Interfaces/mitkInteractionEventObserver.h b/Core/Code/Interfaces/mitkInteractionEventObserver.h index 49f44208fc..de1cee1fe0 100644 --- a/Core/Code/Interfaces/mitkInteractionEventObserver.h +++ b/Core/Code/Interfaces/mitkInteractionEventObserver.h @@ -1,62 +1,69 @@ /*=================================================================== 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 InteractionEventObserver_h #define InteractionEventObserver_h #include #include "mitkServiceInterface.h" #include "mitkInteractionEvent.h" namespace mitk { /** * \class InteractionEventObserver * \brief Base class to implement InteractionEventObservers. * * This class also provides state machine infrastructure, * but usage thereof is optional. See the Notify method for more information. */ struct MITK_CORE_EXPORT InteractionEventObserver { + InteractionEventObserver(); virtual ~InteractionEventObserver(); /** * By this method all registered EventObersers are notified about every InteractionEvent, * the isHandled flag indicates if a DataInteractor has already handled that event. * InteractionEventObserver that trigger an action when observing an event may consider * this in order to not confuse the user by, triggering several independent action with one * single user event (such as a mouse click) * * If you want to use the InteractionEventObserver as a state machine give the event to the state machine by implementing, e.g. \code void mitk::InteractionEventObserver::Notify(InteractionEvent::Pointer interactionEvent, bool isHandled) { if (!isHandled) { this->HandleEvent(interactionEvent, NULL); } } \endcode * This overwrites the FilterEvents function of the EventStateMachine to ignore the DataNode, since InteractionEventObservers are not associated with one. virtual bool FilterEvents(InteractionEvent* interactionEvent, DataNode* dataNode); */ virtual void Notify(InteractionEvent* interactionEvent,bool isHandled) = 0; + + void Disable(); + void Enable(); + bool IsEnabled(); + private: + bool m_IsEnabled; }; } /* namespace mitk */ US_DECLARE_SERVICE_INTERFACE(mitk::InteractionEventObserver, "org.mitk.InteractionEventObserver") #endif /* InteractionEventObserver_h */ diff --git a/Core/Code/Rendering/mitkGLMapper.cpp b/Core/Code/Rendering/mitkGLMapper.cpp index e383a306d4..043e31b624 100644 --- a/Core/Code/Rendering/mitkGLMapper.cpp +++ b/Core/Code/Rendering/mitkGLMapper.cpp @@ -1,56 +1,60 @@ /*=================================================================== 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 "mitkGL.h" #include "mitkGLMapper.h" mitk::GLMapper::GLMapper() { } mitk::GLMapper::~GLMapper() { } -void mitk::GLMapper::MitkRender(mitk::BaseRenderer* renderer, mitk::VtkPropRenderer::RenderType /* type */) +void mitk::GLMapper::MitkRender(mitk::BaseRenderer* renderer, mitk::VtkPropRenderer::RenderType type ) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if(!visible) return; - Paint(renderer); + // the if-condition ensures that Paint(renderer) is only called once, otherwise it will be called four times + // it does not mean that OpenGL renders only an opaque scene + if(type == mitk::VtkPropRenderer::Opaque) + Paint(renderer); + } bool mitk::GLMapper::IsVtkBased() const { return false; } void mitk::GLMapper::ApplyColorAndOpacityProperties(mitk::BaseRenderer* renderer, vtkActor* /*actor*/) { float rgba[4]={1.0f,1.0f,1.0f,1.0f}; // check for color prop and use it for rendering if it exists GetDataNode()->GetColor(rgba, renderer, "color"); // check for opacity prop and use it for rendering if it exists GetDataNode()->GetOpacity(rgba[3], renderer, "opacity"); glColor4fv(rgba); } diff --git a/Core/Code/Rendering/mitkGLMapper.h b/Core/Code/Rendering/mitkGLMapper.h index cf35d94971..e170a44aa4 100644 --- a/Core/Code/Rendering/mitkGLMapper.h +++ b/Core/Code/Rendering/mitkGLMapper.h @@ -1,102 +1,102 @@ /*=================================================================== 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 MITKGLMAPPER_H_HEADER_INCLUDED_C197C872 #define MITKGLMAPPER_H_HEADER_INCLUDED_C197C872 #include #include "mitkMapper.h" #include "mitkBaseRenderer.h" #include "mitkVtkPropRenderer.h" namespace mitk { /** \brief Base class of all OpenGL-based mappers. * * Those must implement the abstract method Paint(BaseRenderer), which is called by * method MitkRender(). * The Paint() method should be used to paint into a renderer via OpenGL-drawing commands. * The OpenGL context matrices (GL_MODELVIEWMATRIX/GL_PROJECTIONMATRIX) are preinitialized by * the mitkVtkPropRenderer so that the origin of the 2D-coordinate system of the 2D render * window is located in the lower left corner and has the width and height in display pixels * of the respective renderwindow. The x-axis is horizontally oriented, while the y-axis is * vertically oriented. The drawing commands are directly interpreted as display coordinates. * ApplyColorAndOpacity() can be used in the subclasses to apply color and opacity properties * read from the PropertyList. * * \ingroup Mapper */ class MITK_CORE_EXPORT GLMapper : public Mapper { public: /** \brief Do the painting into the \a renderer */ virtual void Paint(mitk::BaseRenderer *renderer) = 0; /** \brief Apply color and opacity properties read from the PropertyList - * @deprecated Use ApplyColorAndOpacityProperties(...) instead + * \deprecatedSince{2013_03} Use ApplyColorAndOpacityProperties(...) instead */ DEPRECATED(inline virtual void ApplyProperties(mitk::BaseRenderer* renderer)) { ApplyColorAndOpacityProperties(renderer); } /** \brief Apply color and opacity properties read from the PropertyList. * The actor is not used in the GLMappers. Called by mapper subclasses. */ virtual void ApplyColorAndOpacityProperties(mitk::BaseRenderer* renderer, vtkActor* actor = NULL); /** \brief Checks visibility and calls the paint method * * Note: The enumeration is disregarded, since OpenGL rendering only needs a * single render pass. */ void MitkRender(mitk::BaseRenderer* renderer, mitk::VtkPropRenderer::RenderType type); /** \brief Returns whether this is a vtk-based mapper * \return false, since all mappers deriving from this class are OpenGL mappers - * @deprecated All mappers of superclass VTKMapper are vtk based, use a dynamic_cast instead + * \deprecatedSince{2013_03} All mappers of superclass VTKMapper are vtk based, use a dynamic_cast instead */ DEPRECATED( virtual bool IsVtkBased() const ); /** \brief Returns whether this mapper allows picking in the renderwindow virtual bool IsPickable() const { return false; }*/ protected: /** constructor */ GLMapper(); /** virtual destructor in order to derive from this class */ virtual ~GLMapper(); private: /** copy constructor */ GLMapper( const GLMapper &); /** assignment operator */ GLMapper & operator=(const GLMapper &); }; } // namespace mitk #endif /* MITKGLMAPPER2D_H_HEADER_INCLUDED_C197C872 */ diff --git a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp index d171a18839..ef50187136 100644 --- a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp +++ b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp @@ -1,1031 +1,1077 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include "mitkImageStatisticsHolder.h" #include "mitkPlaneClipping.h" //MITK Rendering #include "mitkImageVtkMapper2D.h" #include "vtkMitkThickSlicesFilter.h" #include "vtkMitkLevelWindowFilter.h" #include "vtkNeverTranslucentTexture.h" //VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include //ITK #include +#include mitk::ImageVtkMapper2D::ImageVtkMapper2D() { } mitk::ImageVtkMapper2D::~ImageVtkMapper2D() { //The 3D RW Mapper (Geometry2DDataVtkMapper3D) is listening to this event, //in order to delete the images from the 3D RW. this->InvokeEvent( itk::DeleteEvent() ); } //set the two points defining the textured plane according to the dimension and spacing void mitk::ImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer* renderer, vtkFloatingPointType planeBounds[6]) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); float depth = this->CalculateLayerDepth(renderer); //Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct //plane size in crosshair rotation and swivel mode. localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth); //These two points define the axes of the plane in combination with the origin. //Point 1 is the x-axis and point 2 the y-axis. //Each plane is transformed according to the view (axial, coronal and saggital) afterwards. localStorage->m_Plane->SetPoint1(planeBounds[1] , planeBounds[2], depth); //P1: (xMax, yMin, depth) localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); //P2: (xMin, yMax, depth) } float mitk::ImageVtkMapper2D::CalculateLayerDepth(mitk::BaseRenderer* renderer) { //get the clipping range to check how deep into z direction we can render images double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1]; //Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined float depth = -maxRange*0.01; // divide by 100 int layer = 0; GetDataNode()->GetIntProperty( "layer", layer, renderer); //add the layer property for each image to render images with a higher layer on top of the others depth += layer*10; //*10: keep some room for each image (e.g. for QBalls in between) if(depth > 0.0f) { depth = 0.0f; MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead."; } return depth; } const mitk::Image* mitk::ImageVtkMapper2D::GetInput( void ) { return static_cast< const mitk::Image * >( GetDataNode()->GetData() ); } vtkProp* mitk::ImageVtkMapper2D::GetVtkProp(mitk::BaseRenderer* renderer) { //return the actor corresponding to the renderer return m_LSH.GetLocalStorage(renderer)->m_Actors; } void mitk::ImageVtkMapper2D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); mitk::DataNode* datanode = this->GetDataNode(); if ( input == NULL || input->IsInitialized() == false ) { return; } //check if there is a valid worldGeometry const Geometry2D *worldGeometry = renderer->GetCurrentWorldGeometry2D(); if( ( worldGeometry == NULL ) || ( !worldGeometry->IsValid() ) || ( !worldGeometry->HasReferenceGeometry() )) { return; } input->Update(); // early out if there is no intersection of the current rendering geometry // and the geometry of the image that is to be rendered. if ( !RenderingGeometryIntersectsImage( worldGeometry, input->GetSlicedGeometry() ) ) { // set image to NULL, to clear the texture in 3D, because // the latest image is used there if the plane is out of the geometry // see bug-13275 localStorage->m_ReslicedImage = NULL; localStorage->m_Mapper->SetInput( localStorage->m_EmptyPolyData ); return; } //set main input for ExtractSliceFilter localStorage->m_Reslicer->SetInput(input); localStorage->m_Reslicer->SetWorldGeometry(worldGeometry); localStorage->m_Reslicer->SetTimeStep( this->GetTimestep() ); //set the transformation of the image to adapt reslice axis localStorage->m_Reslicer->SetResliceTransformByGeometry( input->GetTimeSlicedGeometry()->GetGeometry3D( this->GetTimestep() ) ); //is the geometry of the slice based on the input image or the worldgeometry? bool inPlaneResampleExtentByGeometry = false; datanode->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer); localStorage->m_Reslicer->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry); // Initialize the interpolation mode for resampling; switch to nearest // neighbor if the input image is too small. if ( (input->GetDimension() >= 3) && (input->GetDimension(2) > 1) ) { VtkResliceInterpolationProperty *resliceInterpolationProperty; datanode->GetProperty( - resliceInterpolationProperty, "reslice interpolation" ); + resliceInterpolationProperty, "reslice interpolation" ); int interpolationMode = VTK_RESLICE_NEAREST; if ( resliceInterpolationProperty != NULL ) { interpolationMode = resliceInterpolationProperty->GetInterpolation(); } switch ( interpolationMode ) { case VTK_RESLICE_NEAREST: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); break; case VTK_RESLICE_LINEAR: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_LINEAR); break; case VTK_RESLICE_CUBIC: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_CUBIC); break; } } else { localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); } //set the vtk output property to true, makes sure that no unneeded mitk image convertion //is done. localStorage->m_Reslicer->SetVtkOutputRequest(true); //Thickslicing int thickSlicesMode = 0; int thickSlicesNum = 1; // Thick slices parameters if( input->GetPixelType().GetNumberOfComponents() == 1 ) // for now only single component are allowed { DataNode *dn=renderer->GetCurrentWorldGeometry2DNode(); if(dn) { ResliceMethodProperty *resliceMethodEnumProperty=0; if( dn->GetProperty( resliceMethodEnumProperty, "reslice.thickslices" ) && resliceMethodEnumProperty ) thickSlicesMode = resliceMethodEnumProperty->GetValueAsId(); IntProperty *intProperty=0; if( dn->GetProperty( intProperty, "reslice.thickslices.num" ) && intProperty ) { thickSlicesNum = intProperty->GetValue(); if(thickSlicesNum < 1) thickSlicesNum=1; if(thickSlicesNum > 10) thickSlicesNum=10; } } else { MITK_WARN << "no associated widget plane data tree node found"; } } const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( worldGeometry ); if(thickSlicesMode > 0) { double dataZSpacing = 1.0; Vector3D normInIndex, normal; if ( planeGeometry != NULL ){ normal = planeGeometry->GetNormal(); }else{ const mitk::AbstractTransformGeometry* abstractGeometry = dynamic_cast< const AbstractTransformGeometry * >(worldGeometry); if(abstractGeometry != NULL) normal = abstractGeometry->GetPlane()->GetNormal(); else return; //no fitting geometry set } normal.Normalize(); input->GetTimeSlicedGeometry()->GetGeometry3D( this->GetTimestep() )->WorldToIndex( normal, normInIndex ); dataZSpacing = 1.0 / normInIndex.GetNorm(); localStorage->m_Reslicer->SetOutputDimensionality( 3 ); localStorage->m_Reslicer->SetOutputSpacingZDirection(dataZSpacing); localStorage->m_Reslicer->SetOutputExtentZDirection( -thickSlicesNum, 0+thickSlicesNum ); // Do the reslicing. Modified() is called to make sure that the reslicer is // executed even though the input geometry information did not change; this // is necessary when the input /em data, but not the /em geometry changes. localStorage->m_TSFilter->SetThickSliceMode( thickSlicesMode-1 ); localStorage->m_TSFilter->SetInput( localStorage->m_Reslicer->GetVtkOutput() ); //vtkFilter=>mitkFilter=>vtkFilter update mechanism will fail without calling manually localStorage->m_Reslicer->Modified(); localStorage->m_Reslicer->Update(); localStorage->m_TSFilter->Modified(); localStorage->m_TSFilter->Update(); localStorage->m_ReslicedImage = localStorage->m_TSFilter->GetOutput(); } else { //this is needed when thick mode was enable bevore. These variable have to be reset to default values localStorage->m_Reslicer->SetOutputDimensionality( 2 ); localStorage->m_Reslicer->SetOutputSpacingZDirection(1.0); localStorage->m_Reslicer->SetOutputExtentZDirection( 0, 0 ); localStorage->m_Reslicer->Modified(); //start the pipeline with updating the largest possible, needed if the geometry of the input has changed localStorage->m_Reslicer->UpdateLargestPossibleRegion(); localStorage->m_ReslicedImage = localStorage->m_Reslicer->GetVtkOutput(); } - // Bounds information for reslicing (only reuqired if reference geometry // is present) //this used for generating a vtkPLaneSource with the right size vtkFloatingPointType sliceBounds[6]; for ( int i = 0; i < 6; ++i ) { sliceBounds[i] = 0.0; } localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds); //get the spacing of the slice localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing(); - // calculate minimum bounding rect of IMAGE in texture - vtkFloatingPointType textureClippingBounds[6]; - for ( int i = 0; i < 6; ++i ) { - textureClippingBounds[i] = 0.0; + vtkFloatingPointType textureClippingBounds[6]; + for ( int i = 0; i < 6; ++i ) + { + textureClippingBounds[i] = 0.0; + } + // Calculate the actual bounds of the transformed plane clipped by the + // dataset bounding box; this is required for drawing the texture at the + // correct position during 3D mapping. + mitk::PlaneClipping::CalculateClippedPlaneBounds( input->GetGeometry(), planeGeometry, textureClippingBounds ); + + textureClippingBounds[0] = static_cast< int >( textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5 ); + textureClippingBounds[1] = static_cast< int >( textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5 ); + textureClippingBounds[2] = static_cast< int >( textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5 ); + textureClippingBounds[3] = static_cast< int >( textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5 ); + + //clipping bounds for cutting the image + localStorage->m_LevelWindowFilter->SetClippingBounds(textureClippingBounds); } - // Calculate the actual bounds of the transformed plane clipped by the - // dataset bounding box; this is required for drawing the texture at the - // correct position during 3D mapping. - mitk::PlaneClipping::CalculateClippedPlaneBounds( input->GetGeometry(), planeGeometry, textureClippingBounds ); - - textureClippingBounds[0] = static_cast< int >( textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5 ); - textureClippingBounds[1] = static_cast< int >( textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5 ); - textureClippingBounds[2] = static_cast< int >( textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5 ); - textureClippingBounds[3] = static_cast< int >( textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5 ); //get the number of scalar components to distinguish between different image types int numberOfComponents = localStorage->m_ReslicedImage->GetNumberOfScalarComponents(); //get the binary property bool binary = false; bool binaryOutline = false; datanode->GetBoolProperty( "binary", binary, renderer ); if(binary) //binary image { datanode->GetBoolProperty( "outline binary", binaryOutline, renderer ); if(binaryOutline) //contour rendering { if ( input->GetPixelType().GetBpe() <= 8 ) { //generate contours/outlines localStorage->m_OutlinePolyData = CreateOutlinePolyData(renderer); float binaryOutlineWidth(1.0); if ( datanode->GetFloatProperty( "outline width", binaryOutlineWidth, renderer ) ) { if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) { float binaryOutlineShadowWidth(1.5); datanode->GetFloatProperty( "outline shadow width", binaryOutlineShadowWidth, renderer ); dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0)) - ->GetProperty()->SetLineWidth( binaryOutlineWidth * binaryOutlineShadowWidth ); + ->GetProperty()->SetLineWidth( binaryOutlineWidth * binaryOutlineShadowWidth ); } localStorage->m_Actor->GetProperty()->SetLineWidth( binaryOutlineWidth ); } } else { binaryOutline = false; - this->ApplyLookuptable(renderer, textureClippingBounds); + this->ApplyLookuptable(renderer); MITK_WARN << "Type of all binary images should be (un)signed char. Outline does not work on other pixel types!"; } } else //standard binary image { if(numberOfComponents != 1) { MITK_ERROR << "Rendering Error: Binary Images with more then 1 component are not supported!"; } } } if (!(numberOfComponents == 1 || numberOfComponents == 3 || numberOfComponents == 4)) { MITK_WARN << "Unknown number of components!"; } - this->ApplyLookuptable(renderer, textureClippingBounds); + this->ApplyOpacity( renderer ); + this->ApplyRenderingMode(renderer); // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter) localStorage->m_Texture->MapColorScalarsThroughLookupTableOff(); - this->ApplyColor( renderer ); - this->ApplyOpacity( renderer ); + //connect the input with the levelwindow filter + localStorage->m_LevelWindowFilter->SetInput(localStorage->m_ReslicedImage); + //connect the texture with the output of the levelwindow filter + + // check for texture interpolation property + bool textureInterpolation = false; + GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); + + //set the interpolation modus according to the property + localStorage->m_Texture->SetInterpolate(textureInterpolation); + + localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort()); + this->TransformActor( renderer ); vtkActor* contourShadowActor = dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0)); if(binary && binaryOutline) //connect the mapper with the polyData which contains the lines { //We need the contour for the binary outline property as actor localStorage->m_Mapper->SetInput(localStorage->m_OutlinePolyData); localStorage->m_Actor->SetTexture(NULL); //no texture for contours bool binaryOutlineShadow( false ); datanode->GetBoolProperty( "outline binary shadow", binaryOutlineShadow, renderer ); if ( binaryOutlineShadow ) contourShadowActor->SetVisibility( true ); else contourShadowActor->SetVisibility( false ); - } else { //Connect the mapper with the input texture. This is the standard case. //setup the textured plane this->GeneratePlane( renderer, sliceBounds ); //set the plane as input for the mapper localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort()); //set the texture for the actor localStorage->m_Actor->SetTexture(localStorage->m_Texture); contourShadowActor->SetVisibility( false ); } // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } +void mitk::ImageVtkMapper2D::ApplyLevelWindow(mitk::BaseRenderer *renderer) +{ + LocalStorage *localStorage = this->GetLocalStorage( renderer ); + + LevelWindow levelWindow; + this->GetDataNode()->GetLevelWindow( levelWindow, renderer, "levelwindow" ); + localStorage->m_LevelWindowFilter->GetLookupTable()->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); + + mitk::LevelWindow opacLevelWindow; + if( this->GetDataNode()->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) + { + //pass the opaque level window to the filter + localStorage->m_LevelWindowFilter->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); + localStorage->m_LevelWindowFilter->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); + } + else + { + //no opaque level window + localStorage->m_LevelWindowFilter->SetMinOpacity(0.0); + localStorage->m_LevelWindowFilter->SetMaxOpacity(255.0); + } +} + void mitk::ImageVtkMapper2D::ApplyColor( mitk::BaseRenderer* renderer ) { LocalStorage *localStorage = this->GetLocalStorage( renderer ); float rgb[3]= { 1.0f, 1.0f, 1.0f }; // check for color prop and use it for rendering if it exists // binary image hovering & binary image selection bool hover = false; bool selected = false; GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); GetDataNode()->GetBoolProperty("selected", selected, renderer); if(hover && !selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty - ("binaryimage.hoveringcolor", renderer)); + ("binaryimage.hoveringcolor", renderer)); if(colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); } else { GetDataNode()->GetColor( rgb, renderer, "color" ); } } if(selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty - ("binaryimage.selectedcolor", renderer)); + ("binaryimage.selectedcolor", renderer)); if(colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); } else { GetDataNode()->GetColor(rgb, renderer, "color"); } } if(!hover && !selected) { GetDataNode()->GetColor( rgb, renderer, "color" ); } double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv); localStorage->m_Actor->GetProperty()->SetColor(rgbConv); if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) { float rgb[3]= { 1.0f, 1.0f, 1.0f }; mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty - ("outline binary shadow color", renderer)); + ("outline binary shadow color", renderer)); if(colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); } double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetColor(rgbConv); } } void mitk::ImageVtkMapper2D::ApplyOpacity( mitk::BaseRenderer* renderer ) { LocalStorage* localStorage = this->GetLocalStorage( renderer ); float opacity = 1.0f; // check for opacity prop and use it for rendering if it exists GetDataNode()->GetOpacity( opacity, renderer, "opacity" ); //set the opacity according to the properties localStorage->m_Actor->GetProperty()->SetOpacity(opacity); if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) { dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetOpacity(opacity); } } -void mitk::ImageVtkMapper2D::ApplyLookuptable( mitk::BaseRenderer* renderer, vtkFloatingPointType* bounds ) +void mitk::ImageVtkMapper2D::ApplyRenderingMode( mitk::BaseRenderer* renderer ) { - //Have the following 4 different use cases how to generate the lookuptable: - //1. We have a binary image -> The lut range is set to 0.0, 1.0 - //2. The user sets a lut we can use - //3. The user sets a transfer function we can use - //4. Nothing defined: The default color lookuptable is used - //@Warning: If the user sets a lut and a transfer function the lut will be used! LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); - bool binary = false; + bool binary = false; this->GetDataNode()->GetBoolProperty( "binary", binary, renderer ); - - float blackOpacity = 0.0; - if (!binary) - { - this->GetDataNode()->GetFloatProperty( "black opacity", blackOpacity, renderer); - } - - vtkLookupTable *usedLookupTable = localStorage->m_DefaultLookupTable; - vtkScalarsToColors *usedScalarsToColors = localStorage->m_DefaultLookupTable; - - // If lookup table or transferfunction use is requested... - mitk::LookupTableProperty::Pointer lookupTableProp = dynamic_cast(this->GetDataNode()->GetProperty("LookupTable")); - mitk::TransferFunctionProperty::Pointer transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("Image Rendering.Transfer Function",renderer )); - if(binary) // is it a binary image? { - usedScalarsToColors = usedLookupTable = localStorage->m_BinaryLookupTable; + //for binary images, we always use our default LuT and map every value to (0,1) + //the opacity of 0 will always be 0.0. We never a apply a LuT/TfF nor a level window. + localStorage->m_LevelWindowFilter->SetLookupTable(localStorage->m_BinaryLookupTable); } - else if( lookupTableProp.IsNotNull() ) // is a lookuptable set? + else { - if( transferFunctionProp.IsNotNull() ) + //all other image types can make use of the rendering mode + int renderingMode = mitk::RenderingModeProperty::LEVELWINDOW_COLOR; + mitk::RenderingModeProperty::Pointer mode = dynamic_cast(this->GetDataNode()->GetProperty( "Image Rendering.Mode", renderer )); + if(mode.IsNotNull()) { - MITK_WARN << "A LookupTable and a transfer function TransferFunction property is set! Only the Image Rendering.Transfer Function will be used. If you want to use the color transfer function, remove or rename the LookupTable property."; + renderingMode = mode->GetRenderingMode(); } - //If a lookup table is supplied by the user: - //only update the lut, when the properties have changed... - if( lookupTableProp->GetLookupTable()->GetMTime() - <= this->GetDataNode()->GetPropertyList()->GetMTime() ) + switch(renderingMode) { - lookupTableProp->GetLookupTable()->ChangeOpacityForAll( lookupTableProp->GetLookupTable()->GetVtkLookupTable()->GetAlpha()*localStorage->m_Actor->GetProperty()->GetOpacity() ); - lookupTableProp->GetLookupTable()->ChangeOpacity(0, blackOpacity); + case mitk::RenderingModeProperty::LEVELWINDOW_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_Color"; + localStorage->m_LevelWindowFilter->SetLookupTable( localStorage->m_DefaultLookupTable ); + this->ApplyLevelWindow( renderer ); + break; + case mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_LookupTable_Color"; + this->ApplyLookuptable( renderer ); + this->ApplyLevelWindow( renderer ); + break; + case mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_LEVELWINDOW_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_ColorTransferFunction_Color"; + this->ApplyColorTransferFunction( renderer ); + this->ApplyLevelWindow( renderer ); + break; + case mitk::RenderingModeProperty::LOOKUPTABLE_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = LookupTable_Color"; + this->ApplyLookuptable( renderer ); + break; + case mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = ColorTransferFunction_Color"; + this->ApplyColorTransferFunction( renderer ); + break; + default: + MITK_ERROR << "No valid 'Image Rendering.Mode' set"; + break; } - //If the user defines a lut, we dont want to use the color and take white instead. - dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(1.0, 1.0, 1.0); - localStorage->m_Actor->GetProperty()->SetColor(1.0, 1.0, 1.0); - usedScalarsToColors = usedLookupTable = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); } - else if(transferFunctionProp.IsNotNull()) // is a color transfer function set? - { - usedScalarsToColors = transferFunctionProp->GetValue()->GetColorTransferFunction(); - usedLookupTable = 0; - } - else - { - //default lookuptable - LevelWindow levelWindow; - GetDataNode()->GetLevelWindow( levelWindow, renderer, "levelwindow" ); - usedLookupTable->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); - } - + //we apply color for all images (including binaries). this->ApplyColor( renderer ); +} - // check for texture interpolation property - bool textureInterpolation = false; - GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); +void mitk::ImageVtkMapper2D::ApplyLookuptable( mitk::BaseRenderer* renderer ) +{ + LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); + vtkLookupTable* usedLookupTable = localStorage->m_ColorLookupTable; - //set the interpolation modus according to the property - localStorage->m_Texture->SetInterpolate(textureInterpolation); + // If lookup table or transferfunction use is requested... + mitk::LookupTableProperty::Pointer lookupTableProp = dynamic_cast(this->GetDataNode()->GetProperty("LookupTable")); - mitk::LevelWindow opacLevelWindow; - if( GetDataNode()->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) + if( lookupTableProp.IsNotNull() ) // is a lookuptable set? { - //pass the opaque level window to the filter - localStorage->m_LevelWindowFilter->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); - localStorage->m_LevelWindowFilter->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); + usedLookupTable = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); } else { - //no opaque level window - localStorage->m_LevelWindowFilter->SetMinOpacity(0.0); - localStorage->m_LevelWindowFilter->SetMaxOpacity(255.0); + MITK_WARN << "Image Rendering.Mode was set to use a lookup table but there is no property 'LookupTable'. A default (rainbow) lookup table will be used."; } - - localStorage->m_LevelWindowFilter->SetLookupTable(usedScalarsToColors); - localStorage->m_LevelWindowFilter->SetInput(localStorage->m_ReslicedImage); - localStorage->m_LevelWindowFilter->SetClippingBounds(bounds); - //connect the texture with the output of the levelwindow filter - localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort()); + localStorage->m_LevelWindowFilter->SetLookupTable(usedLookupTable); } +void mitk::ImageVtkMapper2D::ApplyColorTransferFunction(mitk::BaseRenderer *renderer) +{ + mitk::TransferFunctionProperty::Pointer transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("Image Rendering.Transfer Function",renderer )); + + if( transferFunctionProp.IsNull() ) + { + MITK_ERROR << "'Image Rendering.Mode'' was set to use a color transfer function but there is no property 'Image Rendering.Transfer Function'. Nothing will be done."; + return; + } + LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); + //pass the transfer function to our level window filter + localStorage->m_LevelWindowFilter->SetLookupTable(transferFunctionProp->GetValue()->GetColorTransferFunction()); +} void mitk::ImageVtkMapper2D::Update(mitk::BaseRenderer* renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) { return; } mitk::Image* data = const_cast( this->GetInput() ); if ( data == NULL ) { return; } // Calculate time step of the input data for the specified renderer (integer value) this->CalculateTimeStep( renderer ); // Check if time step is valid const TimeSlicedGeometry *dataTimeGeometry = data->GetTimeSlicedGeometry(); if ( ( dataTimeGeometry == NULL ) - || ( dataTimeGeometry->GetTimeSteps() == 0 ) - || ( !dataTimeGeometry->IsValidTime( this->GetTimestep() ) ) ) + || ( dataTimeGeometry->GetTimeSteps() == 0 ) + || ( !dataTimeGeometry->IsValidTime( this->GetTimestep() ) ) ) { return; } const DataNode *node = this->GetDataNode(); data->UpdateOutputInformation(); LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); //check if something important has changed and we need to rerender if ( (localStorage->m_LastUpdateTime < node->GetMTime()) //was the node modified? - || (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) //Was the data modified? - || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2DUpdateTime()) //was the geometry modified? - || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2D()->GetMTime()) - || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) //was a property modified? - || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) + || (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) //Was the data modified? + || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2DUpdateTime()) //was the geometry modified? + || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2D()->GetMTime()) + || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) //was a property modified? + || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) { this->GenerateDataForRenderer( renderer ); } // since we have checked that nothing important has changed, we can set // m_LastUpdateTime to the current time localStorage->m_LastUpdateTime.Modified(); } void mitk::ImageVtkMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { mitk::Image::Pointer image = dynamic_cast(node->GetData()); // Properties common for both images and segmentations node->AddProperty( "depthOffset", mitk::FloatProperty::New( 0.0 ), renderer, overwrite ); node->AddProperty( "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "outline width", mitk::FloatProperty::New( 1.0 ), renderer, overwrite ); node->AddProperty( "outline binary shadow", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "outline binary shadow color", ColorProperty::New(0.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "outline shadow width", mitk::FloatProperty::New( 1.5 ), renderer, overwrite ); if(image->IsRotated()) node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC) ); else node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ); node->AddProperty( "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ); // set to user configurable default value (see global options) node->AddProperty( "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ); node->AddProperty( "bounding box", mitk::BoolProperty::New( false ) ); + mitk::RenderingModeProperty::Pointer renderingModeProperty = mitk::RenderingModeProperty::New(); + node->AddProperty( "Image Rendering.Mode", renderingModeProperty); + std::string photometricInterpretation; // DICOM tag telling us how pixel values should be displayed if ( node->GetStringProperty( "dicom.pixel.PhotometricInterpretation", photometricInterpretation ) ) { // modality provided by DICOM or other reader if ( photometricInterpretation.find("MONOCHROME1") != std::string::npos ) // meaning: display MINIMUM pixels as WHITE { // generate LUT (white to black) mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); vtkLookupTable* bwLut = mitkLut->GetVtkLookupTable(); bwLut->SetTableRange (0, 1); bwLut->SetSaturationRange (0, 0); bwLut->SetHueRange (0, 0); bwLut->SetValueRange (1, 0); bwLut->SetAlphaRange (1, 1); bwLut->SetRampToLinear(); bwLut->Build(); mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); mitkLutProp->SetLookupTable(mitkLut); node->SetProperty( "LookupTable", mitkLutProp ); } else if ( photometricInterpretation.find("MONOCHROME2") != std::string::npos ) // meaning: display MINIMUM pixels as BLACK { // apply default LUT (black to white) node->SetProperty( "color", mitk::ColorProperty::New( 1,1,1 ), renderer ); } - // PALETTE interpretation should be handled ok by RGB loading + // PALETTE interpretation should be handled ok by RGB loading } bool isBinaryImage(false); if ( ! node->GetBoolProperty("binary", isBinaryImage) ) { // ok, property is not set, use heuristic to determine if this // is a binary image mitk::Image::Pointer centralSliceImage; ScalarType minValue = 0.0; ScalarType maxValue = 0.0; ScalarType min2ndValue = 0.0; ScalarType max2ndValue = 0.0; mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New(); sliceSelector->SetInput(image); sliceSelector->SetSliceNr(image->GetDimension(2)/2); sliceSelector->SetTimeNr(image->GetDimension(3)/2); sliceSelector->SetChannelNr(image->GetDimension(4)/2); sliceSelector->Update(); centralSliceImage = sliceSelector->GetOutput(); if ( centralSliceImage.IsNotNull() && centralSliceImage->IsInitialized() ) { minValue = centralSliceImage->GetStatistics()->GetScalarValueMin(); maxValue = centralSliceImage->GetStatistics()->GetScalarValueMax(); min2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMin(); max2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMax(); } if ((maxValue == min2ndValue && minValue == max2ndValue) || minValue == maxValue) { // centralSlice is strange, lets look at all data minValue = image->GetStatistics()->GetScalarValueMin(); maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(); min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(); max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(); } isBinaryImage = ( maxValue == min2ndValue && minValue == max2ndValue ); } // some more properties specific for a binary... if (isBinaryImage) { node->AddProperty( "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ); node->AddProperty( "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.selectedcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.selectedannotationcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.hoveringcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.hoveringannotationcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( true ), renderer, overwrite ); node->AddProperty("layer", mitk::IntProperty::New(10), renderer, overwrite); } else //...or image type object { node->AddProperty( "opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite ); - node->AddProperty( "black opacity", mitk::FloatProperty::New( 0.0 ), renderer, overwrite ); node->AddProperty( "color", ColorProperty::New(1.0,1.0,1.0), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty("layer", mitk::IntProperty::New(0), renderer, overwrite); } if(image.IsNotNull() && image->IsInitialized()) { if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) { /* initialize level/window from DICOM tags */ std::string sLevel; std::string sWindow; if ( image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowCenter", sLevel ) - && image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowWidth", sWindow ) ) + && image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowWidth", sWindow ) ) { float level = atof( sLevel.c_str() ); float window = atof( sWindow.c_str() ); mitk::LevelWindow contrast; std::string sSmallestPixelValueInSeries; std::string sLargestPixelValueInSeries; if ( image->GetPropertyList()->GetStringProperty( "dicom.series.SmallestPixelValueInSeries", sSmallestPixelValueInSeries ) - && image->GetPropertyList()->GetStringProperty( "dicom.series.LargestPixelValueInSeries", sLargestPixelValueInSeries ) ) + && image->GetPropertyList()->GetStringProperty( "dicom.series.LargestPixelValueInSeries", sLargestPixelValueInSeries ) ) { float smallestPixelValueInSeries = atof( sSmallestPixelValueInSeries.c_str() ); float largestPixelValueInSeries = atof( sLargestPixelValueInSeries.c_str() ); contrast.SetRangeMinMax( smallestPixelValueInSeries-1, largestPixelValueInSeries+1 ); // why not a little buffer? // might remedy some l/w widget challenges } else { contrast.SetAuto( static_cast(node->GetData()), false, true ); // we need this as a fallback } contrast.SetLevelWindow( level, window, true ); node->SetProperty( "levelwindow", LevelWindowProperty::New( contrast ), renderer ); } } if(((overwrite) || (node->GetProperty("opaclevelwindow", renderer)==NULL)) - && (image->GetPixelType().GetPixelTypeId() == itk::ImageIOBase::RGBA) - && (image->GetPixelType().GetTypeId() == typeid( unsigned char)) ) + && (image->GetPixelType().GetPixelTypeId() == itk::ImageIOBase::RGBA) + && (image->GetPixelType().GetTypeId() == typeid( unsigned char)) ) { mitk::LevelWindow opaclevwin; opaclevwin.SetRangeMinMax(0,255); opaclevwin.SetWindowBounds(0,255); mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(opaclevwin); node->SetProperty( "opaclevelwindow", prop, renderer ); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } mitk::ImageVtkMapper2D::LocalStorage* mitk::ImageVtkMapper2D::GetLocalStorage(mitk::BaseRenderer* renderer) { return m_LSH.GetLocalStorage(renderer); } vtkSmartPointer mitk::ImageVtkMapper2D::CreateOutlinePolyData(mitk::BaseRenderer* renderer ){ LocalStorage* localStorage = this->GetLocalStorage(renderer); //get the min and max index values of each direction int* extent = localStorage->m_ReslicedImage->GetExtent(); int xMin = extent[0]; int xMax = extent[1]; int yMin = extent[2]; int yMax = extent[3]; int* dims = localStorage->m_ReslicedImage->GetDimensions(); //dimensions of the image int line = dims[0]; //how many pixels per line? int x = xMin; //pixel index x int y = yMin; //pixel index y char* currentPixel; //get the depth for each contour float depth = CalculateLayerDepth(renderer); vtkSmartPointer points = vtkSmartPointer::New(); //the points to draw vtkSmartPointer lines = vtkSmartPointer::New(); //the lines to connect the points // We take the pointer to the first pixel of the image currentPixel = static_cast(localStorage->m_ReslicedImage->GetScalarPointer() ); while (y <= yMax) { //if the current pixel value is set to something if ((currentPixel) && (*currentPixel != 0)) { //check in which direction a line is necessary //a line is added if the neighbor of the current pixel has the value 0 //and if the pixel is located at the edge of the image //if vvvvv not the first line vvvvv if (y > yMin && *(currentPixel-line) == 0) { //x direction - bottom edge of the pixel //add the 2 points vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); //add the line between both points lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } //if vvvvv not the last line vvvvv if (y < yMax && *(currentPixel+line) == 0) { //x direction - top edge of the pixel vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } //if vvvvv not the first pixel vvvvv if ( (x > xMin || y > yMin) && *(currentPixel-1) == 0) { //y direction - left edge of the pixel vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } //if vvvvv not the last pixel vvvvv if ( (y < yMax || (x < xMax) ) && *(currentPixel+1) == 0) { //y direction - right edge of the pixel vtkIdType p1 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } /* now consider pixels at the edge of the image */ //if vvvvv left edge of image vvvvv if (x == xMin) { //draw left edge of the pixel vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } //if vvvvv right edge of image vvvvv if (x == xMax) { //draw right edge of the pixel vtkIdType p1 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } //if vvvvv bottom edge of image vvvvv if (y == yMin) { //draw bottom edge of the pixel vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } //if vvvvv top edge of image vvvvv if (y == yMax) { //draw top edge of the pixel vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } }//end if currentpixel is set x++; if (x > xMax) { //reached end of line x = xMin; y++; } // Increase the pointer-position to the next pixel. // This is safe, as the while-loop and the x-reset logic above makes // sure we do not exceed the bounds of the image currentPixel++; }//end of while // Create a polydata to store everything in vtkSmartPointer polyData = vtkSmartPointer::New(); // Add the points to the dataset polyData->SetPoints(points); // Add the lines to the dataset polyData->SetLines(lines); return polyData; } void mitk::ImageVtkMapper2D::TransformActor(mitk::BaseRenderer* renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); //get the transformation matrix of the reslicer in order to render the slice as axial, coronal or saggital vtkSmartPointer trans = vtkSmartPointer::New(); vtkSmartPointer matrix = localStorage->m_Reslicer->GetResliceAxes(); trans->SetMatrix(matrix); //transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or saggital) localStorage->m_Actor->SetUserTransform(trans); //transform the origin to center based coordinates, because MITK is center based. localStorage->m_Actor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) { vtkActor* secondaryActor = dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) ); secondaryActor->SetUserTransform(trans); secondaryActor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); } } bool mitk::ImageVtkMapper2D::RenderingGeometryIntersectsImage( const Geometry2D* renderingGeometry, SlicedGeometry3D* imageGeometry ) { // if either one of the two geometries is NULL we return true // for safety reasons if ( renderingGeometry == NULL || imageGeometry == NULL ) return true; // get the distance for the first cornerpoint ScalarType initialDistance = renderingGeometry->SignedDistance( imageGeometry->GetCornerPoint( 0 ) ); for( int i=1; i<8; i++ ) { mitk::Point3D cornerPoint = imageGeometry->GetCornerPoint( i ); // get the distance to the other cornerpoints ScalarType distance = renderingGeometry->SignedDistance( cornerPoint ); // if it has not the same signing as the distance of the first point if ( initialDistance * distance < 0 ) { // we have an intersection and return true return true; } } // all distances have the same sign, no intersection and we return false return false; } +mitk::ImageVtkMapper2D::LocalStorage::~LocalStorage() +{ +} + mitk::ImageVtkMapper2D::LocalStorage::LocalStorage() { + + m_LevelWindowFilter = vtkSmartPointer::New(); + //Do as much actions as possible in here to avoid double executions. m_Plane = vtkSmartPointer::New(); m_Texture = vtkSmartPointer::New().GetPointer(); m_DefaultLookupTable = vtkSmartPointer::New(); m_BinaryLookupTable = vtkSmartPointer::New(); + m_ColorLookupTable = vtkSmartPointer::New(); m_Mapper = vtkSmartPointer::New(); m_Actor = vtkSmartPointer::New(); m_Actors = vtkSmartPointer::New(); m_Reslicer = mitk::ExtractSliceFilter::New(); m_TSFilter = vtkSmartPointer::New(); m_OutlinePolyData = vtkSmartPointer::New(); m_ReslicedImage = vtkSmartPointer::New(); m_EmptyPolyData = vtkSmartPointer::New(); //the following actions are always the same and thus can be performed //in the constructor for each image (i.e. the image-corresponding local storage) m_TSFilter->ReleaseDataFlagOn(); //built a default lookuptable m_DefaultLookupTable->SetRampToLinear(); m_DefaultLookupTable->SetSaturationRange( 0.0, 0.0 ); m_DefaultLookupTable->SetHueRange( 0.0, 0.0 ); m_DefaultLookupTable->SetValueRange( 0.0, 1.0 ); m_DefaultLookupTable->Build(); m_BinaryLookupTable->SetRampToLinear(); m_BinaryLookupTable->SetSaturationRange( 0.0, 0.0 ); m_BinaryLookupTable->SetHueRange( 0.0, 0.0 ); m_BinaryLookupTable->SetValueRange( 0.0, 1.0 ); m_BinaryLookupTable->SetRange(0.0, 1.0); m_BinaryLookupTable->Build(); + + // add a default rainbow lookup table for color mapping + m_ColorLookupTable->SetRampToLinear(); + m_ColorLookupTable->SetHueRange(0.6667, 0.0); + m_ColorLookupTable->SetTableRange(0.0, 20.0); + m_ColorLookupTable->Build(); // make first value transparent { double rgba[4]; m_BinaryLookupTable->GetTableValue(0, rgba); - m_BinaryLookupTable->SetTableValue(0, rgba[0], rgba[1], rgba[2], 0); // background to 0 + m_BinaryLookupTable->SetTableValue(0, rgba[0], rgba[1], rgba[2], 0.0); // background to 0 } //do not repeat the texture (the image) m_Texture->RepeatOff(); //set the mapper for the actor m_Actor->SetMapper( m_Mapper ); vtkSmartPointer outlineShadowActor = vtkSmartPointer::New(); outlineShadowActor->SetMapper( m_Mapper ); m_Actors->AddPart( outlineShadowActor ); m_Actors->AddPart( m_Actor ); - - //level window filter - m_LevelWindowFilter = new vtkMitkLevelWindowFilter(); } diff --git a/Core/Code/Rendering/mitkImageVtkMapper2D.h b/Core/Code/Rendering/mitkImageVtkMapper2D.h index 59c068206e..9f2e6955d5 100644 --- a/Core/Code/Rendering/mitkImageVtkMapper2D.h +++ b/Core/Code/Rendering/mitkImageVtkMapper2D.h @@ -1,292 +1,306 @@ /*=================================================================== 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 MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E #define MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E //MITK #include //MITK Rendering #include "mitkBaseRenderer.h" #include "mitkVtkMapper.h" #include "mitkExtractSliceFilter.h" //VTK #include #include class vtkActor; class vtkPolyDataMapper; class vtkPlaneSource; class vtkImageData; class vtkLookupTable; class vtkImageReslice; class vtkImageChangeInformation; class vtkPoints; class vtkMitkThickSlicesFilter; class vtkPolyData; class vtkMitkApplyLevelWindowToRGBFilter; class vtkMitkLevelWindowFilter; namespace mitk { /** \brief Mapper to resample and display 2D slices of a 3D image. * * The following image gives a brief overview of the mapping and the involved parts. * * \image html imageVtkMapper2Darchitecture.png * * First, the image is resliced by means of vtkImageReslice. The volume image * serves as input to the mapper in addition to spatial placement of the slice and a few other * properties such as thick slices. This code was already present in the old version * (mitkImageMapperGL2D). * * Next, the obtained slice (m_ReslicedImage) is put into a vtkMitkLevelWindowFilter * and the scalar levelwindow, opacity levelwindow and optional clipping to * local image bounds are applied * * Next, the output of the vtkMitkLevelWindowFilter is used to create a texture * (m_Texture) and a plane onto which the texture is rendered (m_Plane). For * mapping purposes, a vtkPolyDataMapper (m_Mapper) is utilized. Orthographic * projection is applied to create the effect of a 2D image. The mapper and the * texture are assigned to the actor (m_Actor) which is passed to the VTK rendering * pipeline via the method GetVtkProp(). * * In order to transform the textured plane to the correct position in space, the * same transformation as used for reslicing is applied to both the camera and the * vtkActor. All important steps are explained in more detail below. The resulting * 2D image (by reslicing the underlying 3D input image appropriately) can either * be directly rendered in a 2D view or just be calculated to be used later by another * rendering entity, e.g. in texture mapping in a 3D view. * * Properties that can be set for images and influence the imageMapper2D are: * * - \b "opacity": (FloatProperty) Opacity of the image * - \b "black opacity": (FloatProperty) The opacity of black (first index in lookup tables) * - \b "color": (ColorProperty) Color of the image * - \b "LookupTable": (mitkLookupTableProperty) If this property is set, * the default lookuptable will be ignored and the "LookupTable" value * will be used instead. + * - \b "Image Rendering.Mode": This property decides which mode is used to render images. (E.g. if a lookup table or a transferfunction is applied). Detailed documentation about the modes can be found here: \link mitk::RenderingerModeProperty \endlink * - \b "Image Rendering.Transfer Function": (mitkTransferFunctionProperty) If this * property is set, a color transferfunction will be used to color the image. - * \warning This property will not have any effect if, the "LookupTable" property - * is set. * - \b "binary": (BoolProperty) is the image a binary image or not * - \b "outline binary": (BoolProperty) show outline of the image or not * - \b "texture interpolation": (BoolProperty) texture interpolation of the image * - \b "reslice interpolation": (VtkResliceInterpolationProperty) reslice interpolation of the image * - \b "in plane resample extent by geometry": (BoolProperty) Do it or not * - \b "bounding box": (BoolProperty) Is the Bounding Box of the image shown or not * - \b "layer": (IntProperty) Layer of the image * - \b "volume annotation color": (ColorProperty) color of the volume annotation, TODO has to be reimplemented * - \b "volume annotation unit": (StringProperty) annotation unit as string (does not implicit convert the unit!) unit is ml or cm3, TODO has to be reimplemented * The default properties are: * - \b "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ) * - \b "black opacity", mitk::FloatProperty::New(0.0f), renderer, overwrite ) * - \b "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ) * - \b "binary", mitk::BoolProperty::New( true ), renderer, overwrite ) * - \b "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ) * - \b "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ) * - \b "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ) * - \b "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ) * - \b "bounding box", mitk::BoolProperty::New( false ) ) * - \b "layer", mitk::IntProperty::New(10), renderer, overwrite) * - \b "Image Rendering.Transfer Function": Default color transfer function for CTs - * - \b "LookupTable": Undefined. Must be set by the user. + * - \b "LookupTable": Rainbow color. * If the modality-property is set for an image, the mapper uses modality-specific default properties, * e.g. color maps, if they are defined. * \ingroup Mapper */ - class MITK_CORE_EXPORT ImageVtkMapper2D : public VtkMapper - { +class MITK_CORE_EXPORT ImageVtkMapper2D : public VtkMapper +{ - public: - /** Standard class typedefs. */ - mitkClassMacro( ImageVtkMapper2D,VtkMapper ); +public: + /** Standard class typedefs. */ + mitkClassMacro( ImageVtkMapper2D,VtkMapper ); /** Method for creation through the object factory. */ itkNewMacro(Self); /** \brief Get the Image to map */ const mitk::Image *GetInput(void); /** \brief Checks whether this mapper needs to update itself and generate * data. */ virtual void Update(mitk::BaseRenderer * renderer); - //### methods of MITK-VTK rendering pipeline - virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); - //### end of methods of MITK-VTK rendering pipeline + //### methods of MITK-VTK rendering pipeline + virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); + //### end of methods of MITK-VTK rendering pipeline /** \brief Internal class holding the mapper, actor, etc. for each of the 3 2D render windows */ /** * To render transveral, coronal, and sagittal, the mapper is called three times. * For performance reasons, the corresponding data for each view is saved in the * internal helper class LocalStorage. This allows rendering n views with just * 1 mitkMapper using n vtkMapper. * */ class MITK_CORE_EXPORT LocalStorage : public mitk::Mapper::BaseLocalStorage { public: /** \brief Actor of a 2D render window. */ vtkSmartPointer m_Actor; vtkSmartPointer m_Actors; /** \brief Mapper of a 2D render window. */ vtkSmartPointer m_Mapper; /** \brief Current slice of a 2D render window.*/ vtkSmartPointer m_ReslicedImage; /** \brief Empty vtkPolyData that is set when rendering geometry does not * intersect the image geometry. * \warning This member variable is set to NULL, * if no image geometry is inside the plane geometry * of the respective render window. Any user of this * slice has to check whether it is set to NULL! */ - vtkSmartPointer m_EmptyPolyData; - /** \brief Plane on which the slice is rendered as texture. */ - vtkSmartPointer m_Plane; - /** \brief The texture which is used to render the current slice. */ - vtkSmartPointer m_Texture; - /** \brief The lookuptable for colors and level window */ - vtkSmartPointer m_DefaultLookupTable; - vtkSmartPointer m_BinaryLookupTable; - /** \brief The actual reslicer (one per renderer) */ + vtkSmartPointer m_EmptyPolyData; + /** \brief Plane on which the slice is rendered as texture. */ + vtkSmartPointer m_Plane; + /** \brief The texture which is used to render the current slice. */ + vtkSmartPointer m_Texture; + /** \brief The lookuptables for colors and level window */ + vtkSmartPointer m_DefaultLookupTable; + vtkSmartPointer m_BinaryLookupTable; + vtkSmartPointer m_ColorLookupTable; + /** \brief The actual reslicer (one per renderer) */ mitk::ExtractSliceFilter::Pointer m_Reslicer; /** \brief Filter for thick slices */ vtkSmartPointer m_TSFilter; /** \brief PolyData object containg all lines/points needed for outlining the contour. This container is used to save a computed contour for the next rendering execution. For instance, if you zoom or pann, there is no need to recompute the contour. */ vtkSmartPointer m_OutlinePolyData; - /** \brief Timestamp of last update of stored data. */ itk::TimeStamp m_LastUpdateTime; /** \brief mmPerPixel relation between pixel and mm. (World spacing).*/ mitk::ScalarType* m_mmPerPixel; - /** \brief This filter is used to apply the level window to Grayvalue and RBG(A) images. */ - vtkMitkLevelWindowFilter* m_LevelWindowFilter; + /** \brief This filter is used to apply the level window to Grayvalue and RBG(A) images. */ + vtkSmartPointer m_LevelWindowFilter; /** \brief Default constructor of the local storage. */ LocalStorage(); /** \brief Default deconstructor of the local storage. */ - ~LocalStorage() - { - } + ~LocalStorage(); }; /** \brief The LocalStorageHandler holds all (three) LocalStorages for the three 2D render windows. */ mitk::Mapper::LocalStorageHandler m_LSH; /** \brief Get the LocalStorage corresponding to the current renderer. */ LocalStorage* GetLocalStorage(mitk::BaseRenderer* renderer); /** \brief Set the default properties for general image rendering. */ static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); + /** \brief This method switches between different rendering modes (e.g. use a lookup table or a transfer function). + * Detailed documentation about the modes can be found here: \link mitk::RenderingerModeProperty \endlink + */ + void ApplyRenderingMode(mitk::BaseRenderer *renderer); + protected: /** \brief Transforms the actor to the actual position in 3D. * \param renderer The current renderer corresponding to the render window. */ void TransformActor(mitk::BaseRenderer* renderer); /** \brief Generates a plane according to the size of the resliced image in milimeters. * * \image html texturedPlane.png * * In VTK a vtkPlaneSource is defined through three points. The origin and two * points defining the axes of the plane (see VTK documentation). The origin is * set to (xMin; yMin; Z), where xMin and yMin are the minimal bounds of the * resliced image in space. Z is relevant for blending and the layer property. * The center of the plane (C) is also the center of the view plane (cf. the image above). * * \note For the standard MITK view with three 2D render windows showing three * different slices, three such planes are generated. All these planes are generated * in the XY-plane (even if they depict a YZ-slice of the volume). * */ void GeneratePlane(mitk::BaseRenderer* renderer, vtkFloatingPointType planeBounds[6]); /** \brief Generates a vtkPolyData object containing the outline of a given binary slice. \param renderer: Pointer to the renderer containing the needed information \note This code is based on code from the iil library. */ vtkSmartPointer CreateOutlinePolyData(mitk::BaseRenderer* renderer); /** Default constructor */ ImageVtkMapper2D(); /** Default deconstructor */ virtual ~ImageVtkMapper2D(); /** \brief Does the actual resampling, without rendering the image yet. * All the data is generated inside this method. The vtkProp (or Actor) * is filled with content (i.e. the resliced image). * * After generation, a 4x4 transformation matrix(t) of the current slice is obtained * from the vtkResliceImage object via GetReslicesAxis(). This matrix is * applied to each textured plane (actor->SetUserTransform(t)) to transform everything * to the actual 3D position (cf. the following image). * * \image html cameraPositioning3D.png * */ virtual void GenerateDataForRenderer(mitk::BaseRenderer *renderer); /** \brief This method uses the vtkCamera clipping range and the layer property * to calcualte the depth of the object (e.g. image or contour). The depth is used * to keep the correct order for the final VTK rendering.*/ float CalculateLayerDepth(mitk::BaseRenderer* renderer); - /** \brief This method applies (or modifies) the lookuptable for all types of images. */ - void ApplyLookuptable( mitk::BaseRenderer* renderer, vtkFloatingPointType* bounds ); - - /** \brief This method applies a color transfer function, if no LookuptableProperty is set. - Internally, a vtkColorTransferFunction is used. This is usefull for coloring continous - images (e.g. float) */ + /** \brief This method applies (or modifies) the lookuptable for all types of images. + * \warning To use the lookup table, the property 'Lookup Table' must be set and a 'Image Rendering.Mode' + * which uses the lookup table must be set. +*/ + void ApplyLookuptable(mitk::BaseRenderer* renderer); + + /** \brief This method applies a color transfer function. + * Internally, a vtkColorTransferFunction is used. This is usefull for coloring continous + * images (e.g. float) + * \warning To use the color transfer function, the property 'Image Rendering.Transfer Function' must be set and a 'Image Rendering.Mode' which uses the color transfer function must be set. +*/ void ApplyColorTransferFunction(mitk::BaseRenderer* renderer); + /** + * @brief ApplyLevelWindow Apply the level window for the given renderer. + * \warning To use the level window, the property 'LevelWindow' must be set and a 'Image Rendering.Mode' which uses the level window must be set. + * @param renderer Level window for which renderer? + */ + void ApplyLevelWindow(mitk::BaseRenderer* renderer); + /** \brief Set the color of the image/polydata */ void ApplyColor( mitk::BaseRenderer* renderer ); /** \brief Set the opacity of the actor. */ void ApplyOpacity( mitk::BaseRenderer* renderer ); /** * \brief Calculates whether the given rendering geometry intersects the * given SlicedGeometry3D. * * This method checks if the given Geometry2D intersects the given * SlicedGeometry3D. It calculates the distance of the Geometry2D to all * 8 cornerpoints of the SlicedGeometry3D. If all distances have the same * sign (all positive or all negative) there is no intersection. * If the distances have different sign, there is an intersection. **/ bool RenderingGeometryIntersectsImage( const Geometry2D* renderingGeometry, SlicedGeometry3D* imageGeometry ); }; } // namespace mitk #endif /* MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E */ diff --git a/Core/Code/Rendering/mitkMapper.h b/Core/Code/Rendering/mitkMapper.h index 10700a442b..09d72df6d7 100644 --- a/Core/Code/Rendering/mitkMapper.h +++ b/Core/Code/Rendering/mitkMapper.h @@ -1,298 +1,298 @@ /*=================================================================== 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 MAPPER_H_HEADER_INCLUDED_C1E6EA08 #define MAPPER_H_HEADER_INCLUDED_C1E6EA08 #include #include "mitkBaseRenderer.h" #include "mitkVtkPropRenderer.h" #include "mitkLevelWindow.h" #include "mitkCommon.h" #include #include //Just included to get VTK version #include class vtkWindow; class vtkProp; namespace mitk { class BaseRenderer; class BaseData; class DataNode; /** \brief Interface for accessing (templated) LocalStorageHandler instances. */ class BaseLocalStorageHandler { public: virtual ~BaseLocalStorageHandler() {} virtual void ClearLocalStorage(mitk::BaseRenderer *renderer,bool unregisterFromBaseRenderer=true )=0; }; /** \brief Base class of all mappers, Vtk as well as OpenGL mappers * * By the help of mappers, the input data is transformed to tangible primitives, * such as surfaces, points, lines, etc. * This is the base class of all mappers, Vtk as well as OpenGL mappers. * Subclasses of mitk::Mapper control the creation of rendering primitives * that interface to the graphics library (e.g., OpenGL, vtk). * * \todo Should Mapper be a subclass of ImageSource? * \ingroup Mapper */ class MITK_CORE_EXPORT Mapper : public itk::Object { public: mitkClassMacro(Mapper, itk::Object); /** \brief Set the DataNode containing the data to map */ itkSetObjectMacro(DataNode, DataNode); /** \brief Get the DataNode containing the data to map */ virtual DataNode* GetDataNode() const; /**\brief Get the data to map * * Returns the mitk::BaseData object associated with this mapper. * \return the mitk::BaseData associated with this mapper. - * @deprecated Use GetDataNode()->GetData() instead to access the data + * \deprecatedSince{2013_03} Use GetDataNode()->GetData() instead to access the data */ DEPRECATED(BaseData* GetData() const); /** \brief Convenience access method for color properties (instances of * ColorProperty) * \return \a true property was found - * @deprecated Use GetDataNode()->GetColor(...) instead to get the color + * \deprecatedSince{2013_03} Use GetDataNode()->GetColor(...) instead to get the color */ DEPRECATED(virtual bool GetColor(float rgb[3], BaseRenderer* renderer, const char* name = "color") const); /** \brief Convenience access method for visibility properties (instances * of BoolProperty) * \return \a true property was found * \sa IsVisible - * @deprecated Use GetDataNode()->GetVisibility(...) instead to get the visibility + * \deprecatedSince{2013_03} Use GetDataNode()->GetVisibility(...) instead to get the visibility */ DEPRECATED(virtual bool GetVisibility(bool &visible, BaseRenderer* renderer, const char* name = "visible") const); /** \brief Convenience access method for opacity properties (instances of * FloatProperty) * \return \a true property was found - * @deprecated Use GetDataNode()->GetOpacity(...) instead to get the opacity + * \deprecatedSince{2013_03} Use GetDataNode()->GetOpacity(...) instead to get the opacity */ DEPRECATED(virtual bool GetOpacity(float &opacity, BaseRenderer* renderer, const char* name = "opacity") const); /** \brief Convenience access method for color properties (instances of * LevelWindoProperty) * \return \a true property was found - * @deprecated Use GetDataNode->GetLevelWindow(...) instead to get the levelwindow + * \deprecatedSince{2013_03} Use GetDataNode->GetLevelWindow(...) instead to get the levelwindow */ DEPRECATED(virtual bool GetLevelWindow(LevelWindow &levelWindow, BaseRenderer* renderer, const char* name = "levelwindow") const); /** \brief Convenience access method for visibility properties (instances * of BoolProperty). Return value is the visibility. Default is * visible==true, i.e., true is returned even if the property (\a * propertyKey) is not found. * * Thus, the return value has a different meaning than in the * GetVisibility method! * \sa GetVisibility - * @deprecated Use GetDataNode()->GetVisibility(...) instead + * \deprecatedSince{2013_03} Use GetDataNode()->GetVisibility(...) instead */ DEPRECATED(virtual bool IsVisible(BaseRenderer* renderer, const char* name = "visible") const); /** \brief Returns whether this is an vtk-based mapper - * @deprecated All mappers of superclass VTKMapper are vtk based, use a dynamic_cast instead + * \deprecatedSince{2013_03} All mappers of superclass VTKMapper are vtk based, use a dynamic_cast instead */ virtual bool IsVtkBased() const = 0; /** \brief Calls the time step of the input data for the specified renderer and checks * whether the time step is valid and calls method GenerateDataForRenderer() */ virtual void Update(BaseRenderer* renderer); /** \brief Responsible for calling the appropriate render functions. * To be implemented in sub-classes. */ virtual void MitkRender(mitk::BaseRenderer* renderer, mitk::VtkPropRenderer::RenderType type) = 0; /** * \brief Apply specific color and opacity properties read from the PropertyList. * Reimplemented in GLmapper (does not use the actor) and the VtkMapper class. * The function is called by the individual mapper (mostly in the ApplyProperties() or ApplyAllProperties() * method). */ virtual void ApplyColorAndOpacityProperties(mitk::BaseRenderer* renderer, vtkActor* actor = NULL) = 0; /** \brief Set default values of properties used by this mapper * to \a node * * \param node The node for which the properties are set * \param overwrite overwrite existing properties (default: \a false) * \param renderer defines which property list of node is used * (default: \a NULL, i.e. default property list) */ static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = NULL, bool overwrite = false); /** \brief Returns the current time step as calculated from the renderer */ int GetTimestep() const { return m_TimeStep; }; /** Returns true if this Mapper currently allows for Level-of-Detail rendering. * This reflects whether this Mapper currently invokes StartEvent, EndEvent, and * ProgressEvent on BaseRenderer. */ virtual bool IsLODEnabled( BaseRenderer * /*renderer*/ ) const { return false; } protected: /** \brief explicit constructor which disallows implicit conversions */ explicit Mapper(); /** \brief virtual destructor in order to derive from this class */ virtual ~Mapper(); - - /** \brief Generate the data needed for rendering (independent of a specific renderer) */ - // @deprecated Use GenerateDataForRenderer(BaseRenderer* renderer) instead. - DEPRECATED( virtual void GenerateData()) { } + /** \brief Generate the data needed for rendering (independent of a specific renderer) + * \deprecatedSince{2013_03} Use GenerateDataForRenderer(BaseRenderer* renderer) instead. + */ + DEPRECATED( virtual void GenerateData() { }); /** \brief Generate the data needed for rendering into \a renderer */ virtual void GenerateDataForRenderer(BaseRenderer* /* renderer */) { } /** \brief Updates the time step, which is sometimes needed in subclasses */ virtual void CalculateTimeStep( BaseRenderer* renderer ); /** \brief Reset the mapper (i.e., make sure that nothing is displayed) if no * valid data is present. In most cases the reimplemented function * disables the according actors (toggling visibility off) * * To be implemented in sub-classes. */ virtual void ResetMapper( BaseRenderer* /*renderer*/ ) { }; //\brief not thread-safe itk::WeakPointer m_DataNode; /** \brief timestamp of last update of stored data */ itk::TimeStamp m_LastUpdateTime; private: /** \brief The current time step of the dataset to be rendered, * for use in subclasses. * The current timestep can be accessed via the GetTimestep() method. */ int m_TimeStep; /** \brief copy constructor */ Mapper( const Mapper &); /** \brief assignment operator */ Mapper &operator=(const Mapper &); public: /** \brief Base class for mapper specific rendering ressources. */ class BaseLocalStorage { }; /** \brief Templated class for management of LocalStorage implementations in Mappers. * * The LocalStorageHandler is responsible for providing a LocalStorage to a * concrete mitk::Mapper subclass. Each RenderWindow / mitk::BaseRenderer is * assigned its own LocalStorage instance so that all contained ressources * (actors, shaders, textures, ...) are provided individually per window. * */ template class LocalStorageHandler : public mitk::BaseLocalStorageHandler { protected: std::map m_BaseRenderer2LS; public: /** \brief deallocates a local storage for a specifc BaseRenderer (if the * BaseRenderer is itself deallocating it in its destructor, it has to set * unregisterFromBaseRenderer=false) */ virtual void ClearLocalStorage(mitk::BaseRenderer *renderer,bool unregisterFromBaseRenderer=true ) { //MITK_INFO << "deleting a localstorage on a mapper request"; if(unregisterFromBaseRenderer) renderer->UnregisterLocalStorageHandler( this ); L *l = m_BaseRenderer2LS[renderer]; m_BaseRenderer2LS.erase( renderer ); delete l; } /** \brief Retrieves a LocalStorage for a specific BaseRenderer. * * Should be used by mappers in GenerateDataForRenderer() */ L *GetLocalStorage(mitk::BaseRenderer *forRenderer) { L *l = m_BaseRenderer2LS[ forRenderer ]; if(!l) { //MITK_INFO << "creating new localstorage"; l = new L; m_BaseRenderer2LS[ forRenderer ] = l; forRenderer->RegisterLocalStorageHandler( this ); } return l; } ~LocalStorageHandler() { typename std::map::iterator it; for ( it=m_BaseRenderer2LS.begin() ; it != m_BaseRenderer2LS.end(); it++ ) { (*it).first->UnregisterLocalStorageHandler(this); delete (*it).second; } m_BaseRenderer2LS.clear(); } }; }; } // namespace mitk #endif /* MAPPER_H_HEADER_INCLUDED_C1E6EA08 */ diff --git a/Core/Code/Rendering/mitkShaderRepository.cpp b/Core/Code/Rendering/mitkShaderRepository.cpp index 421c2ed3b2..249eef08ae 100644 --- a/Core/Code/Rendering/mitkShaderRepository.cpp +++ b/Core/Code/Rendering/mitkShaderRepository.cpp @@ -1,425 +1,519 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define SR_INFO MITK_INFO("shader.repository") #define SR_WARN MITK_WARN("shader.repository") #define SR_ERROR MITK_ERROR("shader.repository") #include "mitkShaderRepository.h" #include "mitkShaderProperty.h" #include "mitkProperties.h" +#include "mitkDataNode.h" +#include #include #include #include #include #include #include -#include "mitkStandardFileLocations.h" +int mitk::ShaderRepository::shaderId = 0; mitk::ShaderRepository::ShaderRepository() { LoadShaders(); } mitk::ShaderRepository::~ShaderRepository() { } mitk::ShaderRepository *mitk::ShaderRepository::GetGlobalShaderRepository() { static mitk::ShaderRepository::Pointer i; if(i.IsNull()) { i=mitk::ShaderRepository::New(); } return i; } void mitk::ShaderRepository::LoadShaders() { itk::Directory::Pointer dir = itk::Directory::New(); - std::string mitkLighting = mitk::StandardFileLocations::GetInstance()->FindFile("mitkShaderLighting.xml", "Core/Code/Rendering"); - std::string dirPath = "./vtk_shader"; - - if(mitkLighting.size() > 0) - { - // we found the default shader - dirPath = itksys::SystemTools::GetFilenamePath( mitkLighting ); - - SR_INFO << "found default mitk shader at '" << dirPath << "'"; - } - - - if( dir->Load( dirPath.c_str() ) ) { int n = dir->GetNumberOfFiles(); for(int r=0;rGetFile( r ); std::string extension = itksys::SystemTools::GetFilenameExtension(filename); if(extension.compare(".xml")==0) { Shader::Pointer element=Shader::New(); - element->name = itksys::SystemTools::GetFilenameWithoutExtension(filename); - element->path = dirPath + std::string("/") + element->name + std::string(".xml"); + element->SetName(itksys::SystemTools::GetFilenameWithoutExtension(filename)); + std::string filePath = dirPath + std::string("/") + element->GetName() + std::string(".xml"); + element->path = filePath; - SR_INFO << "found shader '" << element->name << "'"; + SR_INFO << "found shader '" << element->GetName() << "'"; - element->LoadPropertiesFromPath(); + element->LoadProperties(filePath); shaders.push_back(element); } } } } -void mitk::ShaderRepository::LoadShader(std::string filename) +mitk::ShaderRepository::Shader::Pointer mitk::ShaderRepository::GetShaderImpl(const std::string &name) const +{ + std::list::const_iterator i = shaders.begin(); + + while( i != shaders.end() ) + { + if( (*i)->GetName() == name) + return (*i); + + i++; + } + + return Shader::Pointer(); +} + +int mitk::ShaderRepository::LoadShader(const std::string& filename) { std::string extension = itksys::SystemTools::GetFilenameExtension(filename); if (extension.compare(".xml")==0) { Shader::Pointer element=Shader::New(); - element->name = itksys::SystemTools::GetFilenameWithoutExtension(filename); + element->SetName(itksys::SystemTools::GetFilenameWithoutExtension(filename)); + element->name = element->GetName(); element->path = filename; - element->LoadPropertiesFromPath(); + element->SetId(shaderId++); + element->LoadProperties(filename); shaders.push_back(element); - SR_INFO << "found shader '" << element->name << "'"; + SR_INFO << "found shader '" << element->GetName() << "'"; + return element->GetId(); } - else { SR_INFO << "Error: no xml shader file!"; + return -1; + } +} + +int mitk::ShaderRepository::LoadShader(std::istream& stream, const std::string& filename) +{ + Shader::Pointer element=Shader::New(); + element->SetName(filename); + element->name = filename; + element->SetId(shaderId++); + element->LoadProperties(stream); + shaders.push_back(element); + SR_INFO << "found shader '" << element->GetName() << "'"; + return element->GetId(); +} + +bool mitk::ShaderRepository::UnloadShader(int id) +{ + for (std::list::iterator i = shaders.begin(); + i != shaders.end(); ++i) + { + if ((*i)->GetId() == id) + { + shaders.erase(i); + return true; + } } + return false; } mitk::ShaderRepository::Shader::Shader() { } mitk::ShaderRepository::Shader::~Shader() { } void mitk::ShaderRepository::Shader::LoadPropertiesFromPath() { - vtkProperty *p; - - p = vtkProperty::New(); - - p->LoadMaterial(path.c_str()); + LoadProperties(path); +} +void mitk::ShaderRepository::Shader::LoadProperties(vtkProperty* p) +{ vtkXMLMaterial *m=p->GetMaterial(); + if (m == NULL) return; // Vertexshader uniforms { vtkXMLShader *s=m->GetVertexShader(); - vtkXMLDataElement *x=s->GetRootElement(); - int n=x->GetNumberOfNestedElements(); - for(int r=0;rGetNestedElement(r); - if(!strcmp(y->GetName(),"ApplicationUniform")) + vtkXMLDataElement *x=s->GetRootElement(); + int n=x->GetNumberOfNestedElements(); + for(int r=0;rGetNestedElement(r); + if(!strcmp(y->GetName(),"ApplicationUniform")) + { Uniform::Pointer element=Uniform::New(); element->LoadFromXML(y); uniforms.push_back(element); + } } } } // Fragmentshader uniforms { vtkXMLShader *s=m->GetFragmentShader(); - vtkXMLDataElement *x=s->GetRootElement(); - int n=x->GetNumberOfNestedElements(); - for(int r=0;rGetNestedElement(r); - if(!strcmp(y->GetName(),"ApplicationUniform")) + vtkXMLDataElement *x=s->GetRootElement(); + int n=x->GetNumberOfNestedElements(); + for(int r=0;rGetNestedElement(r); + if(!strcmp(y->GetName(),"ApplicationUniform")) + { Uniform::Pointer element=Uniform::New(); element->LoadFromXML(y); uniforms.push_back(element); + } } } } +} +void mitk::ShaderRepository::Shader::LoadProperties(const std::string& path) +{ + vtkProperty *p = vtkProperty::New(); + p->LoadMaterial(path.c_str()); + LoadProperties(p); p->Delete(); } +void mitk::ShaderRepository::Shader::LoadProperties(std::istream& stream) +{ + std::string content; + content.reserve(2048); + char buffer[2048]; + while (stream.read(buffer, sizeof(buffer))) + { + content.append(buffer, sizeof(buffer)); + } + content.append(buffer, static_cast(stream.gcount())); + + if (content.empty()) return; + this->SetMaterialXml(content); + vtkProperty *p = vtkProperty::New(); + p->LoadMaterialFromString(content.c_str()); + LoadProperties(p); + p->Delete(); +} mitk::ShaderRepository::Shader::Uniform::Uniform() { } mitk::ShaderRepository::Shader::Uniform::~Uniform() { } -mitk::ShaderRepository::Shader *mitk::ShaderRepository::GetShader(const char *id) +mitk::ShaderRepository::Shader *mitk::ShaderRepository::GetShader(const char *id) const { std::list::const_iterator i = shaders.begin(); while( i != shaders.end() ) { - if( (*i)->name.compare(id) == 0) + if( (*i)->GetName() ==id) return (*i); i++; } return 0; } void mitk::ShaderRepository::Shader::Uniform::LoadFromXML(vtkXMLDataElement *y) { //MITK_INFO << "found uniform '" << y->GetAttribute("name") << "' type=" << y->GetAttribute("type");// << " default=" << y->GetAttribute("value"); name = y->GetAttribute("name"); const char *sType=y->GetAttribute("type"); if(!strcmp(sType,"float")) type=glsl_float; else if(!strcmp(sType,"vec2")) type=glsl_vec2; else if(!strcmp(sType,"vec3")) type=glsl_vec3; else if(!strcmp(sType,"vec4")) type=glsl_vec4; else if(!strcmp(sType,"int")) type=glsl_int; else if(!strcmp(sType,"ivec2")) type=glsl_ivec2; else if(!strcmp(sType,"ivec3")) type=glsl_ivec3; else if(!strcmp(sType,"ivec4")) type=glsl_ivec4; else { type=glsl_none; SR_WARN << "unknown type for uniform '" << name << "'" ; } defaultFloat[0]=defaultFloat[1]=defaultFloat[2]=defaultFloat[3]=0; /* const char *sDefault=y->GetAttribute("value"); switch(type) { case glsl_float: sscanf(sDefault,"%f",&defaultFloat[0]); break; case glsl_vec2: sscanf(sDefault,"%f %f",&defaultFloat[0],&defaultFloat[1]); break; case glsl_vec3: sscanf(sDefault,"%f %f %f",&defaultFloat[0],&defaultFloat[1],&defaultFloat[2]); break; case glsl_vec4: sscanf(sDefault,"%f %f %f %f",&defaultFloat[0],&defaultFloat[1],&defaultFloat[2],&defaultFloat[3]); break; } */ } -void mitk::ShaderRepository::AddDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) +void mitk::ShaderRepository::AddDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) const { node->AddProperty( "shader", mitk::ShaderProperty::New(), renderer, overwrite ); std::list::const_iterator i = shaders.begin(); while( i != shaders.end() ) { std::list *l = (*i)->GetUniforms(); - std::string shaderName = (*i)->name; + std::string shaderName = (*i)->GetName(); std::list::const_iterator j = l->begin(); while( j != l->end() ) { std::string propertyName = "shader." + shaderName + "." + (*j)->name; switch( (*j)->type ) { case Shader::Uniform::glsl_float: node->AddProperty( propertyName.c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[0] ), renderer, overwrite ); break; case Shader::Uniform::glsl_vec2: node->AddProperty( (propertyName+".x").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[0] ), renderer, overwrite ); node->AddProperty( (propertyName+".y").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[1] ), renderer, overwrite ); break; case Shader::Uniform::glsl_vec3: node->AddProperty( (propertyName+".x").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[0] ), renderer, overwrite ); node->AddProperty( (propertyName+".y").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[1] ), renderer, overwrite ); node->AddProperty( (propertyName+".z").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[2] ), renderer, overwrite ); break; case Shader::Uniform::glsl_vec4: node->AddProperty( (propertyName+".x").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[0] ), renderer, overwrite ); node->AddProperty( (propertyName+".y").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[1] ), renderer, overwrite ); node->AddProperty( (propertyName+".z").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[2] ), renderer, overwrite ); node->AddProperty( (propertyName+".w").c_str(), mitk::FloatProperty::New( (*j)->defaultFloat[3] ), renderer, overwrite ); break; default: break; } j++; } i++; } } -void mitk::ShaderRepository::ApplyProperties(mitk::DataNode* node, vtkActor *actor, mitk::BaseRenderer* renderer,itk::TimeStamp &MTime) +void mitk::ShaderRepository::ApplyProperties(mitk::DataNode* node, vtkActor *actor, mitk::BaseRenderer* renderer,itk::TimeStamp &MTime) const { bool setMTime = false; vtkProperty* property = actor->GetProperty(); unsigned long ts = MTime.GetMTime(); - mitk::ShaderProperty *sep=(mitk::ShaderProperty *)node->GetProperty("shader",renderer); + mitk::ShaderProperty *sep= dynamic_cast(node->GetProperty("shader",renderer)); if(!sep) { property->ShadingOff(); return; } std::string shader=sep->GetValueAsString(); // Need update pipeline mode if(sep->GetMTime() > ts) { if(shader.compare("fixed")==0) { //MITK_INFO << "disabling shader"; property->ShadingOff(); } else { - Shader *s=GetShader(shader.c_str()); - if(s) + Shader::Pointer s=GetShaderImpl(shader); + if(s.IsNotNull()) { //MITK_INFO << "enabling shader"; property->ShadingOn(); - property->LoadMaterial(s->path.c_str()); + property->LoadMaterialFromString(s->GetMaterialXml().c_str()); } } setMTime = true; } if(shader.compare("fixed")!=0) { - Shader *s=GetShader(shader.c_str()); + Shader::Pointer s=GetShaderImpl(shader); - if(!s) + if(s.IsNull()) return; std::list::const_iterator j = s->uniforms.begin(); while( j != s->uniforms.end() ) { - std::string propertyName = "shader." + s->name + "." + (*j)->name; + std::string propertyName = "shader." + s->GetName() + "." + (*j)->name; // MITK_INFO << "querying property: " << propertyName; // mitk::BaseProperty *p = node->GetProperty( propertyName.c_str(), renderer ); // if( p && p->GetMTime() > MTime.GetMTime() ) { float fval[4]; // MITK_INFO << "copying property " << propertyName << " ->->- " << (*j)->name << " type=" << (*j)->type ; switch( (*j)->type ) { case Shader::Uniform::glsl_float: node->GetFloatProperty( propertyName.c_str(), fval[0], renderer ); property->AddShaderVariable( (*j)->name.c_str(), 1 , fval ); break; case Shader::Uniform::glsl_vec2: node->GetFloatProperty( (propertyName+".x").c_str(), fval[0], renderer ); node->GetFloatProperty( (propertyName+".y").c_str(), fval[1], renderer ); property->AddShaderVariable( (*j)->name.c_str(), 2 , fval ); break; case Shader::Uniform::glsl_vec3: node->GetFloatProperty( (propertyName+".x").c_str(), fval[0], renderer ); node->GetFloatProperty( (propertyName+".y").c_str(), fval[1], renderer ); node->GetFloatProperty( (propertyName+".z").c_str(), fval[2], renderer ); property->AddShaderVariable( (*j)->name.c_str(), 3 , fval ); break; case Shader::Uniform::glsl_vec4: node->GetFloatProperty( (propertyName+".x").c_str(), fval[0], renderer ); node->GetFloatProperty( (propertyName+".y").c_str(), fval[1], renderer ); node->GetFloatProperty( (propertyName+".z").c_str(), fval[2], renderer ); node->GetFloatProperty( (propertyName+".w").c_str(), fval[3], renderer ); property->AddShaderVariable( (*j)->name.c_str(), 4 , fval ); break; default: break; } //setMTime=true; } j++; } } if(setMTime) MTime.Modified(); } +std::list mitk::ShaderRepository::GetShaders() const +{ + std::list result; + for (std::list::const_iterator i = shaders.begin(); + i != shaders.end(); ++i) + { + result.push_back(i->GetPointer()); + } + return result; +} + +mitk::IShaderRepository::Shader::Pointer mitk::ShaderRepository::GetShader(const std::string& name) const +{ + for (std::list::const_iterator i = shaders.begin(); + i != shaders.end(); ++i) + { + if ((*i)->GetName() == name) return i->GetPointer(); + } + return IShaderRepository::Shader::Pointer(); +} + +mitk::IShaderRepository::Shader::Pointer mitk::ShaderRepository::GetShader(int id) const +{ + for (std::list::const_iterator i = shaders.begin(); + i != shaders.end(); ++i) + { + if ((*i)->GetId() == id) return i->GetPointer(); + } + return IShaderRepository::Shader::Pointer(); +} diff --git a/Core/Code/Rendering/mitkShaderRepository.h b/Core/Code/Rendering/mitkShaderRepository.h index f72df04f1f..f7c718065a 100644 --- a/Core/Code/Rendering/mitkShaderRepository.h +++ b/Core/Code/Rendering/mitkShaderRepository.h @@ -1,166 +1,196 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITKSHADERREPOSITORY_H_ #define _MITKSHADERREPOSITORY_H_ #include -#include "itkObject.h" -#include "itkObjectFactory.h" -#include -#include "mitkBaseRenderer.h" -#include "mitkDataNode.h" +#include "mitkIShaderRepository.h" + +class vtkXMLDataElement; +class vtkProperty; namespace mitk { /** * \brief Management class for vtkShader XML descriptions. * * Looks for all XML shader files in a given directory and adds default properties * for each shader object (shader uniforms) to the specified mitk::DataNode. * * Additionally, it provides a utility function for applying properties for shaders * in mappers. + * + * \deprecatedSince{2013_03} Use the micro service interface IShaderRepository instead. */ -class MITK_CORE_EXPORT ShaderRepository : public itk::Object +class MITK_CORE_EXPORT ShaderRepository : public itk::LightObject, public IShaderRepository { public: - mitkClassMacro( ShaderRepository, itk::Object ); + mitkClassMacro( ShaderRepository, itk::LightObject ) - itkNewMacro( Self ); + itkFactorylessNewMacro( Self ) - static ShaderRepository *GetGlobalShaderRepository(); + DEPRECATED(static ShaderRepository *GetGlobalShaderRepository()); - class Shader : public itk::Object + /** + * \deprecatedSince{2013_03} Use IShaderRepository::Shader instead. + */ + class Shader : public IShaderRepository::Shader { public: - mitkClassMacro( Shader, itk::Object ); - itkNewMacro( Self ); + mitkClassMacro( Shader, itk::Object ) + itkFactorylessNewMacro( Self ) class Uniform : public itk::Object { public: - mitkClassMacro( Uniform, itk::Object ); - itkNewMacro( Self ); + mitkClassMacro( Uniform, itk::Object ) + itkFactorylessNewMacro( Self ) enum Type { glsl_none, glsl_float, glsl_vec2, glsl_vec3, glsl_vec4, glsl_int, glsl_ivec2, glsl_ivec3, glsl_ivec4 }; /** * Constructor */ Uniform(); /** * Destructor */ ~Uniform(); Type type; std::string name; int defaultInt[4]; float defaultFloat[4]; void LoadFromXML(vtkXMLDataElement *e); }; std::list uniforms; /** * Constructor */ Shader(); /** * Destructor */ ~Shader(); + // DEPRECATED since 2013.03 std::string name; + // DEPRECATED since 2013.03 std::string path; - void LoadPropertiesFromPath(); + DEPRECATED(void LoadPropertiesFromPath()); Uniform *GetUniform(char * /*id*/) { return 0; } std::list *GetUniforms() { return &uniforms; } + + private: + + friend class ShaderRepository; + + void LoadProperties(vtkProperty* prop); + void LoadProperties(const std::string& path); + void LoadProperties(std::istream& stream); + }; protected: std::list shaders; void LoadShaders(); + Shader::Pointer GetShaderImpl(const std::string& name) const; + /** * Constructor */ ShaderRepository(); /** * Destructor */ ~ShaderRepository(); +private: + + static int shaderId; + public: - std::list *GetShaders() + DEPRECATED(std::list *GetShaders()) { return &shaders; } - Shader *GetShader(const char *id); + DEPRECATED(Shader *GetShader(const char *id) const); + + std::list GetShaders() const; + IShaderRepository::Shader::Pointer GetShader(const std::string& name) const; + + IShaderRepository::Shader::Pointer GetShader(int id) const; /** \brief Adds all parsed shader uniforms to property list of the given DataNode; * used by mappers. */ - void AddDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite); + void AddDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) const; /** \brief Applies shader and shader specific variables of the specified DataNode * to the VTK object by updating the shader variables of its vtkProperty. */ - void ApplyProperties(mitk::DataNode* node, vtkActor *actor, mitk::BaseRenderer* renderer,itk::TimeStamp &MTime); + void ApplyProperties(mitk::DataNode* node, vtkActor *actor, mitk::BaseRenderer* renderer,itk::TimeStamp &MTime) const; /** \brief Loads a shader from a given file. Make sure that this file is in the XML shader format. */ - void LoadShader(std::string filename); + DEPRECATED(int LoadShader(const std::string& filename)); + + int LoadShader(std::istream& stream, const std::string& name); + + bool UnloadShader(int id); }; } //end of namespace mitk #endif diff --git a/Core/Code/Rendering/mitkSurfaceVtkMapper3D.cpp b/Core/Code/Rendering/mitkSurfaceVtkMapper3D.cpp index 8157babcf9..307a06e52d 100644 --- a/Core/Code/Rendering/mitkSurfaceVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkSurfaceVtkMapper3D.cpp @@ -1,504 +1,511 @@ /*=================================================================== 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 "mitkSurfaceVtkMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkColorProperty.h" #include "mitkLookupTableProperty.h" #include "mitkVtkRepresentationProperty.h" #include "mitkVtkInterpolationProperty.h" #include "mitkVtkScalarModeProperty.h" #include "mitkClippingProperty.h" #include "mitkSmartPointerProperty.h" #include "mitkShaderProperty.h" -#include "mitkShaderRepository.h" +#include "mitkIShaderRepository.h" #include #include +#include //VTK #include #include #include #include #include #include #include #include const mitk::Surface* mitk::SurfaceVtkMapper3D::GetInput() { return static_cast ( GetDataNode()->GetData() ); } mitk::SurfaceVtkMapper3D::SurfaceVtkMapper3D() { // m_Prop3D = vtkActor::New(); m_GenerateNormals = false; } mitk::SurfaceVtkMapper3D::~SurfaceVtkMapper3D() { // m_Prop3D->Delete(); } void mitk::SurfaceVtkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if(!visible) { ls->m_Actor->VisibilityOff(); return; } // // set the input-object at time t for the mapper // mitk::Surface::Pointer input = const_cast< mitk::Surface* >( this->GetInput() ); vtkPolyData * polydata = input->GetVtkPolyData( this->GetTimestep() ); if(polydata == NULL) { ls->m_Actor->VisibilityOff(); return; } if ( m_GenerateNormals ) { ls->m_VtkPolyDataNormals->SetInput( polydata ); ls->m_VtkPolyDataMapper->SetInput( ls->m_VtkPolyDataNormals->GetOutput() ); } else { ls->m_VtkPolyDataMapper->SetInput( polydata ); } // // apply properties read from the PropertyList // ApplyAllProperties(renderer, ls->m_Actor); if(visible) ls->m_Actor->VisibilityOn(); } void mitk::SurfaceVtkMapper3D::ResetMapper( BaseRenderer* renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); ls->m_Actor->VisibilityOff(); } void mitk::SurfaceVtkMapper3D::ApplyMitkPropertiesToVtkProperty(mitk::DataNode *node, vtkProperty* property, mitk::BaseRenderer* renderer) { // Backface culling { mitk::BoolProperty::Pointer p; node->GetProperty(p, "Backface Culling", renderer); bool useCulling = false; if(p.IsNotNull()) useCulling = p->GetValue(); property->SetBackfaceCulling(useCulling); } // Colors { double ambient [3] = { 0.5,0.5,0.0 }; double diffuse [3] = { 0.5,0.5,0.0 }; double specular[3] = { 1.0,1.0,1.0 }; float coeff_ambient = 0.5f; float coeff_diffuse = 0.5f; float coeff_specular= 0.5f; float power_specular=10.0f; // Color { mitk::ColorProperty::Pointer p; node->GetProperty(p, "color", renderer); if(p.IsNotNull()) { mitk::Color c = p->GetColor(); ambient[0]=c.GetRed(); ambient[1]=c.GetGreen(); ambient[2]=c.GetBlue(); diffuse[0]=c.GetRed(); diffuse[1]=c.GetGreen(); diffuse[2]=c.GetBlue(); // Setting specular color to the same, make physically no real sense, however vtk rendering slows down, if these colors are different. specular[0]=c.GetRed(); specular[1]=c.GetGreen(); specular[2]=c.GetBlue(); } } // Ambient { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.ambientColor", renderer); if(p.IsNotNull()) { mitk::Color c = p->GetColor(); ambient[0]=c.GetRed(); ambient[1]=c.GetGreen(); ambient[2]=c.GetBlue(); } } // Diffuse { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.diffuseColor", renderer); if(p.IsNotNull()) { mitk::Color c = p->GetColor(); diffuse[0]=c.GetRed(); diffuse[1]=c.GetGreen(); diffuse[2]=c.GetBlue(); } } // Specular { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.specularColor", renderer); if(p.IsNotNull()) { mitk::Color c = p->GetColor(); specular[0]=c.GetRed(); specular[1]=c.GetGreen(); specular[2]=c.GetBlue(); } } // Ambient coeff { node->GetFloatProperty("material.ambientCoefficient", coeff_ambient, renderer); } // Diffuse coeff { node->GetFloatProperty("material.diffuseCoefficient", coeff_diffuse, renderer); } // Specular coeff { node->GetFloatProperty("material.specularCoefficient", coeff_specular, renderer); } // Specular power { node->GetFloatProperty("material.specularPower", power_specular, renderer); } property->SetAmbient( coeff_ambient ); property->SetDiffuse( coeff_diffuse ); property->SetSpecular( coeff_specular ); property->SetSpecularPower( power_specular ); property->SetAmbientColor( ambient ); property->SetDiffuseColor( diffuse ); property->SetSpecularColor( specular ); } // Render mode { // Opacity { float opacity = 1.0f; if( node->GetOpacity(opacity,renderer) ) property->SetOpacity( opacity ); } // Wireframe line width { float lineWidth = 1; node->GetFloatProperty("material.wireframeLineWidth", lineWidth, renderer); property->SetLineWidth( lineWidth ); } // Representation { mitk::VtkRepresentationProperty::Pointer p; node->GetProperty(p, "material.representation", renderer); if(p.IsNotNull()) property->SetRepresentation( p->GetVtkRepresentation() ); } // Interpolation { mitk::VtkInterpolationProperty::Pointer p; node->GetProperty(p, "material.interpolation", renderer); if(p.IsNotNull()) property->SetInterpolation( p->GetVtkInterpolation() ); } } } void mitk::SurfaceVtkMapper3D::ApplyAllProperties( mitk::BaseRenderer* renderer, vtkActor* /*actor*/) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // Applying shading properties { Superclass::ApplyColorAndOpacityProperties( renderer, ls->m_Actor ) ; // VTK Properties ApplyMitkPropertiesToVtkProperty( this->GetDataNode(), ls->m_Actor->GetProperty(), renderer ); // Shaders - mitk::ShaderRepository::GetGlobalShaderRepository()->ApplyProperties(this->GetDataNode(),ls->m_Actor,renderer,ls->m_ShaderTimestampUpdate); + IShaderRepository* shaderRepo = CoreServices::GetShaderRepository(); + if (shaderRepo != NULL) + { + shaderRepo->ApplyProperties(this->GetDataNode(),ls->m_Actor,renderer,ls->m_ShaderTimestampUpdate); + } } mitk::LookupTableProperty::Pointer lookupTableProp; this->GetDataNode()->GetProperty(lookupTableProp, "LookupTable", renderer); if (lookupTableProp.IsNotNull() ) { ls->m_VtkPolyDataMapper->SetLookupTable(lookupTableProp->GetLookupTable()->GetVtkLookupTable()); } mitk::LevelWindow levelWindow; if(this->GetDataNode()->GetLevelWindow(levelWindow, renderer, "levelWindow")) { ls->m_VtkPolyDataMapper->SetScalarRange(levelWindow.GetLowerWindowBound(),levelWindow.GetUpperWindowBound()); } else if(this->GetDataNode()->GetLevelWindow(levelWindow, renderer)) { ls->m_VtkPolyDataMapper->SetScalarRange(levelWindow.GetLowerWindowBound(),levelWindow.GetUpperWindowBound()); } bool scalarVisibility = false; this->GetDataNode()->GetBoolProperty("scalar visibility", scalarVisibility); ls->m_VtkPolyDataMapper->SetScalarVisibility( (scalarVisibility ? 1 : 0) ); if(scalarVisibility) { mitk::VtkScalarModeProperty* scalarMode; if(this->GetDataNode()->GetProperty(scalarMode, "scalar mode", renderer)) { ls->m_VtkPolyDataMapper->SetScalarMode(scalarMode->GetVtkScalarMode()); } else ls->m_VtkPolyDataMapper->SetScalarModeToDefault(); bool colorMode = false; this->GetDataNode()->GetBoolProperty("color mode", colorMode); ls->m_VtkPolyDataMapper->SetColorMode( (colorMode ? 1 : 0) ); float scalarsMin = 0; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum")) != NULL) scalarsMin = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum"))->GetValue(); float scalarsMax = 1.0; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum")) != NULL) scalarsMax = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum"))->GetValue(); ls->m_VtkPolyDataMapper->SetScalarRange(scalarsMin,scalarsMax); } mitk::SmartPointerProperty::Pointer imagetextureProp; imagetextureProp = dynamic_cast< mitk::SmartPointerProperty * >( GetDataNode()->GetProperty("Surface.Texture", renderer)); if(imagetextureProp.IsNotNull()) { mitk::Image* miktTexture = dynamic_cast< mitk::Image* >( imagetextureProp->GetSmartPointer().GetPointer() ); vtkSmartPointer vtkTxture = vtkSmartPointer::New(); //Either select the first slice of a volume if(miktTexture->GetDimension(2) > 1) { MITK_WARN << "3D Textures are not supported by VTK and MITK. The first slice of the volume will be used instead!"; mitk::ImageSliceSelector::Pointer sliceselector = mitk::ImageSliceSelector::New(); sliceselector->SetSliceNr(0); sliceselector->SetChannelNr(0); sliceselector->SetTimeNr(0); sliceselector->SetInput(miktTexture); sliceselector->Update(); vtkTxture->SetInput(sliceselector->GetOutput()->GetVtkImageData()); } else //or just use the 2D image { vtkTxture->SetInput(miktTexture->GetVtkImageData()); } //pass the texture to the actor ls->m_Actor->SetTexture(vtkTxture); if(ls->m_VtkPolyDataMapper->GetInput()->GetPointData()->GetTCoords() == NULL) { MITK_ERROR << "Surface.Texture property was set, but there are no texture coordinates. Please provide texture coordinates for the vtkPolyData via vtkPolyData->GetPointData()->SetTCoords()."; } } // deprecated settings bool deprecatedUseCellData = false; this->GetDataNode()->GetBoolProperty("deprecated useCellDataForColouring", deprecatedUseCellData); bool deprecatedUsePointData = false; this->GetDataNode()->GetBoolProperty("deprecated usePointDataForColouring", deprecatedUsePointData); if (deprecatedUseCellData) { ls->m_VtkPolyDataMapper->SetColorModeToDefault(); ls->m_VtkPolyDataMapper->SetScalarRange(0,255); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_VtkPolyDataMapper->SetScalarModeToUseCellData(); ls->m_Actor->GetProperty()->SetSpecular (1); ls->m_Actor->GetProperty()->SetSpecularPower (50); ls->m_Actor->GetProperty()->SetInterpolationToPhong(); } else if (deprecatedUsePointData) { float scalarsMin = 0; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum")) != NULL) scalarsMin = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum"))->GetValue(); float scalarsMax = 0.1; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum")) != NULL) scalarsMax = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum"))->GetValue(); ls->m_VtkPolyDataMapper->SetScalarRange(scalarsMin,scalarsMax); ls->m_VtkPolyDataMapper->SetColorModeToMapScalars(); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_Actor->GetProperty()->SetSpecular (1); ls->m_Actor->GetProperty()->SetSpecularPower (50); ls->m_Actor->GetProperty()->SetInterpolationToPhong(); } int deprecatedScalarMode = VTK_COLOR_MODE_DEFAULT; if(this->GetDataNode()->GetIntProperty("deprecated scalar mode", deprecatedScalarMode, renderer)) { ls->m_VtkPolyDataMapper->SetScalarMode(deprecatedScalarMode); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_Actor->GetProperty()->SetSpecular (1); ls->m_Actor->GetProperty()->SetSpecularPower (50); //m_Actor->GetProperty()->SetInterpolationToPhong(); } // Check whether one or more ClippingProperty objects have been defined for // this node. Check both renderer specific and global property lists, since // properties in both should be considered. const PropertyList::PropertyMap *rendererProperties = this->GetDataNode()->GetPropertyList( renderer )->GetMap(); const PropertyList::PropertyMap *globalProperties = this->GetDataNode()->GetPropertyList( NULL )->GetMap(); // Add clipping planes (if any) ls->m_ClippingPlaneCollection->RemoveAllItems(); PropertyList::PropertyMap::const_iterator it; for ( it = rendererProperties->begin(); it != rendererProperties->end(); ++it ) { this->CheckForClippingProperty( renderer,(*it).second.GetPointer() ); } for ( it = globalProperties->begin(); it != globalProperties->end(); ++it ) { this->CheckForClippingProperty( renderer,(*it).second.GetPointer() ); } if ( ls->m_ClippingPlaneCollection->GetNumberOfItems() > 0 ) { ls->m_VtkPolyDataMapper->SetClippingPlanes( ls->m_ClippingPlaneCollection ); } else { ls->m_VtkPolyDataMapper->RemoveAllClippingPlanes(); } } vtkProp *mitk::SurfaceVtkMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); return ls->m_Actor; } void mitk::SurfaceVtkMapper3D::CheckForClippingProperty( mitk::BaseRenderer* renderer, mitk::BaseProperty *property ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // m_Prop3D = ls->m_Actor; ClippingProperty *clippingProperty = dynamic_cast< ClippingProperty * >( property ); if ( (clippingProperty != NULL) && (clippingProperty->GetClippingEnabled()) ) { const Point3D &origin = clippingProperty->GetOrigin(); const Vector3D &normal = clippingProperty->GetNormal(); vtkPlane *clippingPlane = vtkPlane::New(); clippingPlane->SetOrigin( origin[0], origin[1], origin[2] ); clippingPlane->SetNormal( normal[0], normal[1], normal[2] ); ls->m_ClippingPlaneCollection->AddItem( clippingPlane ); clippingPlane->UnRegister( NULL ); } } void mitk::SurfaceVtkMapper3D::SetDefaultPropertiesForVtkProperty(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { // Shading { node->AddProperty( "material.wireframeLineWidth", mitk::FloatProperty::New(1.0f) , renderer, overwrite ); node->AddProperty( "material.ambientCoefficient" , mitk::FloatProperty::New(0.05f) , renderer, overwrite ); node->AddProperty( "material.diffuseCoefficient" , mitk::FloatProperty::New(0.9f) , renderer, overwrite ); node->AddProperty( "material.specularCoefficient", mitk::FloatProperty::New(1.0f) , renderer, overwrite ); node->AddProperty( "material.specularPower" , mitk::FloatProperty::New(16.0f) , renderer, overwrite ); //node->AddProperty( "material.ambientColor" , mitk::ColorProperty::New(1.0f,1.0f,1.0f), renderer, overwrite ); //node->AddProperty( "material.diffuseColor" , mitk::ColorProperty::New(1.0f,1.0f,1.0f), renderer, overwrite ); //node->AddProperty( "material.specularColor" , mitk::ColorProperty::New(1.0f,1.0f,1.0f), renderer, overwrite ); node->AddProperty( "material.representation" , mitk::VtkRepresentationProperty::New() , renderer, overwrite ); node->AddProperty( "material.interpolation" , mitk::VtkInterpolationProperty::New() , renderer, overwrite ); } // Shaders + IShaderRepository* shaderRepo = CoreServices::GetShaderRepository(); + if (shaderRepo) { - mitk::ShaderRepository::GetGlobalShaderRepository()->AddDefaultProperties(node,renderer,overwrite); + shaderRepo->AddDefaultProperties(node,renderer,overwrite); } } void mitk::SurfaceVtkMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "color", mitk::ColorProperty::New(1.0f,1.0f,1.0f), renderer, overwrite ); node->AddProperty( "opacity", mitk::FloatProperty::New(1.0), renderer, overwrite ); mitk::SurfaceVtkMapper3D::SetDefaultPropertiesForVtkProperty(node,renderer,overwrite); // Shading node->AddProperty( "scalar visibility", mitk::BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "color mode", mitk::BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "scalar mode", mitk::VtkScalarModeProperty::New(), renderer, overwrite ); mitk::Surface::Pointer surface = dynamic_cast(node->GetData()); if(surface.IsNotNull()) { if((surface->GetVtkPolyData() != 0) && (surface->GetVtkPolyData()->GetPointData() != NULL) && (surface->GetVtkPolyData()->GetPointData()->GetScalars() != 0)) { node->AddProperty( "scalar visibility", mitk::BoolProperty::New(true), renderer, overwrite ); node->AddProperty( "color mode", mitk::BoolProperty::New(true), renderer, overwrite ); } } // Backface culling node->AddProperty( "Backface Culling", mitk::BoolProperty::New(false), renderer, overwrite ); Superclass::SetDefaultProperties(node, renderer, overwrite); } void mitk::SurfaceVtkMapper3D::SetImmediateModeRenderingOn(int /*on*/) { /* if (m_VtkPolyDataMapper != NULL) m_VtkPolyDataMapper->SetImmediateModeRendering(on); */ } diff --git a/Core/Code/Rendering/mitkVtkMapper.h b/Core/Code/Rendering/mitkVtkMapper.h index cb544e5473..6344bcfe5d 100644 --- a/Core/Code/Rendering/mitkVtkMapper.h +++ b/Core/Code/Rendering/mitkVtkMapper.h @@ -1,145 +1,145 @@ /*=================================================================== 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. ===================================================================*/ // change number #ifndef VTKMAPPER_H_HEADER_INCLUDED_C1C5453B #define VTKMAPPER_H_HEADER_INCLUDED_C1C5453B #include #include "mitkMapper.h" #include "mitkBaseRenderer.h" #include "mitkDataNode.h" #include "mitkVtkPropRenderer.h" #include #include #include #include #include #include #include #include class vtkProp; class vtkProp3D; class vtkActor; namespace mitk { /** \brief Base class of all Vtk Mappers in order to display primitives * by exploiting Vtk functionality. * * Rendering of opaque, translucent or volumetric geometry and overlays * is done in consecutive render passes. * * \ingroup Mapper */ class MITK_CORE_EXPORT VtkMapper : public Mapper { public: mitkClassMacro(VtkMapper,Mapper); virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer) = 0; /** \brief Re-issues all drawing commands required to describe * the entire scene each time a new frame is required, * regardless of actual changes. */ static void SetVtkMapperImmediateModeRendering(vtkMapper *mapper); /** * \brief Returns whether this is an vtk-based mapper - * @deprecated All mappers of superclass VTKMapper are vtk based, use a dynamic_cast instead + * \deprecatedSince{2013_03} All mappers of superclass VTKMapper are vtk based, use a dynamic_cast instead */ DEPRECATED( virtual bool IsVtkBased() const ); /** \brief Determines which geometry should be rendered * (opaque, translucent, volumetric, overlay) * and calls the appropriate function. * * Called by mitk::VtkPropRenderer::Render */ void MitkRender(mitk::BaseRenderer* renderer, mitk::VtkPropRenderer::RenderType type); /** \brief Checks visibility and renders the overlay */ virtual void MitkRenderOverlay(BaseRenderer* renderer); /** \brief Checks visibility and renders untransparent geometry */ virtual void MitkRenderOpaqueGeometry(BaseRenderer* renderer); /** \brief Checks visiblity and renders transparent geometry */ virtual void MitkRenderTranslucentGeometry(BaseRenderer* renderer); /** \brief Checks visibility and renders volumes */ virtual void MitkRenderVolumetricGeometry(BaseRenderer* renderer); /** \brief Returns true if this mapper owns the specified vtkProp for * the given BaseRenderer. * * Note: returns false by default; should be implemented for VTK-based * Mapper subclasses. */ virtual bool HasVtkProp( const vtkProp *prop, BaseRenderer *renderer ); /** \brief Set the vtkTransform of the m_Prop3D for * the current time step of \a renderer * * Called by mitk::VtkPropRenderer::Update before rendering */ virtual void UpdateVtkTransform(mitk::BaseRenderer *renderer); /** * \brief Apply color and opacity properties read from the PropertyList - * @deprecated Use ApplyColorAndOpacityProperties(mitk::BaseRenderer* renderer, vtkActor * actor) instead + * \deprecatedSince{2013_03} Use ApplyColorAndOpacityProperties(mitk::BaseRenderer* renderer, vtkActor * actor) instead */ DEPRECATED(inline virtual void ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer)) { ApplyColorAndOpacityProperties(renderer, actor); } /** * \brief Apply color and opacity properties read from the PropertyList. * Called by mapper subclasses. */ virtual void ApplyColorAndOpacityProperties(mitk::BaseRenderer* renderer, vtkActor * actor); /** * \brief Release vtk-based graphics resources that are being consumed by this mapper. * The parameter window could be used to determine which graphic * resources to releases. Must be overwritten in individual subclasses * if vtkProps are used. */ virtual void ReleaseGraphicsResources(vtkWindow* /*renWin*/) { }; protected: /** constructor */ VtkMapper(); /** virtual destructor in order to derive from this class */ virtual ~VtkMapper(); private: /** copy constructor */ VtkMapper( const VtkMapper &); /** assignment operator */ VtkMapper & operator=(const VtkMapper &); }; } // namespace mitk #endif /* VTKMAPPER_H_HEADER_INCLUDED_C1C5453B */ diff --git a/Core/Code/Rendering/mitkVtkPropRenderer.cpp b/Core/Code/Rendering/mitkVtkPropRenderer.cpp index 59fc8efcef..22e1a83215 100644 --- a/Core/Code/Rendering/mitkVtkPropRenderer.cpp +++ b/Core/Code/Rendering/mitkVtkPropRenderer.cpp @@ -1,926 +1,927 @@ /*=================================================================== 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 "mitkVtkPropRenderer.h" // MAPPERS #include "mitkMapper.h" #include "mitkImageVtkMapper2D.h" #include "mitkVtkMapper.h" #include "mitkGLMapper.h" #include "mitkGeometry2DDataVtkMapper3D.h" #include "mitkPointSetGLMapper2D.h" #include "mitkImageSliceSelector.h" #include "mitkRenderingManager.h" #include "mitkGL.h" #include "mitkGeometry3D.h" #include "mitkDisplayGeometry.h" #include "mitkLevelWindow.h" #include "mitkCameraController.h" #include "mitkVtkInteractorCameraController.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include "mitkSurface.h" #include "mitkNodePredicateDataType.h" #include "mitkVtkInteractorStyle.h" // VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include mitk::VtkPropRenderer::VtkPropRenderer( const char* name, vtkRenderWindow * renWin, mitk::RenderingManager* rm ) : BaseRenderer(name,renWin, rm), m_VtkMapperPresent(false), m_CameraInitializedForMapperID(0) { didCount=false; m_WorldPointPicker = vtkWorldPointPicker::New(); m_PointPicker = vtkPointPicker::New(); m_PointPicker->SetTolerance( 0.0025 ); m_CellPicker = vtkCellPicker::New(); m_CellPicker->SetTolerance( 0.0025 ); mitk::Geometry2DDataVtkMapper3D::Pointer geometryMapper = mitk::Geometry2DDataVtkMapper3D::New(); m_CurrentWorldGeometry2DMapper = geometryMapper; m_CurrentWorldGeometry2DNode->SetMapper(2, geometryMapper); m_LightKit = vtkLightKit::New(); m_LightKit->AddLightsToRenderer(m_VtkRenderer); m_PickingMode = WorldPointPicking; m_TextRenderer = vtkRenderer::New(); m_TextRenderer->SetRenderWindow(renWin); m_TextRenderer->SetInteractive(0); m_TextRenderer->SetErase(0); } /*! \brief Destructs the VtkPropRenderer. */ mitk::VtkPropRenderer::~VtkPropRenderer() { // Workaround for GLDisplayList Bug { m_MapperID=0; checkState(); } if (m_LightKit != NULL) m_LightKit->Delete(); if (m_VtkRenderer!=NULL) { m_CameraController = NULL; m_VtkRenderer->Delete(); m_VtkRenderer = NULL; } else m_CameraController = NULL; if (m_WorldPointPicker != NULL) m_WorldPointPicker->Delete(); if (m_PointPicker != NULL) m_PointPicker->Delete(); if (m_CellPicker != NULL) m_CellPicker->Delete(); if (m_TextRenderer != NULL) m_TextRenderer->Delete(); } void mitk::VtkPropRenderer::SetDataStorage( mitk::DataStorage* storage ) { if ( storage == NULL ) return; BaseRenderer::SetDataStorage(storage); static_cast(m_CurrentWorldGeometry2DMapper.GetPointer())->SetDataStorageForTexture( m_DataStorage.GetPointer() ); // Compute the geometry from the current data tree bounds and set it as world geometry this->SetWorldGeometryToDataStorageBounds(); } bool mitk::VtkPropRenderer::SetWorldGeometryToDataStorageBounds() { if ( m_DataStorage.IsNull() ) return false; //initialize world geometry mitk::TimeSlicedGeometry::Pointer geometry = m_DataStorage->ComputeVisibleBoundingGeometry3D( NULL, "includeInBoundingBox" ); if ( geometry.IsNull() ) return false; this->SetWorldGeometry(geometry); //this->GetDisplayGeometry()->SetSizeInDisplayUnits( this->m_TextRenderer->GetRenderWindow()->GetSize()[0], this->m_TextRenderer->GetRenderWindow()->GetSize()[1] ); this->GetDisplayGeometry()->Fit(); this->GetVtkRenderer()->ResetCamera(); this->Modified(); return true; } /*! \brief Called by the vtkMitkRenderProp in order to start MITK rendering process. */ int mitk::VtkPropRenderer::Render(mitk::VtkPropRenderer::RenderType type) { // Do we have objects to render? if ( this->GetEmptyWorldGeometry()) return 0; if ( m_DataStorage.IsNull()) return 0; // Update mappers and prepare mapper queue if (type == VtkPropRenderer::Opaque) this->PrepareMapperQueue(); //go through the generated list and let the sorted mappers paint bool lastVtkBased = true; //bool sthVtkBased = false; for(MappersMapType::iterator it = m_MappersMap.begin(); it != m_MappersMap.end(); it++) { Mapper * mapper = (*it).second; VtkMapper* vtkmapper = dynamic_cast(mapper); if(vtkmapper) { //sthVtkBased = true; if(!lastVtkBased) { Disable2DOpenGL(); lastVtkBased = true; } } else if(lastVtkBased) { Enable2DOpenGL(); lastVtkBased = false; } mapper->MitkRender(this, type); } if (lastVtkBased == false) Disable2DOpenGL(); // Render text if (type == VtkPropRenderer::Overlay) { if (m_TextCollection.size() > 0) { for (TextMapType::iterator it = m_TextCollection.begin(); it != m_TextCollection.end() ; it++) m_TextRenderer->AddViewProp((*it).second); m_TextRenderer->Render(); } } return 1; } /*! \brief PrepareMapperQueue iterates the datatree PrepareMapperQueue iterates the datatree in order to find mappers which shall be rendered. Also, it sortes the mappers wrt to their layer. */ void mitk::VtkPropRenderer::PrepareMapperQueue() { // variable for counting LOD-enabled mappers m_NumberOfVisibleLODEnabledMappers = 0; // Do we have to update the mappers ? if ( m_LastUpdateTime < GetMTime() || m_LastUpdateTime < GetDisplayGeometry()->GetMTime() ) { Update(); } else if (m_MapperID>=1 && m_MapperID < 6) Update(); // remove all text properties before mappers will add new ones m_TextRenderer->RemoveAllViewProps(); for ( unsigned int i=0; iDelete(); } m_TextCollection.clear(); // clear priority_queue m_MappersMap.clear(); int mapperNo = 0; //DataStorage if( m_DataStorage.IsNull() ) return; DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { DataNode::Pointer node = it->Value(); if ( node.IsNull() ) continue; mitk::Mapper::Pointer mapper = node->GetMapper(m_MapperID); if ( mapper.IsNull() ) continue; bool visible = true; node->GetVisibility(visible, this, "visible"); // The information about LOD-enabled mappers is required by RenderingManager if ( mapper->IsLODEnabled( this ) && visible ) { ++m_NumberOfVisibleLODEnabledMappers; } // mapper without a layer property get layer number 1 int layer = 1; node->GetIntProperty("layer", layer, this); int nr = (layer<<16) + mapperNo; m_MappersMap.insert( std::pair< int, Mapper * >( nr, mapper ) ); mapperNo++; } } /*! \brief Enable2DOpenGL() and Disable2DOpenGL() are used to switch between 2D rendering (orthographic projection) and 3D rendering (perspective projection) */ void mitk::VtkPropRenderer::Enable2DOpenGL() { GLint iViewport[4]; // Get a copy of the viewport glGetIntegerv( GL_VIEWPORT, iViewport ); // Save a copy of the projection matrix so that we can restore it // when it's time to do 3D rendering again. glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); // Set up the orthographic projection glOrtho( iViewport[0], iViewport[0]+iViewport[2], iViewport[1], iViewport[1]+iViewport[3], -1.0, 1.0 ); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); // Make sure depth testing and lighting are disabled for 2D rendering until // we are finished rendering in 2D glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT ); glDisable( GL_DEPTH_TEST ); glDisable( GL_LIGHTING ); // disable the texturing here so crosshair is painted in the correct colors // vtk will reenable texturing every time it is needed glDisable( GL_TEXTURE_1D ); glDisable( GL_TEXTURE_2D ); + glLineWidth(1.0); } /*! \brief Initialize the VtkPropRenderer Enable2DOpenGL() and Disable2DOpenGL() are used to switch between 2D rendering (orthographic projection) and 3D rendering (perspective projection) */ void mitk::VtkPropRenderer::Disable2DOpenGL() { glPopAttrib(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); } void mitk::VtkPropRenderer::Update(mitk::DataNode* datatreenode) { if(datatreenode!=NULL) { mitk::Mapper::Pointer mapper = datatreenode->GetMapper(m_MapperID); if(mapper.IsNotNull()) { GLMapper* glmapper=dynamic_cast(mapper.GetPointer()); if(GetDisplayGeometry()->IsValid()) { if(glmapper != NULL) { glmapper->Update(this); m_VtkMapperPresent=false; } else { VtkMapper* vtkmapper=dynamic_cast(mapper.GetPointer()); if(vtkmapper != NULL) { vtkmapper->Update(this); vtkmapper->UpdateVtkTransform(this); m_VtkMapperPresent=true; } } } } } } void mitk::VtkPropRenderer::Update() { if( m_DataStorage.IsNull() ) return; m_VtkMapperPresent = false; mitk::DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetAll(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) Update(it->Value()); Modified(); m_LastUpdateTime = GetMTime(); } /*! \brief This method is called from the two Constructors */ void mitk::VtkPropRenderer::InitRenderer(vtkRenderWindow* renderWindow) { BaseRenderer::InitRenderer(renderWindow); if(renderWindow == NULL) { m_InitNeeded = false; m_ResizeNeeded = false; return; } m_InitNeeded = true; m_ResizeNeeded = true; m_LastUpdateTime = 0; } /*! \brief Resize the OpenGL Window */ void mitk::VtkPropRenderer::Resize(int w, int h) { BaseRenderer::Resize(w, h); m_RenderingManager->RequestUpdate(this->GetRenderWindow()); } void mitk::VtkPropRenderer::InitSize(int w, int h) { m_RenderWindow->SetSize(w,h); Superclass::InitSize(w, h); Modified(); Update(); if(m_VtkRenderer!=NULL) { int w=vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); m_VtkRenderer->ResetCamera(); vtkObject::SetGlobalWarningDisplay(w); } } void mitk::VtkPropRenderer::SetMapperID(const MapperSlotId mapperId) { if(m_MapperID != mapperId) Superclass::SetMapperID(mapperId); // Workaround for GL Displaylist Bug checkState(); } /*! \brief Activates the current renderwindow. */ void mitk::VtkPropRenderer::MakeCurrent() { if(m_RenderWindow!=NULL) m_RenderWindow->MakeCurrent(); } void mitk::VtkPropRenderer::PickWorldPoint(const mitk::Point2D& displayPoint, mitk::Point3D& worldPoint) const { if(m_VtkMapperPresent) { //m_WorldPointPicker->SetTolerance (0.0001); switch ( m_PickingMode ) { case (WorldPointPicking) : { m_WorldPointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_WorldPointPicker->GetPickPosition(), worldPoint); break; } case (PointPicking) : { // create a new vtkRenderer // give it all necessary information (camera position, etc.) // get all surfaces from datastorage, get actors from them // add all those actors to the new renderer // give this new renderer to pointpicker /* vtkRenderer* pickingRenderer = vtkRenderer::New(); pickingRenderer->SetActiveCamera( ); DataStorage* dataStorage = m_DataStorage; TNodePredicateDataType isSurface; DataStorage::SetOfObjects::ConstPointer allSurfaces = dataStorage->GetSubset( isSurface ); MITK_INFO << "in picking: got " << allSurfaces->size() << " surfaces." << std::endl; for (DataStorage::SetOfObjects::const_iterator iter = allSurfaces->begin(); iter != allSurfaces->end(); ++iter) { const DataNode* currentNode = *iter; VtkMapper3D* baseVtkMapper3D = dynamic_cast( currentNode->GetMapper( BaseRenderer::Standard3D ) ); if ( baseVtkMapper3D ) { vtkActor* actor = dynamic_cast( baseVtkMapper3D->GetViewProp() ); if (actor) { MITK_INFO << "a" << std::flush; pickingRenderer->AddActor( actor ); } } } MITK_INFO << ";" << std::endl; */ m_PointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_PointPicker->GetPickPosition(), worldPoint); break; } } } else { Superclass::PickWorldPoint(displayPoint, worldPoint); } } mitk::DataNode * mitk::VtkPropRenderer::PickObject( const Point2D &displayPosition, Point3D &worldPosition ) const { if ( m_VtkMapperPresent ) { m_CellPicker->InitializePickList(); // Iterate over all DataStorage objects to determine all vtkProps intended // for picking DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for ( DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it ) { DataNode *node = it->Value(); if ( node == NULL ) continue; bool pickable = false; node->GetBoolProperty( "pickable", pickable ); if ( !pickable ) continue; VtkMapper *mapper = dynamic_cast < VtkMapper * > ( node->GetMapper( m_MapperID ) ); if ( mapper == NULL ) continue; vtkProp *prop = mapper->GetVtkProp( (mitk::BaseRenderer *)this ); if ( prop == NULL ) continue; m_CellPicker->AddPickList( prop ); } // Do the picking and retrieve the picked vtkProp (if any) m_CellPicker->PickFromListOn(); m_CellPicker->Pick( displayPosition[0], displayPosition[1], 0.0, m_VtkRenderer ); m_CellPicker->PickFromListOff(); vtk2itk( m_CellPicker->GetPickPosition(), worldPosition ); vtkProp *prop = m_CellPicker->GetViewProp(); if ( prop == NULL ) { return NULL; } // Iterate over all DataStorage objects to determine if the retrieved // vtkProp is owned by any associated mapper. for ( DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { DataNode::Pointer node = it->Value(); if ( node.IsNull() ) continue; mitk::Mapper * mapper = node->GetMapper( m_MapperID ); if ( mapper == NULL) continue; mitk::VtkMapper * vtkmapper = dynamic_cast< VtkMapper * >(mapper); if(vtkmapper){ //if vtk-based, then ... if ( vtkmapper->HasVtkProp( prop, const_cast< mitk::VtkPropRenderer * >( this ) ) ) { return node; } } } return NULL; } else { return Superclass::PickObject( displayPosition, worldPosition ); } }; /*! \brief Writes some 2D text as overlay. Function returns an unique int Text_ID for each call, which can be used via the GetTextLabelProperty(int text_id) function in order to get a vtkTextProperty. This property enables the setup of font, font size, etc. */ int mitk::VtkPropRenderer::WriteSimpleText(std::string text, double posX, double posY, double color1, double color2, double color3, float opacity) { if(text.size() > 0) { vtkTextActor* textActor = vtkTextActor::New(); textActor->SetPosition(posX,posY); textActor->SetInput(text.c_str()); textActor->GetTextProperty()->SetColor(color1, color2, color3); //TODO: Read color from node property textActor->GetTextProperty()->SetOpacity( opacity ); int text_id = m_TextCollection.size(); m_TextCollection.insert(TextMapType::value_type(text_id,textActor)); return text_id; } return -1; } /*! \brief Can be used in order to get a vtkTextProperty for a specific text_id. This property enables the setup of font, font size, etc. */ vtkTextProperty* mitk::VtkPropRenderer::GetTextLabelProperty(int text_id) { return this->m_TextCollection[text_id]->GetTextProperty(); } void mitk::VtkPropRenderer::InitPathTraversal() { if (m_DataStorage.IsNotNull()) { m_PickingObjects = m_DataStorage->GetAll(); m_PickingObjectsIterator = m_PickingObjects->begin(); } } vtkAssemblyPath* mitk::VtkPropRenderer::GetNextPath() { if (m_DataStorage.IsNull() ) { return NULL; } if ( m_PickingObjectsIterator == m_PickingObjects->end() ) { return NULL; } vtkAssemblyPath* returnPath = vtkAssemblyPath::New(); //returnPath->Register(NULL); bool success = false; while (!success) { // loop until AddNode can be called successfully const DataNode* node = *m_PickingObjectsIterator; if (node) { Mapper* mapper = node->GetMapper( BaseRenderer::Standard3D ); if (mapper) { VtkMapper* vtkmapper = dynamic_cast( mapper ); if (vtkmapper) { vtkProp* prop = vtkmapper->GetVtkProp(this); if ( prop && prop->GetVisibility() ) { // add to assembly path returnPath->AddNode( prop, prop->GetMatrix() ); success = true; } } } } ++m_PickingObjectsIterator; if ( m_PickingObjectsIterator == m_PickingObjects->end() ) break; } if ( success ) { return returnPath; } else { return NULL; } } void mitk::VtkPropRenderer::ReleaseGraphicsResources(vtkWindow *renWin) { if( m_DataStorage.IsNull() ) return; DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (DataStorage::SetOfObjects::const_iterator iter = allObjects->begin(); iter != allObjects->end(); ++iter) { DataNode::Pointer node = *iter; if ( node.IsNull() ) continue; Mapper * mapper = node->GetMapper(m_MapperID); if (mapper) { VtkMapper* vtkmapper = dynamic_cast( mapper ); if(vtkmapper) vtkmapper->ReleaseGraphicsResources(renWin); } } } const vtkWorldPointPicker *mitk::VtkPropRenderer::GetWorldPointPicker() const { return m_WorldPointPicker; } const vtkPointPicker *mitk::VtkPropRenderer::GetPointPicker() const { return m_PointPicker; } const vtkCellPicker *mitk::VtkPropRenderer::GetCellPicker() const { return m_CellPicker; } mitk::VtkPropRenderer::MappersMapType mitk::VtkPropRenderer::GetMappersMap() const { return m_MappersMap; } // Workaround for GL Displaylist bug static int glWorkAroundGlobalCount = 0; bool mitk::VtkPropRenderer::useImmediateModeRendering() { return glWorkAroundGlobalCount>1; } void mitk::VtkPropRenderer::checkState() { if (m_MapperID == Standard3D) { if (!didCount) { didCount = true; glWorkAroundGlobalCount++; if (glWorkAroundGlobalCount == 2) { MITK_INFO << "Multiple 3D Renderwindows active...: turning Immediate Rendering ON for legacy mappers"; // vtkMapper::GlobalImmediateModeRenderingOn(); } //MITK_INFO << "GLOBAL 3D INCREASE " << glWorkAroundGlobalCount << "\n"; } } else { if(didCount) { didCount=false; glWorkAroundGlobalCount--; if(glWorkAroundGlobalCount==1) { MITK_INFO << "Single 3D Renderwindow active...: turning Immediate Rendering OFF for legacy mappers"; // vtkMapper::GlobalImmediateModeRenderingOff(); } //MITK_INFO << "GLOBAL 3D DECREASE " << glWorkAroundGlobalCount << "\n"; } } } //### Contains all methods which are neceassry before each VTK Render() call void mitk::VtkPropRenderer::PrepareRender() { if ( this->GetMapperID() != m_CameraInitializedForMapperID ) { Initialize2DvtkCamera(); //Set parallel projection etc. } AdjustCameraToScene(); //Prepare camera for 2D render windows } bool mitk::VtkPropRenderer::Initialize2DvtkCamera() { if ( this->GetMapperID() == Standard3D ) { //activate parallel projection for 2D this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(false); this->GetRenderWindow()->GetInteractor()->SetInteractorStyle( vtkInteractorStyleTrackballCamera::New() ); m_CameraInitializedForMapperID = Standard3D; } else if( this->GetMapperID() == Standard2D) { //activate parallel projection for 2D this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(true); //turn the light out in the scene in order to render correct grey values. //TODO Implement a property for light in the 2D render windows (in another method) this->GetVtkRenderer()->RemoveAllLights(); this->GetRenderWindow()->GetInteractor()->SetInteractorStyle( mitkVtkInteractorStyle::New() ); m_CameraInitializedForMapperID = Standard2D; } return true; } void mitk::VtkPropRenderer::AdjustCameraToScene(){ if(this->GetMapperID() == Standard2D) { const mitk::DisplayGeometry* displayGeometry = this->GetDisplayGeometry(); double objectHeightInMM = this->GetCurrentWorldGeometry2D()->GetExtentInMM(1);//the height of the current object slice in mm double displayHeightInMM = displayGeometry->GetSizeInMM()[1]; //the display height in mm (gets smaller when you zoom in) double zoomFactor = objectHeightInMM/displayHeightInMM; //displayGeometry->GetScaleFactorMMPerDisplayUnit() //determine how much of the object can be displayed Vector2D displayGeometryOriginInMM = displayGeometry->GetOriginInMM(); //top left of the render window (Origin) Vector2D displayGeometryCenterInMM = displayGeometryOriginInMM + displayGeometry->GetSizeInMM()*0.5; //center of the render window: (Origin + Size/2) //Scale the rendered object: //The image is scaled by a single factor, because in an orthographic projection sizes //are preserved (so you cannot scale X and Y axis with different parameters). The //parameter sets the size of the total display-volume. If you set this to the image //height, the image plus a border with the size of the image will be rendered. //Therefore, the size is imageHeightInMM / 2. this->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(objectHeightInMM*0.5 ); //zooming with the factor calculated by dividing displayHeight through imegeHeight. The factor is inverse, because the VTK zoom method is working inversely. this->GetVtkRenderer()->GetActiveCamera()->Zoom(zoomFactor); //the center of the view-plane double viewPlaneCenter[3]; viewPlaneCenter[0] = displayGeometryCenterInMM[0]; viewPlaneCenter[1] = displayGeometryCenterInMM[1]; viewPlaneCenter[2] = 0.0; //the view-plane is located in the XY-plane with Z=0.0 //define which direction is "up" for the ciamera (like default for vtk (0.0, 1.0, 0.0) double cameraUp[3]; cameraUp[0] = 0.0; cameraUp[1] = 1.0; cameraUp[2] = 0.0; //the position of the camera (center[0], center[1], 900000) double cameraPosition[3]; cameraPosition[0] = viewPlaneCenter[0]; cameraPosition[1] = viewPlaneCenter[1]; cameraPosition[2] = 900000.0; //Reason for 900000: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. //set the camera corresponding to the textured plane vtkSmartPointer camera = this->GetVtkRenderer()->GetActiveCamera(); if (camera) { camera->SetPosition( cameraPosition ); //set the camera position on the textured plane normal (in our case this is the view plane normal) camera->SetFocalPoint( viewPlaneCenter ); //set the focal point to the center of the textured plane camera->SetViewUp( cameraUp ); //set the view-up for the camera // double distance = sqrt((cameraPosition[2]-viewPlaneCenter[2])*(cameraPosition[2]-viewPlaneCenter[2])); // camera->SetClippingRange(distance-50, distance+50); //Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. camera->SetClippingRange(0.1, 1000000); //Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. } const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( this->GetCurrentWorldGeometry2D() ); if ( planeGeometry != NULL ) { //Transform the camera to the current position (transveral, coronal and saggital plane). //This is necessary, because the SetUserTransform() method does not manipulate the vtkCamera. //(Without not all three planes would be visible). vtkSmartPointer trans = vtkSmartPointer::New(); vtkSmartPointer matrix = vtkSmartPointer::New(); Point3D origin; Vector3D right, bottom, normal; origin = planeGeometry->GetOrigin(); right = planeGeometry->GetAxisVector( 0 ); // right = Extent of Image in mm (worldspace) bottom = planeGeometry->GetAxisVector( 1 ); normal = planeGeometry->GetNormal(); right.Normalize(); bottom.Normalize(); normal.Normalize(); matrix->SetElement(0, 0, right[0]); matrix->SetElement(1, 0, right[1]); matrix->SetElement(2, 0, right[2]); matrix->SetElement(0, 1, bottom[0]); matrix->SetElement(1, 1, bottom[1]); matrix->SetElement(2, 1, bottom[2]); matrix->SetElement(0, 2, normal[0]); matrix->SetElement(1, 2, normal[1]); matrix->SetElement(2, 2, normal[2]); matrix->SetElement(0, 3, origin[0]); matrix->SetElement(1, 3, origin[1]); matrix->SetElement(2, 3, origin[2]); matrix->SetElement(3, 0, 0.0); matrix->SetElement(3, 1, 0.0); matrix->SetElement(3, 2, 0.0); matrix->SetElement(3, 3, 1.0); trans->SetMatrix(matrix); //Transform the camera to the current position (transveral, coronal and saggital plane). this->GetVtkRenderer()->GetActiveCamera()->ApplyTransform(trans); } } } diff --git a/Core/Code/Rendering/vtkMitkLevelWindowFilter.cpp b/Core/Code/Rendering/vtkMitkLevelWindowFilter.cpp index d12d23b1c4..b76eb6c44e 100644 --- a/Core/Code/Rendering/vtkMitkLevelWindowFilter.cpp +++ b/Core/Code/Rendering/vtkMitkLevelWindowFilter.cpp @@ -1,597 +1,600 @@ /*=================================================================== 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 "vtkMitkLevelWindowFilter.h" #include #include #include #include +#include "vtkObjectFactory.h" //used for acos etc. #include //used for PI #include #include static const double PI = itk::Math::pi; +vtkStandardNewMacro(vtkMitkLevelWindowFilter); + vtkMitkLevelWindowFilter::vtkMitkLevelWindowFilter():m_MinOpacity(0.0),m_MaxOpacity(255.0) { //MITK_INFO << "mitk level/window filter uses " << GetNumberOfThreads() << " thread(s)"; } vtkMitkLevelWindowFilter::~vtkMitkLevelWindowFilter() { } unsigned long int vtkMitkLevelWindowFilter::GetMTime() { unsigned long mTime=this->vtkObject::GetMTime(); unsigned long time; if ( this->m_LookupTable != NULL ) { time = this->m_LookupTable->GetMTime(); mTime = ( time > mTime ? time : mTime ); } return mTime; } void vtkMitkLevelWindowFilter::SetLookupTable(vtkScalarsToColors *lookupTable) { if (m_LookupTable != lookupTable) { m_LookupTable = lookupTable; this->Modified(); } } vtkScalarsToColors* vtkMitkLevelWindowFilter::GetLookupTable() { return m_LookupTable; } //This code was copied from the iil. The template works only for float and double. //Internal method which should never be used anywhere else and should not be in th header. // Convert color pixels from (R,G,B) to (H,S,I). // Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002. template void RGBtoHSI(T* RGB, T* HSI) { T R = RGB[0], G = RGB[1], B = RGB[2], nR = (R<0?0:(R>255?255:R))/255, nG = (G<0?0:(G>255?255:G))/255, nB = (B<0?0:(B>255?255:B))/255, m = nR0) H = (nB<=nG)?theta:360-theta; if (sum>0) S = 1 - 3/sum*m; I = sum/3; HSI[0] = (T)H; HSI[1] = (T)S; HSI[2] = (T)I; } //This code was copied from the iil. The template works only for float and double. //Internal method which should never be used anywhere else and should not be in th header. // Convert color pixels from (H,S,I) to (R,G,B). template void HSItoRGB(T* HSI, T* RGB) { T H = (T)HSI[0], S = (T)HSI[1], I = (T)HSI[2], a = I*(1-S), R = 0, G = 0, B = 0; if (H<120) { B = a; R = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); G = 3*I-(R+B); } else if (H<240) { H-=120; R = a; G = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); B = 3*I-(R+G); } else { H-=240; G = a; B = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); R = 3*I-(G+B); } R*=255; G*=255; B*=255; RGB[0] = (T)(R<0?0:(R>255?255:R)); RGB[1] = (T)(G<0?0:(G>255?255:G)); RGB[2] = (T)(B<0?0:(B>255?255:B)); } //Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkApplyLookupTableOnRGBA(vtkMitkLevelWindowFilter* self, vtkImageData* inData, vtkImageData* outData, int outExt[6], vtkFloatingPointType* clippingBounds, T*) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); vtkLookupTable* lookupTable; const int maxC = inData->GetNumberOfScalarComponents(); double tableRange[2]; lookupTable = dynamic_cast(self->GetLookupTable()); lookupTable->GetTableRange(tableRange); //parameters for RGB level window double scale = (tableRange[1] -tableRange[0] > 0 ? 255.0 / (tableRange[1] - tableRange[0]) : 0.0); double bias = tableRange[0] * scale; //parameters for opaque level window double scaleOpac = (self->GetMaxOpacity() -self->GetMinOpacity() > 0 ? 255.0 / (self->GetMaxOpacity() - self->GetMinOpacity()) : 0.0); double biasOpac = self->GetMinOpacity() * scaleOpac; int y = outExt[2]; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { T* inputSI = inputIt.BeginSpan(); T* outputSI = outputIt.BeginSpan(); T* outputSIEnd = outputIt.EndSpan(); if( y >= clippingBounds[2] && y < clippingBounds[3] ) { int x = outExt[0]; while (outputSI != outputSIEnd) { if ( x >= clippingBounds[0] && x < clippingBounds[1]) { double rgb[3], alpha, hsi[3]; // level/window mechanism for intensity in HSI space rgb[0] = static_cast(*inputSI); inputSI++; rgb[1] = static_cast(*inputSI); inputSI++; rgb[2] = static_cast(*inputSI); inputSI++; RGBtoHSI(rgb,hsi); hsi[2] = hsi[2] * 255.0 * scale - bias; hsi[2] = (hsi[2] > 255.0 ? 255 : (hsi[2] < 0.0 ? 0 : hsi[2])); hsi[2] /= 255.0; HSItoRGB(hsi,rgb); *outputSI = static_cast(rgb[0]); outputSI++; *outputSI = static_cast(rgb[1]); outputSI++; *outputSI = static_cast(rgb[2]); outputSI++; unsigned char finalAlpha = 255; //RGBA case if(maxC >= 4) { // level/window mechanism for opacity alpha = static_cast(*inputSI); inputSI++; alpha = alpha * scaleOpac - biasOpac; if(alpha > 255.0) { alpha = 255.0; } else if(alpha < 0.0) { alpha = 0.0; } finalAlpha = static_cast(alpha); for( int c = 4; c < maxC; c++ ) inputSI++; } *outputSI = static_cast(finalAlpha); outputSI++; } else { inputSI+=maxC; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; } x++; } } else { while (outputSI != outputSIEnd) { *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; *outputSI = 0; outputSI++; } } inputIt.NextSpan(); outputIt.NextSpan(); y++; } } //Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkApplyLookupTableOnScalarsFast(vtkMitkLevelWindowFilter *self, vtkImageData *inData, vtkImageData *outData, int outExt[6], T *) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); double tableRange[2]; // access vtkLookupTable vtkLookupTable* lookupTable = dynamic_cast(self->GetLookupTable()); lookupTable->GetTableRange(tableRange); // access elements of the vtkLookupTable int * realLookupTable = reinterpret_cast(lookupTable->GetTable()->GetPointer(0)); int maxIndex = lookupTable->GetNumberOfColors() - 1; float scale = (tableRange[1] -tableRange[0] > 0 ? (maxIndex + 1) / (tableRange[1] - tableRange[0]) : 0.0); // ensuring that starting point is zero float bias = - tableRange[0] * scale; // due to later conversion to int for rounding bias += 0.5f; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { unsigned char* outputSI = outputIt.BeginSpan(); unsigned char* outputSIEnd = outputIt.EndSpan(); T* inputSI = inputIt.BeginSpan(); while (outputSI != outputSIEnd) { // map to an index int idx = static_cast( *inputSI * scale + bias ); if (idx < 0) idx = 0; else if (idx > maxIndex) idx = maxIndex; * reinterpret_cast(outputSI) = realLookupTable[idx]; inputSI++; outputSI+=4; } inputIt.NextSpan(); outputIt.NextSpan(); } } //Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkApplyLookupTableOnScalars(vtkMitkLevelWindowFilter *self, vtkImageData *inData, vtkImageData *outData, int outExt[6], vtkFloatingPointType* clippingBounds, T *) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); vtkScalarsToColors* lookupTable = self->GetLookupTable(); int y = outExt[2]; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { unsigned char* outputSI = outputIt.BeginSpan(); unsigned char* outputSIEnd = outputIt.EndSpan(); // do we iterate over the inner vertical clipping bounds if( y >= clippingBounds[2] && y < clippingBounds[3] ) { T* inputSI = inputIt.BeginSpan(); int x= outExt[0]; while (outputSI != outputSIEnd) { // is this pixel within horizontal clipping bounds if ( x >= clippingBounds[0] && x < clippingBounds[1]) { // fetching original value double grayValue = static_cast(*inputSI); // applying lookuptable - copy the 4 (RGBA) chars as a single int *reinterpret_cast(outputSI) = *reinterpret_cast(lookupTable->MapValue( grayValue )); } else { // outer horizontal clipping bounds - write a transparent RGBA pixel as a single int *reinterpret_cast(outputSI) = 0; } inputSI++; outputSI+=4; x++; } } else { // outer vertical clipping bounds - write a transparent RGBA line as ints while (outputSI != outputSIEnd) { *reinterpret_cast(outputSI) = 0; outputSI+=4; } } inputIt.NextSpan(); outputIt.NextSpan(); y++; } } //Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkApplyLookupTableOnScalarsCTF(vtkMitkLevelWindowFilter *self, vtkImageData *inData, vtkImageData *outData, int outExt[6], vtkFloatingPointType* clippingBounds, T *) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); vtkColorTransferFunction* lookupTable = dynamic_cast(self->GetLookupTable()); int y = outExt[2]; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { unsigned char* outputSI = outputIt.BeginSpan(); unsigned char* outputSIEnd = outputIt.EndSpan(); // do we iterate over the inner vertical clipping bounds if( y >= clippingBounds[2] && y < clippingBounds[3] ) { T* inputSI = inputIt.BeginSpan(); int x= outExt[0]; while (outputSI != outputSIEnd) { // is this pixel within horizontal clipping bounds if ( x >= clippingBounds[0] && x < clippingBounds[1]) { // fetching original value double grayValue = static_cast(*inputSI); // applying directly colortransferfunction // because vtkColorTransferFunction::MapValue is not threadsafe double rgb[3]; lookupTable->GetColor( grayValue, rgb ); outputSI[0] = static_cast(255.0*rgb[0] + 0.5); outputSI[1] = static_cast(255.0*rgb[1] + 0.5); outputSI[2] = static_cast(255.0*rgb[2] + 0.5); outputSI[3] = 255; } else { // outer horizontal clipping bounds - write a transparent RGBA pixel as a single int *reinterpret_cast(outputSI) = 0; } inputSI++; outputSI+=4; x++; } } else { // outer vertical clipping bounds - write a transparent RGBA line as ints while (outputSI != outputSIEnd) { *reinterpret_cast(outputSI) = 0; outputSI+=4; } } inputIt.NextSpan(); outputIt.NextSpan(); y++; } } void vtkMitkLevelWindowFilter::ExecuteInformation() { vtkImageData *input = this->GetInput(); vtkImageData *output = this->GetOutput(); if (!input) { vtkErrorMacro(<< "Input not set."); return; } output->CopyTypeSpecificInformation( input ); // TODO make output RGBA output->SetScalarTypeToUnsignedChar(); output->SetNumberOfScalarComponents(4); int extent[6]; input->GetWholeExtent(extent); output->SetExtent(extent); output->SetWholeExtent(extent); output->SetUpdateExtent(extent); output->AllocateScalars(); } //Method to run the filter in different threads. void vtkMitkLevelWindowFilter::ThreadedExecute(vtkImageData *inData, vtkImageData *outData, int extent[6], int /*id*/) { if(inData->GetNumberOfScalarComponents() > 2) { switch (inData->GetScalarType()) { vtkTemplateMacro( vtkApplyLookupTableOnRGBA( this, inData, outData, extent, m_ClippingBounds, static_cast(0))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } else { bool dontClip = extent[2] >= m_ClippingBounds[2] && extent[3] <= m_ClippingBounds[3] && extent[0] >= m_ClippingBounds[0] && extent[1] <= m_ClippingBounds[1]; if(this->GetLookupTable()) this->GetLookupTable()->Build(); vtkLookupTable *vlt = dynamic_cast(this->GetLookupTable()); vtkColorTransferFunction *ctf = dynamic_cast(this->GetLookupTable()); bool linearLookupTable = vlt && vlt->GetScale() == VTK_SCALE_LINEAR; bool useFast = dontClip && linearLookupTable; if(ctf) { switch (inData->GetScalarType()) { vtkTemplateMacro( vtkApplyLookupTableOnScalarsCTF( this, inData, outData, extent, m_ClippingBounds, static_cast(0))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } else if(useFast) { switch (inData->GetScalarType()) { vtkTemplateMacro( vtkApplyLookupTableOnScalarsFast( this, inData, outData, extent, static_cast(0))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } else { switch (inData->GetScalarType()) { vtkTemplateMacro( vtkApplyLookupTableOnScalars( this, inData, outData, extent, m_ClippingBounds, static_cast(0))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } } } void vtkMitkLevelWindowFilter::ExecuteInformation( vtkImageData *vtkNotUsed(inData), vtkImageData *vtkNotUsed(outData)) { } void vtkMitkLevelWindowFilter::SetMinOpacity(double minOpacity) { m_MinOpacity = minOpacity; } inline double vtkMitkLevelWindowFilter::GetMinOpacity() const { return m_MinOpacity; } void vtkMitkLevelWindowFilter::SetMaxOpacity(double maxOpacity) { m_MaxOpacity = maxOpacity; } inline double vtkMitkLevelWindowFilter::GetMaxOpacity() const { return m_MaxOpacity; } void vtkMitkLevelWindowFilter::SetClippingBounds(vtkFloatingPointType* bounds) // TODO does vtkFloatingPointType[4] work?? { for (unsigned int i = 0 ; i < 4; ++i) m_ClippingBounds[i] = bounds[i]; } diff --git a/Core/Code/Rendering/vtkMitkLevelWindowFilter.h b/Core/Code/Rendering/vtkMitkLevelWindowFilter.h index 723b6f8d0c..84279907aa 100644 --- a/Core/Code/Rendering/vtkMitkLevelWindowFilter.h +++ b/Core/Code/Rendering/vtkMitkLevelWindowFilter.h @@ -1,86 +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. ===================================================================*/ #ifndef __vtkMitkLevelWindowFilter_h #define __vtkMitkLevelWindowFilter_h class vtkScalarsToColors; #include #include #include /** Documentation * \brief Applies the grayvalue or color/opacity level window to scalar or RGB(A) images. * * This filter is used to apply the color level window to RGB images (e.g. * diffusion tensor images). Therefore, the RGB channels are converted to * the HSI color space, where the level window can be applied. Afterwards, * the HSI values transformed back to the RGB space. * * The filter is also able to apply an opacity level window to RGBA images. * * \ingroup Renderer */ class MITK_CORE_EXPORT vtkMitkLevelWindowFilter : public vtkImageToImageFilter { + + public: + vtkTypeMacro(vtkMitkLevelWindowFilter,vtkImageToImageFilter); + + static vtkMitkLevelWindowFilter *New(); + virtual unsigned long int GetMTime(); /** \brief Get the lookup table for the RGB level window */ vtkScalarsToColors* GetLookupTable(); /** \brief Set the lookup table for the RGB level window */ void SetLookupTable(vtkScalarsToColors *lookupTable); /** \brief Get/Set the lower window opacity for the alpha level window */ void SetMinOpacity(double minOpacity); inline double GetMinOpacity() const; /** \brief Get/Set the upper window opacity for the alpha level window */ void SetMaxOpacity(double maxOpacity); inline double GetMaxOpacity() const; /** \brief Set clipping bounds for the opaque part of the resliced 2d image */ void SetClippingBounds(vtkFloatingPointType*); /** Default constructor. */ vtkMitkLevelWindowFilter(); /** Default deconstructor. */ ~vtkMitkLevelWindowFilter(); protected: /** \brief Method for threaded execution of the filter. * \param *inData: The input. * \param *outData: The output of the filter. * \param extent: Specifies the region of the image to be updated inside this thread. * It is a six-component array of the form (xmin, xmax, ymin, ymax, zmin, zmax). * \param id: The thread id. */ void ThreadedExecute(vtkImageData *inData, vtkImageData *outData,int extent[6], int id); /** Standard VTK filter method to apply the filter. See VTK documentation.*/ void ExecuteInformation(); /** Standard VTK filter method to apply the filter. See VTK documentation. Not used at the moment.*/ void ExecuteInformation(vtkImageData *vtkNotUsed(inData), vtkImageData *vtkNotUsed(outData)); private: /** m_LookupTable contains the lookup table for the RGB level window.*/ vtkScalarsToColors* m_LookupTable; /** m_MinOpacity contains the lower bound for the alpha level window.*/ double m_MinOpacity; /** m_MaxOpacity contains the upper bound for the alpha level window.*/ double m_MaxOpacity; vtkFloatingPointType m_ClippingBounds[4]; }; #endif diff --git a/Core/Code/Resources/Interactions/DisplayConfigMITK.xml b/Core/Code/Resources/Interactions/DisplayConfigMITK.xml index 025b59f5fc..78cb9e148c 100644 --- a/Core/Code/Resources/Interactions/DisplayConfigMITK.xml +++ b/Core/Code/Resources/Interactions/DisplayConfigMITK.xml @@ -1,43 +1,41 @@ - + diff --git a/Core/Code/Resources/Interactions/DisplayConfigMITK.xml b/Core/Code/Resources/Interactions/Legacy/DisplayConfigMITKTools.xml similarity index 69% copy from Core/Code/Resources/Interactions/DisplayConfigMITK.xml copy to Core/Code/Resources/Interactions/Legacy/DisplayConfigMITKTools.xml index 025b59f5fc..df1a4adc97 100644 --- a/Core/Code/Resources/Interactions/DisplayConfigMITK.xml +++ b/Core/Code/Resources/Interactions/Legacy/DisplayConfigMITKTools.xml @@ -1,43 +1,49 @@ - + diff --git a/Core/Code/Rendering/mitkShaderLighting.xml b/Core/Code/Resources/Shaders/mitkShaderLighting.xml similarity index 85% rename from Core/Code/Rendering/mitkShaderLighting.xml rename to Core/Code/Resources/Shaders/mitkShaderLighting.xml index 5ba3fa344a..5f4e2c54c7 100644 --- a/Core/Code/Rendering/mitkShaderLighting.xml +++ b/Core/Code/Resources/Shaders/mitkShaderLighting.xml @@ -1,45 +1,45 @@ - - + + - - attribute vec3 scalars; - + + attribute vec3 scalars; + uniform vec3 LightPosition; uniform vec3 SkyColor; uniform vec3 GroundColor; - + varying vec3 DiffuseColor; - - void main(void) + + void main(void) { vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Vertex); vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal); vec3 lightVec = normalize(LightPosition - ecPosition); float costheta = dot(tnorm, lightVec); float a = 0.5 + 0.5 * costheta; DiffuseColor = mix(GroundColor, SkyColor, a); gl_Position = ftransform(); } varying vec3 DiffuseColor; void main(void) { gl_FragColor = vec4(DiffuseColor, 1.0); } diff --git a/Config/mitkLevelWindowPresets.xml b/Core/Code/Resources/mitkLevelWindowPresets.xml similarity index 100% rename from Config/mitkLevelWindowPresets.xml rename to Core/Code/Resources/mitkLevelWindowPresets.xml diff --git a/Core/Code/Testing/CMakeLists.txt b/Core/Code/Testing/CMakeLists.txt index 0c1cd85404..6c46455f78 100644 --- a/Core/Code/Testing/CMakeLists.txt +++ b/Core/Code/Testing/CMakeLists.txt @@ -1,103 +1,113 @@ +# The core tests need relaxed compiler flags... +# TODO fix core tests to compile without these additional no-error flags +if(MSVC_VERSION) + # disable deprecated warnings (they would lead to errors) + mitkFunctionCheckCompilerFlags2("/wd4996" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) +else() + mitkFunctionCheckCompilerFlags2("-Wno-error=deprecated" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + mitkFunctionCheckCompilerFlags2("-Wno-error=deprecated-declarations" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) +endif() + MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) # MITK_INSTALL_TARGETS(EXECUTABLES MitkTestDriver) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_CT mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-ct.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_MR mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-mr.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_SC mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-sc.dcm) mitkAddCustomModuleTest(mitkVolumeCalculatorTest_Png2D-bw mitkVolumeCalculatorTest ${MITK_DATA_DIR}/Png2D-bw.png ${MITK_DATA_DIR}/Pic2DplusT.nrrd) mitkAddCustomModuleTest(mitkEventMapperTest_Test1And2 mitkEventMapperTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) #mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/BallBinary30x30x30.nrrd) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.nrrd) mitkAddCustomModuleTest(mitkStateMachineFactoryTest_TestStateMachine1_2 mitkStateMachineFactoryTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkDicomSeriesReaderTest_CTImage mitkDicomSeriesReaderTest ${MITK_DATA_DIR}/TinyCTAbdomen) mitkAddCustomModuleTest(mitkPointSetReaderTest mitkPointSetReaderTest ${MITK_DATA_DIR}/PointSetReaderTestData.mps) mitkAddCustomModuleTest(mitkImageTest_4DImageData mitkImageTest ${MITK_DATA_DIR}/US4DCyl.nrrd) mitkAddCustomModuleTest(mitkImageTest_2D+tImageData mitkImageTest ${MITK_DATA_DIR}/Pic2DplusT.nrrd) mitkAddCustomModuleTest(mitkImageTest_3DImageData mitkImageTest ${MITK_DATA_DIR}/Pic3D.nrrd) mitkAddCustomModuleTest(mitkImageTest_brainImage mitkImageTest ${MITK_DATA_DIR}/brain.mhd) #mitkAddCustomModuleTest(mitkImageTest_color2DImage mitkImageTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) mitkAddCustomModuleTest(mitkIOUtilTest mitkIOUtilTest #test for a randomly chosen Pic3D swivelled slice ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/pointSet.mps ${MITK_DATA_DIR}/binary.stl ) mitkAddCustomModuleTest(mitkLevelWindowManagerTest mitkLevelWindowManagerTest ${MITK_DATA_DIR}/Pic3D.nrrd ) if(WIN32 OR APPLE OR MITK_ENABLE_GUI_TESTING) ### since the rendering test's do not run in ubuntu, yet, we build them only for other systems or if the user explicitly sets the variable MITK_ENABLE_GUI_TESTING mitkAddCustomModuleTest(mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2DTest ${MITK_DATA_DIR}/RenderingTestData/rgbaImage.png #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/rgbaImage640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3d640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2DColorTest #test for color property (=blue) Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dColorBlue640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2DLevelWindowTest #test for levelwindow property (=blood) #Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dLevelWindowBlood640x480REF.png #corresponding reference #screenshot ) #mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dOpacity640x480 mitkImageVtkMapper2DOpacityTest #test for opacity (=0.5) Pic3D coronal slice # ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage # -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dOpacity640x480REF.png #corresponding reference screenshot #) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DSwivelTest #test for a randomly chosen Pic3D swivelled slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dSwivel640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkSurfaceVtkMapper3DTest_TextureProperty mitkSurfaceVtkMapper3DTest ${MITK_DATA_DIR}/ToF-Data/Kinect_LiverPhantom.vtp ${MITK_DATA_DIR}/ToF-Data/Kinect_LiverPhantom_RGBImage.nrrd -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/texturedLiver640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2DTransferFunctionTest_Png2D-bw mitkImageVtkMapper2DTransferFunctionTest ${MITK_DATA_DIR}/Png2D-bw.png -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Png2D-bw-TransferFunctionRGBImage640x480REF.png #corresponding reference screenshot ) #mitkAddCustomModuleTest(mitkSurfaceVtkMapper3DTexturedSphereTest_Football mitkSurfaceVtkMapper3DTexturedSphereTest # ${MITK_DATA_DIR}/RenderingTestData/texture.jpg #input texture # -V # ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/texturedSphere640x480REF.png corresponding reference screenshot #) SET_PROPERTY(TEST mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DTransferFunctionTest_Png2D-bw #mitkSurfaceVtkMapper3DTest_TextureProperty #mitkSurfaceVtkMapper3DTexturedSphereTest_Football #mitkImageVtkMapper2D_pic3dOpacity640x480 PROPERTY RUN_SERIAL TRUE) endif() add_test(mitkPointSetLocaleTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPointSetLocaleTest ${MITK_DATA_DIR}/pointSet.mps) set_property(TEST mitkPointSetLocaleTest PROPERTY LABELS MITK-Core) add_test(mitkImageWriterTest_nrrdImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) add_test(mitkImageWriterTest_2DPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/Png2D-bw.png) add_test(mitkImageWriterTest_rgbPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/RenderingTestData/rgbImage.png) add_test(mitkImageWriterTest_rgbaPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/RenderingTestData/rgbaImage.png) set_property(TEST mitkImageWriterTest_nrrdImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_2DPNGImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_rgbPNGImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_rgbaPNGImage PROPERTY LABELS MITK-Core) add_subdirectory(DICOMTesting) diff --git a/Core/Code/Testing/files.cmake b/Core/Code/Testing/files.cmake index bf08fa677d..6e25a83a43 100644 --- a/Core/Code/Testing/files.cmake +++ b/Core/Code/Testing/files.cmake @@ -1,129 +1,130 @@ # tests with no extra command line parameter set(MODULE_TESTS mitkAccessByItkTest.cpp mitkCoreObjectFactoryTest.cpp mitkMaterialTest.cpp mitkActionTest.cpp mitkDispatcherTest.cpp mitkEnumerationPropertyTest.cpp mitkEventTest.cpp #mitkEventConfigTest.cpp ## needs to be re-written, test indirect since EventConfig is no longer exported as interface Bug 14529 mitkFocusManagerTest.cpp mitkGenericPropertyTest.cpp mitkGeometry3DTest.cpp mitkGeometryDataToSurfaceFilterTest.cpp mitkGlobalInteractionTest.cpp mitkImageDataItemTest.cpp #mitkImageMapper2DTest.cpp mitkImageGeneratorTest.cpp mitkBaseDataTest.cpp #mitkImageToItkTest.cpp mitkInstantiateAccessFunctionTest.cpp mitkInteractorTest.cpp mitkInteractionEventTest.cpp mitkITKThreadingTest.cpp mitkLevelWindowTest.cpp mitkMessageTest.cpp #mitkPipelineSmartPointerCorrectnessTest.cpp mitkPixelTypeTest.cpp mitkPlaneGeometryTest.cpp mitkPointSetFileIOTest.cpp mitkPointSetTest.cpp mitkPointSetWriterTest.cpp mitkPointSetReaderTest.cpp mitkPointSetInteractorTest.cpp mitkPropertyTest.cpp mitkPropertyListTest.cpp #mitkRegistrationBaseTest.cpp #mitkSegmentationInterpolationTest.cpp mitkSlicedGeometry3DTest.cpp mitkSliceNavigationControllerTest.cpp mitkStateMachineTest.cpp ##mitkStateMachineContainerTest.cpp ## rewrite test, indirect since no longer exported Bug 14529 mitkStateTest.cpp mitkSurfaceTest.cpp mitkSurfaceToSurfaceFilterTest.cpp mitkTimeSlicedGeometryTest.cpp mitkTransitionTest.cpp mitkUndoControllerTest.cpp mitkVtkWidgetRenderingTest.cpp mitkVerboseLimitedLinearUndoTest.cpp mitkWeakPointerTest.cpp mitkTransferFunctionTest.cpp #mitkAbstractTransformGeometryTest.cpp mitkStepperTest.cpp itkTotalVariationDenoisingImageFilterTest.cpp mitkRenderingManagerTest.cpp vtkMitkThickSlicesFilterTest.cpp mitkNodePredicateSourceTest.cpp mitkVectorTest.cpp mitkClippedSurfaceBoundsCalculatorTest.cpp #QmitkRenderingTestHelper.cpp mitkExceptionTest.cpp mitkExtractSliceFilterTest.cpp mitkLogTest.cpp mitkImageDimensionConverterTest.cpp mitkLoggingAdapterTest.cpp mitkUIDGeneratorTest.cpp + mitkShaderRepositoryTest.cpp ) # test with image filename as an extra command line parameter set(MODULE_IMAGE_TESTS mitkPlanePositionManagerTest.cpp mitkSurfaceVtkWriterTest.cpp #mitkImageSliceSelectorTest.cpp mitkImageTimeSelectorTest.cpp # mitkVtkPropRendererTest.cpp mitkDataNodeFactoryTest.cpp #mitkSTLFileReaderTest.cpp mitkImageAccessorTest.cpp ) # list of images for which the tests are run set(MODULE_TESTIMAGES # Pic-Factory no more available in Core, test images now in .nrrd format US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd binary.stl ball.stl ) set(MODULE_CUSTOM_TESTS #mitkLabeledImageToSurfaceFilterTest.cpp #mitkExternalToolsTest.cpp mitkDataStorageTest.cpp mitkDataNodeTest.cpp mitkDicomSeriesReaderTest.cpp mitkDICOMLocaleTest.cpp mitkEventMapperTest.cpp mitkNodeDependentPointSetInteractorTest.cpp mitkStateMachineFactoryTest.cpp mitkPointSetLocaleTest.cpp mitkImageTest.cpp mitkImageWriterTest.cpp mitkImageVtkMapper2DTest.cpp mitkImageVtkMapper2DLevelWindowTest.cpp mitkImageVtkMapper2DOpacityTest.cpp mitkImageVtkMapper2DColorTest.cpp mitkImageVtkMapper2DSwivelTest.cpp mitkImageVtkMapper2DTransferFunctionTest.cpp mitkIOUtilTest.cpp mitkSurfaceVtkMapper3DTest mitkSurfaceVtkMapper3DTexturedSphereTest.cpp mitkVolumeCalculatorTest.cpp mitkLevelWindowManagerTest.cpp ) # Create an artificial module initializing class for # the usServiceListenerTest.cpp usFunctionGenerateModuleInit(testdriver_init_file NAME ${MODULE_NAME}TestDriver DEPENDS "Mitk" VERSION "0.1.0" EXECUTABLE ) set(TEST_CPP_FILES ${testdriver_init_file}) diff --git a/Core/Code/Testing/mitkExtractSliceFilterTest.cpp b/Core/Code/Testing/mitkExtractSliceFilterTest.cpp index 738c650798..a2f5084a2e 100644 --- a/Core/Code/Testing/mitkExtractSliceFilterTest.cpp +++ b/Core/Code/Testing/mitkExtractSliceFilterTest.cpp @@ -1,1160 +1,1162 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //use this to create the test volume on the fly #define CREATE_VOLUME //use this to save the created volume //#define SAVE_VOLUME //use this to calculate the error from the sphere mathematical model to our pixel based one //#define CALC_TESTFAILURE_DEVIATION //use this to render an oblique slice through a specified image //#define SHOW_SLICE_IN_RENDER_WINDOW //use this to have infos printed in mbilog //#define EXTRACTOR_DEBUG /*these are the deviations calculated by the function CalcTestFailureDeviation (see for details)*/ #define Testfailure_Deviation_Mean_128 0.853842 #define Testfailure_Deviation_Volume_128 0.145184 #define Testfailure_Deviation_Diameter_128 1.5625 #define Testfailure_Deviation_Mean_256 0.397693 #define Testfailure_Deviation_Volume_256 0.0141357 #define Testfailure_Deviation_Diameter_256 0.78125 #define Testfailure_Deviation_Mean_512 0.205277 #define Testfailure_Deviation_Volume_512 0.01993 #define Testfailure_Deviation_Diameter_512 0.390625 class mitkExtractSliceFilterTestClass{ public: static void TestSlice(mitk::PlaneGeometry* planeGeometry, std::string testname) { TestPlane = planeGeometry; TestName = testname; float centerCoordValue = TestvolumeSize / 2.0; float center[3] = {centerCoordValue, centerCoordValue, centerCoordValue}; mitk::Point3D centerIndex(center); double radius = TestvolumeSize / 4.0; if(TestPlane->Distance(centerIndex) >= radius ) return;//outside sphere //feed ExtractSliceFilter mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(TestVolume); slicer->SetWorldGeometry(TestPlane); slicer->Update(); MITK_TEST_CONDITION_REQUIRED(slicer->GetOutput() != NULL, "Extractor returned a slice"); mitk::Image::Pointer reslicedImage = slicer->GetOutput(); AccessFixedDimensionByItk(reslicedImage, TestSphereRadiusByItk, 2); AccessFixedDimensionByItk(reslicedImage, TestSphereAreaByItk, 2); + /* double devArea, devDiameter; if(TestvolumeSize == 128.0){ devArea = Testfailure_Deviation_Volume_128; devDiameter = Testfailure_Deviation_Diameter_128; } else if(TestvolumeSize == 256.0){devArea = Testfailure_Deviation_Volume_256; devDiameter = Testfailure_Deviation_Diameter_256;} else if (TestvolumeSize == 512.0){devArea = Testfailure_Deviation_Volume_512; devDiameter = Testfailure_Deviation_Diameter_512;} else{devArea = Testfailure_Deviation_Volume_128; devDiameter = Testfailure_Deviation_Diameter_128;} - + */ std::string areatestName = TestName.append(" area"); std::string diametertestName = TestName.append(" testing diameter"); //TODO think about the deviation, 1% makes no sense at all MITK_TEST_CONDITION(std::abs(100 - testResults.percentageAreaCalcToPixel) < 1, areatestName ); MITK_TEST_CONDITION(std::abs(100 - testResults.percentageRadiusToPixel) < 1, diametertestName ); #ifdef EXTRACTOR_DEBUG MITK_INFO << TestName << " >>> " << "planeDistanceToSphereCenter: " << testResults.planeDistanceToSphereCenter; MITK_INFO << "area in pixels: " << testResults.areaInPixel << " <-> area in mm: " << testResults.areaCalculated << " = " << testResults.percentageAreaCalcToPixel << "%"; MITK_INFO << "calculated diameter: " << testResults.diameterCalculated << " <-> diameter in mm: " << testResults.diameterInMM << " <-> diameter in pixel: " << testResults.diameterInPixel << " = " << testResults.percentageRadiusToPixel << "%"; #endif } /* * get the radius of the slice of a sphere based on pixel distance from edge to edge of the circle. */ template static void TestSphereRadiusByItk (itk::Image* inputImage) { typedef itk::Image InputImageType; //set the index to the middle of the image's edge at x and y axis typename InputImageType::IndexType currentIndexX; currentIndexX[0] = (int)(TestvolumeSize / 2.0); currentIndexX[1] = 0; typename InputImageType::IndexType currentIndexY; currentIndexY[0] = 0; currentIndexY[1] = (int)(TestvolumeSize / 2.0); //remember the last pixel value double lastValueX = inputImage->GetPixel(currentIndexX); double lastValueY = inputImage->GetPixel(currentIndexY); //storage for the index marks std::vector indicesX; std::vector indicesY; /*Get four indices on the edge of the circle*/ while(currentIndexX[1] < TestvolumeSize && currentIndexX[0] < TestvolumeSize) { //move x direction currentIndexX[1] += 1; //move y direction currentIndexY[0] += 1; if(inputImage->GetPixel(currentIndexX) > lastValueX) { //mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexX[0]; markIndex[1] = currentIndexX[1]; indicesX.push_back(markIndex); } else if( inputImage->GetPixel(currentIndexX) < lastValueX) { //mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexX[0]; markIndex[1] = currentIndexX[1] - 1;//value inside the sphere indicesX.push_back(markIndex); } if(inputImage->GetPixel(currentIndexY) > lastValueY) { //mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexY[0]; markIndex[1] = currentIndexY[1]; indicesY.push_back(markIndex); } else if( inputImage->GetPixel(currentIndexY) < lastValueY) { //mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexY[0]; markIndex[1] = currentIndexY[1] - 1;//value inside the sphere indicesY.push_back(markIndex); } //found both marks? if(indicesX.size() == 2 && indicesY.size() == 2) break; //the new 'last' values lastValueX = inputImage->GetPixel(currentIndexX); lastValueY = inputImage->GetPixel(currentIndexY); } /* *If we are here we found the four marks on the edge of the circle. *For the case our plane is rotated and shifted, we have to calculate the center of the circle, *else the center is the intersection of both straight lines between the marks. *When we have the center, the diameter of the circle will be checked to the reference value(math!). */ //each distance from the first mark of each direction to the center of the straight line between the marks double distanceToCenterX = std::abs(indicesX[0][1] - indicesX[1][1]) / 2.0; - double distanceToCenterY = std::abs(indicesY[0][0] - indicesY[1][0]) / 2.0; + //double distanceToCenterY = std::abs(indicesY[0][0] - indicesY[1][0]) / 2.0; //the center of the straight lines - typename InputImageType::IndexType centerX, centerY; + typename InputImageType::IndexType centerX; + //typename InputImageType::IndexType centerY; centerX[0] = indicesX[0][0]; centerX[1] = indicesX[0][1] + distanceToCenterX; //TODO think about implicit cast to int. this is not the real center of the image, which could be between two pixels //centerY[0] = indicesY[0][0] + distanceToCenterY; //centerY[1] = inidcesY[0][1]; typename InputImageType::IndexType currentIndex(centerX); lastValueX = inputImage->GetPixel(currentIndex); long sumpixels = 0; std::vector diameterIndices; //move up while(currentIndex[1] < TestvolumeSize) { currentIndex[1] += 1; if( inputImage->GetPixel(currentIndex) != lastValueX) { typename InputImageType::IndexType markIndex; markIndex[0] = currentIndex[0]; markIndex[1] = currentIndex[1] - 1; diameterIndices.push_back(markIndex); break; } sumpixels++; lastValueX = inputImage->GetPixel(currentIndex); } currentIndex[1] -= sumpixels; //move back to center to go in the other direction lastValueX = inputImage->GetPixel(currentIndex); //move down while(currentIndex[1] >= 0) { currentIndex[1] -= 1; if( inputImage->GetPixel(currentIndex) != lastValueX) { typename InputImageType::IndexType markIndex; markIndex[0] = currentIndex[0]; markIndex[1] = currentIndex[1];//outside sphere because we want to calculate the distance from edge to edge diameterIndices.push_back(markIndex); break; } sumpixels++; lastValueX = inputImage->GetPixel(currentIndex); } /* *Now sumpixels should be the apromximate diameter of the circle. This is checked with the calculated diameter from the plane transformation(math). */ mitk::Point3D volumeCenter; volumeCenter[0] = volumeCenter[1] = volumeCenter[2] = TestvolumeSize / 2.0; double planeDistanceToSphereCenter = TestPlane->Distance(volumeCenter); double sphereRadius = TestvolumeSize/4.0; //calculate the radius of the circle cut from the sphere by the plane double diameter = 2.0 * std::sqrt(std::pow(sphereRadius, 2) - std::pow( planeDistanceToSphereCenter , 2)); double percentageRadiusToPixel = 100 / diameter * sumpixels; /* *calculate the radius in mm by the both marks of the center line by using the world coordinates */ //get the points as 3D coordinates mitk::Vector3D diameterPointRight, diameterPointLeft; diameterPointRight[2] = diameterPointLeft[2] = 0.0; diameterPointLeft[0] = diameterIndices[0][0]; diameterPointLeft[1] = diameterIndices[0][1]; diameterPointRight[0] = diameterIndices[1][0]; diameterPointRight[1] = diameterIndices[1][1]; //transform to worldcoordinates TestVolume->GetGeometry()->IndexToWorld(diameterPointLeft, diameterPointLeft); TestVolume->GetGeometry()->IndexToWorld(diameterPointRight, diameterPointRight); //euklidian distance double diameterInMM = ( (diameterPointLeft * -1.0) + diameterPointRight).GetNorm(); testResults.diameterInMM = diameterInMM; testResults.diameterCalculated = diameter; testResults.diameterInPixel = sumpixels; testResults.percentageRadiusToPixel = percentageRadiusToPixel; testResults.planeDistanceToSphereCenter = planeDistanceToSphereCenter; } /*brute force the area pixel by pixel*/ template static void TestSphereAreaByItk (itk::Image* inputImage) { typedef itk::Image InputImageType; typedef itk::ImageRegionConstIterator< InputImageType > ImageIterator; ImageIterator imageIterator( inputImage, inputImage->GetLargestPossibleRegion() ); imageIterator.GoToBegin(); int sumPixelsInArea = 0; while( !imageIterator.IsAtEnd() ) { if(inputImage->GetPixel(imageIterator.GetIndex()) == pixelValueSet) sumPixelsInArea++; ++imageIterator; } mitk::Point3D volumeCenter; volumeCenter[0] = volumeCenter[1] = volumeCenter[2] = TestvolumeSize / 2.0; double planeDistanceToSphereCenter = TestPlane->Distance(volumeCenter); double sphereRadius = TestvolumeSize/4.0; //calculate the radius of the circle cut from the sphere by the plane double radius = std::sqrt(std::pow(sphereRadius, 2) - std::pow( planeDistanceToSphereCenter , 2)); double areaInMM = 3.14159265358979 * std::pow(radius, 2); testResults.areaCalculated = areaInMM; testResults.areaInPixel = sumPixelsInArea; testResults.percentageAreaCalcToPixel = 100 / areaInMM * sumPixelsInArea; } /* * random a voxel. define plane through this voxel. reslice at the plane. compare the pixel vaues of the voxel * in the volume with the pixel value in the resliced image. * there are some indice shifting problems which causes the test to fail for oblique planes. seems like the chosen * worldcoordinate is not corrresponding to the index in the 2D image. and so the pixel values are not the same as * expected. */ static void PixelvalueBasedTest() { /* setup itk image */ typedef itk::Image ImageType; typedef itk::ImageRegionConstIterator< ImageType > ImageIterator; ImageType::Pointer image = ImageType::New(); ImageType::IndexType start; start[0] = start[1] = start[2] = 0; ImageType::SizeType size; size[0] = size[1] = size[2] = 32; ImageType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); image->SetRegions(imgRegion); image->SetSpacing(1.0); image->Allocate(); ImageIterator imageIterator( image, image->GetLargestPossibleRegion() ); imageIterator.GoToBegin(); unsigned short pixelValue = 0; //fill the image with distinct values while ( !imageIterator.IsAtEnd() ) { image->SetPixel(imageIterator.GetIndex(), pixelValue); ++imageIterator; ++pixelValue; } /* end setup itk image */ mitk::Image::Pointer imageInMitk; CastToMitkImage(image, imageInMitk); /*mitk::ImageWriter::Pointer writer = mitk::ImageWriter::New(); writer->SetInput(imageInMitk); std::string file = "C:\\Users\\schroedt\\Desktop\\cube.nrrd"; writer->SetFileName(file); writer->Update();*/ PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Frontal); PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Sagittal); PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Axial); } static void PixelvalueBasedTestByPlane(mitk::Image* imageInMitk, mitk::PlaneGeometry::PlaneOrientation orientation){ typedef itk::Image ImageType; //set the seed of the rand function srand((unsigned)time(0)); /* setup a random orthogonal plane */ int sliceindex = 17;//rand() % 32; bool isFrontside = true; bool isRotated = false; if( orientation == mitk::PlaneGeometry::Axial) { /*isFrontside = false; isRotated = true;*/ } mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->InitializeStandardPlane(imageInMitk->GetGeometry(), orientation, sliceindex, isFrontside, isRotated); mitk::Point3D origin = plane->GetOrigin(); mitk::Vector3D normal; normal = plane->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 plane->SetOrigin(origin); //we dont need this any more, because we are only testing orthogonal planes /*mitk::Vector3D rotationVector; rotationVector[0] = randFloat(); rotationVector[1] = randFloat(); rotationVector[2] = randFloat(); float degree = randFloat() * 180.0; mitk::RotationOperation* op = new mitk::RotationOperation(mitk::OpROTATE, plane->GetCenter(), rotationVector, degree); plane->ExecuteOperation(op); delete op;*/ /* end setup plane */ /* define a point in the 3D volume. * add the two axis vectors of the plane (each multiplied with a * random number) to the origin. now the two random numbers * become our index coordinates in the 2D image, because the * length of the axis vectors is 1. */ mitk::Point3D planeOrigin = plane->GetOrigin(); mitk::Vector3D axis0, axis1; axis0 = plane->GetAxisVector(0); axis1 = plane->GetAxisVector(1); axis0.Normalize(); axis1.Normalize(); unsigned char n1 = 7;// rand() % 32; unsigned char n2 = 13;// rand() % 32; mitk::Point3D testPoint3DInWorld; testPoint3DInWorld = planeOrigin + (axis0 * n1) + (axis1 * n2); //get the index of the point in the 3D volume ImageType::IndexType testPoint3DInIndex; imageInMitk->GetGeometry()->WorldToIndex(testPoint3DInWorld, testPoint3DInIndex); mitk::Index3D testPoint2DInIndex; /* end define a point in the 3D volume.*/ //do reslicing at the plane mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(imageInMitk); slicer->SetWorldGeometry(plane); slicer->Update(); mitk::Image::Pointer slice = slicer->GetOutput(); // Get TestPoiont3D as Index in Slice slice->GetGeometry()->WorldToIndex(testPoint3DInWorld,testPoint2DInIndex); mitk::Point3D p, sliceIndexToWorld, imageIndexToWorld; p[0] = testPoint2DInIndex[0]; p[1] = testPoint2DInIndex[1]; p[2] = testPoint2DInIndex[2]; slice->GetGeometry()->IndexToWorld(p, sliceIndexToWorld); p[0] = testPoint3DInIndex[0]; p[1] = testPoint3DInIndex[1]; p[2] = testPoint3DInIndex[2]; imageInMitk->GetGeometry()->IndexToWorld(p, imageIndexToWorld); //compare the pixelvalues of the defined point in the 3D volume with the value of the resliced image unsigned short valueAt3DVolume = imageInMitk->GetPixelValueByIndex(testPoint3DInIndex);//image->GetPixel(testPoint3DInIndex); - unsigned short valueAt3DVolumeByWorld = imageInMitk->GetPixelValueByWorldCoordinate(testPoint3DInWorld); + //unsigned short valueAt3DVolumeByWorld = imageInMitk->GetPixelValueByWorldCoordinate(testPoint3DInWorld); unsigned short valueAtSlice = slice->GetPixelValueByIndex(testPoint2DInIndex); //valueAt3DVolume == valueAtSlice is not always working. because of rounding errors //indices are shifted MITK_TEST_CONDITION(valueAt3DVolume == valueAtSlice, "comparing pixelvalues for orthogonal plane"); vtkSmartPointer imageInVtk = vtkSmartPointer::New(); imageInVtk = imageInMitk->GetVtkImageData(); vtkSmartPointer sliceInVtk = vtkSmartPointer::New(); sliceInVtk = slice->GetVtkImageData(); double PixelvalueByMitkOutput = sliceInVtk->GetScalarComponentAsDouble(n1, n2, 0, 0); - double valueVTKinImage = imageInVtk->GetScalarComponentAsDouble(testPoint3DInIndex[0], testPoint3DInIndex[1], testPoint3DInIndex[2], 0); + //double valueVTKinImage = imageInVtk->GetScalarComponentAsDouble(testPoint3DInIndex[0], testPoint3DInIndex[1], testPoint3DInIndex[2], 0); /* Test that everything is working equally if vtkoutput is used instead of the default output * from mitk ImageToImageFilter */ mitk::ExtractSliceFilter::Pointer slicerWithVtkOutput = mitk::ExtractSliceFilter::New(); slicerWithVtkOutput->SetInput(imageInMitk); slicerWithVtkOutput->SetWorldGeometry(plane); slicerWithVtkOutput->SetVtkOutputRequest(true); slicerWithVtkOutput->Update(); vtkSmartPointer vtkImageByVtkOutput = vtkSmartPointer::New(); vtkImageByVtkOutput = slicerWithVtkOutput->GetVtkOutput(); double PixelvalueByVtkOutput = vtkImageByVtkOutput->GetScalarComponentAsDouble(n1, n2, 0, 0); MITK_TEST_CONDITION(PixelvalueByMitkOutput == PixelvalueByVtkOutput, "testing convertion of image output vtk->mitk by reslicer"); /*================ mbilog outputs ===========================*/ #ifdef EXTRACTOR_DEBUG MITK_INFO << "\n" << "TESTINFO index: " << sliceindex << " orientation: " << orientation << " frontside: " << isFrontside << " rotated: " << isRotated; MITK_INFO << "\n" << "slice index to world: " << sliceIndexToWorld; MITK_INFO << "\n" << "image index to world: " << imageIndexToWorld; MITK_INFO << "\n" << "vtk: slice: " << PixelvalueByMitkOutput << ", image: "<< valueVTKinImage; MITK_INFO << "\n" << "testPoint3D InWorld" << testPoint3DInWorld << " is " << testPoint2DInIndex << " in 2D"; MITK_INFO << "\n" << "randoms: " << ((int)n1) << ", " << ((int)n2); MITK_INFO << "\n" << "point is inside plane: " << plane->IsInside(testPoint3DInWorld) << " and volume: " << imageInMitk->GetGeometry()->IsInside(testPoint3DInWorld); MITK_INFO << "\n" << "volume idx: " << testPoint3DInIndex << " = " << valueAt3DVolume ; MITK_INFO << "\n" << "volume world: " << testPoint3DInWorld << " = " << valueAt3DVolumeByWorld ; MITK_INFO << "\n" << "slice idx: " << testPoint2DInIndex << " = " << valueAtSlice ; mitk::Index3D curr; curr[0] = curr[1] = curr[2] = 0; for( int i = 0; i < 32 ; ++i){ for( int j = 0; j < 32; ++j){ ++curr[1]; if(slice->GetPixelValueByIndex(curr) == valueAt3DVolume){ MITK_INFO << "\n" << valueAt3DVolume << " MATCHED mitk " << curr; } } curr[1] = 0; ++curr[0]; } typedef itk::Image Image2DType; Image2DType::Pointer img = Image2DType::New(); CastToItkImage(slice, img); typedef itk::ImageRegionConstIterator< Image2DType > Iterator2D; Iterator2D iter(img, img->GetLargestPossibleRegion()); iter.GoToBegin(); while( !iter.IsAtEnd() ){ if(img->GetPixel(iter.GetIndex()) == valueAt3DVolume) MITK_INFO << "\n" << valueAt3DVolume << " MATCHED itk " << iter.GetIndex(); ++iter; } #endif //EXTRACTOR_DEBUG } /* random a float value */ static float randFloat(){ return (((float)rand()+1.0) / ((float)RAND_MAX + 1.0)) + (((float)rand()+1.0) / ((float)RAND_MAX + 1.0)) / ((float)RAND_MAX + 1.0);} /* create a sphere with the size of the given testVolumeSize*/ static void InitializeTestVolume() { #ifdef CREATE_VOLUME //do sphere creation ItkVolumeGeneration(); #ifdef SAVE_VOLUME //save in file mitk::ImageWriter::Pointer writer = mitk::ImageWriter::New(); writer->SetInput(TestVolume); std::string file; std::ostringstream filename; filename << "C:\\home\\schroedt\\MITK\\Modules\\ImageExtraction\\Testing\\Data\\sphere_"; filename << TestvolumeSize; filename << ".nrrd"; file = filename.str(); writer->SetFileName(file); writer->Update(); #endif//SAVE_VOLUME #endif #ifndef CREATE_VOLUME //read from file mitk::StandardFileLocations::Pointer locator = mitk::StandardFileLocations::GetInstance(); std::string filename = locator->FindFile("sphere_512.nrrd.mhd", "Modules/ImageExtraction/Testing/Data"); mitk::ItkImageFileReader::Pointer reader = mitk::ItkImageFileReader::New(); reader->SetFileName(filename); reader->Update(); TestVolume = reader->GetOutput(); #endif #ifdef CALC_TESTFAILURE_DEVIATION //get the TestFailureDeviation in % AccessFixedDimensionByItk(TestVolume, CalcTestFailureDeviation, 3); #endif } //the test result of the sphere reslice struct SliceProperties{ double planeDistanceToSphereCenter; double diameterInMM; double diameterInPixel; double diameterCalculated; double percentageRadiusToPixel; double areaCalculated; double areaInPixel; double percentageAreaCalcToPixel; }; static mitk::Image::Pointer TestVolume; static double TestvolumeSize; static mitk::PlaneGeometry::Pointer TestPlane; static std::string TestName; static unsigned char pixelValueSet; static SliceProperties testResults; static double TestFailureDeviation; private: /* * Generate a sphere with a radius of TestvolumeSize / 4.0 */ static void ItkVolumeGeneration () { typedef itk::Image TestVolumeType; typedef itk::ImageRegionConstIterator< TestVolumeType > ImageIterator; TestVolumeType::Pointer sphereImage = TestVolumeType::New(); TestVolumeType::IndexType start; start[0] = start[1] = start[2] = 0; TestVolumeType::SizeType size; size[0] = size[1] = size[2] = TestvolumeSize; TestVolumeType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); sphereImage->SetRegions(imgRegion); sphereImage->SetSpacing(1.0); sphereImage->Allocate(); sphereImage->FillBuffer(0); mitk::Vector3D center; center[0] = center[1] = center[2] = TestvolumeSize / 2.0; double radius = TestvolumeSize / 4.0; double pixelValue = pixelValueSet; double distanceToCenter = 0.0; ImageIterator imageIterator( sphereImage, sphereImage->GetLargestPossibleRegion() ); imageIterator.GoToBegin(); mitk::Vector3D currentVoxelInIndex; while ( !imageIterator.IsAtEnd() ) { currentVoxelInIndex[0] = imageIterator.GetIndex()[0]; currentVoxelInIndex[1] = imageIterator.GetIndex()[1]; currentVoxelInIndex[2] = imageIterator.GetIndex()[2]; distanceToCenter = (center + ( currentVoxelInIndex * -1.0 )).GetNorm(); //if distance to center is smaller then the radius of the sphere if( distanceToCenter < radius) { sphereImage->SetPixel(imageIterator.GetIndex(), pixelValue); } ++imageIterator; } CastToMitkImage(sphereImage, TestVolume); } /* calculate the devation of the voxel object to the mathematical sphere object. * this is use to make a statement about the accuracy of the resliced image, eg. the circle's diameter or area. */ template static void CalcTestFailureDeviation (itk::Image* inputImage) { typedef itk::Image InputImageType; typedef itk::ImageRegionConstIterator< InputImageType > ImageIterator; ImageIterator iterator(inputImage, inputImage->GetLargestPossibleRegion()); iterator.GoToBegin(); int volumeInPixel = 0; while( !iterator.IsAtEnd() ) { if(inputImage->GetPixel(iterator.GetIndex()) == pixelValueSet) volumeInPixel++; ++iterator; } double diameter = TestvolumeSize / 2.0; double volumeCalculated = (1.0 / 6.0) * 3.14159265358979 * std::pow(diameter, 3); double volumeDeviation = std::abs( 100 - (100 / volumeCalculated * volumeInPixel) ); typename InputImageType::IndexType index; index[0] = index[1] = TestvolumeSize / 2.0; index[2] = 0; int sumpixels = 0; while (index[2] < TestvolumeSize ) { if(inputImage->GetPixel(index) == pixelValueSet) sumpixels++; index[2] += 1; } double diameterDeviation = std::abs( 100 - (100 / diameter * sumpixels) ); #ifdef DEBUG MITK_INFO << "volume deviation: " << volumeDeviation << " diameter deviation:" << diameterDeviation; #endif mitkExtractSliceFilterTestClass::TestFailureDeviation = (volumeDeviation + diameterDeviation) / 2.0; } }; /*================ #END class ================*/ /*================#BEGIN Instanciation of members ================*/ mitk::Image::Pointer mitkExtractSliceFilterTestClass::TestVolume = mitk::Image::New(); double mitkExtractSliceFilterTestClass::TestvolumeSize = 256.0; mitk::PlaneGeometry::Pointer mitkExtractSliceFilterTestClass::TestPlane = mitk::PlaneGeometry::New(); std::string mitkExtractSliceFilterTestClass::TestName = ""; unsigned char mitkExtractSliceFilterTestClass::pixelValueSet = 255; mitkExtractSliceFilterTestClass::SliceProperties mitkExtractSliceFilterTestClass::testResults = {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}; double mitkExtractSliceFilterTestClass::TestFailureDeviation = 0.0; /*================ #END Instanciation of members ================*/ /*================ #BEGIN test main ================*/ int mitkExtractSliceFilterTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkExtractSliceFilterTest") //pixelvalue based testing mitkExtractSliceFilterTestClass::PixelvalueBasedTest(); //initialize sphere test volume mitkExtractSliceFilterTestClass::InitializeTestVolume(); mitk::Vector3D spacing = mitkExtractSliceFilterTestClass::TestVolume->GetGeometry()->GetSpacing(); //the center of the sphere = center of image double sphereCenter = mitkExtractSliceFilterTestClass::TestvolumeSize / 2.0; double planeSize = mitkExtractSliceFilterTestClass::TestvolumeSize; /* axial plane */ mitk::PlaneGeometry::Pointer geometryAxial = mitk::PlaneGeometry::New(); geometryAxial->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Axial, sphereCenter, false, true); geometryAxial->ChangeImageGeometryConsideringOriginOffset(true); mitk::Point3D origin = geometryAxial->GetOrigin(); mitk::Vector3D normal; normal = geometryAxial->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //geometryAxial->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometryAxial, "Testing axial plane"); /* end axial plane */ /* sagittal plane */ mitk::PlaneGeometry::Pointer geometrySagital = mitk::PlaneGeometry::New(); geometrySagital->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, sphereCenter, true, false); geometrySagital->ChangeImageGeometryConsideringOriginOffset(true); origin = geometrySagital->GetOrigin(); normal = geometrySagital->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //geometrySagital->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometrySagital, "Testing sagittal plane"); /* sagittal plane */ /* sagittal shifted plane */ mitk::PlaneGeometry::Pointer geometrySagitalShifted = mitk::PlaneGeometry::New(); geometrySagitalShifted->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, (sphereCenter - 14), true, false); geometrySagitalShifted->ChangeImageGeometryConsideringOriginOffset(true); origin = geometrySagitalShifted->GetOrigin(); normal = geometrySagitalShifted->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //geometrySagitalShifted->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometrySagitalShifted, "Testing sagittal plane shifted"); /* end sagittal shifted plane */ /* coronal plane */ mitk::PlaneGeometry::Pointer geometryCoronal = mitk::PlaneGeometry::New(); geometryCoronal->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Frontal, sphereCenter, true, false); geometryCoronal->ChangeImageGeometryConsideringOriginOffset(true); origin = geometryCoronal->GetOrigin(); normal = geometryCoronal->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //geometryCoronal->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometryCoronal, "Testing coronal plane"); /* end coronal plane */ /* oblique plane */ mitk::PlaneGeometry::Pointer obliquePlane = mitk::PlaneGeometry::New(); obliquePlane->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, sphereCenter, true, false); obliquePlane->ChangeImageGeometryConsideringOriginOffset(true); origin = obliquePlane->GetOrigin(); normal = obliquePlane->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //obliquePlane->SetOrigin(origin); mitk::Vector3D rotationVector; rotationVector[0] = 0.2; rotationVector[1] = 0.4; rotationVector[2] = 0.62; float degree = 37.0; mitk::RotationOperation* op = new mitk::RotationOperation(mitk::OpROTATE, obliquePlane->GetCenter(), rotationVector, degree); obliquePlane->ExecuteOperation(op); delete op; mitkExtractSliceFilterTestClass::TestSlice(obliquePlane, "Testing oblique plane"); /* end oblique plane */ #ifdef SHOW_SLICE_IN_RENDER_WINDOW /*================ #BEGIN vtk render code ================*/ //set reslicer for renderwindow mitk::ItkImageFileReader::Pointer reader = mitk::ItkImageFileReader::New(); std::string filename = "C:\\home\\Pics\\Pic3D.nrrd"; reader->SetFileName(filename); reader->Update(); mitk::Image::Pointer pic = reader->GetOutput(); vtkSmartPointer slicer = vtkSmartPointer::New(); slicer->SetInput(pic->GetVtkImageData()); mitk::PlaneGeometry::Pointer obliquePl = mitk::PlaneGeometry::New(); obliquePl->InitializeStandardPlane(pic->GetGeometry(), mitk::PlaneGeometry::Sagittal, pic->GetGeometry()->GetCenter()[0], true, false); obliquePl->ChangeImageGeometryConsideringOriginOffset(true); mitk::Point3D origin2 = obliquePl->GetOrigin(); mitk::Vector3D n; n = obliquePl->GetNormal(); n.Normalize(); origin2 += n * 0.5;//pixelspacing is 1, so half the spacing is 0.5 obliquePl->SetOrigin(origin2); mitk::Vector3D rotation; rotation[0] = 0.534307; rotation[1] = 0.000439605; rotation[2] = 0.423017; MITK_INFO << rotation; float rotateDegree = 70; mitk::RotationOperation* operation = new mitk::RotationOperation(mitk::OpROTATE, obliquePl->GetCenter(), rotationVector, degree); obliquePl->ExecuteOperation(operation); delete operation; double origin[3]; origin[0] = obliquePl->GetOrigin()[0]; origin[1] = obliquePl->GetOrigin()[1]; origin[2] = obliquePl->GetOrigin()[2]; slicer->SetResliceAxesOrigin(origin); mitk::Vector3D right, bottom, normal; right = obliquePl->GetAxisVector( 0 ); bottom = obliquePl->GetAxisVector( 1 ); normal = obliquePl->GetNormal(); right.Normalize(); bottom.Normalize(); normal.Normalize(); double cosines[9]; mitk::vnl2vtk(right.GetVnlVector(), cosines);//x mitk::vnl2vtk(bottom.GetVnlVector(), cosines + 3);//y mitk::vnl2vtk(normal.GetVnlVector(), cosines + 6);//n slicer->SetResliceAxesDirectionCosines(cosines); slicer->SetOutputDimensionality(2); slicer->Update(); //set vtk renderwindow vtkSmartPointer vtkPlane = vtkSmartPointer::New(); vtkPlane->SetOrigin(0.0, 0.0, 0.0); //These two points define the axes of the plane in combination with the origin. //Point 1 is the x-axis and point 2 the y-axis. //Each plane is transformed according to the view (axial, coronal and saggital) afterwards. vtkPlane->SetPoint1(1.0, 0.0, 0.0); //P1: (xMax, yMin, depth) vtkPlane->SetPoint2(0.0, 1.0, 0.0); //P2: (xMin, yMax, depth) //these are not the correct values for all slices, only a square plane by now vtkSmartPointer imageMapper = vtkSmartPointer::New(); imageMapper->SetInputConnection(vtkPlane->GetOutputPort()); vtkSmartPointer lookupTable = vtkSmartPointer::New(); //built a default lookuptable lookupTable->SetRampToLinear(); lookupTable->SetSaturationRange( 0.0, 0.0 ); lookupTable->SetHueRange( 0.0, 0.0 ); lookupTable->SetValueRange( 0.0, 1.0 ); lookupTable->Build(); //map all black values to transparent lookupTable->SetTableValue(0, 0.0, 0.0, 0.0, 0.0); lookupTable->SetRange(-255.0, 255.0); //lookupTable->SetRange(-1022.0, 1184.0);//pic3D range vtkSmartPointer texture = vtkSmartPointer::New(); texture->SetInput(slicer->GetOutput()); texture->SetLookupTable(lookupTable); texture->SetMapColorScalarsThroughLookupTable(true); vtkSmartPointer imageActor = vtkSmartPointer::New(); imageActor->SetMapper(imageMapper); imageActor->SetTexture(texture); // Setup renderers vtkSmartPointer renderer = vtkSmartPointer::New(); renderer->AddActor(imageActor); // Setup render window vtkSmartPointer renderWindow = vtkSmartPointer::New(); renderWindow->AddRenderer(renderer); // Setup render window interactor vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); vtkSmartPointer style = vtkSmartPointer::New(); renderWindowInteractor->SetInteractorStyle(style); // Render and start interaction renderWindowInteractor->SetRenderWindow(renderWindow); //renderer->AddViewProp(imageActor); renderWindow->Render(); renderWindowInteractor->Start(); // always end with this! /*================ #END vtk render code ================*/ #endif //SHOW_SLICE_IN_RENDER_WINDOW MITK_TEST_END() } diff --git a/Core/Code/Testing/mitkGeometry3DTest.cpp b/Core/Code/Testing/mitkGeometry3DTest.cpp index d812ce5664..51443d1c33 100644 --- a/Core/Code/Testing/mitkGeometry3DTest.cpp +++ b/Core/Code/Testing/mitkGeometry3DTest.cpp @@ -1,567 +1,567 @@ /*=================================================================== 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 "mitkGeometry3D.h" #include #include #include "mitkRotationOperation.h" #include "mitkInteractionConst.h" #include #include #include "mitkTestingMacros.h" #include #include bool testGetAxisVectorVariants(mitk::Geometry3D* geometry) { int direction; for(direction=0; direction<3; ++direction) { mitk::Vector3D frontToBack; switch(direction) { case 0: frontToBack = geometry->GetCornerPoint(false, false, false)-geometry->GetCornerPoint(true , false, false); break; //7-3 case 1: frontToBack = geometry->GetCornerPoint(false, false, false)-geometry->GetCornerPoint(false, true , false); break; //7-5 case 2: frontToBack = geometry->GetCornerPoint(false, false, false)-geometry->GetCornerPoint(false , false, true); break; //7-2 } std::cout << "Testing GetAxisVector(int) vs GetAxisVector(bool, bool, bool): "; if(mitk::Equal(geometry->GetAxisVector(direction), frontToBack) == false) { std::cout<<"[FAILED]"<GetAxisVector(direction).GetNorm(), geometry->GetExtentInMM(direction)) == false) { std::cout<<"[FAILED]"<GetOrigin(); mitk::Point3D dummy; MITK_TEST_OUTPUT( << " Testing index->world->index conversion consistency"); geometry3d->WorldToIndex(origin, dummy); geometry3d->IndexToWorld(dummy, dummy); MITK_TEST_CONDITION_REQUIRED(dummy == origin, ""); MITK_TEST_OUTPUT( << " Testing WorldToIndex(origin, mitk::Point3D)==(0,0,0)"); mitk::Point3D globalOrigin; mitk::FillVector3D(globalOrigin, 0,0,0); mitk::Point3D originContinuousIndex; geometry3d->WorldToIndex(origin, originContinuousIndex); MITK_TEST_CONDITION_REQUIRED(originContinuousIndex == globalOrigin, ""); MITK_TEST_OUTPUT( << " Testing WorldToIndex(origin, itk::Index)==(0,0,0)"); itk::Index<3> itkindex; geometry3d->WorldToIndex(origin, itkindex); itk::Index<3> globalOriginIndex; mitk::vtk2itk(globalOrigin, globalOriginIndex); MITK_TEST_CONDITION_REQUIRED(itkindex == globalOriginIndex, ""); MITK_TEST_OUTPUT( << " Testing WorldToIndex(origin-0.5*spacing, itk::Index)==(0,0,0)"); mitk::Vector3D halfSpacingStep = geometry3d->GetSpacing()*0.5; mitk::Matrix3D rotation; mitk::Point3D originOffCenter = origin-halfSpacingStep; geometry3d->WorldToIndex(originOffCenter, itkindex); MITK_TEST_CONDITION_REQUIRED(itkindex == globalOriginIndex, ""); MITK_TEST_OUTPUT( << " Testing WorldToIndex(origin+0.5*spacing-eps, itk::Index)==(0,0,0)"); originOffCenter = origin+halfSpacingStep; originOffCenter -= 0.0001; geometry3d->WorldToIndex( originOffCenter, itkindex); MITK_TEST_CONDITION_REQUIRED(itkindex == globalOriginIndex, ""); MITK_TEST_OUTPUT( << " Testing WorldToIndex(origin+0.5*spacing, itk::Index)==(1,1,1)"); originOffCenter = origin+halfSpacingStep; itk::Index<3> global111; mitk::FillVector3D(global111, 1,1,1); geometry3d->WorldToIndex( originOffCenter, itkindex); MITK_TEST_CONDITION_REQUIRED(itkindex == global111, ""); MITK_TEST_OUTPUT( << " Testing WorldToIndex(GetCenter())==BoundingBox.GetCenter: "); mitk::Point3D center = geometry3d->GetCenter(); mitk::Point3D centerContIndex; geometry3d->WorldToIndex(center, centerContIndex); mitk::BoundingBox::ConstPointer boundingBox = geometry3d->GetBoundingBox(); mitk::BoundingBox::PointType centerBounds = boundingBox->GetCenter(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(centerContIndex,centerBounds), ""); MITK_TEST_OUTPUT( << " Testing GetCenter()==IndexToWorld(BoundingBox.GetCenter): "); center = geometry3d->GetCenter(); mitk::Point3D centerBoundsInWorldCoords; geometry3d->IndexToWorld(centerBounds, centerBoundsInWorldCoords); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(center,centerBoundsInWorldCoords), ""); return EXIT_SUCCESS; } int testIndexAndWorldConsistencyForVectors(mitk::Geometry3D* geometry3d) { MITK_TEST_OUTPUT( << "Testing consistency of index and world coordinate systems for vectors: "); mitk::Vector3D xAxisMM = geometry3d->GetAxisVector(0); mitk::Vector3D xAxisContinuousIndex; mitk::Vector3D xAxisContinuousIndexDeprecated; mitk::Point3D p, pIndex, origin; origin = geometry3d->GetOrigin(); p[0] = xAxisMM[0]; p[1] = xAxisMM[1]; p[2] = xAxisMM[2]; geometry3d->WorldToIndex(p,pIndex); geometry3d->WorldToIndex(xAxisMM, xAxisContinuousIndexDeprecated); geometry3d->WorldToIndex(xAxisMM,xAxisContinuousIndex); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[0] == pIndex[0],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[1] == pIndex[1],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[2] == pIndex[2],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[0] == xAxisContinuousIndexDeprecated[0],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[1] == xAxisContinuousIndexDeprecated[1],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[2] == xAxisContinuousIndexDeprecated[2],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndexDeprecated[0] == pIndex[0],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndexDeprecated[1] == pIndex[1],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndexDeprecated[2] == pIndex[2],""); geometry3d->IndexToWorld(xAxisContinuousIndex,xAxisContinuousIndex); geometry3d->IndexToWorld(xAxisContinuousIndexDeprecated,xAxisContinuousIndexDeprecated); geometry3d->IndexToWorld(pIndex,p); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex == xAxisMM,""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[0] == p[0],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[1] == p[1],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndex[2] == p[2],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndexDeprecated == xAxisMM,""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndexDeprecated[0] == p[0],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndexDeprecated[1] == p[1],""); MITK_TEST_CONDITION_REQUIRED(xAxisContinuousIndexDeprecated[2] == p[2],""); return EXIT_SUCCESS; } #include int testItkImageIsCenterBased() { MITK_TEST_OUTPUT(<< "Testing whether itk::Image coordinates are center-based."); typedef itk::Image ItkIntImage3D; ItkIntImage3D::Pointer itkintimage = ItkIntImage3D::New(); ItkIntImage3D::SizeType size; size.Fill(10); mitk::Point3D origin; mitk::FillVector3D(origin, 2,3,7); itkintimage->Initialize(); itkintimage->SetRegions(size); itkintimage->SetOrigin(origin); std::cout<<"[PASSED]"< originContinuousIndex; itkintimage->TransformPhysicalPointToContinuousIndex(origin, originContinuousIndex); MITK_TEST_CONDITION_REQUIRED(originContinuousIndex == globalOrigin, ""); MITK_TEST_OUTPUT( << " Testing itk::Image::TransformPhysicalPointToIndex(origin)==(0,0,0)"); itk::Index<3> itkindex; itkintimage->TransformPhysicalPointToIndex(origin, itkindex); itk::Index<3> globalOriginIndex; mitk::vtk2itk(globalOrigin, globalOriginIndex); MITK_TEST_CONDITION_REQUIRED(itkindex == globalOriginIndex, ""); MITK_TEST_OUTPUT( << " Testing itk::Image::TransformPhysicalPointToIndex(origin-0.5*spacing)==(0,0,0)"); mitk::Vector3D halfSpacingStep = itkintimage->GetSpacing()*0.5; mitk::Matrix3D rotation; mitk::Point3D originOffCenter = origin-halfSpacingStep; itkintimage->TransformPhysicalPointToIndex(originOffCenter, itkindex); MITK_TEST_CONDITION_REQUIRED(itkindex == globalOriginIndex, ""); MITK_TEST_OUTPUT( << " Testing itk::Image::TransformPhysicalPointToIndex(origin+0.5*spacing-eps, itk::Index)==(0,0,0)"); originOffCenter = origin+halfSpacingStep; originOffCenter -= 0.0001; itkintimage->TransformPhysicalPointToIndex( originOffCenter, itkindex); MITK_TEST_CONDITION_REQUIRED(itkindex == globalOriginIndex, ""); MITK_TEST_OUTPUT( << " Testing itk::Image::TransformPhysicalPointToIndex(origin+0.5*spacing, itk::Index)==(1,1,1)"); originOffCenter = origin+halfSpacingStep; itk::Index<3> global111; mitk::FillVector3D(global111, 1,1,1); itkintimage->TransformPhysicalPointToIndex( originOffCenter, itkindex); MITK_TEST_CONDITION_REQUIRED(itkindex == global111, ""); MITK_TEST_OUTPUT( << "=> Yes, itk::Image coordinates are center-based."); return EXIT_SUCCESS; } int testGeometry3D(bool imageGeometry) { // Build up a new image Geometry mitk::Geometry3D::Pointer geometry3d = mitk::Geometry3D::New(); float bounds[ ] = {-10.0, 17.0, -12.0, 188.0, 13.0, 211.0}; MITK_TEST_OUTPUT( << "Initializing"); geometry3d->Initialize(); MITK_TEST_OUTPUT(<< "Setting ImageGeometry to " << imageGeometry); geometry3d->SetImageGeometry(imageGeometry); MITK_TEST_OUTPUT(<< "Setting bounds by SetFloatBounds(): " << bounds); geometry3d->SetFloatBounds(bounds); MITK_TEST_OUTPUT( << "Testing AxisVectors"); if(testGetAxisVectorVariants(geometry3d) == false) return EXIT_FAILURE; if(testGetAxisVectorExtent(geometry3d) == false) return EXIT_FAILURE; MITK_TEST_OUTPUT( << "Creating an AffineTransform3D transform"); mitk::AffineTransform3D::MatrixType matrix; matrix.SetIdentity(); matrix(1,1) = 2; mitk::AffineTransform3D::Pointer transform; transform = mitk::AffineTransform3D::New(); transform->SetMatrix(matrix); MITK_TEST_OUTPUT( << "Testing a SetIndexToWorldTransform"); geometry3d->SetIndexToWorldTransform(transform); MITK_TEST_OUTPUT( << "Testing correctness of value returned by GetSpacing"); const mitk::Vector3D& spacing1 = geometry3d->GetSpacing(); mitk::Vector3D expectedSpacing; expectedSpacing.Fill(1.0); expectedSpacing[1] = 2; if( mitk::Equal(spacing1, expectedSpacing) == false ) { MITK_TEST_OUTPUT( << " [FAILED]"); return EXIT_FAILURE; } MITK_TEST_OUTPUT( << "Testing a Compose(transform)"); geometry3d->Compose(transform); MITK_TEST_OUTPUT( << "Testing correctness of value returned by GetSpacing"); const mitk::Vector3D& spacing2 = geometry3d->GetSpacing(); expectedSpacing[1] = 4; if( mitk::Equal(spacing2, expectedSpacing) == false ) { MITK_TEST_OUTPUT( << " [FAILED]"); return EXIT_FAILURE; } MITK_TEST_OUTPUT( << "Testing correctness of SetSpacing"); mitk::Vector3D newspacing; mitk::FillVector3D(newspacing, 1.5, 2.5, 3.5); geometry3d->SetSpacing(newspacing); const mitk::Vector3D& spacing3 = geometry3d->GetSpacing(); if( mitk::Equal(spacing3, newspacing) == false ) { MITK_TEST_OUTPUT( << " [FAILED]"); return EXIT_FAILURE; } // Seperate Test function for Index and World consistency testIndexAndWorldConsistency(geometry3d); testIndexAndWorldConsistencyForVectors(geometry3d); MITK_TEST_OUTPUT( << "Testing a rotation of the geometry"); double angle = 35.0; mitk::Vector3D rotationVector; mitk::FillVector3D( rotationVector, 1, 0, 0 ); mitk::Point3D center = geometry3d->GetCenter(); mitk::RotationOperation* op = new mitk::RotationOperation( mitk::OpROTATE, center, rotationVector, angle ); geometry3d->ExecuteOperation(op); MITK_TEST_OUTPUT( << "Testing mitk::GetRotation() and success of rotation"); mitk::Matrix3D rotation; mitk::GetRotation(geometry3d, rotation); mitk::Vector3D voxelStep=rotation*newspacing; mitk::Vector3D voxelStepIndex; geometry3d->WorldToIndex(voxelStep, voxelStepIndex); mitk::Vector3D expectedVoxelStepIndex; expectedVoxelStepIndex.Fill(1); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(voxelStepIndex,expectedVoxelStepIndex), ""); delete op; std::cout<<"[PASSED]"<GetImageGeometry() == imageGeometry, ""); //Test if the translate function moves the origin correctly. mitk::Point3D oldOrigin = geometry3d->GetOrigin(); //use some random values for translation mitk::Vector3D translationVector; translationVector.SetElement(0, 17.5f); translationVector.SetElement(1, -32.3f); translationVector.SetElement(2, 4.0f); //compute ground truth mitk::Point3D tmpResult = geometry3d->GetOrigin() + translationVector; geometry3d->Translate(translationVector); MITK_TEST_CONDITION( mitk::Equal( geometry3d->GetOrigin(), tmpResult ), "Testing if origin was translated."); translationVector*=-1; //vice versa geometry3d->Translate(translationVector); MITK_TEST_CONDITION( mitk::Equal( geometry3d->GetOrigin(), oldOrigin ), "Testing if the translation could be done vice versa." ); return EXIT_SUCCESS; } int testGeometryAfterCasting() { // Epsilon. Allowed difference for rotationvalue float eps = 0.0001; // Cast ITK and MITK images and see if geometry stays typedef itk::Image Image2DType; typedef itk::Image Image3DType; // Create 3D ITK Image from Scratch, cast to 3D MITK image, compare Geometries Image3DType::Pointer image3DItk = Image3DType::New(); Image3DType::RegionType myRegion; Image3DType::SizeType mySize; Image3DType::IndexType myIndex; Image3DType::SpacingType mySpacing; Image3DType::DirectionType myDirection, rotMatrixX, rotMatrixY, rotMatrixZ; mySpacing[0] = 31; mySpacing[1] = 0.1; mySpacing[2] = 2.9; myIndex[0] = -15; myIndex[1] = 15; - myIndex[2] = 12.1; + myIndex[2] = 12; mySize[0] = 10; mySize[1] = 2; - mySize[2] = 555.5; + mySize[2] = 555; myRegion.SetSize( mySize); myRegion.SetIndex( myIndex ); image3DItk->SetSpacing(mySpacing); image3DItk->SetRegions( myRegion); image3DItk->Allocate(); image3DItk->FillBuffer(0); myDirection.SetIdentity(); rotMatrixX.SetIdentity(); rotMatrixY.SetIdentity(); rotMatrixZ.SetIdentity(); mitk::Image::Pointer mitkImage; // direction [row] [coloum] MITK_TEST_OUTPUT( << "Casting a rotated 3D ITK Image to a MITK Image and check if Geometry is still same" ); for (double rotX=0; rotX < (itk::Math::pi*2); rotX+=0.4 ) { // Set Rotation X rotMatrixX[1][1] = cos( rotX ); rotMatrixX[1][2] = -sin( rotX ); rotMatrixX[2][1] = sin( rotX ); rotMatrixX[2][2] = cos( rotX ); for (double rotY=0; rotY < (itk::Math::pi*2); rotY+=0.33 ) { // Set Rotation Y rotMatrixY[0][0] = cos( rotY ); rotMatrixY[0][2] = sin( rotY ); rotMatrixY[2][0] = -sin( rotY ); rotMatrixY[2][2] = cos( rotY ); for (double rotZ=0; rotZ < (itk::Math::pi*2); rotZ+=0.5 ) { // Set Rotation Z rotMatrixZ[0][0] = cos( rotZ ); rotMatrixZ[0][1] = -sin( rotZ ); rotMatrixZ[1][0] = sin( rotZ ); rotMatrixZ[1][1] = cos( rotZ ); // Multiply matrizes myDirection = myDirection * rotMatrixX * rotMatrixY * rotMatrixZ; image3DItk->SetDirection(myDirection); mitk::CastToMitkImage(image3DItk, mitkImage); const mitk::AffineTransform3D::MatrixType& matrix = mitkImage->GetGeometry()->GetIndexToWorldTransform()->GetMatrix(); for (int row=0; row<3; row++) { for (int col=0; col<3; col++) { double mitkValue = matrix[row][col] / mitkImage->GetGeometry()->GetSpacing()[col]; double itkValue = myDirection[row][col]; double diff = mitkValue - itkValue; // if you decrease this value, you can see that there might be QUITE high inaccuracy!!! if (diff > eps) // need to check, how exact it SHOULD be .. since it is NOT EXACT! { std::cout << "Had a difference of : " << diff; std::cout << "Error: Casting altered Geometry!"; std::cout << "ITK Matrix:\n" << myDirection; std::cout << "Mitk Matrix (With Spacing):\n" << matrix; std::cout << "Mitk Spacing: " << mitkImage->GetGeometry()->GetSpacing(); MITK_TEST_CONDITION_REQUIRED(false == true, ""); return false; } } } } } } // Create 2D ITK Image from Scratch, cast to 2D MITK image, compare Geometries Image2DType::Pointer image2DItk = Image2DType::New(); Image2DType::RegionType myRegion2D; Image2DType::SizeType mySize2D; Image2DType::IndexType myIndex2D; Image2DType::SpacingType mySpacing2D; Image2DType::DirectionType myDirection2D, rotMatrix; mySpacing2D[0] = 31; mySpacing2D[1] = 0.1; myIndex2D[0] = -15; myIndex2D[1] = 15; mySize2D[0] = 10; mySize2D[1] = 2; myRegion2D.SetSize( mySize2D); myRegion2D.SetIndex( myIndex2D ); image2DItk->SetSpacing(mySpacing2D); image2DItk->SetRegions( myRegion2D); image2DItk->Allocate(); image2DItk->FillBuffer(0); myDirection2D.SetIdentity(); rotMatrix.SetIdentity(); // direction [row] [coloum] MITK_TEST_OUTPUT( << "Casting a rotated 2D ITK Image to a MITK Image and check if Geometry is still same" ); for (double rotTheta=0; rotTheta < (itk::Math::pi*2); rotTheta+=0.1 ) { // Set Rotation rotMatrix[0][0] = cos(rotTheta); rotMatrix[0][1] = -sin(rotTheta); rotMatrix[1][0] = sin(rotTheta); rotMatrix[1][1] = cos(rotTheta); // Multiply matrizes myDirection2D = myDirection2D * rotMatrix; image2DItk->SetDirection(myDirection2D); mitk::CastToMitkImage(image2DItk, mitkImage); const mitk::AffineTransform3D::MatrixType& matrix = mitkImage->GetGeometry()->GetIndexToWorldTransform()->GetMatrix(); // Compare MITK and ITK matrix for (int row=0; row<3; row++) { for (int col=0; col<3; col++) { double mitkValue = matrix[row][col] / mitkImage->GetGeometry()->GetSpacing()[col]; if ((row == 2) && (col == row)) { if (mitkValue != 1) { MITK_TEST_OUTPUT(<< "After casting a 2D ITK to 3D MITK images, MITK matrix values for 0|2, 1|2, 2|0, 2|1 MUST be 0 and value for 2|2 must be 1"); return false; } } else if ((row == 2) || (col == 2)) { if (mitkValue != 0) { MITK_TEST_OUTPUT(<< "After casting a 2D ITK to 3D MITK images, MITK matrix values for 0|2, 1|2, 2|0, 2|1 MUST be 0 and value for 2|2 must be 1"); return false; } } else { double itkValue = myDirection2D[row][col]; double diff = mitkValue - itkValue; // if you decrease this value, you can see that there might be QUITE high inaccuracy!!! if (diff > eps) // need to check, how exact it SHOULD be .. since it is NOT EXACT! { std::cout << "Had a difference of : " << diff; std::cout << "Error: Casting altered Geometry!"; std::cout << "ITK Matrix:\n" << myDirection2D; std::cout << "Mitk Matrix (With Spacing):\n" << matrix; std::cout << "Mitk Spacing: " << mitkImage->GetGeometry()->GetSpacing(); MITK_TEST_CONDITION_REQUIRED(false == true, ""); return false; } } } } } // THIS WAS TESTED: // 2D ITK -> 2D MITK, // 3D ITK -> 3D MITK, // Still need to test: 2D MITK Image with ADDITIONAL INFORMATION IN MATRIX -> 2D ITK // 1. Possibility: 3x3 MITK matrix can be converted without loss into 2x2 ITK matrix // 2. Possibility: 3x3 MITK matrix can only be converted with loss into 2x2 ITK matrix // .. before implementing this, we wait for further development in geometry classes (e.g. Geoemtry3D::SetRotation(..)) return EXIT_SUCCESS; } int mitkGeometry3DTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN(mitkGeometry3DTest); int result; MITK_TEST_CONDITION_REQUIRED( (result = testItkImageIsCenterBased()) == EXIT_SUCCESS, ""); MITK_TEST_OUTPUT(<< "Running main part of test with ImageGeometry = false"); MITK_TEST_CONDITION_REQUIRED( (result = testGeometry3D(false)) == EXIT_SUCCESS, ""); MITK_TEST_OUTPUT(<< "Running main part of test with ImageGeometry = true"); MITK_TEST_CONDITION_REQUIRED( (result = testGeometry3D(true)) == EXIT_SUCCESS, ""); MITK_TEST_OUTPUT(<< "Running test to see if Casting MITK to ITK and the other way around destroys geometry"); MITK_TEST_CONDITION_REQUIRED( (result = testGeometryAfterCasting()) == EXIT_SUCCESS, ""); MITK_TEST_END(); return EXIT_SUCCESS; } diff --git a/Core/Code/Testing/mitkImageAccessorTest.cpp b/Core/Code/Testing/mitkImageAccessorTest.cpp index da575aebca..ca98be2dcd 100644 --- a/Core/Code/Testing/mitkImageAccessorTest.cpp +++ b/Core/Code/Testing/mitkImageAccessorTest.cpp @@ -1,255 +1,254 @@ /*=================================================================== 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 "mitkImage.h" #include "mitkImageReadAccessor.h" #include "mitkImagePixelReadAccessor.h" #include "mitkImagePixelWriteAccessor.h" #include "mitkImageWriteAccessor.h" #include "mitkDataNodeFactory.h" #include "mitkImageTimeSelector.h" #include #include "itkBarrier.h" #include #include #include #include #include struct ThreadData { itk::Barrier::Pointer m_Barrier; // holds a pointer to the used barrier mitk::Image::Pointer data; // some random data int m_NoOfThreads; // holds the number of generated threads bool m_Successful; // to check if everything worked }; ITK_THREAD_RETURN_TYPE ThreadMethod(void* data) { /* extract data pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)data; // some data validity checking if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } // obtain user data for processing ThreadData* threadData = (ThreadData*) pInfo->UserData; srand( pInfo->ThreadID ); mitk::Image::Pointer im = threadData->data; int nrSlices = im->GetDimension(2); // Create randomly a PixelRead- or PixelWriteAccessor for a slice and access all pixels in it. try { if(rand() % 2) { mitk::ImageDataItem* iDi = im->GetSliceData(rand() % nrSlices); - while(!iDi->IsComplete()); + while(!iDi->IsComplete()) {} //MITK_INFO << "pixeltype: " << im->GetPixelType().GetComponentTypeAsString(); if ((im->GetPixelType().GetComponentTypeAsString() == "short") && (im->GetDimension() == 3) ) { // Use pixeltype&dimension specific read accessor int xlength = im->GetDimension(0); int ylength = im->GetDimension(1); mitk::ImagePixelReadAccessor readAccessor(im, iDi); itk::Index<2> idx; for(int i=0; iGetSliceData(rand() % nrSlices); - while(!iDi->IsComplete()); + while(!iDi->IsComplete()) {} if ((im->GetPixelType().GetComponentTypeAsString() == "short") && (im->GetDimension() == 3) ) { // Use pixeltype&dimension specific read accessor int xlength = im->GetDimension(0); int ylength = im->GetDimension(1); mitk::ImagePixelWriteAccessor writeAccessor(im, iDi); itk::Index<2> idx; for(int i=0; im_Successful = false; } } } } else { // use general accessor mitk::ImageWriteAccessor iB(im,iDi); void* pointer = iB.GetData(); *((char*) pointer) = 0; } } } catch(mitk::MemoryIsLockedException e) { threadData->m_Successful = false; e.Print(std::cout); } catch(mitk::Exception e) { threadData->m_Successful = false; e.Print(std::cout); } // data processing end! threadData->m_Barrier->Wait(); return ITK_THREAD_RETURN_VALUE; } int mitkImageAccessorTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkImageAccessorTest"); std::cout << "Loading file: "; if(argc==0) { std::cout<<"no file specified [FAILED]"<SetFileName( argv[1] ); factory->Update(); if(factory->GetNumberOfOutputs()<1) { std::cout<<"file could not be loaded [FAILED]"<GetOutput( 0 ); image = dynamic_cast(node->GetData()); if(image.IsNull()) { std::cout<<"file not an image - test will not be applied [PASSED]"<GetGeometry()->Initialize(); itk::MultiThreader::Pointer threader = itk::MultiThreader::New(); unsigned int noOfThreads = 1; // initialize barrier itk::Barrier::Pointer barrier = itk::Barrier::New(); barrier->Initialize( noOfThreads + 1); // add one for we stop the base thread when the worker threads are processing ThreadData* threadData = new ThreadData; threadData->m_Barrier = barrier; threadData->m_NoOfThreads = noOfThreads; threadData->data = image; threadData->m_Successful = true; // spawn threads for(unsigned int i=0; i < noOfThreads; ++i) { threader->SpawnThread(ThreadMethod, threadData); } // stop the base thread during worker thread execution barrier->Wait(); // terminate threads for(unsigned int j=0; j < noOfThreads; ++j) { threader->TerminateThread(j); } bool TestSuccessful = threadData->m_Successful ; delete threadData; MITK_TEST_CONDITION_REQUIRED( TestSuccessful, "Testing image access from multiple threads"); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DTransferFunctionTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DTransferFunctionTest.cpp index 4c854deda8..6f5e720acb 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DTransferFunctionTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DTransferFunctionTest.cpp @@ -1,86 +1,89 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" //VTK #include #include #include +#include int mitkImageVtkMapper2DTransferFunctionTest(int argc, char* argv[]) { // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkImageVtkMapper2DTransferFunctionTest") // enough parameters? if ( argc < 2 ) { MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) exit( EXIT_SUCCESS ); } mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); //define an arbitrary colortransferfunction vtkSmartPointer colorTransferFunction = vtkSmartPointer::New(); colorTransferFunction->SetColorSpaceToRGB(); colorTransferFunction->AddRGBPoint(0.0, 1, 0, 0); //black = red colorTransferFunction->AddRGBPoint(127.5, 0, 1, 0); //grey = green colorTransferFunction->AddRGBPoint(255.0, 0, 0, 1); //white = blue mitk::TransferFunction::Pointer transferFucntion = mitk::TransferFunction::New(); transferFucntion->SetColorTransferFunction( colorTransferFunction ); + //set the rendering mode to use the transfer function + renderingHelper.SetImageProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR)); //set the property for the image renderingHelper.SetImageProperty("Image Rendering.Transfer Function", mitk::TransferFunctionProperty::New(transferFucntion)); renderingHelper.Render(); //use this to generate a reference screenshot or save the file: bool generateReferenceScreenshot = false; if(generateReferenceScreenshot) { renderingHelper.SaveAsPNG("/home/kilgus/Pictures/RenderingTestData/output.png"); } renderingHelper.PrepareRender(); //### Usage of vtkRegressionTestImage: //vtkRegressionTestImage( vtkRenderWindow ) //Set a vtkRenderWindow containing the desired scene. //vtkRegressionTestImage automatically searches in argc and argv[] //for a path a valid image with -V. If the test failed with the //first image (foo.png) check if there are images of the form //foo_N.png (where N=1,2,3...) and compare against them. //Default tolerance for rendering tests is 10 (set by VTK). //For this case, small artifacts in Windows occur and boundaries of the fonts, //thus we double the default tolerance threshold and set it to 20. int retVal = vtkTesting::Test(argc, argv, renderingHelper.GetVtkRenderWindow(), 20 ); //retVal meanings: (see VTK/Rendering/vtkTesting.h) //0 = test failed //1 = test passed //2 = test not run //3 = something with vtkInteraction MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkLevelWindowManagerTest.cpp b/Core/Code/Testing/mitkLevelWindowManagerTest.cpp index 0ec80fd91b..e6f788d659 100644 --- a/Core/Code/Testing/mitkLevelWindowManagerTest.cpp +++ b/Core/Code/Testing/mitkLevelWindowManagerTest.cpp @@ -1,157 +1,162 @@ /*=================================================================== 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 "mitkLevelWindowManager.h" #include "mitkStandaloneDataStorage.h" #include #include class mitkLevelWindowManagerTestClass { public: static void TestInstantiation() { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); MITK_TEST_CONDITION_REQUIRED(manager.IsNotNull(),"Testing mitk::LevelWindowManager::New()"); } static void TestSetGetDataStorage() { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); MITK_TEST_OUTPUT(<< "Creating DataStorage: "); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); bool success = true; try { manager->SetDataStorage(ds); } catch(std::exception e) { success = false; MITK_ERROR << "Exception: " << e.what(); } MITK_TEST_CONDITION_REQUIRED(success,"Testing mitk::LevelWindowManager SetDataStorage() "); MITK_TEST_CONDITION_REQUIRED(ds == manager->GetDataStorage(),"Testing mitk::LevelWindowManager GetDataStorage "); } static void TestMethodsWithInvalidParameters() { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); bool success = false; mitk::LevelWindowProperty::Pointer levelWindowProperty = mitk::LevelWindowProperty::New(); try { manager->SetLevelWindowProperty(levelWindowProperty); } catch(mitk::Exception e) { success = true; } MITK_TEST_CONDITION(success,"Testing mitk::LevelWindowManager SetLevelWindowProperty with invalid parameter"); } static void TestOtherMethods() { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); MITK_TEST_CONDITION(manager->isAutoTopMost(),"Testing mitk::LevelWindowManager isAutoTopMost"); + // It is not clear what the following code is supposed to test. The expression in + // the catch(...) block does have no effect, so success is always true. + // Related bugs are 13894 and 13889 + /* bool success = true; try { mitk::LevelWindow levelWindow = manager->GetLevelWindow(); manager->SetLevelWindow(levelWindow); } catch (...) { success == false; } MITK_TEST_CONDITION(success,"Testing mitk::LevelWindowManager GetLevelWindow() and SetLevelWindow()"); + */ manager->SetAutoTopMostImage(true); MITK_TEST_CONDITION(manager->isAutoTopMost(),"Testing mitk::LevelWindowManager isAutoTopMost()"); } static void TestRemoveObserver(std::string testImageFile) { mitk::LevelWindowManager::Pointer manager; manager = mitk::LevelWindowManager::New(); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); manager->SetDataStorage(ds); //add multiple objects to the data storage => multiple observers should be created mitk::Image::Pointer image1 = mitk::IOUtil::LoadImage(testImageFile); mitk::DataNode::Pointer node1 = mitk::DataNode::New(); node1->SetData(image1); mitk::Image::Pointer image2 = mitk::IOUtil::LoadImage(testImageFile); mitk::DataNode::Pointer node2 = mitk::DataNode::New(); node2->SetData(image2); ds->Add(node1); ds->Add(node2); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 2, "Test if nodes have been added"); - MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == manager->GetNumberOfObservers(), "Test if number of nodes is similar to number of observers"); + MITK_TEST_CONDITION_REQUIRED(static_cast(manager->GetRelevantNodes()->size()) == manager->GetNumberOfObservers(), "Test if number of nodes is similar to number of observers"); mitk::Image::Pointer image3 = mitk::IOUtil::LoadImage(testImageFile); mitk::DataNode::Pointer node3 = mitk::DataNode::New(); node3->SetData(image3); ds->Add(node3); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 3, "Test if another node have been added"); - MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == manager->GetNumberOfObservers(), "Test if number of nodes is similar to number of observers"); + MITK_TEST_CONDITION_REQUIRED(static_cast(manager->GetRelevantNodes()->size()) == manager->GetNumberOfObservers(), "Test if number of nodes is similar to number of observers"); ds->Remove(node1); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 2, "Deleted node 1 (test GetRelevantNodes())"); MITK_TEST_CONDITION_REQUIRED(manager->GetNumberOfObservers() == 2, "Deleted node 1 (test GetNumberOfObservers())"); ds->Remove(node2); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 1, "Deleted node 2 (test GetRelevantNodes())"); MITK_TEST_CONDITION_REQUIRED(manager->GetNumberOfObservers() == 1, "Deleted node 2 (test GetNumberOfObservers())"); ds->Remove(node3); MITK_TEST_CONDITION_REQUIRED(manager->GetRelevantNodes()->size() == 0, "Deleted node 3 (test GetRelevantNodes())"); MITK_TEST_CONDITION_REQUIRED(manager->GetNumberOfObservers() == 0, "Deleted node 3 (test GetNumberOfObservers())"); } }; int mitkLevelWindowManagerTest(int argc, char* args[]) { MITK_TEST_BEGIN("mitkLevelWindowManager"); MITK_TEST_CONDITION_REQUIRED( argc >= 2, "Testing if test file is given."); std::string testImage = args[1]; mitkLevelWindowManagerTestClass::TestInstantiation(); mitkLevelWindowManagerTestClass::TestSetGetDataStorage(); mitkLevelWindowManagerTestClass::TestMethodsWithInvalidParameters(); mitkLevelWindowManagerTestClass::TestOtherMethods(); mitkLevelWindowManagerTestClass::TestRemoveObserver(testImage); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkLevelWindowTest.cpp b/Core/Code/Testing/mitkLevelWindowTest.cpp index 2ac59a0fbe..212ed1c12b 100644 --- a/Core/Code/Testing/mitkLevelWindowTest.cpp +++ b/Core/Code/Testing/mitkLevelWindowTest.cpp @@ -1,960 +1,960 @@ /*=================================================================== 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 "mitkLevelWindow.h" #include /* * Reseting the Levelwindow to default values: * i.e. Range = -1000..1000, Level = 0 and Window = 500 */ void resetLevelWindow(mitk::LevelWindow &lw) { //Default window bounds lw.SetRangeMinMax(-10000,10000); lw.SetLevelWindow(0,500,false); if (lw.GetRangeMin() != -10000 || lw.GetRangeMax() != 10000 || lw.GetLevel() != 0 || lw.GetWindow() != 500) { std::cout << "[Failed] To reset Levelwindow"<GetDefaultWindow(); if (!(defaultWindow == 500)) { - std::cout<<(int)(defaultWindow) + "[FAILED]"<GetDefaultLevel(); if (!(defaultLevel == 256)) { std::cout<<"[FAILED]"<GetWindow(); if (!(window == 500)) { std::cout<<"[FAILED]"<GetLowerWindowBound() == 6)) { std::cout<<"[FAILED]"<GetUpperWindowBound() == 506)) { std::cout<<"[FAILED]"<GetLevel(); if (!(level == 256)) { std::cout<<"[FAILED]"<SetLevelWindow(20, 100); if (!(levWin->GetLevel() == 20)) { std::cout<<"[FAILED]"<GetWindow() == 100)) { std::cout<<"[FAILED]"<SetLevelWindow(levWin->GetDefaultLevel(), levWin->GetDefaultWindow()); if (!(levWin->GetLevel() == 256) && !(levWin->GetWindow() == 500)) { std::cout<<"[FAILED]"<SetDefaultLevelWindow(20, 200); if (!(levWin->GetDefaultLevel() == 20) && !(levWin->GetDefaultWindow() == 200)) { std::cout<<"[FAILED]"<SetLevelWindow(100, 50); levWin->ResetDefaultLevelWindow(); //double a = levWin->GetLevel(); //double d = levWin->GetWindow(); if (!((levWin->GetLevel() == 20) &&(levWin->GetWindow() == 200))) { std::cout<<"[FAILED]"<SetWindowBounds(0, 2); if (!((levWin->GetLowerWindowBound() == 0) && (levWin->GetUpperWindowBound() == 2) && (levWin->GetLevel() == 1) && (levWin->GetWindow() == 2))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(2000, 2000); if (!(levWin->GetRangeMin() == 1999 && levWin->GetRangeMax() == 2000)) { std::cout<<"[FAILED]"< rangemax"; levWin->SetRangeMinMax(2100, 2000); if (!(levWin->GetRangeMin() == 2000 && levWin->GetRangeMax() == 2100)) { std::cout<<"[FAILED]"<SetRangeMinMax(-1000, 2000); std::cout<<"[PASSED]"<GetRangeMin() == -1000)) { std::cout<<"[FAILED]"<GetRangeMax() == 2000)) { std::cout<<"[FAILED]"<GetRangeMax() - levWin->GetRangeMin()) == levWin->GetRange())) { std::cout<<"[FAILED]"<SetDefaultBoundaries(2000, 2000); if (!(levWin->GetDefaultLowerBound() == 1999 && levWin->GetDefaultUpperBound() == 2000)) { std::cout<<"[FAILED]"< rangemax"; levWin->SetDefaultBoundaries(2100, 2000); if (!(levWin->GetDefaultLowerBound() == 2000 && levWin->GetDefaultUpperBound() == 2100)) { std::cout<<"[FAILED]"<SetDefaultBoundaries(-2000, 8000); std::cout<<"[PASSED]"<GetDefaultLowerBound() == -2000)) { std::cout<<"[FAILED]"<GetDefaultUpperBound() == 8000)) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); if (!((levWin->GetRangeMin() == levWin->GetDefaultLowerBound()) && (levWin->GetRangeMax() == levWin->GetDefaultUpperBound()))) { std::cout<<"[FAILED]"< maxRange "; levWin->SetRangeMinMax(2000, 1000); if (!((levWin->GetRangeMin() == 1000) && (levWin->GetRangeMax() == 2000))) { std::cout<<"[FAILED]"<SetRangeMinMax(2000, -1000); if (!((levWin->GetRangeMin() == -1000) && (levWin->GetRangeMax() == 2000))) { std::cout<<"[FAILED]"<SetRangeMinMax(-2000, -3000); if (!((levWin->GetRangeMin() == -3000) && (levWin->GetRangeMax() == -2000))) { std::cout<<"[FAILED]"<SetRangeMinMax(0, -1000); if (!((levWin->GetRangeMin() == -1000) && (levWin->GetRangeMax() == 0))) { std::cout<<"[FAILED]"<SetRangeMinMax(2000, 0); if (!((levWin->GetRangeMin() == 0) && (levWin->GetRangeMax() == 2000))) { std::cout<<"[FAILED]"<SetRangeMinMax(-10000, 10000); std::cout<<"[PASSED]"< defaultMaxRange "; levWin->SetDefaultBoundaries(2000, 1000); if (!((levWin->GetDefaultLowerBound() == 1000) && (levWin->GetDefaultUpperBound() == 2000))) { std::cout<<"[FAILED]"<SetDefaultBoundaries(2000, -1000); if (!((levWin->GetDefaultLowerBound() == -1000) && (levWin->GetDefaultUpperBound() == 2000))) { std::cout<<"[FAILED]"<SetDefaultBoundaries(-2000, -3000); if (!((levWin->GetDefaultLowerBound() == -3000) && (levWin->GetDefaultUpperBound() == -2000))) { std::cout<<"[FAILED]"<SetDefaultBoundaries(0, -1000); if (!((levWin->GetDefaultLowerBound() == -1000) && (levWin->GetDefaultUpperBound() == 0))) { std::cout<<"[FAILED]"<SetDefaultBoundaries(2000, 0); if (!((levWin->GetDefaultLowerBound() == 0) && (levWin->GetDefaultUpperBound() == 2000))) { std::cout<<"[FAILED]"<SetDefaultBoundaries(-10000, 10000); std::cout<<"[PASSED]"< max "; levWin->SetWindowBounds(2000, 1000); if (!((levWin->GetLowerWindowBound() == 1000) && (levWin->GetUpperWindowBound() == 2000))) { std::cout<<"[FAILED]"<SetWindowBounds(2000, -1000); if (!((levWin->GetLowerWindowBound() == -1000) && (levWin->GetUpperWindowBound() == 2000))) { std::cout<<"[FAILED]"<SetWindowBounds(-2000, -3000); if (!((levWin->GetLowerWindowBound() == -3000) && (levWin->GetUpperWindowBound() == -2000))) { std::cout<<"[FAILED]"<SetWindowBounds(0, -1000); if (!((levWin->GetLowerWindowBound() == -1000) && (levWin->GetUpperWindowBound() == 0))) { std::cout<<"[FAILED]"<SetWindowBounds(2000, 0); if (!((levWin->GetLowerWindowBound() == 0) && (levWin->GetUpperWindowBound() == 2000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange, minmax < minrange, minmaxrange, min < minrange & max > minrange // max < minrange & min > minrange, min > maxrange & max < maxrange, min < minrange & max > maxrange // min > maxrange & max < minrange std::cout << "Testing mitk::LevelWindow max > min > maxrange autoexpand = FALSE"; levWin->SetWindowBounds(11000, 12000, false); if (!((levWin->GetLowerWindowBound() == 9999) && (levWin->GetUpperWindowBound() == 10000))) { std::cout<<"[FAILED]"<GetLowerWindowBound()<<","<GetUpperWindowBound()<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< min > maxrange autoexpand = TRUE"; levWin->SetWindowBounds(11000, 12000); if (!((levWin->GetLowerWindowBound() == 11000) && (levWin->GetUpperWindowBound() == 12000))) { std::cout<<"[FAILED]"<GetLowerWindowBound()<<","<GetUpperWindowBound()<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< max > maxrange autoexpand = FALSE"; levWin->SetWindowBounds(12000, 11000, false); if (!((levWin->GetLowerWindowBound() == 9999) && (levWin->GetUpperWindowBound() == 10000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< max > maxrange autoexpand = TRUE"; levWin->SetWindowBounds(12000, 11000); if (!((levWin->GetLowerWindowBound() == 11000) && (levWin->GetUpperWindowBound() == 12000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(-12000, -11000, false); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == -9999))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(-12000, -11000); if (!((levWin->GetLowerWindowBound() == -12000) && (levWin->GetUpperWindowBound() == -11000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(-11000, -12000, false); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == -9999))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(-11000, -12000); if (!((levWin->GetLowerWindowBound() == -12000) && (levWin->GetUpperWindowBound() == -11000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange autoexpand = FALSE"; levWin->SetWindowBounds(9999, 12000, false); if (!((levWin->GetLowerWindowBound() == 9999) && (levWin->GetUpperWindowBound() == 10000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange autoexpand = TRUE"; levWin->SetWindowBounds(9999, 12000); if (!((levWin->GetLowerWindowBound() == 9999) && (levWin->GetUpperWindowBound() == 12000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< minrange autoexpand = FALSE"; levWin->SetWindowBounds(-11000, -9999, false); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == -9999))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< minrange autoexpand = TRUE"; levWin->SetWindowBounds(-11000, -9999); if (!((levWin->GetLowerWindowBound() == -11000) && (levWin->GetUpperWindowBound() == -9999))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange autoexpand = FALSE"; levWin->SetWindowBounds(-11000, 11000, false); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == 10000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange autoexpand = TRUE"; levWin->SetWindowBounds(-11000, 11000); if (!((levWin->GetLowerWindowBound() == -11000) && (levWin->GetUpperWindowBound() == 11000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< min = max > minrange autoexpand = FALSE"; levWin->SetWindowBounds(5000, 5000, false); if (!((levWin->GetLowerWindowBound() == 4999) && (levWin->GetUpperWindowBound() == 5000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< min = max > minrange autoexpand = TRUE"; levWin->SetWindowBounds(5000, 5000); if (!((levWin->GetLowerWindowBound() == 4999) && (levWin->GetUpperWindowBound() == 5000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(-10000, -10000, false); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == -9999))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(-10000, -10000); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == -9999))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(10000, 10000, false); if (!((levWin->GetLowerWindowBound() == 9999) && (levWin->GetUpperWindowBound() == 10000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(10000, 10000); if (!((levWin->GetLowerWindowBound() == 9999) && (levWin->GetUpperWindowBound() == 10000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange autoexpand = FALSE"; levWin->SetWindowBounds(11000, 11000, false); if (!((levWin->GetLowerWindowBound() == 9999) && (levWin->GetUpperWindowBound() == 10000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange autoexpand = TRUE"; levWin->SetWindowBounds(11000, 11000); if (!((levWin->GetLowerWindowBound() == 10999) && (levWin->GetUpperWindowBound() == 11000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(-11000, -11000, false); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == -9999))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetWindowBounds(-11000, -11000); if (!((levWin->GetLowerWindowBound() == -11000) && (levWin->GetUpperWindowBound() == -10999))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< min > minrange > max autoexpand = FALSE"; levWin->SetWindowBounds(-9000, -11000, false); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == -9000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< min > minrange > max autoexpand = TRUE"; levWin->SetWindowBounds(-9000, -11000, true); if (!((levWin->GetLowerWindowBound() == -11000) && (levWin->GetUpperWindowBound() == -9000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange > minrange > max autoexpand = FALSE"; levWin->SetWindowBounds(11000, -11000, false); if (!((levWin->GetLowerWindowBound() == -10000) && (levWin->GetUpperWindowBound() == 10000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange > minrange > max autoexpand = TRUE"; levWin->SetWindowBounds(11000, -11000); if (!((levWin->GetLowerWindowBound() == -11000) && (levWin->GetUpperWindowBound() == 11000))) { std::cout<<"[FAILED]"<ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(-20000, -15000); if (!((levWin->GetLowerWindowBound() == -15001) && (levWin->GetUpperWindowBound() == -15000))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange & maxrange < min < max "; levWin->ResetDefaultLevelWindow(); levWin->SetRangeMinMax(-15000, -20000); if (!((levWin->GetLowerWindowBound() == -15001) && (levWin->GetUpperWindowBound() == -15000))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(-80, 1000); levWin->SetWindowBounds(-1000,110, false); if (!((levWin->GetLowerWindowBound() == -80) && (levWin->GetUpperWindowBound() == 110))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(-80, 1000); levWin->SetWindowBounds(-1000,110); if (!((levWin->GetLowerWindowBound() == -1000) && (levWin->GetUpperWindowBound() == 110))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(1000,-80); levWin->SetWindowBounds(-1000,110, false ); if (!((levWin->GetLowerWindowBound() == -80) && (levWin->GetUpperWindowBound() == 110))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(1000,-80); levWin->SetWindowBounds(-1000,110 ); if (!((levWin->GetLowerWindowBound() == -1000) && (levWin->GetUpperWindowBound() == 110))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(20, 110); if (!((levWin->GetLowerWindowBound() == 20) && (levWin->GetUpperWindowBound() == 110))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxRange & min < maxrange < max "; levWin->SetWindowBounds(-90,1000); levWin->SetRangeMinMax(100, -80); if (!((levWin->GetLowerWindowBound() == -80) && (levWin->GetUpperWindowBound() == 100))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxRange & min < minrange < maxrange SetRangeMinMax(20, 100); if (!((levWin->GetLowerWindowBound() == 20) && (levWin->GetUpperWindowBound() == 100))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(20000, 15000); if (!((levWin->GetLowerWindowBound() == 15000) && (levWin->GetUpperWindowBound() == 15001))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"< maxrange & min < max < minrange "; levWin->SetRangeMinMax(20000, 15000); if (!((levWin->GetLowerWindowBound() == 15000) && (levWin->GetUpperWindowBound() == 15001))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<SetRangeMinMax(-20000, -15000); if (!((levWin->GetLowerWindowBound() == -15001) && (levWin->GetUpperWindowBound() == -15000))) { std::cout<<"[FAILED]"<ResetDefaultRangeMinMax(); levWin->ResetDefaultLevelWindow(); std::cout<<"[PASSED]"<DebugOn(); image->Initialize( mitk::MakePixelType(), 3, dim); int *p = (int*)image->GetData(); int size = dim[0]*dim[1]*dim[2]; int i; for(i=0; iGetRange() == levelwindow.GetRange())) { std::cout<<"[FAILED]"< #include #include #include #include class mitkPointSetTestClass { public: static void TestGetITKPointSet(mitk::PointSet *pointSet) { //try to get the itkPointSet mitk::PointSet::DataType::Pointer itkdata = NULL; itkdata = pointSet->GetPointSet(); MITK_TEST_CONDITION( itkdata.IsNotNull(), "try to get the itkPointSet from a newly created PointSet" ) } static void TestGetSizeIsZero(mitk::PointSet *pointSet) { //fresh PointSet has to be empty! MITK_TEST_CONDITION( pointSet->GetSize() == 0, "check if the PointSet size is 0 " ) } static void TestIsEmpty(mitk::PointSet *pointSet) { MITK_TEST_CONDITION(pointSet->IsEmptyTimeStep(0), "check if the PointSet is empty" ) } static void TestCreateOperationAndAddPoint(mitk::PointSet *pointSet) { int id = 0; mitk::Point3D point; point.Fill(1); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpINSERT, point, id); pointSet->ExecuteOperation(doOp); MITK_TEST_CONDITION( pointSet->GetSize()==1 && pointSet->IndexExists(id), "check if added points exists" ) delete doOp; mitk::Point3D tempPoint; tempPoint.Fill(0); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION( point == tempPoint, "check if added point contains real value" ) } static void TestAddSecondPoint(mitk::PointSet *pointSet) { //add a point directly int id=0; mitk::Point3D point; mitk::FillVector3D(point, 1.0, 2.0, 3.0); ++id; pointSet->GetPointSet()->GetPoints()->InsertElement(id, point); MITK_TEST_CONDITION( pointSet->GetSize()==2 ||pointSet->IndexExists(id), "check if added points exists" ) mitk::Point3D tempPoint; tempPoint.Fill(0); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION( point == tempPoint, "check if added point contains real value" ) } static void TestIsNotEmpty(mitk::PointSet *pointSet) { //PointSet can not be empty! MITK_TEST_CONDITION( !pointSet->IsEmptyTimeStep(0), "check if the PointSet is not empty " ) /* std::cout << "check if the PointSet is not empty "; if (pointSet->IsEmpty(0)) { std::cout<<"[FAILED]"<GetPoint(1); pointSet->SwapPointPosition(1, true); tempPoint = pointSet->GetPoint(0); MITK_TEST_CONDITION( point == tempPoint, "check SwapPointPosition upwards" ) /* if(point != tempPoint) { std::cout<<"[FAILED]"<SwapPointPosition(0, true)==false, "check SwapPointPosition upwards not possible" ) /* if(pointSet->SwapPointPosition(0, true)) { std::cout<<"[FAILED]"<GetPoint(0); pointSet->SwapPointPosition(0, false); tempPoint = pointSet->GetPoint(1); MITK_TEST_CONDITION( point == tempPoint, "check SwapPointPosition down" ) /* if(point != tempPoint) { std::cout<<"[FAILED]"<SetPoint(id, point); //Check SwapPointPosition downwards not possible MITK_TEST_CONDITION(!pointSet2->SwapPointPosition(id, false), "check SwapPointPosition downwards not possible" ) /* if(pointSet->SwapPointPosition(1, false)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION(tempPoint == point1 , "check PointOperation OpMove " ) delete doOp; /* if (tempPoint != point1) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpREMOVE, point, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION(!pointSet->IndexExists(id) , "check PointOperation OpREMOVE " ) delete doOp; /* if(pointSet->IndexExists(id)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); MITK_TEST_CONDITION(pointSet->GetSelectInfo(4) , "check PointOperation OpSELECTPOINT " ) delete doOp; /* if (!pointSet->GetSelectInfo(4)) { std::cout<<"[FAILED]"<GetNumberOfSelected() == 1 , "check GetNumeberOfSelected " ) /* if(pointSet->GetNumberOfSelected() != 1) { std::cout<<"[FAILED]"<SearchSelectedPoint() == 4 , "check SearchSelectedPoint " ) /* if( pointSet->SearchSelectedPoint() != 4) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); MITK_TEST_CONDITION(!pointSet->GetSelectInfo(4) , "check PointOperation OpDESELECTPOINT " ) MITK_TEST_CONDITION(pointSet->GetNumberOfSelected() == 0 , "check GetNumeberOfSelected " ) delete doOp; /* if (pointSet->GetSelectInfo(4)) { std::cout<<"[FAILED]"<GetNumberOfSelected() != 0) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, point4, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id-1); MITK_TEST_CONDITION(tempPoint == point , "check PointOperation OpMOVEPOINTUP " ) delete doOp; /* if (tempPoint != point) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTDOWN, point2, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id+1); MITK_TEST_CONDITION(tempPoint == point , "check PointOperation OpMOVEPOINTDOWN " ) delete doOp; /* if (tempPoint != point) { std::cout<<"[FAILED]"<SetSelectInfo(2, true); MITK_TEST_CONDITION(pointSet->GetSelectInfo(2) , "check SetSelectInfo" ) /* if (!pointSet->GetSelectInfo(2)) { std::cout<<"[FAILED]"<SetPoint(5, point5, mitk::PTEDGE ); tempPoint = pointSet->GetPoint(5); MITK_TEST_CONDITION(tempPoint == point5, "check InsertPoint with PointSpecification" ) /* if (tempPoint != point5) { std::cout<<"[FAILED]"<GetPointIfExists(5, &tmpPoint); MITK_TEST_CONDITION(tmpPoint == point5, "check GetPointIfExists: " ) /* if (tmpPoint != point5) { std::cout<<"[FAILED]"<InsertPoint(10, p10); pointSet->InsertPoint(11, p11); pointSet->InsertPoint(12, p12); MITK_TEST_CONDITION((pointSet->IndexExists(10) == true) || (pointSet->IndexExists(11) == true) || (pointSet->IndexExists(12) == true), "add points with id 10, 11, 12: " ) //check OpREMOVE ExecuteOperation int id = 11; mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpREMOVE, point, id); pointSet->ExecuteOperation(doOp); MITK_TEST_CONDITION(!pointSet->IndexExists(id), "remove point id 11: ") /* if(pointSet->IndexExists(id)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); delete doOp; //check OpMOVEPOINTUP ExecuteOperation doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, p12, 12); pointSet->ExecuteOperation(doOp); delete doOp; mitk::PointSet::PointType newP10 = pointSet->GetPoint(10); mitk::PointSet::PointType newP12 = pointSet->GetPoint(12); MITK_TEST_CONDITION(((newP10 == p12) && (newP12 == p10)) == true, "check PointOperation OpMOVEPOINTUP for point id 12:" ) //check OpMOVEPOINTDOWN ExecuteOperation doOp = new mitk::PointOperation(mitk::OpMOVEPOINTDOWN, p10, 10); pointSet->ExecuteOperation(doOp); delete doOp; newP10 = pointSet->GetPoint(10); newP12 = pointSet->GetPoint(12); MITK_TEST_CONDITION(((newP10 == p10) && (newP12 == p12)) == true, "check PointOperation OpMOVEPOINTDOWN for point id 10: ") } static void TestOpMovePointUpOnFirstPoint(mitk::PointSet *pointSet) { //check OpMOVEPOINTUP on first point ExecuteOperation mitk::PointSet::PointType p1 = pointSet->GetPoint(1); mitk::PointSet::PointType p2 = pointSet->GetPoint(2); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, p1, 1); pointSet->ExecuteOperation(doOp); delete doOp; mitk::PointSet::PointType newP1 = pointSet->GetPoint(1); mitk::PointSet::PointType newP2 = pointSet->GetPoint(2); MITK_TEST_CONDITION(((newP1 == p1) && (newP2 == p2)) == true, "check PointOperation OpMOVEPOINTUP for point id 1: ") /* if (((newP1 == p1) && (newP2 == p2)) == false) { std::cout<<"[FAILED]"<GetPointSet()->GetPoints(); mitk::PointSet::PointDataContainer* pd = ps->GetPointSet()->GetPointData(); MITK_TEST_CONDITION_REQUIRED(pc->Size() == pd->Size(), "PointContainer and PointDataContainer have same size"); mitk::PointSet::PointsContainer::ConstIterator pIt = pc->Begin(); mitk::PointSet::PointDataContainer::ConstIterator dIt = pd->Begin(); bool failed = false; for (; pIt != pc->End(); ++pIt, ++dIt) if (pIt->Index() != dIt->Index()) { failed = true; break; } MITK_TEST_CONDITION(failed == false, "Indices in PointContainer and PointDataContainer are equal"); } }; int mitkPointSetTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("PointSet") //Create PointSet mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(),"Testing instantiation") mitkPointSetTestClass::TestGetITKPointSet(pointSet); mitkPointSetTestClass::TestGetSizeIsZero(pointSet); mitkPointSetTestClass::TestIsEmpty(pointSet); mitkPointSetTestClass::TestCreateOperationAndAddPoint(pointSet); mitk::Point3D point2, point3, point4; point2.Fill(3); point3.Fill(4); point4.Fill(5); pointSet->InsertPoint(2,point2); pointSet->InsertPoint(3,point3); pointSet->InsertPoint(4,point4); mitkPointSetTestClass::TestAddSecondPoint(pointSet); mitkPointSetTestClass::TestIsNotEmpty(pointSet); mitkPointSetTestClass::TestSwapPointPositionUpwards(pointSet); mitkPointSetTestClass::TestSwapPointPositionUpwardsNotPossible(pointSet); mitkPointSetTestClass::TestSwapPointPositionDownwards(pointSet); mitkPointSetTestClass::TestSwapPointPositionDownwardsNotPossible(pointSet); mitkPointSetTestClass::TestPointOperationOpMove(pointSet); mitkPointSetTestClass::TestPointOperationOpRemove(pointSet); mitkPointSetTestClass::TestPointOperationOpSelectPoint(pointSet); mitkPointSetTestClass::TestGetNumberOfSelected(pointSet); mitkPointSetTestClass::TestSearchSelectedPoint(pointSet); mitkPointSetTestClass::TestOpDeselectPoint(pointSet); mitkPointSetTestClass::TestOpMovePointUp(pointSet); mitkPointSetTestClass::TestOpMovePointDown(pointSet); mitkPointSetTestClass::TestSetSelectInfo(pointSet); mitkPointSetTestClass::TestInsertPointWithPointSpecification(pointSet); mitkPointSetTestClass::TestGetPointIfExists(pointSet); mitkPointSetTestClass::TestCreateHoleInThePointIDs(pointSet); mitkPointSetTestClass::TestOpMovePointUpOnFirstPoint(pointSet); MITK_TEST_OUTPUT(<< "Test InsertPoint(), SetPoint() and SwapPointPosition()"); mitk::PointSet::PointType point; mitk::FillVector3D(point, 2.2, 3.3, -4.4); /* call everything that might modify PointContainer and PointDataContainer */ pointSet->InsertPoint(17, point); pointSet->SetPoint(4, point); pointSet->SetPoint(7, point); pointSet->SetPoint(2, point); pointSet->SwapPointPosition(7, true); pointSet->SwapPointPosition(3, true); pointSet->SwapPointPosition(2, false); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpREMOVE"); mitk::PointOperation op1(mitk::OpREMOVE, mitk::Point3D(), 2); // existing index pointSet->ExecuteOperation(&op1); mitk::PointOperation op1b(mitk::OpREMOVE, mitk::Point3D(), 112); // non existing index pointSet->ExecuteOperation(&op1b); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpMove"); mitk::PointOperation op2(mitk::OpMOVE, mitk::Point3D(), 4); // existing index pointSet->ExecuteOperation(&op2); mitk::PointOperation op3(mitk::OpMOVE, mitk::Point3D(), 34); // non existing index pointSet->ExecuteOperation(&op3); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpINSERT"); mitk::PointOperation op4(mitk::OpINSERT, mitk::Point3D(), 38); // non existing index pointSet->ExecuteOperation(&op4); mitk::PointOperation op5(mitk::OpINSERT, mitk::Point3D(), 17); // existing index pointSet->ExecuteOperation(&op5); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); pointSet = mitk::PointSet::New(); pointSet->Expand(3); mitk::Point3D new0, new1, new2; new0.Fill(0); new1.Fill(1); new2.Fill(2); pointSet->InsertPoint(0,new0,0); pointSet->InsertPoint(1,new1,0); pointSet->InsertPoint(2,new2,0); pointSet->InsertPoint(2,new0,1); pointSet->InsertPoint(1,new1,1); pointSet->InsertPoint(0,new2,1); pointSet->InsertPoint(0,new0,2); pointSet->InsertPoint(2,new1,2); pointSet->InsertPoint(1,new2,2); MITK_INFO << "... pointset ts: " << pointSet->GetTimeSteps(); mitk::PointSet::Pointer clonePS = pointSet->Clone(); MITK_INFO << "... clone pointset ts: " << clonePS->GetTimeSteps(); - for (int t=0; t< pointSet->GetTimeSteps(); t++) + for (unsigned int t=0; t< pointSet->GetTimeSteps(); t++) { MITK_INFO << "testing timestep: " << t; for (int i=0; iGetSize(t); i++) { mitk::Point3D point = pointSet->GetPoint(i,t); mitk::Point3D clonedPoint = clonePS->GetPoint(i,t); MITK_INFO << point << " and " << clonedPoint; MITK_TEST_CONDITION_REQUIRED(mitk::Equal(point,clonedPoint), "Cloned PS and PS have same points"); } } mitkPointSetTestClass::TestIsNotEmpty(clonePS); MITK_TEST_CONDITION_REQUIRED(clonePS->GetPointSetSeriesSize() == pointSet->GetPointSetSeriesSize(), "Testing cloned point set's size!"); MITK_TEST_CONDITION_REQUIRED(clonePS.GetPointer() != pointSet.GetPointer(), "Testing that the clone is not the source PS!"); MITK_TEST_CONDITION_REQUIRED(clonePS->GetGeometry()->GetCenter() == pointSet->GetGeometry()->GetCenter() , "Testing if the geometry is cloned correctly!"); MITK_TEST_CONDITION_REQUIRED(clonePS->GetPropertyList()->GetMap()->size() == pointSet->GetPropertyList()->GetMap()->size() , "Testing if the property list is cloned correctly!"); // Also testing, that clone is independent from original mitk::Point3D p, p2; p.Fill(42); p2.Fill(84); clonePS->InsertPoint(0,p); pointSet->InsertPoint(0,p2); p = clonePS->GetPoint(0); p2 = pointSet->GetPoint(0); MITK_TEST_CONDITION_REQUIRED(p != p2, "Testing that the clone is independent from source!"); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkShaderRepositoryTest.cpp b/Core/Code/Testing/mitkShaderRepositoryTest.cpp new file mode 100644 index 0000000000..397ae506c2 --- /dev/null +++ b/Core/Code/Testing/mitkShaderRepositoryTest.cpp @@ -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. + +===================================================================*/ + + +#include "mitkIShaderRepository.h" +#include "mitkGetModuleContext.h" +#include "mitkModuleContext.h" +#include "mitkServiceReference.h" + +#include "mitkTestingMacros.h" + +#include + + +int mitkShaderRepositoryTest(int /*argc*/, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("ShaderRepository") + + mitk::ModuleContext* context = mitk::GetModuleContext(); + mitk::ServiceReference serviceRef = context->GetServiceReference(); + MITK_TEST_CONDITION_REQUIRED(serviceRef, "IShaderRepository service ref") + + mitk::IShaderRepository* shaderRepo = context->GetService(serviceRef); + MITK_TEST_CONDITION_REQUIRED(shaderRepo, "Check non-empty IShaderRepositry") + + mitk::IShaderRepository::Shader::Pointer shader = shaderRepo->GetShader("mitkShaderLighting"); + MITK_TEST_CONDITION_REQUIRED(shader.IsNotNull(), "Non-null mitkShaderLighting shader") + + MITK_TEST_CONDITION(shader->GetName() == "mitkShaderLighting", "Shader name") + MITK_TEST_CONDITION(!shader->GetMaterialXml().empty(), "Shader content") + + const std::string testShader = + "" + "" + "" + "" + ""; + + const std::size_t shaderCount = shaderRepo->GetShaders().size(); + + std::stringstream testShaderStream(testShader); + const std::string testShaderName = "SmoothPlastic"; + int id = shaderRepo->LoadShader(testShaderStream, testShaderName); + MITK_TEST_CONDITION_REQUIRED(id > -1, "New shader id") + MITK_TEST_CONDITION(shaderRepo->GetShaders().size() == shaderCount+1, "Shader count") + mitk::IShaderRepository::Shader::Pointer shader2 = shaderRepo->GetShader(testShaderName); + MITK_TEST_CONDITION_REQUIRED(shader2.IsNotNull(), "Non-null shader") + MITK_TEST_CONDITION(shader2->GetId() == id, "Shader id") + MITK_TEST_CONDITION(shader2->GetName() == testShaderName, "Shader name") + mitk::IShaderRepository::Shader::Pointer shader3 = shaderRepo->GetShader(id); + MITK_TEST_CONDITION_REQUIRED(shader3.IsNotNull(), "Non-null shader") + MITK_TEST_CONDITION(shader3->GetId() == id, "Shader id") + MITK_TEST_CONDITION(shader3->GetName() == testShaderName, "Shader name") + + MITK_TEST_CONDITION_REQUIRED(shaderRepo->UnloadShader(id), "Unload shader") + MITK_TEST_CONDITION(shaderRepo->GetShader(testShaderName).IsNull(), "Null shader") + MITK_TEST_CONDITION(shaderRepo->GetShader(id).IsNull(), "Null shader") + + MITK_TEST_END() +} diff --git a/Core/Code/Testing/mitkVolumeCalculatorTest.cpp b/Core/Code/Testing/mitkVolumeCalculatorTest.cpp index 18c41a3a0b..b79d3c8626 100644 --- a/Core/Code/Testing/mitkVolumeCalculatorTest.cpp +++ b/Core/Code/Testing/mitkVolumeCalculatorTest.cpp @@ -1,82 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkVolumeCalculator.h" #include "mitkImage.h" #include "mitkTestingMacros.h" #include #include int mitkVolumeCalculatorTest(int /*argc*/, char* argv[]) { MITK_TEST_BEGIN("VolumeCalculator") const char * filename = argv[1]; const char * filename3D = argv[2]; mitk::VolumeCalculator::Pointer volumeCalculator = mitk::VolumeCalculator::New(); mitk::DataNodeFactory::Pointer nodeReader = mitk::DataNodeFactory::New(); //********************************************************************* // Part I: Testing calculated volume. // The correct values have been manually calculated using external software. //********************************************************************* nodeReader->SetFileName(filename); nodeReader->Update(); mitk::DataNode::Pointer node = nodeReader->GetOutput(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); MITK_TEST_CONDITION_REQUIRED( image.IsNotNull() , "01 Check if test image could be loaded"); volumeCalculator->SetImage(image); volumeCalculator->SetThreshold(0); volumeCalculator->ComputeVolume(); float volume = volumeCalculator->GetVolume(); MITK_TEST_CONDITION_REQUIRED( volume == 1600 , "02 Test Volume Result. Expected 1600 actual value " << volume); volumeCalculator->SetThreshold(255); volumeCalculator->ComputeVolume(); volume = volumeCalculator->GetVolume(); MITK_TEST_CONDITION_REQUIRED( volume == 1272.50 , "03 Test Volume Result. Expected 1272.50 actual value " << volume); nodeReader->SetFileName(filename3D); nodeReader->Update(); node = nodeReader->GetOutput(); image = dynamic_cast(node->GetData()); volumeCalculator->SetImage(image); volumeCalculator->SetThreshold(-1023); volumeCalculator->ComputeVolume(); std::vector volumes = volumeCalculator->GetVolumes(); - std::vector::iterator it = volumes.begin(); for (std::vector::iterator it = volumes.begin(); it != volumes.end(); it++) { MITK_TEST_CONDITION_REQUIRED( (*it) == 24.576f , "04 Test Volume Result."); } MITK_TEST_END() } diff --git a/Core/Code/files.cmake b/Core/Code/files.cmake index 5ca0ce8172..5ac0ab1c8c 100644 --- a/Core/Code/files.cmake +++ b/Core/Code/files.cmake @@ -1,355 +1,363 @@ set(H_FILES Algorithms/itkImportMitkImageContainer.h Algorithms/itkImportMitkImageContainer.txx Algorithms/itkLocalVariationImageFilter.h Algorithms/itkLocalVariationImageFilter.txx Algorithms/itkMITKScalarImageToHistogramGenerator.h Algorithms/itkMITKScalarImageToHistogramGenerator.txx Algorithms/itkTotalVariationDenoisingImageFilter.h Algorithms/itkTotalVariationDenoisingImageFilter.txx Algorithms/itkTotalVariationSingleIterationImageFilter.h Algorithms/itkTotalVariationSingleIterationImageFilter.txx Algorithms/mitkBilateralFilter.h Algorithms/mitkBilateralFilter.cpp Algorithms/mitkInstantiateAccessFunctions.h Algorithms/mitkPixelTypeList.h # Preprocessor macros taken from Boost Algorithms/mitkPPArithmeticDec.h Algorithms/mitkPPArgCount.h Algorithms/mitkPPCat.h Algorithms/mitkPPConfig.h Algorithms/mitkPPControlExprIIf.h Algorithms/mitkPPControlIf.h Algorithms/mitkPPControlIIf.h Algorithms/mitkPPDebugError.h Algorithms/mitkPPDetailAutoRec.h Algorithms/mitkPPDetailDMCAutoRec.h Algorithms/mitkPPExpand.h Algorithms/mitkPPFacilitiesEmpty.h Algorithms/mitkPPFacilitiesExpand.h Algorithms/mitkPPLogicalBool.h Algorithms/mitkPPRepetitionDetailDMCFor.h Algorithms/mitkPPRepetitionDetailEDGFor.h Algorithms/mitkPPRepetitionDetailFor.h Algorithms/mitkPPRepetitionDetailMSVCFor.h Algorithms/mitkPPRepetitionFor.h Algorithms/mitkPPSeqElem.h Algorithms/mitkPPSeqForEach.h Algorithms/mitkPPSeqForEachProduct.h Algorithms/mitkPPSeq.h Algorithms/mitkPPSeqEnum.h Algorithms/mitkPPSeqSize.h Algorithms/mitkPPSeqToTuple.h Algorithms/mitkPPStringize.h Algorithms/mitkPPTupleEat.h Algorithms/mitkPPTupleElem.h Algorithms/mitkPPTupleRem.h Algorithms/mitkClippedSurfaceBoundsCalculator.h Algorithms/mitkExtractSliceFilter.h Algorithms/mitkConvert2Dto3DImageFilter.h Algorithms/mitkPlaneClipping.h Common/mitkExceptionMacro.h Common/mitkServiceBaseObject.h Common/mitkTestingMacros.h DataManagement/mitkImageAccessByItk.h DataManagement/mitkImageCast.h DataManagement/mitkImagePixelAccessor.h DataManagement/mitkImagePixelReadAccessor.h DataManagement/mitkImagePixelWriteAccessor.h DataManagement/mitkImageReadAccessor.h DataManagement/mitkImageWriteAccessor.h DataManagement/mitkITKImageImport.h DataManagement/mitkITKImageImport.txx DataManagement/mitkImageToItk.h DataManagement/mitkImageToItk.txx Interactions/mitkEventMapperAddOn.h Interfaces/mitkIDataNodeReader.h IO/mitkPixelTypeTraits.h ) set(CPP_FILES Algorithms/mitkBaseDataSource.cpp Algorithms/mitkBaseProcess.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkGeometry2DDataToSurfaceFilter.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Algorithms/mitkExtractSliceFilter.cpp Algorithms/mitkConvert2Dto3DImageFilter.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkCoreActivator.cpp Controllers/mitkFocusManager.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkSlicesRotator.cpp Controllers/mitkSlicesSwiveller.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkInteractorCameraController.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkChannelDescriptor.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataStorage.cpp #DataManagement/mitkDataTree.cpp DataManagement/mitkDataNode.cpp DataManagement/mitkDataNodeFactory.cpp #DataManagement/mitkDataTreeStorage.cpp DataManagement/mitkDisplayGeometry.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkGeometry2D.cpp DataManagement/mitkGeometry2DData.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageAccessorBase.cpp DataManagement/mitkImageCaster.cpp DataManagement/mitkImageCastPart1.cpp DataManagement/mitkImageCastPart2.cpp DataManagement/mitkImageCastPart3.cpp DataManagement/mitkImageCastPart4.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkImageDescriptor.cpp DataManagement/mitkImageVtkAccessor.cpp DataManagement/mitkImageStatisticsHolder.cpp DataManagement/mitkLandmarkBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModeOperation.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStateTransitionOperation.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeSlicedGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionProperty.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkVector.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp + DataManagement/mitkRenderingModeProperty.cpp DataManagement/mitkShaderProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkMaterial.cpp Interactions/mitkAction.cpp Interactions/mitkAffineInteractor.cpp Interactions/mitkBindDispatcherInteractor.cpp Interactions/mitkCoordinateSupplier.cpp Interactions/mitkDataInteractor.cpp Interactions/mitkDispatcher.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkDisplayPositionEvent.cpp # Interactions/mitkDisplayVectorInteractorLevelWindow.cpp # legacy, prob even now unneeded # Interactions/mitkDisplayVectorInteractorScroll.cpp Interactions/mitkEvent.cpp Interactions/mitkEventConfig.cpp Interactions/mitkEventDescription.cpp Interactions/mitkEventFactory.cpp Interactions/mitkInteractionEventHandler.cpp Interactions/mitkEventMapper.cpp Interactions/mitkEventStateMachine.cpp Interactions/mitkGlobalInteraction.cpp Interactions/mitkInteractor.cpp Interactions/mitkInternalEvent.cpp Interactions/mitkInteractionEvent.cpp Interactions/mitkInteractionPositionEvent.cpp Interactions/mitkInteractionKeyEvent.cpp Interactions/mitkMousePressEvent.cpp Interactions/mitkMouseMoveEvent.cpp Interactions/mitkMouseReleaseEvent.cpp Interactions/mitkMouseWheelEvent.cpp Interactions/mitkMouseModeSwitcher.cpp Interactions/mitkMouseMovePointSetInteractor.cpp Interactions/mitkMoveBaseDataInteractor.cpp Interactions/mitkNodeDepententPointSetInteractor.cpp Interactions/mitkPointSetDataInteractor.cpp Interactions/mitkPointSetInteractor.cpp Interactions/mitkPositionEvent.cpp Interactions/mitkPositionTracker.cpp Interactions/mitkStateMachineAction.cpp Interactions/mitkStateMachineState.cpp Interactions/mitkStateMachineTransition.cpp Interactions/mitkState.cpp Interactions/mitkStateMachineContainer.cpp Interactions/mitkStateEvent.cpp Interactions/mitkStateMachine.cpp Interactions/mitkStateMachineFactory.cpp Interactions/mitkTransition.cpp Interactions/mitkWheelEvent.cpp Interactions/mitkKeyEvent.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkVtkInteractorStyle.cxx Interactions/mitkCrosshairPositionEvent.cpp Interfaces/mitkInteractionEventObserver.cpp + Interfaces/mitkIShaderRepository.cpp IO/mitkBaseDataIOFactory.cpp IO/mitkCoreDataNodeReader.cpp IO/mitkDicomSeriesReader.cpp IO/mitkFileReader.cpp IO/mitkFileSeriesReader.cpp IO/mitkFileWriter.cpp #IO/mitkIpPicGet.c IO/mitkImageGenerator.cpp IO/mitkImageWriter.cpp IO/mitkImageWriterFactory.cpp IO/mitkItkImageFileIOFactory.cpp IO/mitkItkImageFileReader.cpp IO/mitkItkLoggingAdapter.cpp IO/mitkItkPictureWrite.cpp IO/mitkIOUtil.cpp IO/mitkLookupTableProperty.cpp IO/mitkOperation.cpp #IO/mitkPicFileIOFactory.cpp #IO/mitkPicFileReader.cpp #IO/mitkPicFileWriter.cpp #IO/mitkPicHelper.cpp #IO/mitkPicVolumeTimeSeriesIOFactory.cpp #IO/mitkPicVolumeTimeSeriesReader.cpp IO/mitkPixelType.cpp IO/mitkPointSetIOFactory.cpp IO/mitkPointSetReader.cpp IO/mitkPointSetWriter.cpp IO/mitkPointSetWriterFactory.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSTLFileIOFactory.cpp IO/mitkSTLFileReader.cpp IO/mitkSurfaceVtkWriter.cpp IO/mitkSurfaceVtkWriterFactory.cpp IO/mitkVtkLoggingAdapter.cpp IO/mitkVtiFileIOFactory.cpp IO/mitkVtiFileReader.cpp IO/mitkVtkImageIOFactory.cpp IO/mitkVtkImageReader.cpp IO/mitkVtkSurfaceIOFactory.cpp IO/mitkVtkSurfaceReader.cpp IO/vtkPointSetXMLParser.cpp IO/mitkLog.cpp Rendering/mitkBaseRenderer.cpp Rendering/mitkVtkMapper.cpp Rendering/mitkRenderWindowFrame.cpp Rendering/mitkGeometry2DDataMapper2D.cpp Rendering/mitkGeometry2DDataVtkMapper3D.cpp Rendering/mitkGLMapper.cpp Rendering/mitkGradientBackground.cpp Rendering/mitkManufacturerLogo.cpp Rendering/mitkMapper.cpp Rendering/mitkPointSetGLMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkPolyDataGLMapper2D.cpp Rendering/mitkSurfaceGLMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVolumeDataVtkMapper3D.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkShaderRepository.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/vtkMitkThickSlicesFilter.cpp Rendering/vtkMitkLevelWindowFilter.cpp Rendering/vtkNeverTranslucentTexture.cpp Rendering/mitkRenderingTestHelper.cpp Common/mitkException.cpp Common/mitkCommon.h Common/mitkCoreObjectFactoryBase.cpp Common/mitkCoreObjectFactory.cpp + Common/mitkCoreServices.cpp ) list(APPEND CPP_FILES ${CppMicroServices_SOURCES}) set(RESOURCE_FILES Interactions/globalConfig.xml Interactions/DisplayInteraction.xml Interactions/DisplayConfig.xml Interactions/DisplayConfigPACS.xml Interactions/DisplayConfigPACSPan.xml Interactions/DisplayConfigPACSScroll.xml Interactions/DisplayConfigPACSZoom.xml Interactions/DisplayConfigPACSLevelWindow.xml Interactions/DisplayConfigMITK.xml Interactions/PointSet.xml Interactions/Legacy/StateMachine.xml +Interactions/Legacy/DisplayConfigMITKTools.xml Interactions/PointSetConfig.xml Interactions/Tests/AddAndRemovePoints.xml Interactions/Tests/globalConfig.xml Interactions/Tests/StatemachineTest.xml Interactions/Tests/StatemachineConfigTest.xml + +Shaders/mitkShaderLighting.xml + +mitkLevelWindowPresets.xml ) diff --git a/Core/Documentation/Doxygen/Concepts/QVTKRendering.dox b/Core/Documentation/Doxygen/Concepts/QVTKRendering.dox index ea919df38c..fd50b5c7e7 100644 --- a/Core/Documentation/Doxygen/Concepts/QVTKRendering.dox +++ b/Core/Documentation/Doxygen/Concepts/QVTKRendering.dox @@ -1,83 +1,100 @@ /** \page QVTKRendering Rendering Concept The MITK rendering pipeline is derived from the VTK rendering pipeline. \section QVTKRendering_Pipeline_VTK VTK Rendering Pipeline \image html RenderingOverviewVTK.png "Rendering in VTK" -In VTK, the vtkRenderWindow coordinates the rendering process. Several vtkRenderers may be associated to one vtkRenderWindow. +In VTK, the vtkRenderWindow coordinates the rendering process. Several vtkRenderers may be associated to one vtkRenderWindow. All visible objects, which can exist in a rendered scene (2D and 3D scene), inherit from vtkProp (or any subclass e.g. vtkActor). A vtkPropAssembly is an assembly of several vtkProps, which appears like one single vtkProp. MITK uses a new interface class, the "vtkMitkRenderProp", which is inherited from vtkProp. Similar to a vtkPropAssembly, all MITK rendering stuff is performed via this interface class. Thus, the MITK rendering process is completely integrated into the VTK rendering pipeline. From VTK point of view, MITK renders like a custom vtkProp object. More information about the VTK rendering pipeline can be found at http://www.vtk.org and in the several VTK books. \section QVTKRendering_Pipeline_MITK MITK Rendering Pipeline This process is tightly connected to VTK, which makes it straight forward and simple. We use the above mentioned "vtkMitkRenderProp" in conjunction with the mitk::VtkPropRenderer for integration into the VTK pipeline. The QmitkRenderWindow does not inherit from mitk::RenderWindow, but from the QVTKWidget, which is provided by VTK. The main classes of the MITK rendering process can be illustrated like this: \image html qVtkRenderingClassOverview.png "Rendering in MITK" A render request to the vtkRenderWindow does not only update the VTK pipeline, but also the MITK pipeline. However, the mitk::RenderingManager still coordinates the rendering update behavior. -Update requests should be sent to the RenderingManager, which then, if needed, will request an update of the overall vtkRenderWindow. The vtkRenderWindow then starts to call the Render() function of all vtkRenderers, which are associated to the vtkRenderWindow. Currently, MITK uses specific vtkRenderers (outside the standard MITK rendering pipeline) for purposes, like displaying a gradient background (mitk::GradientBackground), displaying video sources (QmitkVideoBackround and mitk::VideoSource), or displaying a (department) logo (mitk::ManufacturerLogo), etc.. +Update requests should be sent to the RenderingManager, which then, if needed, will request an update of the overall vtkRenderWindow. The vtkRenderWindow then starts to call the Render() function of all vtkRenderers, which are associated to the vtkRenderWindow. Currently, MITK uses specific vtkRenderers (outside the standard MITK rendering pipeline) for purposes, like displaying a gradient background (mitk::GradientBackground), displaying video sources (QmitkVideoBackround and mitk::VideoSource), or displaying a (department) logo (mitk::ManufacturerLogo), etc.. Despite these specific renderers, a kind of "SceneRenderer" is member of each QmitkRenderWindow. This vtkRenderer is associated with the custom vtkMitkRenderProp and is responsible for the MITK rendering. -A sequence diagram, which illustrates the actions after calling the Render() function of the MITK-Scene vtkRenderer is shown below: +The vtkRenderer calls four different functions in vtkMitkRenderProp, namely RenderOpaqueGeometry(), RenderTranslucentPolygonalGeometry(), RenderVolumetricGeometry() and RenderOverlay(). These function calls are forwarded to the mitk::VtkPropRenderer. +Then, depending on the mapper type (OpenGL- or VTK-based), OpenGL is enabled or disabled. In the case of OpenGL rendering, the Paint()-method of each individual mapper is called. If the mapper is VTK-based, the four function calls are forwarded to mitk::VtkMapper and within these methods the corresponding VtkProp is evaluated. +Both strategies are illustrated in the sequence diagrams below: -\image html qVtkRenderingSequence.png "Sequence overview MITK scene rendering" +\image html qVtkRenderingSequenceVTK.png "Sequence diagram for MITK VTK rendering" + +In MITK, VTK-based mapper are more common and we recommend on implementing VTK-based mappers. However, MITK supports OpenGL-based mappers as well. + +\image html qVtkRenderingSequenceGL.png "Sequence diagram for MITK OpenGL rendering" + + +\section QVTKRendering_Mapper MITK Mapper Architecture + +Mappers are used to transform the input data in tangible primitives, such as surfaces, points, lines, etc. The base class of all mappers is mitk::Mapper. The mapper hierarchy reflects the two possible ways to render in MITK: Subclasses of mitk::Mapper control the creation of rendering primitives +that interface to the graphics library (e.g. via OpenGL, vtk). The mapper architecture is illustrated in the following UML diagram: + +\image html qVtkRenderingMapper.jpg "Mapper architecture" + +mitk::Mapper::Update() calls the time step of the input data for the specified renderer and checks whether the time step is valid and calls method mitk::Mapper::GenerateDataForRenderer(), which is reimplemented in the individual mappers and should be used to generate primitives. +mitk::Mapper::SetDefaultProperties() should be used to define mapper-specific properties. \section QVTKRendering_programmerGuide User Guide: Programming hints for rendering related stuff (in plugins) \li The QmitkRenderWindow can be accessed like this: this->GetRenderWindowPart()->GetRenderWindow("axial"); \li The vtkRenderWindow can be accessed like this: this->GetRenderWindowPart()->GetRenderWindow("axial")->GetVtkRenderWindow(); \li The mitkBaseRenderer can be accessed like this: mitk::BaseRenderer* renderer = mitk::BaseRenderer::GetInstance(this->GetRenderWindowPart()->GetRenderWindow("sagittal")->GetRenderWindow()); \li An update request of the overall QmitkStdMultiWidget can be performed with: this->GetRenderWindowPart()->GetRenderingManager()->RequestUpdateAll(); \li A single QmitkRenderWindow update request can be done like this: this->GetRenderWindowPart()->GetRenderingManager()->RequestUpdate(this->GetRenderWindowPart()->GetRenderWindow("axial")->GetVtkRenderWindow()); \note The usage of ForceImmediateUpdateAll() is not desired in most common use-cases. \subsection QVTKRendering_distinctRenderWindow Setting up a distinct Rendering-Pipeline It is sometimes desired to have one (or more) QmitkRenderWindows that are managed totally independent of the 'usual' renderwindows defined by the QmitkStdMultiWidget. This may include the data that is rendered as well as possible interactions. In order to achieve this, a set of objects is needed: \li mitk::RenderingManager -> Manages the rendering \li mitk::DataStorage -> Manages the data that is rendered \li mitk::GlobalInteraction -> Manages all interaction \li QmitkRenderWindow -> Actually visualizes the data The actual setup, respectively the connection, of these classes is rather simple: \code // create a new instance of mitk::RenderingManager mitk::RenderingManager::Pointer renderingManager = mitk::RenderingManager::New(); // create new instances of DataStorage and GlobalInteraction mitk::DataStorage::Pointer dataStorage = mitk::DataStorage::New(); mitk::GlobalInteraction::Pointer globalInteraction = mitk::GlobalInteraction::New(); // add both to the RenderingManager renderingManager->SetDataStorage( dataStorage ); renderingManager->SetGlobalInteraction( globalInteraction ); // now create a new QmitkRenderWindow with this renderingManager as parameter QmitkRenderWindow* renderWindow = new QmitkRenderWindow( parent, "name", renderer, renderingManager ); \endcode That is basically all you need to setup your own rendering pipeline. Obviously you have to add all data you want to render to your new DataStorage. If you want to interact with this renderwindow, you will also have to add additional Interactors/Listeners. \note Dynamic casts of a mitk::BaseRenderer class to an OpenGLRenderer (or now, to an VtkPropRenderer) should be avoided. The "MITK Scene" vtkRenderer and the vtkRenderWindow as well, are therefore now included in the mitk::BaseRenderer. */ diff --git a/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingMapper.jpg b/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingMapper.jpg new file mode 100644 index 0000000000..9be3f8f4dc Binary files /dev/null and b/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingMapper.jpg differ diff --git a/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingSequenceGL.png b/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingSequenceGL.png new file mode 100644 index 0000000000..cd6f36c415 Binary files /dev/null and b/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingSequenceGL.png differ diff --git a/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingSequenceVTK.png b/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingSequenceVTK.png new file mode 100644 index 0000000000..80a5b29602 Binary files /dev/null and b/Core/Documentation/Doxygen/Concepts/images/rendering/qVtkRenderingSequenceVTK.png differ diff --git a/Documentation/Doxygen/DeveloperManual/DeveloperManualPortal.dox b/Documentation/Doxygen/DeveloperManual/DeveloperManualPortal.dox index aa9276cf30..8de6fe65b6 100644 --- a/Documentation/Doxygen/DeveloperManual/DeveloperManualPortal.dox +++ b/Documentation/Doxygen/DeveloperManual/DeveloperManualPortal.dox @@ -1,31 +1,29 @@ /** \page DeveloperManualPortal MITK: Developer Manual -Development with MITK can happen under several disctinct conditions. Depending on whether you are using the Toolkit or the entire application, different sections may apply to you. In case you are unsure about what you need, please refer to \link Architecture The Architecture of MITK text\endlink. An extensive Introduction to MITK is available under \link StartingDevelopment Starting your MITK Development\endlink. +Development with MITK can happen under several conditions. Depending on whether you are using the Toolkit or the entire application, different sections may apply to you. In case you are unsure about what you need, please refer to \link Architecture The Architecture of MITK text\endlink. An extensive Introduction to MITK is available under \link StartingDevelopment Starting your MITK Development\endlink. Depending on whether you are working with the \link DevelopmentToolkit Toolkit\endlink or the \link DevelopmentApplication Application\endlink, you can refer to their respective pages. Generated API-Documentation can be found \link DevelopmentAPI here\endlink. -\section DeveloperManualStarting Starting your MITK Development -
  • \subpage StartingDevelopment
    • \ref Architecture
    • \ref SettingUpMITK
    • \ref GettingToKnowMITK
    • \ref FirstSteps
    • \ref AboutTestingPage
  • \subpage DevelopmentToolkit
    • \ref Concepts
    • \ref MITKModuleManualsListPage
  • \subpage DevelopmentApplication
    • \ref mitkExtPointsIndex
  • \subpage DeploymentPage
*/ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/FirstSteps.dox b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/FirstSteps.dox index 72d5728de0..c447f4c886 100644 --- a/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/FirstSteps.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/FirstSteps.dox @@ -1,13 +1,13 @@ /** \page FirstSteps First steps in Development -TODO +This section will show you how to extend MITK for your own project.
  • \subpage NewPluginPage
  • \subpage NewModulePage
  • \subpage CMAKE_FAQ
  • \subpage StatemachineEditor
*/ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/GettingToKnowMITK.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/GettingToKnowMITK.dox index e418a0b301..898696a69a 100644 --- a/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/GettingToKnowMITK.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/GettingToKnowMITK.dox @@ -1,14 +1,15 @@ /** \page GettingToKnowMITK Getting to know MITK -TODO +This section will show you around MITK and acquaint you with the basic concepts. +
  • \subpage DirectoryStructurePage
  • \subpage TutorialPage
  • \subpage CMAKE_FAQ
  • \subpage StyleGuideAndNotesPage
  • \subpage DocumentationGuide
  • \subpage CodingPage
  • \subpage KnownProblemsPage
*/ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox index 785b8ad672..d1d8bf0a02 100644 --- a/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox @@ -1,203 +1,204 @@ /** \page BuildInstructionsPage Build Instructions \section BuildInstructions_Introduction Introduction The MITK build system (which is based on CMake) supports a "superbuild" process, meaning that it will download, configure, and build all required third-party libraries (except Qt) automatically. These instructions will show you how to use the MITK superbuild. \note This page explains explicitly how to build MITK itself. If you want to create your own project based on MITK, the process described below is completely automated. Please see \ref HowToNewProject. For more advanced users, the last sections explain how to inject custom build libraries into the superbuild process. \section BuildInstructions_Prerequisites Prerequisites You need: -# Git from http://git-scm.com (there are also numerous third-party graphical clients available). We recomment using Git, but see below for a way how to get the current source code without using it. -# CMake (version 2.8.4 or higher) -# Qt 4.x if you plan to develop Qt-based applications (version 4.6 or above is recommended, we cannot guarantee compatibility with lower versions) -# If you are using Mac OS X you need an Xcode installation as this provides the neccessary compilers and SDKs \attention For Mac OS X it is strongly recommended to use CMake version 2.8.8 or higher \section BuildInstructions_Qt A note about Qt Nokia provides several binary packages for Qt. You must make sure that the package you download matches your toolchain. On Linux, getting Qt by installing the packages provided by your Linux package manager is the preferred way. On Windows, the Nokia provided binaries are compiled for 32bit architectures. You cannot build your own project for a 64bit machine and use the 32bit Qt libraries. You have two options for a 64bit Qt-based application: -# Download an inofficial 64bit installer, for example here. Note that we cannot offer support for problems with MITK due to the usage of this kind of installers. -# Compile Qt yourself. This is shortly described below. To compile Qt on Windows using Visual Studio, follow the steps below: -# Download the Qt sources and unpack them, e.g. to C:/qt-everywhere-opensource-src-4.7.4 -# Open a Visual Studio command prompt. Make sure to use the appropriate command prompt for either a 32 bit or 64 bit build. Note that Visual Studio Express does not come with 64bit compilers out of the box (the Professional version does). -# Configure Qt by executing the configure.exe command in your Qt source directory. The following configure options will build a Qt compatible with MITK: \verbatim configure.exe -prefix C:\Qt\4.7.4_vc9_x64 -debug-and-release -qt-sql-sqlite -no-multimedia -no-audio-backend -no-phonon -no-phonon-backend -no-declarative -mp -nomake examples -nomake demos -nomake docs \endverbatim -# Build and install the Qt libraries \verbatim nmake nmake install \endverbatim After "nmake install" completed successfully, you may delete your Qt source directory. \section BuildInstructions_Get_Source Get a source tree -Since MITK is under active development we recommend to use git to get -the most recent version. To make sure you get a stable tree, check the +Since MITK is under active development we recommend to use git to check out +the latest stable release from the homepage. If you decide to use the most current nightly +release, make sure to get a stable tree: Check the MITK dashboard before checking out. If the build tree is not clean, you can specify an older revision for the checkout or get a stable tar ball from www.mitk.org. If you don't want to use Git, you may also download the current source code (or any other older version) as a tar.gz package by clicking on the snapshot link. You can then skip the clone step below. To clone MITK's current git repository do: \code git clone http://git.mitk.org/MITK.git \endcode \section BuildInstructions_Build_With_CMake Build MITK with CMake Create a new directory for the superbuild binary tree, change to it and call CMake: In the shell (assuming you current directory is the same as the one where you issued the git clone command): \code mkdir MITK-superbuild cd MITK-superbuild ccmake ../MITK \endcode If you use Windows, then you just start the CMake GUI and enter the location of the source and of the binary tree, choose a suitable generator and configure the project. If you use Mac OS X you will have to tweak the CMake configuration: - First of all you have to check the selected compilers, i.e.: - CMAKE_CXX_COMPILER - CMAKE_C_COMPILER - both should be either apple's clang or apple's gcc compiler - Next you have to assure hat CMAKE_OSX_SYSROOT points to the correct SDK location: - This is either /Developer/SDKs/Developer/SDKs/MacOSX10.7.sdk or if you have installed Xcode 4.3+ it is located in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/ - Finally you should set the cmake variable MITK_USE_VTK_5_8_IN_SUPERBUILD to ON CMake will present you a couple of options, these are the most important ones: - MITK_USE_BLUEBERRY Build the BlueBerry application framework - MITK_USE_Boost Build MITK code which depends on Boost (this will download Boost 1.45.0) - MITK_USE_Boost_LIBRARIES If you need binary Boost libraries, specify them here. - MITK_USE_OpenCV Build MITK code which depends on OpenCV (this will download and build OpenCV 2.3) - MITK_USE_Python Enables Python wrapping in MITK. This will also configure ITK, VTK, and OpenCV (if enabled) to build Python wrappers. - MITK_USE_QT Build MITK code which depends on Qt - MITK_USE_SOFA Build MITK code which depends on SOFA (this will download and build SOFA 1.0 RC1) - QT_QMAKE_EXECUTABLE The path to the qmake executable of your Qt installation If you are satisfied with the configuration of your MITK superbuild, generate the project files with CMake by pressing "Generate". Linux and Mac OS X users usually just enter "make" (optionally supplying the number threads to be used for a parallel build): \code make -j4 \endcode \note On Mac OS X: If you follow these steps CMake will produce Makefiles and therefore you cannot use Xcode but you have to use e.g. the QtCreator for programming. At the moment developing MITK with Xcode is not supported and using Xcode the superbuild doesn't complete without errors. Windows users using Visual Studio can open the generated MITK-superbuild.sln solution file in the MITK-superbuild directory and start the build by building the BUILD_ALL project. \section BuildInstructions_Customize Customize your MITK superbuild The MITK superbuild configured MITK with all needed external libraries. The build directories of these libraries, and of MITK itself are located inside the MITK-superbuild directory. For example, the directory layout may look like: \code MITK-superbuild |- ITK-build |- VTK-build |- MITK-build \endcode To change the configuration of the MITK build, choose the MITK-build directory as the binary directory in the CMake GUI. After generating the project files, build the MITK project by either issuing "make" in the MITK-build directory (Linux), or by opening MITK-build/MITK.sln and building the project with Visual Studio. You may also change the configuration of any project configured via the superbuild process. Make sure to also build the changed project and also the projects which depend on it. \section BuildInstructions_Running Running Applications On Linux, just execute the application you want to run. MITK executables are located in MITK-superbuild/MITK-build/bin On Windows, the PATH environment variable must contain the directories containging third-party libraries. The MITK build system generated Windows Batch files in the MITK-build directory which set up a correct environment and opens the appropriate Visual Studio solution file. Use (and maybe modify/enhance) these Batch files to be able to start and debug MITK applications from inside Visual Studio. \section BuildInstructions_Documentation Documentation If you have the Doxygen documentation tool installed, you get a new project (Visual Studio) or "make" target named "doc". You can build this to generate the HTML documentation of MITK in the Documentation/Doxygen directory of your MITK-build binary tree or in the MITK_DOXYGEN_OUTPUT_DIR CMake variable (if specified). \section BuildInstructions_Extending Extend MITK on your own (using the application framework BlueBerry) Please see \ref NewPluginPage \section BuildInstructions_As_Toolkit Use MITK in your own project (as a toolkit) To use MITK in your external project, add the CMake command find_package(MITK REQUIRED) to your CMakeLists.txt and make use of the CMake macros MITK_CHECK_MODULE(result_var ) and MITK_USE_MODULE() provided by MITK. Here is an example CMakeLists.txt (from the Examples/QtAppExample/ directory) which allows you to create a Qt based application using MITK to display an image. \include QtAppExample/CMakeLists.txt \section BuildInstructions_Advanced_Customization Superbuild Customization You can inject pre-build third-party libraries into the MITK superbuild by setting certain CMake variables before the first configure step. MITK will then use these third-party libraries instead of downloading and building them itself. Note you must take care to configure those libraries with all options MITK requires. The variables listed below are provided for injecting third-party libraries. Their occurrence in the CMake GUI or in ccmake may depend on specific MITK_USE_* options set to ON. You may also use the variable names below without the EXTERNAL_ prefix, for example when providing their values on a command line call to CMake. - EXTERNAL_BOOST_ROOT Set this variable to your custom Boost installation - EXTERNAL_CTK_DIR Set this variable to your CTK binary tree (the directory containing the CTKConfig.cmake file) - EXTERNAL_CableSwig_DIR Set this variable to your CableSwig binary tree for Python wrapping (the directory containing the CableSwigConfig.cmake file) - EXTERNAL_DCMTK_DIR Set this variable to your DCMTK binary tree (the directory containing the DCMTKConfig.cmake file) - EXTERNAL_GDCM_DIR Set this variable to your GDCM binary tree (the directory containing the GDCMConfig.cmake file) - EXTERNAL_ITK_DIR Set this variable to your ITK binary tree (the directory containing the ITKConfig.cmake file) - EXTERNAL_OpenCV_DIR Set this variable to your OpenCV binary tree (the directory containing the OpenCVConfig.cmake file) - EXTERNAL_SOFA_DIR Set this variable to your SOFA binary tree (the directory containing the SOFAConfig.cmake file) - EXTERNAL_VTK_DIR Set this variable to your VTK binary tree (the directory containing the VTKConfig.cmake file) To set CMake options before the first configure step is invoked, supply them on the command line, i.e. \code ccmake -DITK_DIR:PATH=/opt/ITK-release ../MITK \endcode See the following link for more information about how to configure third-party libraries: \subpage BuildToolkits "How to build ITK, VTK and QT" */ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SettingUpMITK.dox b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SettingUpMITK.dox index 5b67763c66..8bfd90a9a2 100644 --- a/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SettingUpMITK.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SettingUpMITK.dox @@ -1,14 +1,14 @@ /** \page SettingUpMITK Setting Up Mitk -TODO +This section will get you started with your MITK Development environment.
  • \subpage SupportedPlatformsPage
  • \subpage BuildInstructionsPage
  • \subpage thirdpartylibs
  • \subpage HowToNewProject
  • \subpage Testing
*/ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/Starting.dox b/Documentation/Doxygen/DeveloperManual/Starting/Starting.dox index fa78a1bb8d..e0a56cddbb 100644 --- a/Documentation/Doxygen/DeveloperManual/Starting/Starting.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/Starting.dox @@ -1,37 +1,44 @@ /** \page StartingDevelopment Starting your MITK Development -This Introduction will acquaint you with the most important workflows to get you started with your MITK Development. +This Introduction will acquaint you with the most important work flows to get you started with your MITK Development. +First, \ref Architecture will explain the difference between the application and the toolkit. +\ref SettingUpMITK will get you started with a working MITK Development environment. \GettingToKnowMITK will walk you trough the folder structure and the module and plugin system. This chapter also contains an extensive tutorial on how to work with MITK. +The \ref FirstSteps section will then show you how to extend MITK for your own project. + + +
  • \subpage Architecture
  • \subpage SettingUpMITK
    • \ref SupportedPlatformsPage
    • \ref BuildInstructionsPage
    • \ref thirdpartylibs
    • -
    • \ref HowToNewProject
    • +
    • \ref HowToNewProject
  • \subpage GettingToKnowMITK
    • \ref DirectoryStructurePage
    • \ref TutorialPage
    • \ref CMAKE_FAQ
    • \ref StyleGuideAndNotesPage
    • \ref DocumentationGuide
    • \ref CodingPage
    • \ref KnownProblemsPage
  • \subpage FirstSteps
    • \ref NewPluginPage
    • \ref NewModulePage
    • +
    • \ref CMAKE_FAQ
    • \ref StatemachineEditor
  • \subpage AboutTestingPage
*/ diff --git a/Documentation/Doxygen/DeveloperManual/Toolkit/DevelopmentToolkit.dox b/Documentation/Doxygen/DeveloperManual/Toolkit/DevelopmentToolkit.dox index ae77b729ea..19ed8049b3 100644 --- a/Documentation/Doxygen/DeveloperManual/Toolkit/DevelopmentToolkit.dox +++ b/Documentation/Doxygen/DeveloperManual/Toolkit/DevelopmentToolkit.dox @@ -1,13 +1,15 @@ /** \page DevelopmentToolkit Developing with the MITK Toolkit -Todo +Two major sections are available for your reference. \ref Concepts will explain several core concepts of MITK on a more abstract level. +We advise to read this section and to understand the available concepts, as this will prevent you from reimplementing functionality. +\ref MITKModuleManualsListPage shows a list of the available module manuals for in depth advice on how to use each module.
  • \subpage Concepts
  • \subpage MITKModuleManualsListPage
*/ diff --git a/Documentation/Doxygen/DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox b/Documentation/Doxygen/DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox index 6dfede77e3..f2a4ff42fb 100644 --- a/Documentation/Doxygen/DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox @@ -1,21 +1,22 @@ /** \page MITKModuleManualsListPage MITK Module Manuals \section MITKModuleManualsListPageOverview Overview The modules are shared libraries that provide functionality that can be used by developers. \section MITKModuleManualsListPageModuleManualList List of Module Manuals \li \subpage IGTGeneralModulePage \li \subpage MitkOpenCL_Overview \li \subpage SimulationManualPage \li \subpage GeneratingDeviceModulesPage + \li \subpage mitkPython_Overview \section MITKModuleManualsListPageAdditionalInformation Additional Information on Certain Modules \li \ref PlanarPropertiesPage \li \subpage DiffusionImagingPropertiesPage \li \subpage ConnectomicsRenderingPropertiesPage */ diff --git a/Documentation/Doxygen/Overview/Overview.dox b/Documentation/Doxygen/Overview/Overview.dox index 565f32e6f2..5427954822 100644 --- a/Documentation/Doxygen/Overview/Overview.dox +++ b/Documentation/Doxygen/Overview/Overview.dox @@ -1,29 +1,31 @@ /** \page Overview MITK: An Overview -The Medical Imaging Interaction Toolkit (MITK) can be used in several different ways. If you are a new user to MITK the first question is in what manner you intend to use it. The following options are simplified and condensed versions of the most common usage scenarios. +The Medical Imaging Interaction Toolkit (MITK) is a powerful application and can also be used as either a framework or a toolkiit for Software development. The following options are the most common usage scenarios. -\tableofcontents -\section ShortIntroductionToMITKAsToolkit I want to develop my own software framework, but use some of MITK's data structures and algorithms + + + + I want to use MITK as an application + +You will use the MITK Workbench as an end user and will find user manuals in \ref UserManualPortal and \ref PluginListPage. + + I want to develop my own software framework, and use some of MITK's data structures and algorithms You will use MITK as a toolkit and probably benefit most from the \ref BuildInstructionsPage and MITK API Documentation. -\section ShortIntroductionToMITKAsFramework I want to use the MITK and BlueBerry software framework to develop my own software +I want to use the MITK and BlueBerry software framework to develop my own software Here you have again two options. -\subsection ShortIntroductionToMITKAsFrameworkExtendingWorkbench I want use the MITK Workbench and extend its capabilities +I want use the MITK Workbench and extend its capabilities You are using MITK as software framework and writing your own modules and plugins for MITK. You want to read the \ref BuildInstructionsPage and further on \ref Development. Also you might want to take a look at our \ref CMAKE_FAQ. -\subsection ShortIntroductionToMITKAsFrameworkExternalProject I want to create my own application based on MITK but with major customizations and changes +I want to create my own application based on MITK This is probably the most common way to use MITK. You are using MITK as software framework and building your own project and application using MITK. You want to read \ref HowToNewProject and the general information in \ref Development. Also you might want to take a look at our \ref CMAKE_FAQ. -\section ShortIntroductionToMITKAsFrameworkEndUser I want to use the MITK Workbench to do image processing - -You are using MITK and the MITK Workbench as an end user and will find user manuals in \ref MITKUserManualPage and \ref PluginListPage. - */ \ No newline at end of file diff --git a/Documentation/Doxygen/UserManual/Applications.dox b/Documentation/Doxygen/UserManual/Applications.dox index 7620fc8046..68ee016c23 100644 --- a/Documentation/Doxygen/UserManual/Applications.dox +++ b/Documentation/Doxygen/UserManual/Applications.dox @@ -1,30 +1,27 @@ /** \page ApplicationsPage Using MITK and Applications -Available sections: - - \ref ApplicationsPageUsingMITK - - \ref ApplicationsPageApplications - - \ref ApplicationsPageApplicationsList +\tableofcontents \section ApplicationsPageUsingMITK Using MITK Many of the applications created with the use of MITK share common basic functionalities. Due to this, there is one manual which explains the basic usage of MITK. For more information on the use of the advanced features of an application please take a look the \ref ApplicationsPageApplicationsList , whereas if you are interested in a certain view further information can be found in \ref PluginListPage . The basic usage information on MITK can be found in \ref MITKUserManualPage . \section ApplicationsPageApplications What are Applications? Applications are executables, which contain a certain configuration of views and perspectives. Usually they are aimed at a selective audience or solving a particular problem. As such they focus on certain capabilities of MITK, while ignoring others. The main reason for this is to supply the users of the application with the power of MITK for solving their tasks, without daunting them with an overwhelming number of menus and options. At the same time, this allows, together with the use of perspectives, the creation of sleek and elegant workflows, which are easily comprehensible. A typical example of this would be an application which contains only views related to the analysis of the human brain (particular question) or one which contains only what is necessary for displaying medical data in the classroom (specific audience). \section ApplicationsPageApplicationsList List of Applications If you are interested in using a specific application, currently developed by the MITK team you might want to take a look first at the \ref MITKUserManualPage . Further information on any application can be found here:
  • \subpage org_mitkworkbench
  • \subpage org_dti_atlas_application
  • \subpage org_mitk_gui_qt_diffusionimagingapp
*/ \ No newline at end of file diff --git a/Documentation/Doxygen/UserManual/MITKPluginManualsList.dox b/Documentation/Doxygen/UserManual/MITKPluginManualsList.dox index ca31f1bb1b..e39be9efb1 100644 --- a/Documentation/Doxygen/UserManual/MITKPluginManualsList.dox +++ b/Documentation/Doxygen/UserManual/MITKPluginManualsList.dox @@ -1,42 +1,42 @@ /** \page PluginListPage MITK Plugin Manuals \section PluginListPageOverview Overview The plugins and bundles provide much of the extended functionality of MITK. Each encapsulates a solution to a problem and associated features. This way one can easily assemble the necessary capabilites for a workflow without adding a lot of bloat, by combining plugins as needed. The distinction between developer and end user use is for convenience only and mainly distinguishes which group a plugin is primarily aimed at. \section PluginListPageEndUserPluginList List of Plugins for End User Use \li \subpage org_blueberry_ui_qt_log \li \subpage org_mitk_views_basicimageprocessing \li \subpage org_mitk_views_cmdlinemodules \li \subpage org_mitk_views_datamanager \li \subpage org_mitk_gui_qt_diffusionimaging \li \subpage org_mitk_views_imagecropper \li \subpage org_mitk_views_imagenavigator \li \subpage org_mitk_gui_qt_measurementtoolbox \li \subpage org_mitk_views_moviemaker \li \subpage org_mitk_views_meshdecimation \li \subpage org_mitk_views_pointsetinteraction \li \subpage org_mitk_gui_qt_registration \li \subpage org_mitk_views_segmentation \li \subpage org_mitk_views_volumevisualization \li \subpage org_mitk_gui_qt_dicom \li \subpage org_mitk_gui_qt_ultrasound - \li \subpage org_mitk_views_fiberfoxview + \li \subpage org_mitk_gui_qt_python \section PluginListPageDevPluginList List of Plugins for Developer Use and Examples \li \subpage org_surfacematerialeditor \li \subpage org_toftutorial \li \subpage org_mitk_gui_qt_examples \li \subpage org_mitkexamplesopencv \li \ref org_mitk_gui_qt_igtexample \li \ref org_mitk_gui_qt_igttracking \li \subpage org_blueberry_ui_qt_objectinspector \li \subpage org_mitk_gui_InteractionTests */ diff --git a/Documentation/Doxygen/UserManual/UserManualPortal.dox b/Documentation/Doxygen/UserManual/UserManualPortal.dox index bca8c867fe..5892a8147d 100644 --- a/Documentation/Doxygen/UserManual/UserManualPortal.dox +++ b/Documentation/Doxygen/UserManual/UserManualPortal.dox @@ -1,14 +1,15 @@ /** \page UserManualPortal MITK: User Manual -Due to the modular architecture of MITK the user documentation is split in different parts. You can find a short description of the intended purpose and audience of MITK based applications developed by us at \ref ApplicationsPage. To get an introduction into the usage of any MITK based application please read \ref MITKUserManualPage. It will give you an overview of most of the common questions, such as how to load or save data or navigate within it. +To get an introduction into the usage of any MITK based application please read \ref MITKUserManualPage. It will give you an overview of most of the common questions, such as how to load or save data or navigate within it. You can find a short description of the intended purpose and audience of MITK based applications developed by us at \ref ApplicationsPage. +For more specific questions regarding the usage of a certain plugin (like e.g. the segmentation view) you can refer to a list of \ref PluginListPage -For any more specific documentation of how a plugin operates you can find the plugin documentation in \ref PluginListPage. Depending on the application you are using you might have only some or all of the listed plugins available. +For more specific information on how a plugin operates you can find the plugin documentation in \ref PluginListPage. Depending on the application you are using you might have only some or all of the listed plugins available. \section UserManualPortalTopics List of topics
    -
  • \subpage ApplicationsPage
  • \subpage MITKUserManualPage
  • +
  • \subpage ApplicationsPage
  • \subpage PluginListPage
*/ \ No newline at end of file diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer.views/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.customviewer.views/CMakeLists.txt index b86f0e16ae..3169aa4945 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer.views/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.customviewer.views/CMakeLists.txt @@ -1,11 +1,12 @@ project(org_mitk_example_gui_customviewer_views) set(QT_USE_QTSQL 1) include_directories(${CTK_INCLUDE_DIRS}) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_customviewer_views_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDENCIES QmitkExt mitkDicomUI + NO_INSTALL ) diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.customviewer/CMakeLists.txt index f55eee63a3..70d489232a 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.customviewer/CMakeLists.txt @@ -1,8 +1,9 @@ project(org_mitk_example_gui_customviewer) include_directories(${CTK_INCLUDE_DIRS}) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_customviewer_EXPORT EXPORTED_INCLUDE_SUFFIXES src - ) \ No newline at end of file + NO_INSTALL + ) diff --git a/Examples/Plugins/org.mitk.example.gui.extensionpointcontribution/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.extensionpointcontribution/CMakeLists.txt index 6c23a9f182..09d9b502b8 100644 --- a/Examples/Plugins/org.mitk.example.gui.extensionpointcontribution/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.extensionpointcontribution/CMakeLists.txt @@ -1,6 +1,7 @@ project(org_mitk_example_gui_extensionpointcontribution) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_extensionpointcontribution_EXPORT EXPORTED_INCLUDE_SUFFIXES src + NO_INSTALL ) diff --git a/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/CMakeLists.txt index 67e0348420..93cc545565 100644 --- a/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/CMakeLists.txt @@ -1,6 +1,7 @@ project(org_mitk_example_gui_extensionpointdefinition) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_extensionpointdefinition_EXPORT EXPORTED_INCLUDE_SUFFIXES src + NO_INSTALL ) diff --git a/Examples/Plugins/org.mitk.example.gui.minimalapplication/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.minimalapplication/CMakeLists.txt index b6611427c9..e08c7dafc8 100644 --- a/Examples/Plugins/org.mitk.example.gui.minimalapplication/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.minimalapplication/CMakeLists.txt @@ -1,6 +1,7 @@ project(org_mitk_example_gui_minimalapplication) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_minimalapplication_EXPORT EXPORTED_INCLUDE_SUFFIXES src + NO_INSTALL ) diff --git a/Examples/Plugins/org.mitk.example.gui.multipleperspectives/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.multipleperspectives/CMakeLists.txt index 9d13bf194d..b53cfc7232 100644 --- a/Examples/Plugins/org.mitk.example.gui.multipleperspectives/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.multipleperspectives/CMakeLists.txt @@ -1,6 +1,7 @@ project(org_mitk_example_gui_multipleperspectives) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_multipleperspectives_EXPORT EXPORTED_INCLUDE_SUFFIXES src + NO_INSTALL ) diff --git a/Examples/Plugins/org.mitk.example.gui.regiongrowing/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.regiongrowing/CMakeLists.txt index 315f17997a..7727603c2f 100644 --- a/Examples/Plugins/org.mitk.example.gui.regiongrowing/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.regiongrowing/CMakeLists.txt @@ -1,7 +1,8 @@ project(org_mitk_example_gui_regiongrowing) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE REGIONGROWING_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDENCIES QmitkExt + NO_INSTALL ) diff --git a/Examples/Plugins/org.mitk.example.gui.selectionservicemitk.views/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.selectionservicemitk.views/CMakeLists.txt index ecf5467bcc..a70fde93f8 100644 --- a/Examples/Plugins/org.mitk.example.gui.selectionservicemitk.views/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.selectionservicemitk.views/CMakeLists.txt @@ -1,7 +1,8 @@ project(org_mitk_example_gui_selectionservicemitk_views) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_selectionservicemitk_views_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDENCIES Qmitk + NO_INSTALL ) diff --git a/Examples/Plugins/org.mitk.example.gui.selectionservicemitk/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.selectionservicemitk/CMakeLists.txt index 700cfe161d..b58b752c93 100644 --- a/Examples/Plugins/org.mitk.example.gui.selectionservicemitk/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.selectionservicemitk/CMakeLists.txt @@ -1,6 +1,7 @@ project(org_mitk_example_gui_selectionservicemitk) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_selectionservicemitk_EXPORT EXPORTED_INCLUDE_SUFFIXES src + NO_INSTALL ) diff --git a/Examples/Plugins/org.mitk.example.gui.selectionserviceqt/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.selectionserviceqt/CMakeLists.txt index 149e49e0f1..26b5285d40 100644 --- a/Examples/Plugins/org.mitk.example.gui.selectionserviceqt/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.selectionserviceqt/CMakeLists.txt @@ -1,6 +1,7 @@ project(org_mitk_example_gui_selectionserviceqt) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE org_mitk_example_gui_selectionserviceqt_EXPORT EXPORTED_INCLUDE_SUFFIXES src + NO_INSTALL ) diff --git a/MITKConfig.cmake.in b/MITKConfig.cmake.in index da9148fc24..49a6dfcaba 100644 --- a/MITKConfig.cmake.in +++ b/MITKConfig.cmake.in @@ -1,149 +1,161 @@ # Update the CMake module path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "@MITK_SOURCE_DIR@/CMake") include(@MITK_BINARY_DIR@/Core/Code/CppMicroServices/CppMicroServicesConfig.cmake) # Include MITK macros include(MacroParseArguments) include(mitkFunctionCheckMitkCompatibility) include(mitkFunctionOrganizeSources) include(mitkFunctionCreateWindowsBatchScript) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallAutoLoadModules) include(mitkMacroCreateModuleConf) include(mitkMacroCreateModule) include(mitkMacroCheckModule) include(mitkMacroCreateModuleTests) include(mitkFunctionAddCustomModuleTest) include(mitkMacroUseModule) include(mitkMacroMultiplexPicType) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroGenerateToolsLibrary) include(mitkMacroCreateCTKPlugin) # The MITK version number set(MITK_VERSION_MAJOR "@MITK_VERSION_MAJOR@") set(MITK_VERSION_MINOR "@MITK_VERSION_MINOR@") set(MITK_VERSION_PATCH "@MITK_VERSION_PATCH@") set(MITK_VERSION_STRING "@MITK_VERSION_STRING@") +# MITK compiler flags +set(MITK_C_FLAGS "@MITK_C_FLAGS@") +set(MTTK_C_FLAGS_DEBUG "@MITK_C_FLAGS_DEBUG@") +set(MITK_C_FLAGS_RELEASE "@MITK_C_FLAGS_RELEASE@") +set(MITK_CXX_FLAGS "@MITK_CXX_FLAGS@") +set(MTTK_CXX_FLAGS_DEBUG "@MITK_CXX_FLAGS_DEBUG@") +set(MITK_CXX_FLAGS_RELEASE "@MITK_CXX_FLAGS_RELEASE@") + +set(MITK_EXE_LINKER_FLAGS "@MITK_EXE_LINKER_FLAGS@") +set(MITK_SHARED_LINKER_FLAGS "@MITK_SHARED_LINKER_FLAGS@") +set(MITK_MODULE_LINKER_FLAGS "@MITK_MODULE_LINKER_FLAGS@") + # Internal version numbers, used for approximate compatibility checks # of a MITK development version (non-release). set(MITK_VERSION_PLUGIN_SYSTEM 2) # dropped legacy BlueBerry plug-in CMake support # MITK specific variables set(MITK_SOURCE_DIR "@MITK_SOURCE_DIR@") set(MITK_BINARY_DIR "@MITK_BINARY_DIR@") set(UTILITIES_DIR "@UTILITIES_DIR@") set(REGISTER_QFUNCTIONALITY_CPP_IN "@REGISTER_QFUNCTIONALITY_CPP_IN@") set(MITK_MODULES_PACKAGE_DEPENDS_DIR "@MITK_MODULES_PACKAGE_DEPENDS_DIR@") set(MODULES_PACKAGE_DEPENDS_DIRS "@MODULES_PACKAGE_DEPENDS_DIRS@") set(MITK_DOXYGEN_TAGFILE_NAME "@MITK_DOXYGEN_TAGFILE_NAME@") if(MODULES_CONF_DIRS) list(APPEND MODULES_CONF_DIRS "@MODULES_CONF_DIRS@") list(REMOVE_DUPLICATES MODULES_CONF_DIRS) else() set(MODULES_CONF_DIRS "@MODULES_CONF_DIRS@") endif() set(MODULES_CONF_DIRNAME "@MODULES_CONF_DIRNAME@") foreach(_module @MITK_MODULE_NAMES@) set(${_module}_CONFIG_FILE "@MITK_BINARY_DIR@/@MODULES_CONF_DIRNAME@/${_module}Config.cmake") endforeach() # Include directory variables set(MITK_INCLUDE_DIRS "@MITK_INCLUDE_DIRS@") set(QMITK_INCLUDE_DIRS "@QMITK_INCLUDE_DIRS@") set(ANN_INCLUDE_DIR "@ANN_INCLUDE_DIR@") set(IPSEGMENTATION_INCLUDE_DIR "@IPSEGMENTATION_INCLUDE_DIR@") set(VECMATH_INCLUDE_DIR "@VECMATH_INCLUDE_DIR@") set(IPFUNC_INCLUDE_DIR "@IPFUNC_INCLUDE_DIR@") set(MITK_IGT_INCLUDE_DIRS "@MITK_IGT_INCLUDE_DIRS@") # Library variables set(MITK_LIBRARIES "@MITK_LIBRARIES@") set(QMITK_LIBRARIES "@QMITK_LIBRARIES@") # Link directory variables set(MITK_LINK_DIRECTORIES "@MITK_LINK_DIRECTORIES@") set(QMITK_LINK_DIRECTORIES "@QMITK_LINK_DIRECTORIES@") set(MITK_LIBRARY_DIRS "@CMAKE_LIBRARY_OUTPUT_DIRECTORY@" "@CMAKE_LIBRARY_OUTPUT_DIRECTORY@/plugins") set(MITK_VTK_LIBRARY_DIRS "@MITK_VTK_LIBRARY_DIRS@") set(MITK_ITK_LIBRARY_DIRS "@MITK_ITK_LIBRARY_DIRS@") # External projects set(ITK_DIR "@ITK_DIR@") set(VTK_DIR "@VTK_DIR@") set(DCMTK_DIR "@DCMTK_DIR@") set(GDCM_DIR "@GDCM_DIR@") set(BOOST_ROOT "@BOOST_ROOT@") set(OpenCV_DIR "@OpenCV_DIR@") set(SOFA_DIR "@SOFA_DIR@") set(MITK_QMAKE_EXECUTABLE "@QT_QMAKE_EXECUTABLE@") set(MITK_DATA_DIR "@MITK_DATA_DIR@") set(MITK_RUNTIME_PATH "@MITK_RUNTIME_PATH@") # MITK use variables set(MITK_USE_QT @MITK_USE_QT@) set(MITK_USE_BLUEBERRY @MITK_USE_BLUEBERRY@) set(MITK_USE_SYSTEM_Boost @MITK_USE_SYSTEM_Boost@) set(MITK_USE_Boost @MITK_USE_Boost@) set(MITK_USE_Boost_LIBRARIES @MITK_USE_Boost_LIBRARIES@) set(MITK_USE_CTK @MITK_USE_CTK@) set(MITK_USE_DCMTK @MITK_USE_DCMTK@) set(MITK_USE_OpenCV @MITK_USE_OpenCV@) set(MITK_USE_SOFA @MITK_USE_SOFA@) set(MITK_USE_Python @MITK_USE_Python@) # There is no PocoConfig.cmake, so we set Poco specific CMake variables # here. This way the call to find_package(Poco) in BlueBerryConfig.cmake # finds the Poco distribution supplied by MITK set(Poco_INCLUDE_DIR "@MITK_SOURCE_DIR@/Utilities/Poco") set(Poco_LIBRARY_DIR "@MITK_BINARY_DIR@/bin") if(MITK_USE_IGT) #include(${MITK_DIR}/mitkIGTConfig.cmake) endif() if(NOT MITK_EXPORTS_FILE_INCLUDED) if(EXISTS "@MITK_EXPORTS_FILE@") set(MITK_EXPORTS_FILE_INCLUDED 1) include("@MITK_EXPORTS_FILE@") endif(EXISTS "@MITK_EXPORTS_FILE@") endif() # BlueBerry support if(MITK_USE_BLUEBERRY) set(BlueBerry_DIR "@MITK_BINARY_DIR@/BlueBerry") # Don't include the BlueBerry exports file, since the targets are # also exported in the MITK exports file set(BB_PLUGIN_EXPORTS_FILE_INCLUDED 1) find_package(BlueBerry) if(NOT BlueBerry_FOUND) message(SEND_ERROR "MITK does not seem to be configured with BlueBerry support. Set MITK_USE_BLUEBERRY to ON in your MITK build configuration.") endif(NOT BlueBerry_FOUND) set(MITK_PLUGIN_USE_FILE @MITK_PLUGIN_USE_FILE@) if(MITK_PLUGIN_USE_FILE) if(EXISTS ${MITK_PLUGIN_USE_FILE}) include(${MITK_PLUGIN_USE_FILE}) endif() endif() set(MITK_PLUGIN_PROVISIONING_FILE "@MITK_EXTAPP_PROVISIONING_FILE@") set(MITK_PROVISIONING_FILES "${BLUEBERRY_PLUGIN_PROVISIONING_FILE}" "${MITK_PLUGIN_PROVISIONING_FILE}") endif(MITK_USE_BLUEBERRY) # Set properties on exported targets @MITK_EXPORTED_TARGET_PROPERTIES@ diff --git a/Modules/CMakeLists.txt b/Modules/CMakeLists.txt index 632474b83d..9005b35b9d 100644 --- a/Modules/CMakeLists.txt +++ b/Modules/CMakeLists.txt @@ -1,58 +1,59 @@ set(LIBPOSTFIX "Ext") # Modules must be listed according to their dependencies set(module_dirs SceneSerializationBase PlanarFigure ImageExtraction ImageStatistics LegacyAdaptors IpPicSupport MitkExt SceneSerialization Segmentation Qmitk QmitkExt GraphAlgorithms DiffusionImaging GPGPU IGT CameraCalibration IGTUI RigidRegistration RigidRegistrationUI DeformableRegistration DeformableRegistrationUI OpenCL OpenCVVideoSupport Overlays InputDevices ToFHardware ToFProcessing ToFUI US ClippingTools USUI DicomUI Simulation + Python ) set(MITK_DEFAULT_SUBPROJECTS MITK-Modules) foreach(module_dir ${module_dirs}) add_subdirectory(${module_dir}) endforeach() if(MITK_PRIVATE_MODULES) file(GLOB all_subdirs RELATIVE ${MITK_PRIVATE_MODULES} ${MITK_PRIVATE_MODULES}/*) foreach(subdir ${all_subdirs}) string(FIND ${subdir} "." _result) if(_result EQUAL -1) if(EXISTS ${MITK_PRIVATE_MODULES}/${subdir}/CMakeLists.txt) message(STATUS "Found private module ${subdir}") add_subdirectory(${MITK_PRIVATE_MODULES}/${subdir} private_modules/${subdir}) endif() endif() endforeach() endif(MITK_PRIVATE_MODULES) diff --git a/Modules/DiffusionImaging/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp index 8b5a59d9d6..5b360286c4 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp @@ -1,1280 +1,1255 @@ /*=================================================================== 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 __itkDiffusionMultiShellQballReconstructionImageFilter_cpp #define __itkDiffusionMultiShellQballReconstructionImageFilter_cpp #include #include #include #include namespace itk { template< class T, class TG, class TO, int L, int NODF> DiffusionMultiShellQballReconstructionImageFilter ::DiffusionMultiShellQballReconstructionImageFilter() : m_ReconstructionType(Mode_Standard1Shell), m_Interpolation_Flag(false), m_Interpolation_SHT1_inv(NULL), m_Interpolation_SHT2_inv(NULL), m_Interpolation_SHT3_inv(NULL), m_TARGET_SH_shell1(NULL), m_TARGET_SH_shell2(NULL), m_TARGET_SH_shell3(NULL), m_MaxDirections(0), m_CoeffReconstructionMatrix(NULL), m_ODFSphericalHarmonicBasisMatrix(NULL), m_GradientDirectionContainer(NULL), m_NumberOfGradientDirections(0), m_NumberOfBaselineImages(0), m_Threshold(0), m_BZeroImage(NULL), m_CoefficientImage(NULL), m_BValue(1.0), m_Lambda(0.0), m_IsHemisphericalArrangementOfGradientDirections(false), - m_IsArithmeticProgession(false), - m_UseWeights(false), - m_WeightShell1(0.0), - m_WeightShell2(0.0), - m_WeightShell3(0.0) + m_IsArithmeticProgession(false) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::SetGradientImage( GradientDirectionContainerType *gradientDirection , const GradientImagesType *gradientImage , float bvalue) { m_BValue = bvalue; m_GradientDirectionContainer = gradientDirection; m_NumberOfBaselineImages = 0; if(m_BValueMap.size() == 0){ itkWarningMacro(<< "DiffusionMultiShellQballReconstructionImageFilter.cpp : no GradientIndexMapAvalible"); GradientDirectionContainerType::ConstIterator gdcit; for( gdcit = m_GradientDirectionContainer->Begin(); gdcit != m_GradientDirectionContainer->End(); ++gdcit) { double bValueKey = int(((m_BValue * gdcit.Value().two_norm() * gdcit.Value().two_norm())+7.5)/10)*10; m_BValueMap[bValueKey].push_back(gdcit.Index()); } } if(m_BValueMap.find(0) == m_BValueMap.end()) { itkExceptionMacro(<< "DiffusionMultiShellQballReconstructionImageFilter.cpp : GradientIndxMap with no b-Zero indecies found: check input BValueMap"); } m_NumberOfBaselineImages = m_BValueMap[0].size(); m_NumberOfGradientDirections = gradientDirection->Size() - m_NumberOfBaselineImages; // ensure that the gradient image we received has as many components as // the number of gradient directions if( gradientImage->GetVectorLength() != m_NumberOfBaselineImages + m_NumberOfGradientDirections ) { itkExceptionMacro( << m_NumberOfGradientDirections << " gradients + " << m_NumberOfBaselineImages << "baselines = " << m_NumberOfGradientDirections + m_NumberOfBaselineImages << " directions specified but image has " << gradientImage->GetVectorLength() << " components."); } ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) ); std::string gradientImageClassName(ProcessObject::GetInput(0)->GetNameOfClass()); if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) itkExceptionMacro( << "There is only one Gradient image. I expect that to be a VectorImage. But its of type: " << gradientImageClassName ); m_BZeroImage = BZeroImageType::New(); typename GradientImagesType::Pointer img = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); m_BZeroImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_BZeroImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_BZeroImage->SetDirection( img->GetDirection() ); // Set the image direction m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_BZeroImage->Allocate(); m_CoefficientImage = CoefficientImageType::New(); m_CoefficientImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_CoefficientImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_CoefficientImage->SetDirection( img->GetDirection() ); // Set the image direction m_CoefficientImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_CoefficientImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_CoefficientImage->Allocate(); } template void DiffusionMultiShellQballReconstructionImageFilter ::Normalize( OdfPixelType & out) { for(int i=0; i void DiffusionMultiShellQballReconstructionImageFilter ::Projection1(vnl_vector & vec, double delta) { if (delta==0){ //Clip attenuation values. If att<0 => att=0, if att>1 => att=1 for (unsigned int i=0; i=0 && vec[i]<=1)*vec[i]+(vec[i]>1); } else{ //Use function from Aganj et al, MRM, 2010 for (unsigned int i=0; i< vec.size(); i++) vec[i]=CalculateThreashold(vec[i], delta); } } template double DiffusionMultiShellQballReconstructionImageFilter ::CalculateThreashold(const double value, const double delta) { return (value<0)*(0.5*delta) + (value>=0 && value=delta && value<1-delta)*value+(value>=1-delta && value<1)*(1-0.5*delta-0.5*((1-value)*(1-value))/delta) + (value>=1)*(1-0.5*delta); } template void DiffusionMultiShellQballReconstructionImageFilter ::Projection2( vnl_vector & E1,vnl_vector & E2, vnl_vector & E3, double delta ) { const double sF = sqrt(5.0); vnl_vector vOnes(m_MaxDirections); vOnes.fill(1.0); vnl_matrix T0(m_MaxDirections, 3); vnl_matrix C(m_MaxDirections, 7); vnl_matrix A(m_MaxDirections, 7); vnl_matrix B(m_MaxDirections, 7); vnl_vector s0(m_MaxDirections); vnl_vector a0(m_MaxDirections); vnl_vector b0(m_MaxDirections); vnl_vector ta(m_MaxDirections); vnl_vector tb(m_MaxDirections); vnl_vector e(m_MaxDirections); vnl_vector m(m_MaxDirections); vnl_vector a(m_MaxDirections); vnl_vector b(m_MaxDirections); // logarithmierung aller werte in E for(unsigned int i = 0 ; i < m_MaxDirections; i++) { T0(i,0) = -log(E1(i)); T0(i,1) = -log(E2(i)); T0(i,2) = -log(E3(i)); } //T0 = -T0.apply(std::log); // Summeiere Zeilenweise über alle Shells sum = E1+E2+E3 for(unsigned int i = 0 ; i < m_MaxDirections; i++) { s0[i] = T0(i,0) + T0(i,1) + T0(i,2); } for(unsigned int i = 0; i < m_MaxDirections; i ++) { // Alle Signal-Werte auf der Ersten shell E(N,0) normiert auf s0 a0[i] = T0(i,0) / s0[i]; // Alle Signal-Werte auf der Zweiten shell E(N,1) normiert auf s0 b0[i] = T0(i,1) / s0[i]; } ta = a0 * 3.0; tb = b0 * 3.0; e = tb - (ta * 2.0); m = (tb * 2.0 ) + ta; for(unsigned int i = 0; i =1-3*(sF+2)*delta); C(i,2) = (m[i] > 3-3*sF*delta) && (-1+3*(2*sF+5)*delta= 3-3*sF*delta && e[i] >= -3 *sF * delta); C(i,4) = (2.5 + 1.5*(5+sF)*delta < m[i] && m[i] < 3-3*sF*delta && e[i] > -3*sF*delta); C(i,5) = (ta[i] <= 0.5+1.5 *(sF+1)*delta && m[i] <= 2.5 + 1.5 *(5+sF) * delta); C(i,6) = !((bool) C(i,0) ||(bool) C(i,1) ||(bool) C(i,2) ||(bool) C(i,3) ||(bool) C(i,4) ||(bool) C(i,5) ); // ~ANY(C(i,[0-5] ),2) A(i,0)=(bool)C(i,0) * a0(i); A(i,1)=(bool)C(i,1) * (1.0/3.0-(sF+2)*delta); A(i,2)=(bool)C(i,2) * (0.2+0.8*a0(i)-0.4*b0(i)-delta/sF); A(i,3)=(bool)C(i,3) * (0.2+delta/sF); A(i,4)=(bool)C(i,4) * (0.2*a0(i)+0.4*b0(i)+2*delta/sF); A(i,5)=(bool)C(i,5) * (1.0/6.0+0.5*(sF+1)*delta); A(i,6)=(bool)C(i,6) * a0(i); B(i,0)=(bool)C(i,0) * (1.0/3.0+delta); B(i,1)=(bool)C(i,1) * (1.0/3.0+delta); B(i,2)=(bool)C(i,2) * (0.4-0.4*a0(i)+0.2*b0(i)-2*delta/sF); B(i,3)=(bool)C(i,3) * (0.4-3*delta/sF); B(i,4)=(bool)C(i,4) * (0.4*a0(i)+0.8*b0(i)-delta/sF); B(i,5)=(bool)C(i,5) * (1.0/3.0+delta); B(i,6)=(bool)C(i,6) * b0(i); } for(unsigned int i = 0 ; i < m_MaxDirections; i++) { double sumA = 0; double sumB = 0; for(int j = 0 ; j < 7; j++) { sumA += A(i,j); sumB += B(i,j); } a[i] = sumA; b[i] = sumB; } for(unsigned int i = 0; i < m_MaxDirections; i++) { E1(i) = exp(-(a[i]*s0[i])); E2(i) = exp(-(b[i]*s0[i])); E3(i) = exp(-((1-a[i]-b[i])*s0[i])); } } template void DiffusionMultiShellQballReconstructionImageFilter ::Projection3( vnl_vector & A, vnl_vector & a, vnl_vector & b, double delta0) { const double s6 = sqrt(6.0); const double s15 = s6/2.0; vnl_vector delta(a.size()); delta.fill(delta0); vnl_matrix AM(a.size(), 15); vnl_matrix aM(a.size(), 15); vnl_matrix bM(a.size(), 15); vnl_matrix B(a.size(), 15); AM.set_column(0, A); AM.set_column(1, A); AM.set_column(2, A); AM.set_column(3, delta); AM.set_column(4, (A+a-b - (delta*s6))/3.0); AM.set_column(5, delta); AM.set_column(6, delta); AM.set_column(7, delta); AM.set_column(8, A); AM.set_column(9, 0.2*(a*2+A-2*(s6+1)*delta)); AM.set_column(10,0.2*(b*(-2)+A+2-2*(s6+1)*delta)); AM.set_column(11, delta); AM.set_column(12, delta); AM.set_column(13, delta); AM.set_column(14, 0.5-(1+s15)*delta); aM.set_column(0, a); aM.set_column(1, a); aM.set_column(2, -delta + 1); aM.set_column(3, a); aM.set_column(4, (A*2+a*5+b+s6*delta)/6.0); aM.set_column(5, a); aM.set_column(6, -delta + 1); aM.set_column(7, 0.5*(a+b)+(1+s15)*delta); aM.set_column(8, -delta + 1); aM.set_column(9, 0.2*(a*4+A*2+(s6+1)*delta)); aM.set_column(10, -delta + 1); aM.set_column(11, (s6+3)*delta); aM.set_column(12, -delta + 1); aM.set_column(13, -delta + 1); aM.set_column(14, -delta + 1); bM.set_column(0, b); bM.set_column(1, delta); bM.set_column(2, b); bM.set_column(3, b); bM.set_column(4, (A*(-2)+a+b*5-s6*delta)/6.0); bM.set_column(5, delta); bM.set_column(6, b); bM.set_column(7, 0.5*(a+b)-(1+s15)*delta); bM.set_column(8, delta); bM.set_column(9, delta); bM.set_column(10, 0.2*(b*4-A*2+1-(s6+1)*delta)); bM.set_column(11, delta); bM.set_column(12, delta); bM.set_column(13, -delta*(s6+3) + 1); bM.set_column(14, delta); delta0 *= 0.99; vnl_matrix R2(a.size(), 15); std::vector I(a.size()); for (unsigned int i=0; idelta0 && aM(i,j)<1-delta0) R2(i,j) = (AM(i,j)-A(i))*(AM(i,j)-A(i))+ (aM(i,j)-a(i))*(aM(i,j)-a(i))+(bM(i,j)-b(i))*(bM(i,j)-b(i)); else R2(i,j) = 1e20; } unsigned int index = 0; double minvalue = 999; for(int j = 0 ; j < 15 ; j++) { if(R2(i,j) < minvalue){ minvalue = R2(i,j); index = j; } } I[i] = index; } for (unsigned int i=0; i < A.size(); i++){ A(i) = AM(i,(int)I[i]); a(i) = aM(i,(int)I[i]); b(i) = bM(i,(int)I[i]); } } template void DiffusionMultiShellQballReconstructionImageFilter ::S_S0Normalization( vnl_vector & vec, double S0 ) { for(unsigned int i = 0; i < vec.size(); i++) { if (S0==0) S0 = 0.01; vec[i] /= S0; } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::DoubleLogarithm(vnl_vector & vec) { for(unsigned int i = 0; i < vec.size(); i++) { vec[i] = log(-log(vec[i])); } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::BeforeThreadedGenerateData() { m_ReconstructionType = Mode_Standard1Shell; if(m_BValueMap.size() == 4 ){ BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry const unsigned int bValue_shell1 = it->first; const unsigned int size_shell1 = it->second.size(); IndiciesVector shell1 = it->second; it++; const unsigned int bValue_shell2 = it->first; const unsigned int size_shell2 = it->second.size(); IndiciesVector shell2 = it->second; it++; const unsigned int bValue_shell3 = it->first; const unsigned int size_shell3 = it->second.size(); IndiciesVector shell3 = it->second; // arithmetic progrssion if(bValue_shell2 - bValue_shell1 == bValue_shell1 && bValue_shell3 - bValue_shell2 == bValue_shell1 ) { // check if Interpolation is needed // if shells with different numbers of directions exist m_Interpolation_Flag = false; if(size_shell1 != size_shell2 || size_shell2 != size_shell3 || size_shell1 != size_shell3) { m_Interpolation_Flag = true; MITK_INFO << "Shell interpolation: shells with different numbers of directions"; } else { // else if each shell holds same numbers of directions, but the gradient direction differ more than one 1 degree m_Interpolation_Flag = CheckForDifferingShellDirections(); if(m_Interpolation_Flag) MITK_INFO << "Shell interpolation: gradient direction differ more than one 1 degree"; } m_ReconstructionType = Mode_Analytical3Shells; if(m_Interpolation_Flag) { unsigned int interp_SHOrder_shell1 = 12; while( ((interp_SHOrder_shell1+1)*(interp_SHOrder_shell1+2)/2) > size_shell1 && interp_SHOrder_shell1 > L ) interp_SHOrder_shell1 -= 2 ; const int number_coeffs_shell1 = (int)(interp_SHOrder_shell1*interp_SHOrder_shell1 + interp_SHOrder_shell1 + 2.0)/2.0 + interp_SHOrder_shell1; unsigned int interp_SHOrder_shell2 = 12; while( ((interp_SHOrder_shell2+1)*(interp_SHOrder_shell2+2)/2) > size_shell2 && interp_SHOrder_shell2 > L ) interp_SHOrder_shell2 -= 2 ; const int number_coeffs_shell2 = (int)(interp_SHOrder_shell2*interp_SHOrder_shell2 + interp_SHOrder_shell2 + 2.0)/2.0 + interp_SHOrder_shell2; unsigned int interp_SHOrder_shell3 = 12; while( ((interp_SHOrder_shell3+1)*(interp_SHOrder_shell3+2)/2) > size_shell3 && interp_SHOrder_shell3 > L ) interp_SHOrder_shell3 -= 2 ; const int number_coeffs_shell3 = (int)(interp_SHOrder_shell3*interp_SHOrder_shell3 + interp_SHOrder_shell3 + 2.0)/2.0 + interp_SHOrder_shell3; - - // find shell with max(dirs) - if(m_UseWeights){ - double maxDirs = size_shell3; - if(size_shell2 > maxDirs) maxDirs = size_shell2; - if(size_shell1 > maxDirs) maxDirs = size_shell1; - - // calculate weights - m_WeightShell1 = size_shell1 / maxDirs; - m_WeightShell2 = size_shell2 / maxDirs; - m_WeightShell3 = size_shell3 / maxDirs; - } - // Create direction container for all directions (no duplicates, different directions from all shells) IndiciesVector all_directions_container = GetAllDirections(); m_MaxDirections = all_directions_container.size(); // create target SH-Basis // initialize empty target matrix and set the wanted directions vnl_matrix * Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); // initialize a SH Basis, neede to interpolate from oldDirs -> newDirs m_TARGET_SH_shell1 = new vnl_matrix(m_MaxDirections, number_coeffs_shell1); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell1, interp_SHOrder_shell1); delete Q; Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); m_TARGET_SH_shell2 = new vnl_matrix(m_MaxDirections, number_coeffs_shell2); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell2, interp_SHOrder_shell2); delete Q; Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); m_TARGET_SH_shell3 = new vnl_matrix(m_MaxDirections, number_coeffs_shell3); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell3, interp_SHOrder_shell3); delete Q; // end creat target SH-Basis // create measured-SHBasis // Shell 1 vnl_matrix * tempSHBasis; vnl_matrix_inverse * temp; // initialize empty matrix and set the measured directions of shell1 Q = new vnl_matrix(3, shell1.size()); ComputeSphericalFromCartesian(Q, shell1); // initialize a SH Basis, need to get the coeffs from measuredShell tempSHBasis = new vnl_matrix(shell1.size(), number_coeffs_shell1); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell1); // inversion of the SH=Basis // c_s1 = B^-1 * shell1 // interp_Values = targetSHBasis * c_s1 // Values = m_TARGET_SH_shell1 * Interpolation_SHT1_inv * DataShell1; temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT1_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; // Shell 2 Q = new vnl_matrix(3, shell2.size()); ComputeSphericalFromCartesian(Q, shell2); tempSHBasis = new vnl_matrix(shell2.size(), number_coeffs_shell2); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell2); temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT2_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; // Shell 3 Q = new vnl_matrix(3, shell3.size()); ComputeSphericalFromCartesian(Q, shell3); tempSHBasis = new vnl_matrix(shell3.size(), number_coeffs_shell3); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell3); temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT3_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; ComputeReconstructionMatrix(all_directions_container); MITK_INFO << "Reconstruction information: Multishell Reconstruction filter - Interpolation"; MITK_INFO << "Shell 1"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell1; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell1; MITK_INFO << " Number of Gradientdirections: " << size_shell1; - if(m_WeightShell1 != 0) MITK_INFO << " Information content: " << m_WeightShell1; + MITK_INFO << "Shell 2"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell2; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell2; MITK_INFO << " Number of Gradientdirections: " << size_shell2; - if(m_WeightShell2 != 0) MITK_INFO << " Information content: " << m_WeightShell2; + MITK_INFO << "Shell 3"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell3; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell3; MITK_INFO << " Number of Gradientdirections: " << size_shell3; - if(m_WeightShell3 != 0) MITK_INFO << " Information content: " << m_WeightShell3; + MITK_INFO << "Overall"; MITK_INFO << " SHOrder: " << L; MITK_INFO << " Number of Coeffs: " << (L+1)*(L+2)*0.5; MITK_INFO << " Number of Gradientdirections: " << m_MaxDirections; return; }else { ComputeReconstructionMatrix(shell1); } } } if(m_BValueMap.size() > 2 && m_ReconstructionType != Mode_Analytical3Shells) { m_ReconstructionType = Mode_NumericalNShells; } if(m_BValueMap.size() == 2){ BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry IndiciesVector shell = it->second; ComputeReconstructionMatrix(shell); } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int /*NumberOfThreads*/) { itk::TimeProbe clock; clock.Start(); switch(m_ReconstructionType) { case Mode_Standard1Shell: StandardOneShellReconstruction(outputRegionForThread); break; case Mode_Analytical3Shells: AnalyticalThreeShellReconstruction(outputRegionForThread); break; case Mode_NumericalNShells: break; } clock.Stop(); MITK_INFO << "Reconstruction in : " << clock.GetTotal() << " s"; } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::StandardOneShellReconstruction(const OutputImageRegionType& outputRegionForThread) { // Get output image pointer typename OdfImageType::Pointer outputImage = static_cast< OdfImageType * >(ProcessObject::GetOutput(0)); // Get input gradient image pointer typename GradientImagesType::Pointer gradientImagePointer = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); // ImageRegionIterator for the output image ImageRegionIterator< OdfImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); // ImageRegionIterator for the BZero (output) image ImageRegionIterator< BZeroImageType > bzeroIterator(m_BZeroImage, outputRegionForThread); bzeroIterator.GoToBegin(); // Const ImageRegionIterator for input gradient image typedef ImageRegionConstIterator< GradientImagesType > GradientIteratorType; GradientIteratorType git(gradientImagePointer, outputRegionForThread ); git.GoToBegin(); BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry IndiciesVector SignalIndicies = it->second; IndiciesVector BZeroIndicies = m_BValueMap[0]; unsigned int NumbersOfGradientIndicies = SignalIndicies.size(); typedef typename GradientImagesType::PixelType GradientVectorType; // iterate overall voxels of the gradient image region while( ! git.IsAtEnd() ) { GradientVectorType b = git.Get(); // ODF Vector OdfPixelType odf(0.0); double b0average = 0; const unsigned int b0size = BZeroIndicies.size(); for(unsigned int i = 0; i < b0size ; ++i) { b0average += b[BZeroIndicies[i]]; } b0average /= b0size; bzeroIterator.Set(b0average); ++bzeroIterator; // Create the Signal Vector vnl_vector SignalVector(NumbersOfGradientIndicies); if( (b0average != 0) && (b0average >= m_Threshold) ) { for( unsigned int i = 0; i< SignalIndicies.size(); i++ ) { SignalVector[i] = static_cast(b[SignalIndicies[i]]); } // apply threashold an generate ln(-ln(E)) signal // Replace SignalVector with PreNormalized SignalVector S_S0Normalization(SignalVector, b0average); Projection1(SignalVector); DoubleLogarithm(SignalVector); // approximate ODF coeffs vnl_vector coeffs = ( (*m_CoeffReconstructionMatrix) * SignalVector ); coeffs[0] = 1.0/(2.0*sqrt(M_PI)); odf = element_cast(( (*m_ODFSphericalHarmonicBasisMatrix) * coeffs )).data_block(); odf *= (M_PI*4/NODF); } // set ODF to ODF-Image oit.Set( odf ); ++oit; ++git; } MITK_INFO << "One Thread finished reconstruction"; } //#include "itkLevenbergMarquardtOptimizer.h" template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::NumericalNShellReconstruction(const OutputImageRegionType& outputRegionForThread) { /* itk::LevenbergMarquardtOptimizer::Pointer optimizer = itk::LevenbergMarquardtOptimizer::New(); optimizer->SetUseCostFunctionGradient(false); // Scale the translation components of the Transform in the Optimizer itk::LevenbergMarquardtOptimizer::ScalesType scales(transform->GetNumberOfParameters()); scales.Fill(0.01); unsigned long numberOfIterations = 80000; double gradientTolerance = 1e-10; // convergence criterion double valueTolerance = 1e-10; // convergence criterion double epsilonFunction = 1e-10; // convergence criterion optimizer->SetScales( scales ); optimizer->SetNumberOfIterations( numberOfIterations ); optimizer->SetValueTolerance( valueTolerance ); optimizer->SetGradientTolerance( gradientTolerance ); optimizer->SetEpsilonFunction( epsilonFunction );*/ } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::AnalyticalThreeShellReconstruction(const OutputImageRegionType& outputRegionForThread) { // Input Gradient Image and Output ODF Image typedef typename GradientImagesType::PixelType GradientVectorType; typename OdfImageType::Pointer outputImage = static_cast< OdfImageType * >(ProcessObject::GetOutput(0)); typename GradientImagesType::Pointer gradientImagePointer = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); // Define Image iterators ImageRegionIterator< OdfImageType > odfOutputImageIterator(outputImage, outputRegionForThread); ImageRegionConstIterator< GradientImagesType > gradientInputImageIterator(gradientImagePointer, outputRegionForThread ); ImageRegionIterator< BZeroImageType > bzeroIterator(m_BZeroImage, outputRegionForThread); ImageRegionIterator< CoefficientImageType > coefficientImageIterator(m_CoefficientImage, outputRegionForThread); // All iterators seht to Begin of the specific OutputRegion coefficientImageIterator.GoToBegin(); bzeroIterator.GoToBegin(); odfOutputImageIterator.GoToBegin(); gradientInputImageIterator.GoToBegin(); // Get Shell Indicies for all non-BZero Gradients // it MUST be a arithmetic progression eg.: 1000, 2000, 3000 BValueMapIteraotr it = m_BValueMap.begin(); it++; // it = b-value = 1000 IndiciesVector Shell1Indiecies = it->second; it++; // it = b-value = 2000 IndiciesVector Shell2Indiecies = it->second; it++; // it = b-value = 3000 IndiciesVector Shell3Indiecies = it->second; IndiciesVector BZeroIndicies = m_BValueMap[0]; if(!m_Interpolation_Flag) { m_MaxDirections = Shell1Indiecies.size(); }// else: m_MaxDirection is set in BeforeThreadedGenerateData // Nx3 Signal Matrix with E(0) = Shell 1, E(1) = Shell 2, E(2) = Shell 3 vnl_vector< double > E1(m_MaxDirections); vnl_vector< double > E2(m_MaxDirections); vnl_vector< double > E3(m_MaxDirections); vnl_vector AlphaValues(m_MaxDirections); vnl_vector BetaValues(m_MaxDirections); vnl_vector LAValues(m_MaxDirections); vnl_vector PValues(m_MaxDirections); vnl_vector DataShell1(Shell1Indiecies.size()); vnl_vector DataShell2(Shell2Indiecies.size()); vnl_vector DataShell3(Shell3Indiecies.size()); vnl_matrix tempInterpolationMatrixShell1,tempInterpolationMatrixShell2,tempInterpolationMatrixShell3; if(m_Interpolation_Flag) { tempInterpolationMatrixShell1 = (*m_TARGET_SH_shell1) * (*m_Interpolation_SHT1_inv); tempInterpolationMatrixShell2 = (*m_TARGET_SH_shell2) * (*m_Interpolation_SHT2_inv); tempInterpolationMatrixShell3 = (*m_TARGET_SH_shell3) * (*m_Interpolation_SHT3_inv); } OdfPixelType odf(0.0); typename CoefficientImageType::PixelType coeffPixel(0.0); double P2,A,B2,B,P,alpha,beta,lambda, ER1, ER2; // iterate overall voxels of the gradient image region while( ! gradientInputImageIterator.IsAtEnd() ) { odf = 0.0; coeffPixel = 0.0; GradientVectorType b = gradientInputImageIterator.Get(); // calculate for each shell the corresponding b0-averages double shell1b0Norm =0; double shell2b0Norm =0; double shell3b0Norm =0; double b0average = 0; const unsigned int b0size = BZeroIndicies.size(); if(b0size == 1) { shell1b0Norm = b[BZeroIndicies[0]]; shell2b0Norm = b[BZeroIndicies[0]]; shell3b0Norm = b[BZeroIndicies[0]]; b0average = b[BZeroIndicies[0]]; }else if(b0size % 3 ==0) { for(unsigned int i = 0; i < b0size ; ++i) { if(i < b0size / 3) shell1b0Norm += b[BZeroIndicies[i]]; if(i >= b0size / 3 && i < (b0size / 3)*2) shell2b0Norm += b[BZeroIndicies[i]]; if(i >= (b0size / 3) * 2) shell3b0Norm += b[BZeroIndicies[i]]; } shell1b0Norm /= (b0size/3); shell2b0Norm /= (b0size/3); shell3b0Norm /= (b0size/3); b0average = (shell1b0Norm + shell2b0Norm+ shell3b0Norm)/3; }else { for(unsigned int i = 0; i = m_Threshold) ) { // Get the Signal-Value for each Shell at each direction (specified in the ShellIndicies Vector .. this direction corresponse to this shell...) /*//fsl fix --------------------------------------------------- for(int i = 0 ; i < Shell1Indiecies.size(); i++) DataShell1[i] = static_cast(b[Shell1Indiecies[i]]); for(int i = 0 ; i < Shell2Indiecies.size(); i++) DataShell2[i] = static_cast(b[Shell2Indiecies[i]]); for(int i = 0 ; i < Shell3Indiecies.size(); i++) DataShell3[i] = static_cast(b[Shell2Indiecies[i]]); // Normalize the Signal: Si/S0 S_S0Normalization(DataShell1, shell1b0Norm); S_S0Normalization(DataShell2, shell2b0Norm); S_S0Normalization(DataShell3, shell2b0Norm); *///fsl fix -------------------------------------------ende-- ///correct version for(unsigned int i = 0 ; i < Shell1Indiecies.size(); i++) DataShell1[i] = static_cast(b[Shell1Indiecies[i]]); for(unsigned int i = 0 ; i < Shell2Indiecies.size(); i++) DataShell2[i] = static_cast(b[Shell2Indiecies[i]]); for(unsigned int i = 0 ; i < Shell3Indiecies.size(); i++) DataShell3[i] = static_cast(b[Shell3Indiecies[i]]); // Normalize the Signal: Si/S0 S_S0Normalization(DataShell1, shell1b0Norm); S_S0Normalization(DataShell2, shell2b0Norm); S_S0Normalization(DataShell3, shell3b0Norm); if(m_Interpolation_Flag) { E1 = tempInterpolationMatrixShell1 * DataShell1; E2 = tempInterpolationMatrixShell2 * DataShell2; E3 = tempInterpolationMatrixShell3 * DataShell3; }else{ E1 = (DataShell1); E2 = (DataShell2); E3 = (DataShell3); } - //signal weighting according to information content - if(m_UseWeights) - { - E1 *= m_WeightShell1; - E2 *= m_WeightShell2; - E3 *= m_WeightShell3; - } - //Implements Eq. [19] and Fig. 4. Projection1(E1); Projection1(E2); Projection1(E3); //inqualities [31]. Taking the lograithm of th first tree inqualities //convert the quadratic inqualities to linear ones. Projection2(E1,E2,E3); for( unsigned int i = 0; i< m_MaxDirections; i++ ) { double e1 = E1.get(i); double e2 = E2.get(i); double e3 = E3.get(i); P2 = e2-e1*e1; A = (e3 -e1*e2) / ( 2* P2); B2 = A * A -(e1 * e3 - e2 * e2) /P2; B = 0; if(B2 > 0) B = sqrt(B2); P = 0; if(P2 > 0) P = sqrt(P2); alpha = A + B; beta = A - B; PValues.put(i, P); AlphaValues.put(i, alpha); BetaValues.put(i, beta); } Projection3(PValues, AlphaValues, BetaValues); for(unsigned int i = 0 ; i < m_MaxDirections; i++) { const double fac = (PValues[i] * 2 ) / (AlphaValues[i] - BetaValues[i]); lambda = 0.5 + 0.5 * std::sqrt(1 - fac * fac);; ER1 = std::fabs(lambda * (AlphaValues[i] - BetaValues[i]) + (BetaValues[i] - E1.get(i) )) + std::fabs(lambda * (AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] - E2.get(i) )) + std::fabs(lambda * (AlphaValues[i] * AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] * BetaValues[i] - E3.get(i) )); ER2 = std::fabs((1-lambda) * (AlphaValues[i] - BetaValues[i]) + (BetaValues[i] - E1.get(i) )) + std::fabs((1-lambda) * (AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] - E2.get(i) )) + std::fabs((1-lambda) * (AlphaValues[i] * AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] * BetaValues[i] - E3.get(i))); if(ER1 < ER2) LAValues.put(i, lambda); else LAValues.put(i, 1-lambda); } DoubleLogarithm(AlphaValues); DoubleLogarithm(BetaValues); vnl_vector SignalVector(element_product((LAValues) , (AlphaValues)-(BetaValues)) + (BetaValues)); vnl_vector coeffs((*m_CoeffReconstructionMatrix) *SignalVector ); // the first coeff is a fix value coeffs[0] = 1.0/(2.0*sqrt(M_PI)); coeffPixel = element_cast(coeffs).data_block(); // Cast the Signal-Type from double to float for the ODF-Image odf = element_cast( (*m_ODFSphericalHarmonicBasisMatrix) * coeffs ).data_block(); odf *= ((M_PI*4)/NODF); } // set ODF to ODF-Image coefficientImageIterator.Set(coeffPixel); odfOutputImageIterator.Set( odf ); ++odfOutputImageIterator; ++coefficientImageIterator; ++gradientInputImageIterator; } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter:: ComputeSphericalHarmonicsBasis(vnl_matrix * QBallReference, vnl_matrix *SHBasisOutput, int LOrder , vnl_matrix* LaplaciaBaltramiOutput, vnl_vector* SHOrderAssociation, vnl_matrix* SHEigenvalues) { // MITK_INFO << *QBallReference; for(unsigned int i=0; i< (*SHBasisOutput).rows(); i++) { for(int k = 0; k <= LOrder; k += 2) { for(int m =- k; m <= k; m++) { int j = ( k * k + k + 2 ) / 2 + m - 1; // Compute SHBasisFunctions if(QBallReference){ double phi = (*QBallReference)(0,i); double th = (*QBallReference)(1,i); (*SHBasisOutput)(i,j) = mitk::sh::Yj(m,k,th,phi); } // Laplacian Baltrami Order Association if(LaplaciaBaltramiOutput) (*LaplaciaBaltramiOutput)(j,j) = k*k*(k + 1)*(k+1); // SHEigenvalues with order Accosiation kj if(SHEigenvalues) (*SHEigenvalues)(j,j) = -k* (k+1); // Order Association if(SHOrderAssociation) (*SHOrderAssociation)[j] = k; } } } } template< class T, class TG, class TO, int L, int NOdfDirections> void DiffusionMultiShellQballReconstructionImageFilter ::ComputeReconstructionMatrix(IndiciesVector const & refVector) { typedef std::auto_ptr< vnl_matrix< double> > MatrixDoublePtr; typedef std::auto_ptr< vnl_vector< int > > VectorIntPtr; typedef std::auto_ptr< vnl_matrix_inverse< double > > InverseMatrixDoublePtr; int numberOfGradientDirections = refVector.size(); if( numberOfGradientDirections <= (((L+1)*(L+2))/2) || numberOfGradientDirections < 6 ) { itkExceptionMacro( << "At least (L+1)(L+2)/2 gradient directions for each shell are required; current : " << numberOfGradientDirections ); } CheckDuplicateDiffusionGradients(); const int LOrder = L; int NumberOfCoeffs = (int)(LOrder*LOrder + LOrder + 2.0)/2.0 + LOrder; MatrixDoublePtr SHBasisMatrix(new vnl_matrix(numberOfGradientDirections,NumberOfCoeffs)); SHBasisMatrix->fill(0.0); VectorIntPtr SHOrderAssociation(new vnl_vector(NumberOfCoeffs)); SHOrderAssociation->fill(0.0); MatrixDoublePtr LaplacianBaltrami(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); LaplacianBaltrami->fill(0.0); MatrixDoublePtr FRTMatrix(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); FRTMatrix->fill(0.0); MatrixDoublePtr SHEigenvalues(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); SHEigenvalues->fill(0.0); MatrixDoublePtr Q(new vnl_matrix(3, numberOfGradientDirections)); // Convert Cartesian to Spherical Coordinates refVector -> Q ComputeSphericalFromCartesian(Q.get(), refVector); // SHBasis-Matrix + LaplacianBaltrami-Matrix + SHOrderAssociationVector ComputeSphericalHarmonicsBasis(Q.get() ,SHBasisMatrix.get() , LOrder , LaplacianBaltrami.get(), SHOrderAssociation.get(), SHEigenvalues.get()); // Compute FunkRadon Transformation Matrix Associated to SHBasis Order lj for(int i=0; i(((SHBasisMatrix->transpose()) * (*SHBasisMatrix)) + (m_Lambda * (*LaplacianBaltrami)))); InverseMatrixDoublePtr pseudo_inv(new vnl_matrix_inverse((*temp))); MatrixDoublePtr inverse(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); (*inverse) = pseudo_inv->inverse(); const double factor = (1.0/(16.0*M_PI*M_PI)); MatrixDoublePtr SignalReonstructionMatrix (new vnl_matrix((*inverse) * (SHBasisMatrix->transpose()))); m_CoeffReconstructionMatrix = new vnl_matrix(( factor * ((*FRTMatrix) * ((*SHEigenvalues) * (*SignalReonstructionMatrix))) )); // SH Basis for ODF-reconstruction vnl_matrix_fixed* U = PointShell >::DistributePointShell(); for(int i=0; i( U->as_matrix() )); m_ODFSphericalHarmonicBasisMatrix = new vnl_matrix(NOdfDirections,NumberOfCoeffs); ComputeSphericalHarmonicsBasis(tempPtr.get(), m_ODFSphericalHarmonicBasisMatrix, LOrder); } template< class T, class TG, class TO, int L, int NOdfDirections> void DiffusionMultiShellQballReconstructionImageFilter ::ComputeSphericalFromCartesian(vnl_matrix * Q, IndiciesVector const & refShell) { for(unsigned int i = 0; i < refShell.size(); i++) { double x = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(0); double y = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(1); double z = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(2); double cart[3]; mitk::sh::Cart2Sph(x,y,z,cart); (*Q)(0,i) = cart[0]; (*Q)(1,i) = cart[1]; (*Q)(2,i) = cart[2]; } } template< class T, class TG, class TO, int L, int NODF> bool DiffusionMultiShellQballReconstructionImageFilter ::CheckDuplicateDiffusionGradients() { bool value = false; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; while(mapIterator != m_BValueMap.end()) { std::vector::const_iterator it1 = mapIterator->second.begin(); std::vector::const_iterator it2 = mapIterator->second.begin(); for(; it1 != mapIterator->second.end(); ++it1) { for(; it2 != mapIterator->second.end(); ++it2) { if(m_GradientDirectionContainer->ElementAt(*it1) == m_GradientDirectionContainer->ElementAt(*it2) && it1 != it2) { itkWarningMacro( << "Some of the Diffusion Gradients equal each other. Corresponding image data should be averaged before calling this filter." ); value = true; } } } ++mapIterator; } return value; } template< class T, class TG, class TO, int L, int NODF> std::vector DiffusionMultiShellQballReconstructionImageFilter ::GetAllDirections() { IndiciesVector directioncontainer; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; IndiciesVector shell1 = mapIterator->second; mapIterator++; IndiciesVector shell2 = mapIterator->second; mapIterator++; IndiciesVector shell3 = mapIterator->second; while(shell1.size()>0) { unsigned int wntIndex = shell1.back(); shell1.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } while(shell2.size()>0) { unsigned int wntIndex = shell2.back(); shell2.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } while(shell3.size()>0) { unsigned int wntIndex = shell3.back(); shell3.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } return directioncontainer; } // corresponding directions between shells (e.g. dir1_shell1 vs dir1_shell2) differ more than 1 degree. template< class T, class TG, class TO, int L, int NODF> bool DiffusionMultiShellQballReconstructionImageFilter ::CheckForDifferingShellDirections() { bool interp_flag = false; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; IndiciesVector shell1 = mapIterator->second; mapIterator++; IndiciesVector shell2 = mapIterator->second; mapIterator++; IndiciesVector shell3 = mapIterator->second; for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell1[i]), m_GradientDirectionContainer->ElementAt(shell2[i]))) <= 0.9998) {interp_flag=true; break;} for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell1[i]), m_GradientDirectionContainer->ElementAt(shell3[i]))) <= 0.9998) {interp_flag=true; break;} for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell2[i]), m_GradientDirectionContainer->ElementAt(shell3[i]))) <= 0.9998) {interp_flag=true; break;} return interp_flag; } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { std::locale C("C"); std::locale originalLocale = os.getloc(); os.imbue(C); Superclass::PrintSelf(os,indent); //os << indent << "OdfReconstructionMatrix: " << m_ReconstructionMatrix << std::endl; if ( m_GradientDirectionContainer ) { os << indent << "GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl; } else { os << indent << "GradientDirectionContainer: (Gradient directions not set)" << std::endl; } os << indent << "NumberOfGradientDirections: " << m_NumberOfGradientDirections << std::endl; os << indent << "NumberOfBaselineImages: " << m_NumberOfBaselineImages << std::endl; os << indent << "Threshold for reference B0 image: " << m_Threshold << std::endl; os << indent << "BValue: " << m_BValue << std::endl; os.imbue( originalLocale ); } } #endif // __itkDiffusionMultiShellQballReconstructionImageFilter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h b/Modules/DiffusionImaging/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h index f347bbf59f..22cba4bfe8 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h @@ -1,229 +1,219 @@ /*=================================================================== 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 __itkDiffusionMultiShellQballReconstructionImageFilter_h_ #define __itkDiffusionMultiShellQballReconstructionImageFilter_h_ #include namespace itk{ /** \class DiffusionMultiShellQballReconstructionImageFilter I. Aganj, C. Lenglet, G. Sapiro, E. Yacoub, K. Ugurbil, and N. Harel, “Reconstruction of the orientation distribution function in single and multiple shell q-ball imaging within constant solid angle,†Magnetic Resonance in Medicine, vol. 64, no. 2, pp. 554–566, 2010. */ template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NOrderL, int NrOdfDirections> class DiffusionMultiShellQballReconstructionImageFilter : public ImageToImageFilter< Image< TReferenceImagePixelType, 3 >, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > { public: typedef DiffusionMultiShellQballReconstructionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< TReferenceImagePixelType, 3>, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > Superclass; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef TReferenceImagePixelType ReferencePixelType; /** GradientImageType * (e.g. type short)*/ typedef TGradientImagePixelType GradientPixelType; /** GradientImageType * 3D VectorImage containing GradientPixelTypes */ typedef VectorImage< GradientPixelType, 3 > GradientImagesType; /** ODF PixelType */ typedef Vector< TOdfPixelType, NrOdfDirections > OdfPixelType; /** ODF ImageType */ typedef Image< OdfPixelType, 3 > OdfImageType; /** BzeroImageType */ typedef Image< TOdfPixelType, 3 > BZeroImageType; /** Container to hold gradient directions of the 'n' DW measurements */ typedef VectorContainer< unsigned int, vnl_vector_fixed< double, 3 > > GradientDirectionContainerType; typedef Image< Vector< TOdfPixelType, (NOrderL*NOrderL + NOrderL + 2)/2 + NOrderL >, 3 > CoefficientImageType; typedef std::map > BValueMap; typedef std::map >::iterator BValueMapIteraotr; typedef std::vector IndiciesVector; // --------------------------------------------------------------------------------------------// /** Method for creation through the object factory. */ - itkNewMacro(Self); + itkNewMacro(Self) /** Runtime information support. */ - itkTypeMacro(DiffusionMultiShellQballReconstructionImageFilter, ImageToImageFilter); + itkTypeMacro(DiffusionMultiShellQballReconstructionImageFilter, ImageToImageFilter) /** Get reference image */ virtual typename Superclass::InputImageType * GetInputImage() { return ( static_cast< typename Superclass::InputImageType *>(this->ProcessObject::GetInput(0)) ); } /** Replaces the Input method. * Var vols = mitk::DiffusionImage * ----------------------------------------------------- * GradientDirectionContainerType-Input gradientDirectionContainer (e.g. vols->GetDirections) * GradientImagesType-Input gradientImage (e.g. vols->GetVectorImage) * float-Input bvalue (e.g. vols->GetB_Value) */ void SetGradientImage( GradientDirectionContainerType * gradientDirectionContainer, const GradientImagesType *gradientImage , float bvalue);//, std::vector listOfUserSelctedBValues ); /** Set a BValue Map (key = bvalue, value = indicies splittet for each shell) * If the input image containes more than three q-shells * (e.g. b-Values of 0, 1000, 2000, 3000, 4000, ...). * For the Analytical-Reconstruction it is needed to set a * BValue Map containing three shells in an arithmetic series * (e.g. 0, 1000, 2000, 3000). */ inline void SetBValueMap(BValueMap map){this->m_BValueMap = map;} /** Threshold on the reference image data. The output ODF will be a null * pdf for pixels in the reference image that have a value less than this * threshold. */ - itkSetMacro( Threshold, ReferencePixelType ); - itkGetMacro( Threshold, ReferencePixelType ); + itkSetMacro( Threshold, ReferencePixelType ) + itkGetMacro( Threshold, ReferencePixelType ) - itkGetMacro( CoefficientImage, typename CoefficientImageType::Pointer ); + itkGetMacro( CoefficientImage, typename CoefficientImageType::Pointer ) /** Return non-diffusion weighted images */ - itkGetMacro( BZeroImage, typename BZeroImageType::Pointer); + itkGetMacro( BZeroImage, typename BZeroImageType::Pointer) /** Factor for Laplacian-Baltrami smoothing of the SH-coefficients*/ - itkSetMacro( Lambda, double ); - itkGetMacro( Lambda, double ); - - itkSetMacro( UseWeights, bool); - itkGetMacro( UseWeights, bool); + itkSetMacro( Lambda, double ) + itkGetMacro( Lambda, double ) protected: DiffusionMultiShellQballReconstructionImageFilter(); - ~DiffusionMultiShellQballReconstructionImageFilter() { }; + ~DiffusionMultiShellQballReconstructionImageFilter() { } void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, int NumberOfThreads ); private: enum ReconstructionType { Mode_Analytical3Shells, Mode_NumericalNShells, Mode_Standard1Shell }; ReconstructionType m_ReconstructionType; // Interpolation bool m_Interpolation_Flag; vnl_matrix< double > * m_Interpolation_SHT1_inv; vnl_matrix< double > * m_Interpolation_SHT2_inv; vnl_matrix< double > * m_Interpolation_SHT3_inv; vnl_matrix< double > * m_TARGET_SH_shell1; vnl_matrix< double > * m_TARGET_SH_shell2; vnl_matrix< double > * m_TARGET_SH_shell3; unsigned int m_MaxDirections; vnl_matrix< double > * m_CoeffReconstructionMatrix; vnl_matrix< double > * m_ODFSphericalHarmonicBasisMatrix; /** container to hold gradient directions */ GradientDirectionContainerType::Pointer m_GradientDirectionContainer; /** Number of gradient measurements */ unsigned int m_NumberOfGradientDirections; /** Number of baseline images */ unsigned int m_NumberOfBaselineImages; /** Threshold on the reference image data */ ReferencePixelType m_Threshold; typename BZeroImageType::Pointer m_BZeroImage; typename CoefficientImageType::Pointer m_CoefficientImage; float m_BValue; BValueMap m_BValueMap; double m_Lambda; bool m_IsHemisphericalArrangementOfGradientDirections; bool m_IsArithmeticProgession; - bool m_UseWeights; - - double m_WeightShell1; - double m_WeightShell2; - double m_WeightShell3; - - void ComputeReconstructionMatrix(IndiciesVector const & refVector); void ComputeODFSHBasis(); bool CheckDuplicateDiffusionGradients(); bool CheckForDifferingShellDirections(); IndiciesVector GetAllDirections(); void ComputeSphericalHarmonicsBasis(vnl_matrix* QBallReference, vnl_matrix* SHBasisOutput, int Lorder , vnl_matrix* LaplaciaBaltramiOutput =0 , vnl_vector* SHOrderAssociation =0 , vnl_matrix * SHEigenvalues =0); void Normalize(OdfPixelType & odf ); void S_S0Normalization( vnl_vector & vec, double b0 = 0 ); void DoubleLogarithm(vnl_vector & vec); double CalculateThreashold(const double value, const double delta); void Projection1(vnl_vector & vec, double delta = 0.01); void Projection2( vnl_vector & E1, vnl_vector & E2, vnl_vector & E3, double delta = 0.01); void Projection3( vnl_vector & A, vnl_vector & alpha, vnl_vector & beta, double delta = 0.01); void StandardOneShellReconstruction(const OutputImageRegionType& outputRegionForThread); void AnalyticalThreeShellReconstruction(const OutputImageRegionType& outputRegionForThread); void NumericalNShellReconstruction(const OutputImageRegionType& outputRegionForThread); void GenerateAveragedBZeroImage(const OutputImageRegionType& outputRegionForThread); void ComputeSphericalFromCartesian(vnl_matrix * Q, const IndiciesVector & refShell); //------------------------- VNL-function ------------------------------------ template vnl_vector< WntValue> element_cast (vnl_vector< CurrentValue> const& v1) { vnl_vector result(v1.size()); for(unsigned int i = 0 ; i < v1.size(); i++) result[i] = static_cast< WntValue>(v1[i]); return result; } template double dot (vnl_vector_fixed< type ,3> const& v1, vnl_vector_fixed< type ,3 > const& v2 ) { double result = (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]) / (v1.two_norm() * v2.two_norm()); return result ; } }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionMultiShellQballReconstructionImageFilter.cpp" #endif #endif //__itkDiffusionMultiShellQballReconstructionImageFilter_h_ diff --git a/Modules/DiffusionImaging/DiffusionCore/DicomImport/mitkSiemensMosaicDicomDiffusionImageHeaderReader.cpp b/Modules/DiffusionImaging/DiffusionCore/DicomImport/mitkSiemensMosaicDicomDiffusionImageHeaderReader.cpp index d48931883b..e1b7904b0b 100644 --- a/Modules/DiffusionImaging/DiffusionCore/DicomImport/mitkSiemensMosaicDicomDiffusionImageHeaderReader.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/DicomImport/mitkSiemensMosaicDicomDiffusionImageHeaderReader.cpp @@ -1,243 +1,251 @@ /*=================================================================== 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 "mitkSiemensMosaicDicomDiffusionImageHeaderReader.h" #include "gdcmGlobal.h" //#include "gdcmVersion.h" #include "gdcmFile.h" #include "gdcmImageReader.h" #include "gdcmDict.h" #include "gdcmDicts.h" #include "gdcmDictEntry.h" #include "gdcmDictEntry.h" #include "gdcmDict.h" #include "gdcmFile.h" #include "gdcmSerieHelper.h" mitk::SiemensMosaicDicomDiffusionImageHeaderReader::SiemensMosaicDicomDiffusionImageHeaderReader() { } mitk::SiemensMosaicDicomDiffusionImageHeaderReader::~SiemensMosaicDicomDiffusionImageHeaderReader() { } int mitk::SiemensMosaicDicomDiffusionImageHeaderReader::ExtractSiemensDiffusionInformation( std::string tagString, std::string nameString, std::vector& valueArray ) { std::string::size_type atPosition = tagString.find( nameString ); if ( atPosition == std::string::npos) { return 0; } else { std::string infoAsString = tagString.substr( atPosition, tagString.size()-atPosition+1 ); const char * infoAsCharPtr = infoAsString.c_str(); int vm = *(infoAsCharPtr+64); std::string vr = infoAsString.substr( 68, 4 ); //int syngodt = *(infoAsCharPtr+72); //int nItems = *(infoAsCharPtr+76); //int localDummy = *(infoAsCharPtr+80); int offset = 84; for (int k = 0; k < vm; k++) { int itemLength = *(infoAsCharPtr+offset+4); int strideSize = static_cast (ceil(static_cast(itemLength)/4) * 4); std::string valueString = infoAsString.substr( offset+16, itemLength ); valueArray.push_back( atof(valueString.c_str()) ); offset += 16+strideSize; } return vm; } } // do the work void mitk::SiemensMosaicDicomDiffusionImageHeaderReader::Update() { // check if there are filenames if(m_DicomFilenames.size()) { // adapted from namic-sandbox // DicomToNrrdConverter.cxx VolumeReaderType::DictionaryArrayRawPointer inputDict = m_VolumeReader->GetMetaDataDictionaryArray(); ReadPublicTags(); int mMosaic = 0; // number of raws in each mosaic block; int nMosaic = 0; // number of columns in each mosaic block std::cout << "Siemens SliceMosaic......" << std::endl; m_SliceOrderIS = false; // for siemens mosaic image, figure out mosaic slice order from 0029|1010 std::string tag; tag.clear(); gdcm::ImageReader reader; reader.SetFileName( m_DicomFilenames[0].c_str() ); if( !reader.Read() ) { itkExceptionMacro(<< "Cannot read requested file"); } const gdcm::File &f = reader.GetFile(); const gdcm::DataSet &ds = f.GetDataSet(); // gdcm::DataSet ds = header0->GetDataSet(); gdcm::DataSet::ConstIterator it = ds.Begin(); // Copy of the header->content // copy information stored in 0029,1010 into a string for parsing for(; it != ds.End(); ++it) { const gdcm::DataElement &ref = *it; if (ref.GetTag() == gdcm::Tag(0x0029,0x1010)) { tag = std::string(ref.GetByteValue()->GetPointer(),ref.GetByteValue()->GetLength()); } } // parse SliceNormalVector from 0029,1010 tag std::vector valueArray(0); int nItems = ExtractSiemensDiffusionInformation(tag, "SliceNormalVector", valueArray); if (nItems != 3) // did not find enough information { std::cout << "Warning: Cannot find complete information on SliceNormalVector in 0029|1010\n"; std::cout << " Slice order may be wrong.\n"; } else if (valueArray[2] > 0) { m_SliceOrderIS = true; } // parse NumberOfImagesInMosaic from 0029,1010 tag valueArray.resize(0); nItems = ExtractSiemensDiffusionInformation(tag, "NumberOfImagesInMosaic", valueArray); + + // Hot-Fix for Bug 14459, no valid Tag (0029,1010) + if (valueArray.size() < 1) // NO data was found + { + MITK_ERROR << "MOSAIC Image has no valid tag (0029,1010). ABORTING" << std::endl; + mitkThrow() << "MOSAIC Image has no valid tag (0029,1010). ABORTING"; + return; + } if (nItems == 0) // did not find enough information { std::cout << "Warning: Cannot find complete information on NumberOfImagesInMosaic in 0029|1010\n"; std::cout << " Resulting image may contain empty slices.\n"; } else { this->m_Output->nSliceInVolume = static_cast(valueArray[0]); mMosaic = static_cast (ceil(sqrt(valueArray[0]))); nMosaic = mMosaic; } std::cout << "Mosaic in " << mMosaic << " X " << nMosaic << " blocks (total number of blocks = " << valueArray[0] << ").\n"; ReadPublicTags2(); int nStride = 1; std::cout << "Data in Siemens Mosaic Format\n"; //nVolume = nSlice; //std::cout << "Number of Volume: " << nVolume << std::endl; std::cout << "Number of Slices in each volume: " << this->m_Output->nSliceInVolume << std::endl; nStride = 1; for (int k = 0; k < m_nSlice; k += nStride ) { gdcm::ImageReader reader; reader.SetFileName( m_DicomFilenames[0].c_str() ); if( !reader.Read() ) { itkExceptionMacro(<< "Cannot read requested file"); } const gdcm::File &f = reader.GetFile(); const gdcm::DataSet &ds = f.GetDataSet(); // gdcm::DataSet ds = header0->GetDataSet(); gdcm::DataSet::ConstIterator it = ds.Begin(); // Copy of the header->content // copy information stored in 0029,1010 into a string for parsing for(; it != ds.End(); ++it) { const gdcm::DataElement &ref = *it; if (ref.GetTag() == gdcm::Tag(0x0029,0x1010)) { tag = std::string(ref.GetByteValue()->GetPointer(),ref.GetByteValue()->GetLength()); } } // parse B_value from 0029,1010 tag std::vector valueArray(0); vnl_vector_fixed vect3d; int nItems = ExtractSiemensDiffusionInformation(tag, "B_value", valueArray); if (nItems != 1 || valueArray[0] == 0) // did not find enough information { MITK_INFO << "Reading diffusion info from 0019|100c and 0019|100e tags"; tag.clear(); bool success = itk::ExposeMetaData ( *(*inputDict)[0], "0019|100c", tag ); if(success) { this->m_Output->bValue = atof( tag.c_str() ); tag.clear(); success = itk::ExposeMetaData ( *(*inputDict)[k], "0019|100e", tag); if(success) { memcpy( &vect3d[0], tag.c_str()+0, 8 ); memcpy( &vect3d[1], tag.c_str()+8, 8 ); memcpy( &vect3d[2], tag.c_str()+16, 8 ); vect3d.normalize(); this->m_Output->DiffusionVector = vect3d; TransformGradients(); MITK_INFO << "BV: " << this->m_Output->bValue; MITK_INFO << " GD: " << this->m_Output->DiffusionVector << std::endl; continue; } } } else { MITK_INFO << "Reading diffusion info from 0029|1010 tags"; this->m_Output->bValue = valueArray[0]; // parse DiffusionGradientDirection from 0029,1010 tag valueArray.resize(0); nItems = ExtractSiemensDiffusionInformation(tag, "DiffusionGradientDirection", valueArray); if (nItems == 3) { vect3d[0] = valueArray[0]; vect3d[1] = valueArray[1]; vect3d[2] = valueArray[2]; vect3d.normalize(); this->m_Output->DiffusionVector = vect3d; TransformGradients(); MITK_INFO << "BV: " << this->m_Output->bValue; MITK_INFO << " GD: " << this->m_Output->DiffusionVector; continue; } } MITK_ERROR << "No diffusion info found, assuming BASELINE" << std::endl; this->m_Output->bValue = 0.0; vect3d.fill( 0.0 ); this->m_Output->DiffusionVector = vect3d; } } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkSphereInterpolator.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkSphereInterpolator.cpp new file mode 100644 index 0000000000..ae24059344 --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkSphereInterpolator.cpp @@ -0,0 +1,173 @@ +/*=================================================================== + +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 "mitkSphereInterpolator.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +static const std::string BaryCoordsFileName = "FiberTrackingLUTBaryCoords.bin"; +static const std::string IndicesFileName = "FiberTrackingLUTIndices.bin"; + +SphereInterpolator::SphereInterpolator(const string& lutPath) +{ + m_ValidState = true; + if (lutPath.length()==0) + { + if (!LoadLookuptables()) + { + m_ValidState = false; + return; + } + } + else + { + if (!LoadLookuptables(lutPath)) + { + m_ValidState = false; + return; + } + } + + size = 301; + sN = (size-1)/2; + nverts = QBALL_ODFSIZE; + beta = 0.5; + + inva = (sqrt(1+beta)-sqrt(beta)); + b = 1/(1-sqrt(1/beta + 1)); +} + +SphereInterpolator::~SphereInterpolator() +{ + +} + +bool SphereInterpolator::LoadLookuptables(const string& lutPath) +{ + MITK_INFO << "SphereInterpolator: loading lookuptables from custom path: " << lutPath; + + string path = lutPath; path.append(BaryCoordsFileName); + std::ifstream BaryCoordsStream; + BaryCoordsStream.open(path.c_str(), ios::in | ios::binary); + MITK_INFO << "SphereInterpolator: 1 " << path; + if (!BaryCoordsStream.is_open()) + { + MITK_INFO << "SphereInterpolator: could not load FiberTrackingLUTBaryCoords.bin from " << path; + return false; + } + + ifstream IndicesStream; + path = lutPath; path.append("FiberTrackingLUTIndices.bin"); + IndicesStream.open(path.c_str(), ios::in | ios::binary); + MITK_INFO << "SphereInterpolator: 1 " << path; + if (!IndicesStream.is_open()) + { + MITK_INFO << "SphereInterpolator: could not load FiberTrackingLUTIndices.bin from " << path; + return false; + } + + if (LoadLookuptables(BaryCoordsStream, IndicesStream)) + { + MITK_INFO << "SphereInterpolator: first and second lut loaded successfully"; + return true; + } + + return false; +} + +bool SphereInterpolator::LoadLookuptables() +{ + MITK_INFO << "SphereInterpolator: loading lookuptables"; + + mitk::Module* module = mitk::GetModuleContext()->GetModule(); + mitk::ModuleResource BaryCoordsRes = module->GetResource(BaryCoordsFileName); + if (!BaryCoordsRes.IsValid()) + { + MITK_INFO << "Could not retrieve resource " << BaryCoordsFileName; + return false; + } + + mitk::ModuleResource IndicesRes = module->GetResource(IndicesFileName); + if (!IndicesRes) + { + MITK_INFO << "Could not retrieve resource " << IndicesFileName; + return false; + } + + mitk::ModuleResourceStream BaryCoordsStream(BaryCoordsRes, std::ios_base::binary); + mitk::ModuleResourceStream IndicesStream(IndicesRes, std::ios_base::binary); + return LoadLookuptables(BaryCoordsStream, IndicesStream); +} + +bool SphereInterpolator::LoadLookuptables(std::istream& BaryCoordsStream, std::istream& IndicesStream) +{ + if (BaryCoordsStream) + { + try + { + float tmp; + BaryCoordsStream.seekg (0, ios::beg); + while (!BaryCoordsStream.eof()) + { + BaryCoordsStream.read((char *)&tmp, sizeof(tmp)); + barycoords.push_back(tmp); + } + } + catch (const std::exception& e) + { + MITK_INFO << e.what(); + } + } + else + { + MITK_INFO << "SphereInterpolator: could not load FiberTrackingLUTBaryCoords.bin"; + return false; + } + + if (IndicesStream) + { + try + { + int tmp; + IndicesStream.seekg (0, ios::beg); + while (!IndicesStream.eof()) + { + IndicesStream.read((char *)&tmp, sizeof(tmp)); + indices.push_back(tmp); + } + } + catch (const std::exception& e) + { + MITK_INFO << e.what(); + } + } + else + { + MITK_INFO << "SphereInterpolator: could not load FiberTrackingLUTIndices.bin"; + return false; + } + + return true; +} diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkSphereInterpolator.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkSphereInterpolator.h index 709e1a25d8..6dea78faf4 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkSphereInterpolator.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkSphereInterpolator.h @@ -1,338 +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 _SPHEREINTERPOLATOR #define _SPHEREINTERPOLATOR #include -#include -#include -#include -#include -#include -#include -#include -#include + +#include + +#include using namespace std; /** -* \brief Lookuptable based trilinear interpolation of spherically arranged scalar values. */ - + * \brief Lookuptable based trilinear interpolation of spherically arranged scalar values. + */ class FiberTracking_EXPORT SphereInterpolator { public: int size; // size of LUT int sN; // (sizeofLUT-1)/2 int nverts; // number of data vertices float beta; float inva; float b; bool m_ValidState; vector< float > barycoords; vector< int > indices; vnl_vector_fixed< int, 3 > idx; vnl_vector_fixed< float, 3 > interpw; - SphereInterpolator(string lutPath) - { - m_ValidState = true; - if (lutPath.length()==0) - { - if (!LoadLookuptables()) - { - m_ValidState = false; - return; - } - } - else - { - if (!LoadLookuptables(lutPath)) - { - m_ValidState = false; - return; - } - } - - size = 301; - sN = (size-1)/2; - nverts = QBALL_ODFSIZE; - beta = 0.5; - - inva = (sqrt(1+beta)-sqrt(beta)); - b = 1/(1-sqrt(1/beta + 1)); - } + SphereInterpolator(const string& lutPath); - inline bool IsInValidState() + inline bool IsInValidState() const { return m_ValidState; } - ~SphereInterpolator() - { - - } + ~SphereInterpolator(); - inline void getInterpolation(vnl_vector_fixed N) + inline void getInterpolation(const vnl_vector_fixed& N) { float nx = N[0]; float ny = N[1]; float nz = N[2]; if (nz > 0.5) { int x = float2int(nx); int y = float2int(ny); int i = 3*6*(x+y*size); // (:,1,x,y) idx[0] = indices[i]; idx[1] = indices[i+1]; idx[2] = indices[i+2]; interpw[0] = barycoords[i]; interpw[1] = barycoords[i+1]; interpw[2] = barycoords[i+2]; return; } if (nz < -0.5) { int x = float2int(nx); int y = float2int(ny); int i = 3*(1+6*(x+y*size)); // (:,2,x,y) idx[0] = indices[i]; idx[1] = indices[i+1]; idx[2] = indices[i+2]; interpw[0] = barycoords[i]; interpw[1] = barycoords[i+1]; interpw[2] = barycoords[i+2]; return; } if (nx > 0.5) { int z = float2int(nz); int y = float2int(ny); int i = 3*(2+6*(z+y*size)); // (:,2,x,y) idx[0] = indices[i]; idx[1] = indices[i+1]; idx[2] = indices[i+2]; interpw[0] = barycoords[i]; interpw[1] = barycoords[i+1]; interpw[2] = barycoords[i+2]; return; } if (nx < -0.5) { int z = float2int(nz); int y = float2int(ny); int i = 3*(3+6*(z+y*size)); // (:,2,x,y) idx[0] = indices[i]; idx[1] = indices[i+1]; idx[2] = indices[i+2]; interpw[0] = barycoords[i]; interpw[1] = barycoords[i+1]; interpw[2] = barycoords[i+2]; return; } if (ny > 0) { int x = float2int(nx); int z = float2int(nz); int i = 3*(4+6*(x+z*size)); // (:,1,x,y) idx[0] = indices[i]; idx[1] = indices[i+1]; idx[2] = indices[i+2]; interpw[0] = barycoords[i]; interpw[1] = barycoords[i+1]; interpw[2] = barycoords[i+2]; return; } else { int x = float2int(nx); int z = float2int(nz); int i = 3*(5+6*(x+z*size)); // (:,1,x,y) idx[0] = indices[i]; idx[1] = indices[i+1]; idx[2] = indices[i+2]; interpw[0] = barycoords[i]; interpw[1] = barycoords[i+1]; interpw[2] = barycoords[i+2]; return; } } protected: - bool LoadLookuptables(string lutPath) - { - MITK_INFO << "SphereInterpolator: loading lookuptables from custom path: " << lutPath; + bool LoadLookuptables(const string& lutPath); - string path = lutPath; path.append("FiberTrackingLUTBaryCoords.bin"); - std::ifstream BaryCoordsStream; - BaryCoordsStream.open(path.c_str(), ios::in | ios::binary); - MITK_INFO << "SphereInterpolator: 1 " << path; - if (BaryCoordsStream.is_open()) - { - try - { - float tmp; - BaryCoordsStream.seekg (0, ios::beg); - MITK_INFO << "SphereInterpolator: 2"; - while (!BaryCoordsStream.eof()) - { - BaryCoordsStream.read((char *)&tmp, sizeof(tmp)); - barycoords.push_back(tmp); - } - MITK_INFO << "SphereInterpolator: 3"; - BaryCoordsStream.close(); - } - catch (const std::exception& e) - { - MITK_INFO << e.what(); - } - } - else - { - MITK_INFO << "SphereInterpolator: could not load FiberTrackingLUTBaryCoords.bin from " << path; - return false; - } - MITK_INFO << "SphereInterpolator: first lut loaded successfully"; + bool LoadLookuptables(); - ifstream IndicesStream; - path = lutPath; path.append("FiberTrackingLUTIndices.bin"); - IndicesStream.open(path.c_str(), ios::in | ios::binary); - MITK_INFO << "SphereInterpolator: 1 " << path; - if (IndicesStream.is_open()) - { - try - { - int tmp; - IndicesStream.seekg (0, ios::beg); - MITK_INFO << "SphereInterpolator: 2"; - while (!IndicesStream.eof()) - { - IndicesStream.read((char *)&tmp, sizeof(tmp)); - indices.push_back(tmp); - } - MITK_INFO << "SphereInterpolator: 3"; - IndicesStream.close(); - } - catch (const std::exception& e) - { - MITK_INFO << e.what(); - } - } - else - { - MITK_INFO << "SphereInterpolator: could not load FiberTrackingLUTIndices.bin from " << path; - return false; - } - MITK_INFO << "SphereInterpolator: second lut loaded successfully"; - - return true; - } - - bool LoadLookuptables() - { - MITK_INFO << "SphereInterpolator: loading lookuptables"; - QString applicationDir = QCoreApplication::applicationDirPath(); - applicationDir.append("/"); - mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( applicationDir.toStdString().c_str(), false ); - applicationDir.append("../"); - mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( applicationDir.toStdString().c_str(), false ); - applicationDir.append("../../"); - mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( applicationDir.toStdString().c_str(), false ); - applicationDir = QCoreApplication::applicationDirPath(); - applicationDir.append("/bin/"); - mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( applicationDir.toStdString().c_str(), false ); - - string lutPath = mitk::StandardFileLocations::GetInstance()->FindFile("FiberTrackingLUTBaryCoords.bin"); - std::ifstream BaryCoordsStream; - BaryCoordsStream.open(lutPath.c_str(), ios::in | ios::binary); - if (BaryCoordsStream.is_open()) - { - try - { - float tmp; - BaryCoordsStream.seekg (0, ios::beg); - while (!BaryCoordsStream.eof()) - { - BaryCoordsStream.read((char *)&tmp, sizeof(tmp)); - barycoords.push_back(tmp); - } - BaryCoordsStream.close(); - } - catch (const std::exception& e) - { - MITK_INFO << e.what(); - } - } - else - { - MITK_INFO << "SphereInterpolator: could not load FiberTrackingLUTBaryCoords.bin from " << lutPath; - return false; - } + bool LoadLookuptables(std::istream& BaryCoordsStream, std::istream& IndicesStream); - ifstream IndicesStream; - lutPath = mitk::StandardFileLocations::GetInstance()->FindFile("FiberTrackingLUTIndices.bin"); - IndicesStream.open(lutPath.c_str(), ios::in | ios::binary); - if (IndicesStream.is_open()) - { - try - { - int tmp; - IndicesStream.seekg (0, ios::beg); - while (!IndicesStream.eof()) - { - IndicesStream.read((char *)&tmp, sizeof(tmp)); - indices.push_back(tmp); - } - IndicesStream.close(); - } - catch (const std::exception& e) - { - MITK_INFO << e.what(); - } - } - else - { - MITK_INFO << "SphereInterpolator: could not load FiberTrackingLUTIndices.bin from " << lutPath; - return false; - } - - return true; - } - - inline float invrescale(float f) + inline float invrescale(float f) const { float x = (fabs(f)-b)*inva; if (f>0) return (x*x-beta); else return beta - x*x; } - inline int float2int(float x) + inline int float2int(float x) const { return int((invrescale(x)+1)*sN-0.5); } - }; #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.cpp index d9e7b19764..d8eebc61dd 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.cpp @@ -1,252 +1,254 @@ /*=================================================================== 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 "itkFibersFromPlanarFiguresFilter.h" #define _USE_MATH_DEFINES #include // MITK #include #include #include #include #include #include #include #include #include // ITK #include #include #include #include // MISC #include #include #include #include namespace itk{ FibersFromPlanarFiguresFilter::FibersFromPlanarFiguresFilter() : m_Density(1000) , m_FiberSampling(5) , m_Tension(0) , m_Continuity(0) , m_Bias(0) , m_FiberDistribution(DISTRIBUTE_UNIFORM) , m_Variance(0.1) { } FibersFromPlanarFiguresFilter::~FibersFromPlanarFiguresFilter() { } void FibersFromPlanarFiguresFilter::GeneratePoints() { Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); randGen->SetSeed((unsigned int)0); m_2DPoints.clear(); int count = 0; while (count < m_Density) { mitk::Vector2D p; switch (m_FiberDistribution) { case DISTRIBUTE_GAUSSIAN: p[0] = randGen->GetNormalVariate(0, m_Variance); p[1] = randGen->GetNormalVariate(0, m_Variance); break; default: p[0] = randGen->GetUniformVariate(-1, 1); p[1] = randGen->GetUniformVariate(-1, 1); } if (sqrt(p[0]*p[0]+p[1]*p[1]) <= 1) { m_2DPoints.push_back(p); count++; } } } // perform global tracking void FibersFromPlanarFiguresFilter::GenerateData() { // check if enough fiducials are available for (int i=0; i m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); vector< mitk::PlanarEllipse::Pointer > bundle = m_Fiducials.at(i); vector< unsigned int > fliplist; if (i container = vtkSmartPointer::New(); mitk::PlanarEllipse::Pointer figure = bundle.at(0); mitk::Point2D p0 = figure->GetControlPoint(0); mitk::Point2D p1 = figure->GetControlPoint(1); mitk::Point2D p2 = figure->GetControlPoint(2); mitk::Point2D p3 = figure->GetControlPoint(3); float r1 = p0.EuclideanDistanceTo(p1); float r2 = p0.EuclideanDistanceTo(p2); mitk::Vector2D eDir = p1-p0; eDir.Normalize(); mitk::Vector2D tDir = p3-p0; tDir.Normalize(); // apply twist vnl_matrix_fixed tRot; tRot[0][0] = tDir[0]; tRot[1][1] = tRot[0][0]; tRot[1][0] = sin(acos(tRot[0][0])); tRot[0][1] = -tRot[1][0]; if (tDir[1]<0) tRot.inplace_transpose(); m_2DPoints[j].SetVnlVector(tRot*m_2DPoints[j].GetVnlVector()); // apply new ellipse shape vnl_vector_fixed< float, 2 > newP; newP[0] = m_2DPoints.at(j)[0]; newP[1] = m_2DPoints.at(j)[1]; float alpha = acos(eDir[0]); if (eDir[1]>0) alpha = 2*M_PI-alpha; vnl_matrix_fixed eRot; eRot[0][0] = cos(alpha); eRot[1][1] = eRot[0][0]; eRot[1][0] = sin(alpha); eRot[0][1] = -eRot[1][0]; newP = eRot*newP; newP[0] *= r1; newP[1] *= r2; newP = eRot.transpose()*newP; p0[0] += newP[0]; p0[1] += newP[1]; const mitk::Geometry2D* pfgeometry = figure->GetGeometry2D(); const mitk::PlaneGeometry* planeGeo = dynamic_cast(pfgeometry); mitk::Point3D w, wc; planeGeo->Map(p0, w); wc = figure->GetWorldControlPoint(0); vtkIdType id = m_VtkPoints->InsertNextPoint(w.GetDataPointer()); container->GetPointIds()->InsertNextId(id); vnl_vector_fixed< float, 3 > n = planeGeo->GetNormalVnl(); for (int k=1; kGetControlPoint(0); p1 = figure->GetControlPoint(1); p2 = figure->GetControlPoint(2); p3 = figure->GetControlPoint(3); r1 = p0.EuclideanDistanceTo(p1); r2 = p0.EuclideanDistanceTo(p2); eDir = p1-p0; eDir.Normalize(); mitk::Vector2D tDir2 = p3-p0; tDir2.Normalize(); mitk::Vector2D temp; temp.SetVnlVector(tRot.transpose() * tDir2.GetVnlVector()); // apply twist tRot[0][0] = tDir[0]*tDir2[0] + tDir[1]*tDir2[1]; tRot[1][1] = tRot[0][0]; tRot[1][0] = sin(acos(tRot[0][0])); tRot[0][1] = -tRot[1][0]; if (temp[1]<0) tRot.inplace_transpose(); m_2DPoints[j].SetVnlVector(tRot*m_2DPoints[j].GetVnlVector()); tDir = tDir2; // apply new ellipse shape newP[0] = m_2DPoints.at(j)[0]; newP[1] = m_2DPoints.at(j)[1]; - alpha = acos(eDir[0]); - if (eDir[1]>0) - alpha = 2*M_PI-alpha; - eRot[0][0] = cos(alpha); - eRot[1][1] = eRot[0][0]; - eRot[1][0] = sin(alpha); - eRot[0][1] = -eRot[1][0]; - newP = eRot*newP; - newP[0] *= r1; - newP[1] *= r2; - newP = eRot.transpose()*newP; + // calculate normal mitk::Geometry2D* pfgeometry = const_cast(figure->GetGeometry2D()); mitk::PlaneGeometry* planeGeo = dynamic_cast(pfgeometry); mitk::Vector3D perp = wc-planeGeo->ProjectPointOntoPlane(wc); perp.Normalize(); vnl_vector_fixed< float, 3 > n2 = planeGeo->GetNormalVnl(); wc = figure->GetWorldControlPoint(0); // is flip needed? if (dot_product(perp.GetVnlVector(),n2)>0 && dot_product(n,n2)<=0.00001) newP[0] *= -1; if (fliplist.at(k)>0) newP[0] *= -1; n = n2; + alpha = acos(eDir[0]); + if (eDir[1]>0) + alpha = 2*M_PI-alpha; + eRot[0][0] = cos(alpha); + eRot[1][1] = eRot[0][0]; + eRot[1][0] = sin(alpha); + eRot[0][1] = -eRot[1][0]; + newP = eRot*newP; + newP[0] *= r1; + newP[1] *= r2; + newP = eRot.transpose()*newP; + p0[0] += newP[0]; p0[1] += newP[1]; mitk::Point3D w; planeGeo->Map(p0, w); vtkIdType id = m_VtkPoints->InsertNextPoint(w.GetDataPointer()); container->GetPointIds()->InsertNextId(id); } m_VtkCellArray->InsertNextCell(container); } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(m_VtkPoints); fiberPolyData->SetLines(m_VtkCellArray); mitk::FiberBundleX::Pointer mitkFiberBundle = mitk::FiberBundleX::New(fiberPolyData); mitkFiberBundle->DoFiberSmoothing(m_FiberSampling, m_Tension, m_Continuity, m_Bias); m_FiberBundles.push_back(mitkFiberBundle); } } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp index c3b4440b7a..42c816e097 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp @@ -1,512 +1,512 @@ /*=================================================================== 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 "itkGibbsTrackingFilter.h" // MITK #include #include #include #include #include //#include #include #include // ITK #include #include #include // MISC #include #include #include #include namespace itk{ template< class ItkQBallImageType > GibbsTrackingFilter< ItkQBallImageType >::GibbsTrackingFilter(): m_StartTemperature(0.1), m_EndTemperature(0.001), m_Iterations(500000), m_ParticleWeight(0), m_ParticleWidth(0), m_ParticleLength(0), m_ConnectionPotential(10), m_InexBalance(0), m_ParticlePotential(0.2), m_MinFiberLength(10), m_AbortTracking(false), m_NumConnections(0), m_NumParticles(0), m_NumAcceptedFibers(0), m_CurrentStep(0), m_BuildFibers(false), m_Steps(10), m_ProposalAcceptance(0), m_CurvatureThreshold(0.7), m_DuplicateImage(true), m_RandomSeed(-1), m_LoadParameterFile(""), m_LutPath(""), m_IsInValidState(true) { } template< class ItkQBallImageType > GibbsTrackingFilter< ItkQBallImageType >::~GibbsTrackingFilter() { } // fill output fiber bundle datastructure template< class ItkQBallImageType > typename GibbsTrackingFilter< ItkQBallImageType >::FiberPolyDataType GibbsTrackingFilter< ItkQBallImageType >::GetFiberBundle() { if (!m_AbortTracking) { m_BuildFibers = true; while (m_BuildFibers){} } return m_FiberPolyData; } template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType > ::EstimateParticleWeight() { MITK_INFO << "GibbsTrackingFilter: estimating particle weight"; float minSpacing; if(m_QBallImage->GetSpacing()[0]GetSpacing()[1] && m_QBallImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[0]; else if (m_QBallImage->GetSpacing()[1] < m_QBallImage->GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[1]; else minSpacing = m_QBallImage->GetSpacing()[2]; float m_ParticleLength = 1.5*minSpacing; float m_ParticleWidth = 0.5*minSpacing; // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // instantiate all necessary components SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } ParticleGrid* particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); GibbsEnergyComputer* encomp = new GibbsEnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); // EnergyComputer* encomp = new EnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); MetropolisHastingsSampler* sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); float alpha = log(m_EndTemperature/m_StartTemperature); m_ParticleWeight = 0.01; int ppv = 0; // main loop int neededParts = 3000; while (ppvSetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); for( int step = 0; step < 10; step++ ) { // update temperatur for simulated annealing process float temperature = m_StartTemperature * exp(alpha*(((1.0)*step)/((1.0)*10))); sampler->SetTemperature(temperature); for (unsigned long i=0; i<10000; i++) sampler->MakeProposal(); } ppv = particleGrid->m_NumParticles; particleGrid->ResetGrid(); } delete sampler; delete encomp; delete particleGrid; delete interpolator; MITK_INFO << "GibbsTrackingFilter: finished estimating particle weight"; } // perform global tracking template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType >::GenerateData() { TimeProbe preClock; preClock.Start(); // check if input is qball or tensor image and generate qball if necessary if (m_QBallImage.IsNull() && m_TensorImage.IsNotNull()) { TensorImageToQBallImageFilter::Pointer filter = TensorImageToQBallImageFilter::New(); filter->SetInput( m_TensorImage ); filter->Update(); m_QBallImage = filter->GetOutput(); } else if (m_DuplicateImage) // generate local working copy of QBall image (if not disabled) { typedef itk::ImageDuplicator< ItkQBallImageType > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( m_QBallImage ); duplicator->Update(); m_QBallImage = duplicator->GetOutput(); } // perform mean subtraction on odfs typedef ImageRegionIterator< ItkQBallImageType > InputIteratorType; InputIteratorType it(m_QBallImage, m_QBallImage->GetLargestPossibleRegion() ); it.GoToBegin(); while (!it.IsAtEnd()) { itk::OrientationDistributionFunction odf(it.Get().GetDataPointer()); float mean = odf.GetMeanValue(); odf -= mean; it.Set(odf.GetDataPointer()); ++it; } // check if mask image is given if it needs resampling PrepareMaskImage(); // load parameter file LoadParameters(); // prepare parameters float minSpacing; if(m_QBallImage->GetSpacing()[0]GetSpacing()[1] && m_QBallImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[0]; else if (m_QBallImage->GetSpacing()[1] < m_QBallImage->GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[1]; else minSpacing = m_QBallImage->GetSpacing()[2]; if(m_ParticleLength == 0) m_ParticleLength = 1.5*minSpacing; if(m_ParticleWidth == 0) m_ParticleWidth = 0.5*minSpacing; if(m_ParticleWeight == 0) EstimateParticleWeight(); float alpha = log(m_EndTemperature/m_StartTemperature); m_Steps = m_Iterations/10000; if (m_Steps<10) m_Steps = 10; if (m_Steps>m_Iterations) { MITK_INFO << "GibbsTrackingFilter: not enough iterations!"; m_AbortTracking = true; } if (m_CurvatureThreshold < mitk::eps) m_CurvatureThreshold = 0; unsigned long singleIts = (unsigned long)((1.0*m_Iterations) / (1.0*m_Steps)); // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // load sphere interpolator to evaluate the ODFs SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } // initialize the actual tracking components (ParticleGrid, Metropolis Hastings Sampler and Energy Computer) ParticleGrid* particleGrid; GibbsEnergyComputer* encomp; MetropolisHastingsSampler* sampler; try{ particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); encomp = new GibbsEnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); encomp->SetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); } catch(...) { MITK_ERROR << "Particle grid allocation failed. Not enough memory? Try to increase the particle length."; m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; return; } MITK_INFO << "----------------------------------------"; MITK_INFO << "Iterations: " << m_Iterations; MITK_INFO << "Steps: " << m_Steps; MITK_INFO << "Particle length: " << m_ParticleLength; MITK_INFO << "Particle width: " << m_ParticleWidth; MITK_INFO << "Particle weight: " << m_ParticleWeight; MITK_INFO << "Start temperature: " << m_StartTemperature; MITK_INFO << "End temperature: " << m_EndTemperature; MITK_INFO << "In/Ex balance: " << m_InexBalance; MITK_INFO << "Min. fiber length: " << m_MinFiberLength; MITK_INFO << "Curvature threshold: " << m_CurvatureThreshold; MITK_INFO << "Random seed: " << m_RandomSeed; MITK_INFO << "----------------------------------------"; // main loop preClock.Stop(); TimeProbe clock; clock.Start(); m_NumAcceptedFibers = 0; unsigned long counter = 1; if (!m_AbortTracking) for( m_CurrentStep = 1; m_CurrentStep <= m_Steps; m_CurrentStep++ ) { // update temperatur for simulated annealing process float temperature = m_StartTemperature * exp(alpha*(((1.0)*m_CurrentStep)/((1.0)*m_Steps))); sampler->SetTemperature(temperature); for (unsigned long i=0; iMakeProposal(); if (m_BuildFibers || (i==singleIts-1 && m_CurrentStep==m_Steps)) { m_ProposalAcceptance = (float)sampler->GetNumAcceptedProposals()/counter; m_NumParticles = particleGrid->m_NumParticles; m_NumConnections = particleGrid->m_NumConnections; FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); m_BuildFibers = false; } counter++; } m_ProposalAcceptance = (float)sampler->GetNumAcceptedProposals()/counter; m_NumParticles = particleGrid->m_NumParticles; m_NumConnections = particleGrid->m_NumConnections; MITK_INFO << "GibbsTrackingFilter: proposal acceptance: " << 100*m_ProposalAcceptance << "%"; MITK_INFO << "GibbsTrackingFilter: particles: " << m_NumParticles; MITK_INFO << "GibbsTrackingFilter: connections: " << m_NumConnections; MITK_INFO << "GibbsTrackingFilter: progress: " << 100*(float)m_CurrentStep/m_Steps << "%"; MITK_INFO << "GibbsTrackingFilter: cell overflows: " << particleGrid->m_NumCellOverflows; MITK_INFO << "----------------------------------------"; if (m_AbortTracking) break; } if (m_AbortTracking) { FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); } clock.Stop(); delete sampler; delete encomp; delete interpolator; delete particleGrid; m_AbortTracking = true; m_BuildFibers = false; int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: finished gibbs tracking in " << h << "h, " << m << "m and " << s << "s"; m = (int)preClock.GetTotal()/60; s = (int)preClock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: preparation of the data took " << m << "m and " << s << "s"; MITK_INFO << "GibbsTrackingFilter: " << m_NumAcceptedFibers << " fibers accepted"; SaveParameters(); } template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType >::PrepareMaskImage() { if(m_MaskImage.IsNull()) { MITK_INFO << "GibbsTrackingFilter: generating default mask image"; m_MaskImage = ItkFloatImageType::New(); m_MaskImage->SetSpacing( m_QBallImage->GetSpacing() ); m_MaskImage->SetOrigin( m_QBallImage->GetOrigin() ); m_MaskImage->SetDirection( m_QBallImage->GetDirection() ); m_MaskImage->SetRegions( m_QBallImage->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1.0); } else if ( m_MaskImage->GetLargestPossibleRegion().GetSize()[0]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[0] || m_MaskImage->GetLargestPossibleRegion().GetSize()[1]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[1] || m_MaskImage->GetLargestPossibleRegion().GetSize()[2]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[2] || m_MaskImage->GetSpacing()[0]!=m_QBallImage->GetSpacing()[0] || m_MaskImage->GetSpacing()[1]!=m_QBallImage->GetSpacing()[1] || m_MaskImage->GetSpacing()[2]!=m_QBallImage->GetSpacing()[2] ) { MITK_INFO << "GibbsTrackingFilter: resampling mask image"; typedef itk::ResampleImageFilter< ItkFloatImageType, ItkFloatImageType, float > ResamplerType; ResamplerType::Pointer resampler = ResamplerType::New(); resampler->SetOutputSpacing( m_QBallImage->GetSpacing() ); resampler->SetOutputOrigin( m_QBallImage->GetOrigin() ); resampler->SetOutputDirection( m_QBallImage->GetDirection() ); resampler->SetSize( m_QBallImage->GetLargestPossibleRegion().GetSize() ); resampler->SetInput( m_MaskImage ); - resampler->SetDefaultPixelValue(1.0); + resampler->SetDefaultPixelValue(0.0); resampler->Update(); m_MaskImage = resampler->GetOutput(); MITK_INFO << "GibbsTrackingFilter: resampling finished"; } } // load tracking paramters from xml file (.gtp) template< class ItkQBallImageType > bool GibbsTrackingFilter< ItkQBallImageType >::LoadParameters() { m_AbortTracking = true; try { if( m_LoadParameterFile.length()==0 ) { m_AbortTracking = false; return true; } MITK_INFO << "GibbsTrackingFilter: loading parameter file " << m_LoadParameterFile; TiXmlDocument doc( m_LoadParameterFile ); doc.LoadFile(); TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); pElem = hDoc.FirstChildElement().Element(); hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement("parameter_set").Element(); QString iterations(pElem->Attribute("iterations")); m_Iterations = iterations.toULong(); QString particleLength(pElem->Attribute("particle_length")); m_ParticleLength = particleLength.toFloat(); QString particleWidth(pElem->Attribute("particle_width")); m_ParticleWidth = particleWidth.toFloat(); QString partWeight(pElem->Attribute("particle_weight")); m_ParticleWeight = partWeight.toFloat(); QString startTemp(pElem->Attribute("temp_start")); m_StartTemperature = startTemp.toFloat(); QString endTemp(pElem->Attribute("temp_end")); m_EndTemperature = endTemp.toFloat(); QString inExBalance(pElem->Attribute("inexbalance")); m_InexBalance = inExBalance.toFloat(); QString fiberLength(pElem->Attribute("fiber_length")); m_MinFiberLength = fiberLength.toFloat(); QString curvThres(pElem->Attribute("curvature_threshold")); m_CurvatureThreshold = cos(curvThres.toFloat()*M_PI/180); m_AbortTracking = false; MITK_INFO << "GibbsTrackingFilter: parameter file loaded successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not load parameter file"; return false; } } // save current tracking paramters to xml file (.gtp) template< class ItkQBallImageType > bool GibbsTrackingFilter< ItkQBallImageType >::SaveParameters() { try { if( m_SaveParameterFile.length()==0 ) { MITK_INFO << "GibbsTrackingFilter: no filename specified to save parameters"; return true; } MITK_INFO << "GibbsTrackingFilter: saving parameter file " << m_SaveParameterFile; TiXmlDocument documentXML; TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement("global_tracking_parameter_file"); mainXML->SetAttribute("file_version", "0.1"); documentXML.LinkEndChild(mainXML); TiXmlElement* paramXML = new TiXmlElement("parameter_set"); paramXML->SetAttribute("iterations", QString::number(m_Iterations).toStdString()); paramXML->SetAttribute("particle_length", QString::number(m_ParticleLength).toStdString()); paramXML->SetAttribute("particle_width", QString::number(m_ParticleWidth).toStdString()); paramXML->SetAttribute("particle_weight", QString::number(m_ParticleWeight).toStdString()); paramXML->SetAttribute("temp_start", QString::number(m_StartTemperature).toStdString()); paramXML->SetAttribute("temp_end", QString::number(m_EndTemperature).toStdString()); paramXML->SetAttribute("inexbalance", QString::number(m_InexBalance).toStdString()); paramXML->SetAttribute("fiber_length", QString::number(m_MinFiberLength).toStdString()); paramXML->SetAttribute("curvature_threshold", QString::number(m_CurvatureThreshold).toStdString()); mainXML->LinkEndChild(paramXML); QString filename(m_SaveParameterFile.c_str()); if(!filename.endsWith(".gtp")) filename += ".gtp"; documentXML.SaveFile( filename.toStdString() ); MITK_INFO << "GibbsTrackingFilter: parameter file saved successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not save parameter file"; return false; } } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp index 8b18603b14..4a0b9e729a 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp @@ -1,624 +1,613 @@ /*=================================================================== 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 "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace itk { TractsToDWIImageFilter::TractsToDWIImageFilter() : m_CircleDummy(false) , m_VolumeAccuracy(10) , m_Upsampling(1) , m_NumberOfRepetitions(1) , m_EnforcePureFiberVoxels(false) , m_InterpolationShrink(10) , m_FiberRadius(20) , m_SignalScale(300) { m_Spacing.Fill(2.5); m_Origin.Fill(0.0); m_DirectionMatrix.SetIdentity(); m_ImageRegion.SetSize(0, 10); m_ImageRegion.SetSize(1, 10); m_ImageRegion.SetSize(2, 10); } TractsToDWIImageFilter::~TractsToDWIImageFilter() { } std::vector< TractsToDWIImageFilter::DoubleDwiType::Pointer > TractsToDWIImageFilter::AddKspaceArtifacts( std::vector< DoubleDwiType::Pointer >& images ) { // create slice object SliceType::Pointer slice = SliceType::New(); ImageRegion<2> region; region.SetSize(0, m_UpsampledImageRegion.GetSize()[0]); region.SetSize(1, m_UpsampledImageRegion.GetSize()[1]); slice->SetLargestPossibleRegion( region ); slice->SetBufferedRegion( region ); slice->SetRequestedRegion( region ); slice->Allocate(); boost::progress_display disp(images.size()*images[0]->GetVectorLength()*images[0]->GetLargestPossibleRegion().GetSize(2)); std::vector< DoubleDwiType::Pointer > outImages; for (int i=0; iSetSpacing( m_Spacing ); newImage->SetOrigin( m_Origin ); newImage->SetDirection( m_DirectionMatrix ); newImage->SetLargestPossibleRegion( m_ImageRegion ); newImage->SetBufferedRegion( m_ImageRegion ); newImage->SetRequestedRegion( m_ImageRegion ); newImage->SetVectorLength( image->GetVectorLength() ); newImage->Allocate(); DiffusionSignalModel* signalModel; if (iGetVectorLength(); g++) for (int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { ++disp; // extract slice from channel g for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; SliceType::PixelType pix2D = image->GetPixel(index3D)[g]; slice->SetPixel(index2D, pix2D); } // fourier transform slice itk::FFTRealToComplexConjugateImageFilter< SliceType::PixelType, 2 >::Pointer fft = itk::FFTRealToComplexConjugateImageFilter< SliceType::PixelType, 2 >::New(); fft->SetInput(slice); fft->Update(); ComplexSliceType::Pointer fSlice = fft->GetOutput(); fSlice = RearrangeSlice(fSlice); // add artifacts for (int a=0; aSetT2(signalModel->GetT2()); fSlice = m_KspaceArtifacts.at(a)->AddArtifact(fSlice); } // save k-space slice of s0 image - if (g==0) + if (g==m_FiberModels.at(0)->GetFirstBaselineIndex()) for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; double kpix = sqrt(fSlice->GetPixel(index2D).real()*fSlice->GetPixel(index2D).real()+fSlice->GetPixel(index2D).imag()*fSlice->GetPixel(index2D).imag()); - m_KspaceImage->SetPixel(index3D, kpix); + m_KspaceImage->SetPixel(index3D, m_KspaceImage->GetPixel(index3D)+kpix); } // inverse fourier transform slice SliceType::Pointer newSlice; itk::FFTComplexConjugateToRealImageFilter< SliceType::PixelType, 2 >::Pointer ifft = itk::FFTComplexConjugateToRealImageFilter< SliceType::PixelType, 2 >::New(); ifft->SetInput(fSlice); ifft->Update(); newSlice = ifft->GetOutput(); // put slice back into channel g for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; DoubleDwiType::PixelType pix3D = newImage->GetPixel(index3D); SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; pix3D[g] = newSlice->GetPixel(index2D); newImage->SetPixel(index3D, pix3D); } } outImages.push_back(newImage); } return outImages; } TractsToDWIImageFilter::ComplexSliceType::Pointer TractsToDWIImageFilter::RearrangeSlice(ComplexSliceType::Pointer slice) { ImageRegion<2> region = slice->GetLargestPossibleRegion(); ComplexSliceType::Pointer rearrangedSlice = ComplexSliceType::New(); rearrangedSlice->SetLargestPossibleRegion( region ); rearrangedSlice->SetBufferedRegion( region ); rearrangedSlice->SetRequestedRegion( region ); rearrangedSlice->Allocate(); int xHalf = region.GetSize(0)/2; int yHalf = region.GetSize(1)/2; for (int y=0; y pix = slice->GetPixel(idx); if( idx[0] < xHalf ) idx[0] = idx[0] + xHalf; else idx[0] = idx[0] - xHalf; if( idx[1] < yHalf ) idx[1] = idx[1] + yHalf; else idx[1] = idx[1] - yHalf; rearrangedSlice->SetPixel(idx, pix); } return rearrangedSlice; } void TractsToDWIImageFilter::GenerateData() { // check input data if (m_FiberBundle.IsNull()) itkExceptionMacro("Input fiber bundle is NULL!"); int numFibers = m_FiberBundle->GetNumFibers(); if (numFibers<=0) itkExceptionMacro("Input fiber bundle contains no fibers!"); if (m_FiberModels.empty()) itkExceptionMacro("No diffusion model for fiber compartments defined!"); if (m_NonFiberModels.empty()) itkExceptionMacro("No diffusion model for non-fiber compartments defined!"); int baselineIndex = m_FiberModels[0]->GetFirstBaselineIndex(); if (baselineIndex<0) itkExceptionMacro("No baseline index found!"); // determine k-space undersampling for (int i=0; i*>(m_KspaceArtifacts.at(i)) ) m_Upsampling = dynamic_cast*>(m_KspaceArtifacts.at(i))->GetKspaceCropping(); if (m_Upsampling<1) m_Upsampling = 1; if (m_TissueMask.IsNotNull()) { // use input tissue mask m_Spacing = m_TissueMask->GetSpacing(); m_Origin = m_TissueMask->GetOrigin(); m_DirectionMatrix = m_TissueMask->GetDirection(); m_ImageRegion = m_TissueMask->GetLargestPossibleRegion(); if (m_Upsampling>1) { ImageRegion<3> region = m_ImageRegion; region.SetSize(0, m_ImageRegion.GetSize(0)*m_Upsampling); region.SetSize(1, m_ImageRegion.GetSize(1)*m_Upsampling); mitk::Vector3D spacing = m_Spacing; spacing[0] /= m_Upsampling; spacing[1] /= m_Upsampling; itk::RescaleIntensityImageFilter::Pointer rescaler = itk::RescaleIntensityImageFilter::New(); rescaler->SetInput(0,m_TissueMask); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_TissueMask); resampler->SetSize(region.GetSize()); resampler->SetOutputSpacing(spacing); resampler->Update(); m_TissueMask = resampler->GetOutput(); } MITK_INFO << "Using tissue mask"; } // initialize output dwi image OutputImageType::Pointer outImage = OutputImageType::New(); outImage->SetSpacing( m_Spacing ); outImage->SetOrigin( m_Origin ); outImage->SetDirection( m_DirectionMatrix ); outImage->SetLargestPossibleRegion( m_ImageRegion ); outImage->SetBufferedRegion( m_ImageRegion ); outImage->SetRequestedRegion( m_ImageRegion ); outImage->SetVectorLength( m_FiberModels[0]->GetNumGradients() ); outImage->Allocate(); OutputImageType::PixelType temp; temp.SetSize(m_FiberModels[0]->GetNumGradients()); temp.Fill(0.0); outImage->FillBuffer(temp); // is input slize size a power of two? int x=2; int y=2; while (x " << x; + MITK_INFO << "Adjusting image width: " << m_ImageRegion.GetSize(0) << " --> " << x << " --> " << x*m_Upsampling; m_ImageRegion.SetSize(0, x); } if (y!=m_ImageRegion.GetSize(1)) { - MITK_INFO << "Adjusting image height: " << m_ImageRegion.GetSize(1) << " --> " << y; + MITK_INFO << "Adjusting image height: " << m_ImageRegion.GetSize(1) << " --> " << y << " --> " << y*m_Upsampling; m_ImageRegion.SetSize(1, y); } // initialize k-space image m_KspaceImage = ItkDoubleImgType::New(); m_KspaceImage->SetSpacing( m_Spacing ); m_KspaceImage->SetOrigin( m_Origin ); m_KspaceImage->SetDirection( m_DirectionMatrix ); m_KspaceImage->SetLargestPossibleRegion( m_ImageRegion ); m_KspaceImage->SetBufferedRegion( m_ImageRegion ); m_KspaceImage->SetRequestedRegion( m_ImageRegion ); m_KspaceImage->Allocate(); m_KspaceImage->FillBuffer(0); // apply undersampling to image parameters m_UpsampledSpacing = m_Spacing; m_UpsampledImageRegion = m_ImageRegion; m_UpsampledSpacing[0] /= m_Upsampling; m_UpsampledSpacing[1] /= m_Upsampling; m_UpsampledImageRegion.SetSize(0, m_ImageRegion.GetSize()[0]*m_Upsampling); m_UpsampledImageRegion.SetSize(1, m_ImageRegion.GetSize()[1]*m_Upsampling); // everything from here on is using the upsampled image parameters!!! if (m_TissueMask.IsNull()) { m_TissueMask = ItkUcharImgType::New(); m_TissueMask->SetSpacing( m_UpsampledSpacing ); m_TissueMask->SetOrigin( m_Origin ); m_TissueMask->SetDirection( m_DirectionMatrix ); m_TissueMask->SetLargestPossibleRegion( m_UpsampledImageRegion ); m_TissueMask->SetBufferedRegion( m_UpsampledImageRegion ); m_TissueMask->SetRequestedRegion( m_UpsampledImageRegion ); m_TissueMask->Allocate(); m_TissueMask->FillBuffer(1); } // resample fiber bundle for sufficient voxel coverage - double segmentVolume = 1; + double segmentVolume = 0.0001; float minSpacing = 1; if(m_UpsampledSpacing[0]GetDeepCopy(); fiberBundle->ResampleFibers(minSpacing/m_VolumeAccuracy); double mmRadius = m_FiberRadius/1000; if (mmRadius>0) segmentVolume = M_PI*mmRadius*mmRadius*minSpacing/m_VolumeAccuracy; // generate double images to wokr with because we don't want to lose precision // we use a separate image for each compartment model std::vector< DoubleDwiType::Pointer > compartments; for (int i=0; iSetSpacing( m_UpsampledSpacing ); doubleDwi->SetOrigin( m_Origin ); doubleDwi->SetDirection( m_DirectionMatrix ); doubleDwi->SetLargestPossibleRegion( m_UpsampledImageRegion ); doubleDwi->SetBufferedRegion( m_UpsampledImageRegion ); doubleDwi->SetRequestedRegion( m_UpsampledImageRegion ); doubleDwi->SetVectorLength( m_FiberModels[0]->GetNumGradients() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_FiberModels[0]->GetNumGradients()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); compartments.push_back(doubleDwi); } - if (m_CircleDummy) + double interpFact = 2*atan(-0.5*m_InterpolationShrink); + double maxVolume = 0; + + vtkSmartPointer fiberPolyData = fiberBundle->GetFiberPolyData(); + vtkSmartPointer vLines = fiberPolyData->GetLines(); + vLines->InitTraversal(); + + MITK_INFO << "Generating signal of " << m_FiberModels.size() << " fiber compartments"; + boost::progress_display disp(numFibers); + for( int i=0; iGetNextCell ( numPoints, points ); + if (numPoints<2) + continue; + + for( int j=0; jGetNumGradients()); - pix.Fill(1); - - DoubleDwiType::Pointer doubleDwi = compartments.at(i); - ImageRegion<3> region = doubleDwi->GetLargestPossibleRegion(); - ImageRegionIterator it(doubleDwi, region); - while(!it.IsAtEnd()) + double* temp = fiberPolyData->GetPoint(points[j]); + itk::Point vertex = GetItkPoint(temp); + itk::Vector v = GetItkVector(temp); + + itk::Vector dir(3); + if (jGetPoint(points[j+1]))-v; + else + dir = v-GetItkVector(fiberPolyData->GetPoint(points[j-1])); + + itk::Index<3> idx; + itk::ContinuousIndex contIndex; + m_TissueMask->TransformPhysicalPointToIndex(vertex, idx); + m_TissueMask->TransformPhysicalPointToContinuousIndex(vertex, contIndex); + + double frac_x = contIndex[0] - idx[0]; + double frac_y = contIndex[1] - idx[1]; + double frac_z = contIndex[2] - idx[2]; + if (frac_x<0) { - DoubleDwiType::IndexType index = it.GetIndex(); - double t = region.GetSize(0)/2; - double d1 = index[0]-t+0.5; - t = region.GetSize(1)/2; - double d2 = index[1]-t+0.5; - if (sqrt(d1*d1+d2*d2)<20*m_Upsampling) - it.Set(pix); - ++it; + idx[0] -= 1; + frac_x += 1; + } + if (frac_y<0) + { + idx[1] -= 1; + frac_y += 1; + } + if (frac_z<0) + { + idx[2] -= 1; + frac_z += 1; } - } - } - else - { - double interpFact = 2*atan(-0.5*m_InterpolationShrink); - double maxVolume = 0; - vtkSmartPointer fiberPolyData = fiberBundle->GetFiberPolyData(); - vtkSmartPointer vLines = fiberPolyData->GetLines(); - vLines->InitTraversal(); + frac_x = atan((0.5-frac_x)*m_InterpolationShrink)/interpFact + 0.5; + frac_y = atan((0.5-frac_y)*m_InterpolationShrink)/interpFact + 0.5; + frac_z = atan((0.5-frac_z)*m_InterpolationShrink)/interpFact + 0.5; - MITK_INFO << "Generating signal of " << m_FiberModels.size() << " fiber compartments"; - boost::progress_display disp(numFibers); - for( int i=0; iGetNextCell ( numPoints, points ); - if (numPoints<2) - continue; - - for( int j=0; j newIdx; + for (int x=0; x<2; x++) { - double* temp = fiberPolyData->GetPoint(points[j]); - itk::Point vertex = GetItkPoint(temp); - itk::Vector v = GetItkVector(temp); - - itk::Vector dir(3); - if (jGetPoint(points[j+1]))-v; - else - dir = v-GetItkVector(fiberPolyData->GetPoint(points[j-1])); - - itk::Index<3> idx; - itk::ContinuousIndex contIndex; - m_TissueMask->TransformPhysicalPointToIndex(vertex, idx); - m_TissueMask->TransformPhysicalPointToContinuousIndex(vertex, contIndex); - - double frac_x = contIndex[0] - idx[0]; - double frac_y = contIndex[1] - idx[1]; - double frac_z = contIndex[2] - idx[2]; - if (frac_x<0) + frac_x = 1-frac_x; + for (int y=0; y<2; y++) { - idx[0] -= 1; - frac_x += 1; - } - if (frac_y<0) - { - idx[1] -= 1; - frac_y += 1; - } - if (frac_z<0) - { - idx[2] -= 1; - frac_z += 1; - } + frac_y = 1-frac_y; + for (int z=0; z<2; z++) + { + frac_z = 1-frac_z; - frac_x = atan((0.5-frac_x)*m_InterpolationShrink)/interpFact + 0.5; - frac_y = atan((0.5-frac_y)*m_InterpolationShrink)/interpFact + 0.5; - frac_z = atan((0.5-frac_z)*m_InterpolationShrink)/interpFact + 0.5; + newIdx[0] = idx[0]+x; + newIdx[1] = idx[1]+y; + newIdx[2] = idx[2]+z; - // use trilinear interpolation - itk::Index<3> newIdx; - for (int x=0; x<2; x++) - { - frac_x = 1-frac_x; - for (int y=0; y<2; y++) - { - frac_y = 1-frac_y; - for (int z=0; z<2; z++) + double frac = frac_x*frac_y*frac_z; + + // is position valid? + if (!m_TissueMask->GetLargestPossibleRegion().IsInside(newIdx) || m_TissueMask->GetPixel(newIdx)<=0) + continue; + + // generate signal for each fiber compartment + for (int k=0; kGetLargestPossibleRegion().IsInside(newIdx) || m_TissueMask->GetPixel(newIdx)<=0) - continue; - - // generate signal for each fiber compartment - for (int k=0; kSetFiberDirection(dir); - DoubleDwiType::PixelType pix = doubleDwi->GetPixel(newIdx); - pix += segmentVolume*frac*m_FiberModels[k]->SimulateMeasurement(); - doubleDwi->SetPixel(newIdx, pix ); - if (pix[baselineIndex]>maxVolume) - maxVolume = pix[baselineIndex]; - } + DoubleDwiType::Pointer doubleDwi = compartments.at(k); + m_FiberModels[k]->SetFiberDirection(dir); + DoubleDwiType::PixelType pix = doubleDwi->GetPixel(newIdx); + pix += segmentVolume*frac*m_FiberModels[k]->SimulateMeasurement(); + doubleDwi->SetPixel(newIdx, pix ); + if (pix[baselineIndex]>maxVolume) + maxVolume = pix[baselineIndex]; } } } } } + } - MITK_INFO << "Generating signal of " << m_NonFiberModels.size() << " non-fiber compartments"; - ImageRegionIterator it3(m_TissueMask, m_TissueMask->GetLargestPossibleRegion()); - boost::progress_display disp3(m_TissueMask->GetLargestPossibleRegion().GetNumberOfPixels()); - double voxelVolume = m_UpsampledSpacing[0]*m_UpsampledSpacing[1]*m_UpsampledSpacing[2]; + MITK_INFO << "Generating signal of " << m_NonFiberModels.size() << " non-fiber compartments"; + ImageRegionIterator it3(m_TissueMask, m_TissueMask->GetLargestPossibleRegion()); + boost::progress_display disp3(m_TissueMask->GetLargestPossibleRegion().GetNumberOfPixels()); + double voxelVolume = m_UpsampledSpacing[0]*m_UpsampledSpacing[1]*m_UpsampledSpacing[2]; - double fact = 1; - if (m_FiberRadius<0.0001) - fact = voxelVolume/maxVolume; + double fact = 1; + if (m_FiberRadius<0.0001) + fact = voxelVolume/maxVolume; - while(!it3.IsAtEnd()) + while(!it3.IsAtEnd()) + { + ++disp3; + DoubleDwiType::IndexType index = it3.GetIndex(); + + if (it3.Get()>0) { - ++disp3; - DoubleDwiType::IndexType index = it3.GetIndex(); + // get fiber volume fraction + DoubleDwiType::Pointer fiberDwi = compartments.at(0); + DoubleDwiType::PixelType fiberPix = fiberDwi->GetPixel(index); // intra axonal compartment + if (fact>1) // auto scale intra-axonal if no fiber radius is specified + { + fiberPix *= fact; + fiberDwi->SetPixel(index, fiberPix); + } + double f = fiberPix[baselineIndex]; - if (it3.Get()>0) + if (f>voxelVolume || f>0 && m_EnforcePureFiberVoxels) // more fiber than space in voxel? { - // get fiber volume fraction - double w = 0; - for (int i=0; iSetPixel(index, fiberPix*voxelVolume/f); + + for (int i=1; iGetPixel(index); - if (fact<1) - { - pix *= fact; - compartments.at(i)->SetPixel(index, pix); - } - w += pix[baselineIndex]; + DoubleDwiType::PixelType pix; pix.Fill(0.0); + compartments.at(i)->SetPixel(index, pix); } - - if (w>voxelVolume || w>0 && m_EnforcePureFiberVoxels) // more fiber than space in voxel? + } + else + { + double nonf = voxelVolume-f; // non-fiber volume + double inter = 0; + if (m_FiberModels.size()>1) + inter = nonf * f; // intra-axonal fraction of non fiber compartment scales linearly with f + double other = nonf - inter; // rest of compartment + + // adjust non-fiber and intra-axonal signal + for (int i=1; iSetPixel(index, doubleDwi->GetPixel(index)*voxelVolume/w); - } + DoubleDwiType::Pointer doubleDwi = compartments.at(i); + DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index); + if (pix[baselineIndex]>0) + pix /= pix[baselineIndex]; + pix *= inter; + doubleDwi->SetPixel(index, pix); } - else + for (int i=0; iGetPixel(index) + m_NonFiberModels[i]->SimulateMeasurement()*w/m_NonFiberModels.size(); - doubleDwi->SetPixel(index, pix); - } + DoubleDwiType::Pointer doubleDwi = compartments.at(i+m_FiberModels.size()); + DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index) + m_NonFiberModels[i]->SimulateMeasurement()*other*m_NonFiberModels[i]->GetWeight(); + doubleDwi->SetPixel(index, pix); } } - ++it3; } + ++it3; } // do k-space stuff - if (!m_KspaceArtifacts.empty()) - MITK_INFO << "Generating k-space artifacts"; - else - MITK_INFO << "Generating k-space image"; + MITK_INFO << "Adjusting complex signal"; compartments = AddKspaceArtifacts(compartments); MITK_INFO << "Summing compartments and adding noise"; - double correction = m_SignalScale; ///(m_Upsampling*m_Upsampling); + unsigned int window = 0; + unsigned int min = itk::NumericTraits::max(); ImageRegionIterator it4 (outImage, outImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_FiberModels[0]->GetNumGradients()); boost::progress_display disp4(outImage->GetLargestPossibleRegion().GetNumberOfPixels()); while(!it4.IsAtEnd()) { ++disp4; DWIImageType::IndexType index = it4.GetIndex(); signal.Fill(0.0); // adjust fiber signal for (int i=0; iGetPixel(index)*correction; + signal += compartments.at(i)->GetPixel(index)*m_SignalScale; // adjust non-fiber signal for (int i=0; iGetPixel(index)*correction; + signal += compartments.at(m_FiberModels.size()+i)->GetPixel(index)*m_SignalScale; DoubleDwiType::PixelType accu = signal; accu.Fill(0.0); for (int i=0; iAddNoise(temp); accu += temp; } signal = accu/m_NumberOfRepetitions; for (int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); + + if (!m_FiberModels.at(0)->IsBaselineIndex(i) && signal[i]>window) + window = signal[i]; + if (!m_FiberModels.at(0)->IsBaselineIndex(i) && signal[i]SetNthOutput(0, outImage); } itk::Point TractsToDWIImageFilter::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } itk::Vector TractsToDWIImageFilter::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } vnl_vector_fixed TractsToDWIImageFilter::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } vnl_vector_fixed TractsToDWIImageFilter::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h index 8708ce140c..27044e66da 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h @@ -1,130 +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 __itkTractsToDWIImageFilter_h__ #define __itkTractsToDWIImageFilter_h__ // MITK #include #include #include #include #include -#include +#include // ITK #include #include #include #include #include #include typedef itk::VectorImage< short, 3 > DWIImageType; namespace itk { /** * \brief Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multicompartment model. */ class TractsToDWIImageFilter : public ImageSource< DWIImageType > { public: typedef TractsToDWIImageFilter Self; typedef ImageSource< DWIImageType > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; typedef mitk::FiberBundleX::Pointer FiberBundleType; typedef itk::VectorImage< double, 3 > DoubleDwiType; typedef std::vector< mitk::KspaceArtifact* > KspaceArtifactList; typedef std::vector< mitk::DiffusionSignalModel* > DiffusionModelList; typedef itk::Matrix MatrixType; typedef mitk::DiffusionNoiseModel NoiseModelType; typedef itk::Image< double, 2 > SliceType; typedef itk::FFTRealToComplexConjugateImageFilter< double, 2 >::OutputImageType ComplexSliceType; itkNewMacro(Self) itkTypeMacro( TractsToDWIImageFilter, ImageToImageFilter ) // input itkSetMacro( SignalScale, double ) itkSetMacro( FiberRadius, double ) itkSetMacro( InterpolationShrink, double ) ///< large values shrink (towards nearest neighbour interpolation), small values strech interpolation function (towards linear interpolation) itkSetMacro( VolumeAccuracy, unsigned int ) ///< determines fiber sampling density and thereby the accuracy of the fiber volume fraction itkSetMacro( FiberBundle, FiberBundleType ) ///< input fiber bundle itkSetMacro( Spacing, mitk::Vector3D ) ///< output image spacing itkSetMacro( Origin, mitk::Point3D ) ///< output image origin itkSetMacro( DirectionMatrix, MatrixType ) ///< output image rotation itkSetMacro( EnforcePureFiberVoxels, bool ) ///< treat all voxels containing at least one fiber as fiber-only (actually disable non-fiber compartments for this voxel). itkSetMacro( ImageRegion, ImageRegion<3> ) ///< output image size itkSetMacro( NumberOfRepetitions, unsigned int ) ///< number of acquisition repetitions to reduce noise (default is no additional repetition) itkSetMacro( TissueMask, ItkUcharImgType::Pointer ) ///< voxels outside of this binary mask contain only noise (are treated as air) itkGetMacro( KspaceImage, ItkDoubleImgType::Pointer ) void SetNoiseModel(NoiseModelType* noiseModel){ m_NoiseModel = noiseModel; } ///< generates the noise added to the image values void SetFiberModels(DiffusionModelList modelList){ m_FiberModels = modelList; } ///< generate signal of fiber compartments void SetNonFiberModels(DiffusionModelList modelList){ m_NonFiberModels = modelList; } ///< generate signal of non-fiber compartments void SetKspaceArtifacts(KspaceArtifactList artifactList){ m_KspaceArtifacts = artifactList; } + mitk::LevelWindow GetLevelWindow(){ return m_LevelWindow; } void GenerateData(); protected: TractsToDWIImageFilter(); virtual ~TractsToDWIImageFilter(); itk::Point GetItkPoint(double point[3]); itk::Vector GetItkVector(double point[3]); vnl_vector_fixed GetVnlVector(double point[3]); vnl_vector_fixed GetVnlVector(Vector< float, 3 >& vector); /** Transform generated image compartment by compartment, channel by channel and slice by slice using FFT and add k-space artifacts. */ std::vector< DoubleDwiType::Pointer > AddKspaceArtifacts(std::vector< DoubleDwiType::Pointer >& images); /** Rearrange FFT output to shift low frequencies to the iamge center (correct itk). */ TractsToDWIImageFilter::ComplexSliceType::Pointer RearrangeSlice(ComplexSliceType::Pointer slice); mitk::Vector3D m_Spacing; ///< output image spacing mitk::Vector3D m_UpsampledSpacing; mitk::Point3D m_Origin; ///< output image origin MatrixType m_DirectionMatrix; ///< output image rotation ImageRegion<3> m_ImageRegion; ///< output image size ImageRegion<3> m_UpsampledImageRegion; ItkUcharImgType::Pointer m_TissueMask; ///< voxels outside of this binary mask contain only noise (are treated as air) FiberBundleType m_FiberBundle; ///< input fiber bundle DiffusionModelList m_FiberModels; ///< generate signal of fiber compartments DiffusionModelList m_NonFiberModels; ///< generate signal of non-fiber compartments KspaceArtifactList m_KspaceArtifacts; NoiseModelType* m_NoiseModel; ///< generates the noise added to the image values bool m_CircleDummy; unsigned int m_VolumeAccuracy; ItkDoubleImgType::Pointer m_KspaceImage; unsigned int m_Upsampling; unsigned int m_NumberOfRepetitions; bool m_EnforcePureFiberVoxels; double m_InterpolationShrink; double m_FiberRadius; double m_SignalScale; + mitk::LevelWindow m_LevelWindow; }; } #include "itkTractsToDWIImageFilter.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp index 689aeaeac5..b4f37f75da 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp @@ -1,824 +1,824 @@ #include "itkTractsToVectorImageFilter.h" // VTK #include #include #include // ITK #include #include // misc #define _USE_MATH_DEFINES #include #include namespace itk{ static bool CompareVectorLengths(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } TractsToVectorImageFilter::TractsToVectorImageFilter(): m_AngularThreshold(0.7), m_MaskImage(NULL), m_NumDirectionsImage(NULL), m_NormalizeVectors(false), m_Epsilon(0.999), m_UseWorkingCopy(true), m_MaxNumDirections(3), m_FiberSampling(5), m_UseTrilinearInterpolation(true), m_Thres(0.5) { this->SetNumberOfRequiredOutputs(1); } TractsToVectorImageFilter::~TractsToVectorImageFilter() { } vnl_vector_fixed TractsToVectorImageFilter::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } itk::Point TractsToVectorImageFilter::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } void TractsToVectorImageFilter::GenerateData() { mitk::Geometry3D::Pointer geometry = m_FiberBundle->GetGeometry(); // calculate new image parameters mitk::Vector3D spacing; mitk::Point3D origin; itk::Matrix direction; ImageRegion<3> imageRegion; if (!m_MaskImage.IsNull()) { spacing = m_MaskImage->GetSpacing(); imageRegion = m_MaskImage->GetLargestPossibleRegion(); origin = m_MaskImage->GetOrigin(); direction = m_MaskImage->GetDirection(); } else { spacing = geometry->GetSpacing(); origin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); origin[0] += bounds.GetElement(0); origin[1] += bounds.GetElement(2); origin[2] += bounds.GetElement(4); for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction[j][i] = geometry->GetMatrixColumn(i)[j]; imageRegion.SetSize(0, geometry->GetExtent(0)); imageRegion.SetSize(1, geometry->GetExtent(1)); imageRegion.SetSize(2, geometry->GetExtent(2)); m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing ); m_MaskImage->SetOrigin( origin ); m_MaskImage->SetDirection( direction ); m_MaskImage->SetRegions( imageRegion ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } OutputImageType::RegionType::SizeType outImageSize = imageRegion.GetSize(); m_OutImageSpacing = m_MaskImage->GetSpacing(); m_ClusteredDirectionsContainer = ContainerType::New(); // initialize crossings image m_CrossingsImage = ItkUcharImgType::New(); m_CrossingsImage->SetSpacing( spacing ); m_CrossingsImage->SetOrigin( origin ); m_CrossingsImage->SetDirection( direction ); m_CrossingsImage->SetRegions( imageRegion ); m_CrossingsImage->Allocate(); m_CrossingsImage->FillBuffer(0); // initialize num directions image m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing ); m_NumDirectionsImage->SetOrigin( origin ); m_NumDirectionsImage->SetDirection( direction ); m_NumDirectionsImage->SetRegions( imageRegion ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); // resample fiber bundle float minSpacing = 1; if(m_OutImageSpacing[0]GetDeepCopy(); - if (m_FiberSampling>0) - m_FiberBundle->DoFiberSmoothing(ceil(10.0*m_FiberSampling/minSpacing)); + // resample fiber bundle for sufficient voxel coverage + m_FiberBundle->ResampleFibers(minSpacing/10); // iterate over all fibers vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); vtkSmartPointer vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int numFibers = m_FiberBundle->GetNumFibers(); itk::TimeProbe clock; m_DirectionsContainer = ContainerType::New(); MITK_INFO << "Generating fODFs (trilinear interpolation)"; boost::progress_display disp(numFibers); for( int i=0; iGetNextCell ( numPoints, points ); if (numPoints<2) continue; itk::Index<3> index; index.Fill(0); itk::ContinuousIndex contIndex; vnl_vector_fixed dir, wDir; itk::Point worldPos; vnl_vector v; for( int j=0; jGetPoint(points[j]); worldPos = GetItkPoint(temp); v = GetVnlVector(temp); dir = GetVnlVector(fiberPolyData->GetPoint(points[j+1]))-v; dir.normalize(); m_MaskImage->TransformPhysicalPointToIndex(worldPos, index); m_MaskImage->TransformPhysicalPointToContinuousIndex(worldPos, contIndex); if (m_MaskImage->GetPixel(index)==0) continue; if (!m_UseTrilinearInterpolation) { if (index[0] < 0 || index[0] >= outImageSize[0]) continue; if (index[1] < 0 || index[1] >= outImageSize[1]) continue; if (index[2] < 0 || index[2] >= outImageSize[2]) continue; int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]); DirectionContainerType::Pointer dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, dir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), dir); } else { dirCont->InsertElement(0, dir); m_DirectionsContainer->InsertElement(idx, dirCont); } continue; } float frac_x = contIndex[0] - index[0]; float frac_y = contIndex[1] - index[1]; float frac_z = contIndex[2] - index[2]; if (frac_x<0) { index[0] -= 1; frac_x += 1; } if (frac_y<0) { index[1] -= 1; frac_y += 1; } if (frac_z<0) { index[2] -= 1; frac_z += 1; } frac_x = 1-frac_x; frac_y = 1-frac_y; frac_z = 1-frac_z; // int coordinates inside image? if (index[0] < 0 || index[0] >= outImageSize[0]-1) continue; if (index[1] < 0 || index[1] >= outImageSize[1]-1) continue; if (index[2] < 0 || index[2] >= outImageSize[2]-1) continue; DirectionContainerType::Pointer dirCont; int idx; wDir = dir; float weight = ( frac_x)*( frac_y)*( frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2] ); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = ( frac_x)*(1-frac_y)*( frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0] + outImageSize[0]*(index[1]+1+ outImageSize[1]*index[2] ); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = ( frac_x)*( frac_y)*(1-frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]+outImageSize[1]); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = ( frac_x)*(1-frac_y)*(1-frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0] + outImageSize[0]*(index[1]+1+ outImageSize[1]*index[2]+outImageSize[1]); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = (1-frac_x)*( frac_y)*( frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0]+1 + outImageSize[0]*(index[1] + outImageSize[1]*index[2] ); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = (1-frac_x)*( frac_y)*(1-frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0]+1 + outImageSize[0]*(index[1] + outImageSize[1]*index[2]+outImageSize[1]); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = (1-frac_x)*(1-frac_y)*( frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0]+1 + outImageSize[0]*(index[1]+1+ outImageSize[1]*index[2] ); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = (1-frac_x)*(1-frac_y)*(1-frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0]+1 + outImageSize[0]*(index[1]+1+ outImageSize[1]*index[2]+outImageSize[1]); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } } clock.Stop(); } vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); itk::ImageRegionIterator dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion()); itk::ImageRegionIterator crossIt(m_CrossingsImage, m_CrossingsImage->GetLargestPossibleRegion()); m_DirectionImageContainer = DirectionImageContainerType::New(); int maxNumDirections = 0; MITK_INFO << "Clustering directions"; boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]); for(crossIt.GoToBegin(); !crossIt.IsAtEnd(); ++crossIt) { ++disp2; OutputImageType::IndexType index = crossIt.GetIndex(); int idx = index[0]+(index[1]+index[2]*outImageSize[1])*outImageSize[0]; if (!m_DirectionsContainer->IndexExists(idx)) { ++dirIt; continue; } DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull() || index[0] < 0 || index[0] >= outImageSize[0] || index[1] < 0 || index[1] >= outImageSize[1] || index[2] < 0 || index[2] >= outImageSize[2]) { ++dirIt; continue; } std::vector< DirectionType > directions; for (int i=0; iSize(); i++) if (dirCont->ElementAt(i).magnitude()>0.0001) directions.push_back(dirCont->ElementAt(i)); if (!directions.empty()) directions = FastClustering(directions); std::sort( directions.begin(), directions.end(), CompareVectorLengths ); if ( directions.size() > maxNumDirections ) { for (int i=maxNumDirections; iSetSpacing( spacing ); directionImage->SetOrigin( origin ); directionImage->SetDirection( direction ); directionImage->SetRegions( imageRegion ); directionImage->Allocate(); Vector< float, 3 > nullVec; nullVec.Fill(0.0); directionImage->FillBuffer(nullVec); m_DirectionImageContainer->InsertElement(i, directionImage); } maxNumDirections = std::min((int)directions.size(), m_MaxNumDirections); } int numDir = directions.size(); if (numDir>m_MaxNumDirections) numDir = m_MaxNumDirections; for (int i=0; i container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = index[0]; center[1] = index[1]; center[2] = index[2]; itk::Point worldCenter; m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); DirectionType dir = m_MaskImage->GetDirection()*directions.at(i); // set direction image pixel ItkDirectionImageType::Pointer directionImage = m_DirectionImageContainer->GetElement(i); Vector< float, 3 > pixel; pixel.SetElement(0, dir[0]); pixel.SetElement(1, dir[1]); pixel.SetElement(2, dir[2]); directionImage->SetPixel(index, pixel); // add direction to vector field (with spacing compensation) itk::Point worldStart; worldStart[0] = worldCenter[0]-dir[0]/2*minSpacing; worldStart[1] = worldCenter[1]-dir[1]/2*minSpacing; worldStart[2] = worldCenter[2]-dir[2]/2*minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dir[0]/2*minSpacing; worldEnd[1] = worldCenter[1]+dir[1]/2*minSpacing; worldEnd[2] = worldCenter[2]+dir[2]/2*minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); } dirIt.Set(numDir); ++dirIt; } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundleX::New(directionsPolyData); MITK_INFO << "mean time per fiber: " << clock.GetMean() << "s"; MITK_INFO << "absolute time: " << clock.GetTotal()/60 << "min"; } std::vector< vnl_vector_fixed< double, 3 > > TractsToVectorImageFilter::FastClustering(std::vector< vnl_vector_fixed< double, 3 > >& inDirs) { std::vector< vnl_vector_fixed< double, 3 > > outDirs; if (inDirs.empty()) return outDirs; vnl_vector_fixed< double, 3 > oldMean, currentMean, workingMean; std::vector< vnl_vector_fixed< double, 3 > > normalizedDirs; std::vector< int > touched; for (int i=0; i0.0001) { counter = 0; oldMean = currentMean; workingMean = oldMean; workingMean.normalize(); currentMean.fill(0.0); for (int i=0; i=m_AngularThreshold) { currentMean += inDirs[i]; touched[i] = 1; counter++; } else if (-angle>=m_AngularThreshold) { currentMean -= inDirs[i]; touched[i] = 1; counter++; } } } // found stable mean if (counter>0) { currentMean /= counter; float mag = currentMean.magnitude(); if (mag>0) { if (mag>max) max = mag; outDirs.push_back(currentMean); } } // find next unused seed free = false; for (int i=0; i0) for (int i=0; i > TractsToVectorImageFilter::Clustering(std::vector< vnl_vector_fixed< double, 3 > >& inDirs) { std::vector< vnl_vector_fixed< double, 3 > > outDirs; if (inDirs.empty()) return outDirs; vnl_vector_fixed< double, 3 > oldMean, currentMean, workingMean; std::vector< vnl_vector_fixed< double, 3 > > normalizedDirs; std::vector< int > touched; for (int i=0; i0.0001) { counter = 0; oldMean = currentMean; workingMean = oldMean; workingMean.normalize(); currentMean.fill(0.0); for (int i=0; i=m_AngularThreshold) { currentMean += inDirs[i]; counter++; } else if (-angle>=m_AngularThreshold) { currentMean -= inDirs[i]; counter++; } } } // found stable mean if (counter>0) { bool add = true; vnl_vector_fixed< double, 3 > normMean = currentMean; normMean.normalize(); for (int i=0; i dir = outDirs[i]; dir.normalize(); if ((normMean-dir).magnitude()<=0.0001) { add = false; break; } } currentMean /= counter; if (add) { float mag = currentMean.magnitude(); if (mag>0) { if (mag>max) max = mag; outDirs.push_back(currentMean); } } } } if (m_NormalizeVectors) for (int i=0; i0) for (int i=0; iBegin(); it!=dirCont->End(); ++it) { vnl_vector_fixed mean = ClusterStep(dirCont, it.Value()); if (mean.is_zero()) continue; bool addMean = true; for (DirectionContainerType::ConstIterator it2 = container->Begin(); it2!=container->End(); ++it2) { vnl_vector_fixed dir = it2.Value(); float angle = fabs(dot_product(mean, dir)/(mean.magnitude()*dir.magnitude())); if (angle>=m_Epsilon) { addMean = false; break; } } if (addMean) { if (m_NormalizeVectors) mean.normalize(); else if (mean.magnitude()>max) max = mean.magnitude(); container->InsertElement(container->Size(), mean); } } // max normalize voxel directions if (max>0 && !m_NormalizeVectors) for (int i=0; iSize(); i++) container->ElementAt(i) /= max; if (container->Size()Size()) return MeanShiftClustering(container); else return container; } vnl_vector_fixed TractsToVectorImageFilter::ClusterStep(DirectionContainerType::Pointer dirCont, vnl_vector_fixed currentMean) { vnl_vector_fixed newMean; newMean.fill(0); for (DirectionContainerType::ConstIterator it = dirCont->Begin(); it!=dirCont->End(); ++it) { vnl_vector_fixed dir = it.Value(); float angle = dot_product(currentMean, dir)/(currentMean.magnitude()*dir.magnitude()); if (angle>=m_AngularThreshold) newMean += dir; else if (-angle>=m_AngularThreshold) newMean -= dir; } if (fabs(dot_product(currentMean, newMean)/(currentMean.magnitude()*newMean.magnitude()))>=m_Epsilon || newMean.is_zero()) return newMean; else return ClusterStep(dirCont, newMean); } } diff --git a/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt index b35573c98d..833650d9e1 100644 --- a/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt @@ -1,14 +1,44 @@ +MITK_CHECK_MODULE(_missing_deps DiffusionCore MitkGraphAlgorithms) + +if(NOT _missing_deps) + set(lut_url http://mitk.org/download/data/FibertrackingLUT.tar.gz) + set(lut_tarball ${CMAKE_CURRENT_BINARY_DIR}/FibertrackingLUT.tar.gz) + message("Downloading FiberTracking LUT ${lut_url}...") + file(DOWNLOAD ${lut_url} ${lut_tarball} + EXPECTED_MD5 38ecb6d4a826c9ebb0f4965eb9aeee44 + TIMEOUT 20 + STATUS status + SHOW_PROGRESS + ) + + list(GET status 0 status_code) + list(GET status 1 status_msg) + + if(NOT status_code EQUAL 0) + message(SEND_ERROR "${status_msg} (error code ${status_code})") + else() + message("done.") + endif() + + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Resources) + message("Unpacking FiberTracking LUT tarball...") + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ../FibertrackingLUT.tar.gz + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Resources + RESULT_VARIABLE result + ERROR_VARIABLE err_msg) + if(result) + message(SEND_ERROR "Unpacking FibertrackingLUT.tar.gz failed: ${err_msg}") + else() + message("done.") + endif() +endif() + MITK_CREATE_MODULE( FiberTracking SUBPROJECTS MITK-DTI INCLUDE_DIRS Algorithms Algorithms/GibbsTracking Algorithms/StochasticTracking IODataStructures IODataStructures/FiberBundleX IODataStructures/PlanarFigureComposite Interactions SignalModels Rendering ${CMAKE_CURRENT_BINARY_DIR} DEPENDS DiffusionCore MitkGraphAlgorithms ) if(MODULE_IS_ENABLED) - file(DOWNLOAD http://mitk.org/download/data/FibertrackingLUT.tar.gz ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FibertrackingLUT.tar.gz TIMEOUT 10) - execute_process(COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} tar xzf FibertrackingLUT.tar.gz) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Rendering/mitkShaderFiberClipping.xml ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mitkShaderFiberClipping.xml) - MITK_INSTALL(FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mitkShaderFiberClipping.xml ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FiberTrackingLUTBaryCoords.bin ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FiberTrackingLUTIndices.bin) + add_subdirectory(Testing) endif() - -add_subdirectory(Testing) \ No newline at end of file diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp index 5bdedecc6f..84f0269df5 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp @@ -1,1727 +1,1740 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define _USE_MATH_DEFINES #include "mitkFiberBundleX.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char* mitk::FiberBundleX::COLORCODING_ORIENTATION_BASED = "Color_Orient"; //const char* mitk::FiberBundleX::COLORCODING_FA_AS_OPACITY = "Color_Orient_FA_Opacity"; const char* mitk::FiberBundleX::COLORCODING_FA_BASED = "FA_Values"; const char* mitk::FiberBundleX::COLORCODING_CUSTOM = "custom"; const char* mitk::FiberBundleX::FIBER_ID_ARRAY = "Fiber_IDs"; using namespace std; mitk::FiberBundleX::FiberBundleX( vtkPolyData* fiberPolyData ) : m_CurrentColorCoding(NULL) , m_NumFibers(0) , m_FiberSampling(0) { m_FiberPolyData = vtkSmartPointer::New(); if (fiberPolyData != NULL) { m_FiberPolyData = fiberPolyData; //m_FiberPolyData->DeepCopy(fiberPolyData); this->DoColorCodingOrientationBased(); } m_NumFibers = m_FiberPolyData->GetNumberOfLines(); this->UpdateFiberGeometry(); this->SetColorCoding(COLORCODING_ORIENTATION_BASED); this->GenerateFiberIds(); } mitk::FiberBundleX::~FiberBundleX() { } mitk::FiberBundleX::Pointer mitk::FiberBundleX::GetDeepCopy() { mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(m_FiberPolyData); newFib->SetColorCoding(m_CurrentColorCoding); return newFib; } vtkSmartPointer mitk::FiberBundleX::GeneratePolyDataByIds(std::vector fiberIds) { MITK_DEBUG << "\n=====FINAL RESULT: fib_id ======\n"; MITK_DEBUG << "Number of new Fibers: " << fiberIds.size(); // iterate through the vectorcontainer hosting all desired fiber Ids vtkSmartPointer newFiberPolyData = vtkSmartPointer::New(); vtkSmartPointer newLineSet = vtkSmartPointer::New(); vtkSmartPointer newPointSet = vtkSmartPointer::New(); // if FA array available, initialize fa double array // if color orient array is available init color array vtkSmartPointer faValueArray; vtkSmartPointer colorsT; //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = sizeof(rgba); if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_FA_BASED)){ MITK_DEBUG << "FA VALUES AVAILABLE, init array for new fiberbundle"; faValueArray = vtkSmartPointer::New(); } if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)){ MITK_DEBUG << "colorValues available, init array for new fiberbundle"; colorsT = vtkUnsignedCharArray::New(); colorsT->SetNumberOfComponents(componentSize); colorsT->SetName(COLORCODING_ORIENTATION_BASED); } std::vector::iterator finIt = fiberIds.begin(); while ( finIt != fiberIds.end() ) { if (*finIt < 0 || *finIt>GetNumFibers()){ MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt; break; } vtkSmartPointer fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber); vtkSmartPointer fibPoints = fiber->GetPoints(); vtkSmartPointer newFiber = vtkSmartPointer::New(); newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() ); for(int i=0; iGetNumberOfPoints(); i++) { // MITK_DEBUG << "id: " << fiber->GetPointId(i); // MITK_DEBUG << fibPoints->GetPoint(i)[0] << " | " << fibPoints->GetPoint(i)[1] << " | " << fibPoints->GetPoint(i)[2]; newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints()); newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]); if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_FA_BASED)){ // MITK_DEBUG << m_FiberIdDataSet->GetPointData()->GetArray(FA_VALUE_ARRAY)->GetTuple(fiber->GetPointId(i)); } if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)){ // MITK_DEBUG << "ColorValue: " << m_FiberIdDataSet->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)->GetTuple(fiber->GetPointId(i))[0]; } } newLineSet->InsertNextCell(newFiber); ++finIt; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); MITK_DEBUG << "new fiberbundle polydata points: " << newFiberPolyData->GetNumberOfPoints(); MITK_DEBUG << "new fiberbundle polydata lines: " << newFiberPolyData->GetNumberOfLines(); MITK_DEBUG << "=====================\n"; // mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(newFiberPolyData); return newFiberPolyData; } // merge two fiber bundles mitk::FiberBundleX::Pointer mitk::FiberBundleX::AddBundle(mitk::FiberBundleX* fib) { if (fib==NULL) { MITK_WARN << "trying to call AddBundle with NULL argument"; return NULL; } + MITK_INFO << "Adding fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); // add current fiber bundle int numFibers = GetNumFibers(); + boost::progress_display disp(numFibers); for( int i=0; iGetNextCell ( numPoints, points ); vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } vLines = fib->m_FiberPolyData->GetLines(); vLines->InitTraversal(); // add new fiber bundle numFibers = fib->GetNumFibers(); for( int i=0; iGetNextCell ( numPoints, points ); vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(fib->m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(vNewPolyData); return newFib; } // subtract two fiber bundles mitk::FiberBundleX::Pointer mitk::FiberBundleX::SubtractBundle(mitk::FiberBundleX* fib) { + MITK_INFO << "Subtracting fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); // iterate over current fibers int numFibers = GetNumFibers(); + boost::progress_display disp(numFibers); for( int i=0; iGetNextCell ( numPoints, points ); if (points==NULL) continue; vtkSmartPointer vLines2 = fib->m_FiberPolyData->GetLines(); vLines2->InitTraversal(); int numFibers2 = fib->GetNumFibers(); bool contained = false; for( int i2=0; i2GetNextCell ( numPoints2, points2 ); if (points2==NULL) continue; // check endpoints itk::Point point_start = GetItkPoint(m_FiberPolyData->GetPoint(points[0])); itk::Point point_end = GetItkPoint(m_FiberPolyData->GetPoint(points[numPoints-1])); itk::Point point2_start = GetItkPoint(fib->m_FiberPolyData->GetPoint(points2[0])); itk::Point point2_end = GetItkPoint(fib->m_FiberPolyData->GetPoint(points2[numPoints2-1])); if (point_start.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps || point_start.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps) { // further checking ??? if (numPoints2==numPoints) contained = true; } } // add to result because fiber is not subtracted if (!contained) { vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } } if(vNewLines->GetNumberOfCells()==0) return NULL; // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(vNewPolyData); return newFib; } itk::Point mitk::FiberBundleX::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } /* * set polydata (additional flag to recompute fiber geometry, default = true) */ void mitk::FiberBundleX::SetFiberPolyData(vtkSmartPointer fiberPD, bool updateGeometry) { if (fiberPD == NULL) this->m_FiberPolyData = vtkSmartPointer::New(); else { m_FiberPolyData->DeepCopy(fiberPD); DoColorCodingOrientationBased(); } m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); SetColorCoding(COLORCODING_ORIENTATION_BASED); GenerateFiberIds(); } /* * return vtkPolyData */ vtkSmartPointer mitk::FiberBundleX::GetFiberPolyData() { return m_FiberPolyData; } void mitk::FiberBundleX::DoColorCodingOrientationBased() { //===== FOR WRITING A TEST ======================== // colorT size == tupelComponents * tupelElements // compare color results // to cover this code 100% also polydata needed, where colorarray already exists // + one fiber with exactly 1 point // + one fiber with 0 points //================================================= /* make sure that processing colorcoding is only called when necessary */ if ( m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED) && m_FiberPolyData->GetNumberOfPoints() == m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)->GetNumberOfTuples() ) { // fiberstructure is already colorcoded MITK_DEBUG << " NO NEED TO REGENERATE COLORCODING! " ; this->ResetFiberOpacity(); this->SetColorCoding(COLORCODING_ORIENTATION_BASED); return; } /* Finally, execute color calculation */ vtkPoints* extrPoints = NULL; extrPoints = m_FiberPolyData->GetPoints(); int numOfPoints = 0; if (extrPoints!=NULL) numOfPoints = extrPoints->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; // int componentSize = sizeof(rgba); int componentSize = 4; vtkSmartPointer colorsT = vtkSmartPointer::New(); colorsT->Allocate(numOfPoints * componentSize); colorsT->SetNumberOfComponents(componentSize); colorsT->SetName(COLORCODING_ORIENTATION_BASED); /* checkpoint: does polydata contain any fibers */ int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) { MITK_DEBUG << "\n ========= Number of Fibers is 0 and below ========= \n"; return; } /* extract single fibers of fiberBundle */ vtkCellArray* fiberList = m_FiberPolyData->GetLines(); fiberList->InitTraversal(); for (int fi=0; fiGetNextCell(pointsPerFiber, idList); // MITK_DEBUG << "Fib#: " << fi << " of " << numOfFibers << " pnts in fiber: " << pointsPerFiber ; /* single fiber checkpoints: is number of points valid */ if (pointsPerFiber > 1) { /* operate on points of single fiber */ for (int i=0; i 0) { /* The color value of the current point is influenced by the previous point and next point. */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; vnl_vector_fixed< double, 3 > diff; diff = (diff1 - diff2) / 2.0; diff.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2])); rgba[3] = (unsigned char) (255.0); } else if (i==0) { /* First point has no previous point, therefore only diff1 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; diff1.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2])); rgba[3] = (unsigned char) (255.0); } else if (i==pointsPerFiber-1) { /* Last point has no next point, therefore only diff2 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; diff2.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2])); rgba[3] = (unsigned char) (255.0); } colorsT->InsertTupleValue(idList[i], rgba); } //end for loop } else if (pointsPerFiber == 1) { /* a single point does not define a fiber (use vertex mechanisms instead */ continue; // colorsT->InsertTupleValue(0, rgba); } else { MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ; continue; } }//end for loop m_FiberPolyData->GetPointData()->AddArray(colorsT); /*========================= - this is more relevant for renderer than for fiberbundleX datastructure - think about sourcing this to a explicit method which coordinates colorcoding */ this->SetColorCoding(COLORCODING_ORIENTATION_BASED); // =========================== //mini test, shall be ported to MITK TESTINGS! if (colorsT->GetSize() != numOfPoints*componentSize) MITK_DEBUG << "ALLOCATION ERROR IN INITIATING COLOR ARRAY"; } void mitk::FiberBundleX::DoColorCodingFaBased() { if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED) != 1 ) return; this->SetColorCoding(COLORCODING_FA_BASED); MITK_DEBUG << "FBX: done CC FA based"; this->GenerateFiberIds(); } void mitk::FiberBundleX::DoUseFaFiberOpacity() { if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED) != 1 ) return; if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED) != 1 ) return; vtkDoubleArray* FAValArray = (vtkDoubleArray*) m_FiberPolyData->GetPointData()->GetArray(COLORCODING_FA_BASED); vtkUnsignedCharArray* ColorArray = dynamic_cast (m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)); for(long i=0; iGetNumberOfTuples(); i++) { double faValue = FAValArray->GetValue(i); faValue = faValue * 255.0; ColorArray->SetComponent(i,3, (unsigned char) faValue ); } this->SetColorCoding(COLORCODING_ORIENTATION_BASED); MITK_DEBUG << "FBX: done CC OPACITY"; this->GenerateFiberIds(); } void mitk::FiberBundleX::ResetFiberOpacity() { vtkUnsignedCharArray* ColorArray = dynamic_cast (m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)); if (ColorArray==NULL) return; for(long i=0; iGetNumberOfTuples(); i++) ColorArray->SetComponent(i,3, 255.0 ); } void mitk::FiberBundleX::SetFAMap(mitk::Image::Pointer FAimage) { MITK_DEBUG << "SetFAMap"; vtkSmartPointer faValues = vtkSmartPointer::New(); faValues->SetName(COLORCODING_FA_BASED); faValues->Allocate(m_FiberPolyData->GetNumberOfPoints()); faValues->SetNumberOfValues(m_FiberPolyData->GetNumberOfPoints()); vtkPoints* pointSet = m_FiberPolyData->GetPoints(); for(long i=0; iGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double faPixelValue = 1-FAimage->GetPixelValueByWorldCoordinate(px); faValues->InsertValue(i, faPixelValue); } m_FiberPolyData->GetPointData()->AddArray(faValues); this->GenerateFiberIds(); if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED)) MITK_DEBUG << "FA VALUE ARRAY SET"; } void mitk::FiberBundleX::GenerateFiberIds() { if (m_FiberPolyData == NULL) return; vtkSmartPointer idFiberFilter = vtkSmartPointer::New(); idFiberFilter->SetInput(m_FiberPolyData); idFiberFilter->CellIdsOn(); // idFiberFilter->PointIdsOn(); // point id's are not needed idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY); idFiberFilter->FieldDataOn(); idFiberFilter->Update(); m_FiberIdDataSet = idFiberFilter->GetOutput(); MITK_DEBUG << "Generating Fiber Ids...[done] | " << m_FiberIdDataSet->GetNumberOfCells(); } mitk::FiberBundleX::Pointer mitk::FiberBundleX::ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint) { - vtkSmartPointer polyData = this->GetFiberPolyData(); + vtkSmartPointer polyData = m_FiberPolyData; if (anyPoint) { float minSpacing = 1; if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) minSpacing = mask->GetSpacing()[0]; else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) minSpacing = mask->GetSpacing()[1]; else minSpacing = mask->GetSpacing()[2]; mitk::FiberBundleX::Pointer fibCopy = this->GetDeepCopy(); - fibCopy->ResampleFibers(minSpacing/2); + fibCopy->ResampleFibers(minSpacing/10); polyData = fibCopy->GetFiberPolyData(); } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = polyData->GetLines(); + vtkSmartPointer vLinesOriginal = m_FiberPolyData->GetLines(); vLines->InitTraversal(); + vLinesOriginal->InitTraversal(); MITK_INFO << "Extracting fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, pointIds ); + vtkIdType numPointsOriginal(0); + vtkIdType* pointIdsOriginal(NULL); + vLinesOriginal->GetNextCell ( numPointsOriginal, pointIdsOriginal ); + vtkSmartPointer container = vtkSmartPointer::New(); if (numPoints>1) { if (anyPoint) { for (int j=0; jGetPoint(pointIds[j]); itk::Point itkP; - itkP[0] = p[0]; itkP[1] = p[1]; p[2] = p[2]; + itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); + if ( mask->GetPixel(idx)>0 ) { - for (int j=0; jGetPoint(pointIds[j]); + double* p = m_FiberPolyData->GetPoint(pointIdsOriginal[k]); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } break; } } } else { double* start = polyData->GetPoint(pointIds[0]); itk::Point itkStart; itkStart[0] = start[0]; itkStart[1] = start[1]; itkStart[2] = start[2]; itk::Index<3> idxStart; mask->TransformPhysicalPointToIndex(itkStart, idxStart); double* end = polyData->GetPoint(pointIds[numPoints-1]); itk::Point itkEnd; itkEnd[0] = end[0]; itkEnd[1] = end[1]; itkEnd[2] = end[2]; itk::Index<3> idxEnd; mask->TransformPhysicalPointToIndex(itkEnd, idxEnd); if ( mask->GetPixel(idxStart)>0 && mask->GetPixel(idxEnd)>0 ) { for (int j=0; jGetPoint(pointIds[j]); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } } } } vtkNewCells->InsertNextCell(container); } if (vtkNewCells->GetNumberOfCells()<=0) return NULL; vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); return mitk::FiberBundleX::New(newPolyData); } mitk::FiberBundleX::Pointer mitk::FiberBundleX::ExtractFiberSubset(mitk::PlanarFigure* pf) { if (pf==NULL) return NULL; std::vector tmp = ExtractFiberIdSubset(pf); if (tmp.size()<=0) return mitk::FiberBundleX::New(); vtkSmartPointer pTmp = GeneratePolyDataByIds(tmp); return mitk::FiberBundleX::New(pTmp); } std::vector mitk::FiberBundleX::ExtractFiberIdSubset(mitk::PlanarFigure* pf) { MITK_DEBUG << "Extracting fibers!"; // vector which is returned, contains all extracted FiberIds std::vector FibersInROI; if (pf==NULL) return FibersInROI; /* Handle type of planarfigure */ // if incoming pf is a pfc mitk::PlanarFigureComposite::Pointer pfcomp= dynamic_cast(pf); if (!pfcomp.IsNull()) { // process requested boolean operation of PFC switch (pfcomp->getOperationType()) { case 0: { MITK_DEBUG << "AND PROCESSING"; //AND //temporarly store results of the child in this vector, we need that to accumulate the std::vector childResults = this->ExtractFiberIdSubset(pfcomp->getChildAt(0)); MITK_DEBUG << "first roi got fibers in ROI: " << childResults.size(); MITK_DEBUG << "sorting..."; std::sort(childResults.begin(), childResults.end()); MITK_DEBUG << "sorting done"; std::vector AND_Assamblage(childResults.size()); //std::vector AND_Assamblage; fill(AND_Assamblage.begin(), AND_Assamblage.end(), -1); //AND_Assamblage.reserve(childResults.size()); //max size AND can reach anyway std::vector::iterator it; for (int i=1; igetNumberOfChildren(); ++i) { std::vector tmpChild = this->ExtractFiberIdSubset(pfcomp->getChildAt(i)); MITK_DEBUG << "ROI " << i << " has fibers in ROI: " << tmpChild.size(); sort(tmpChild.begin(), tmpChild.end()); it = std::set_intersection(childResults.begin(), childResults.end(), tmpChild.begin(), tmpChild.end(), AND_Assamblage.begin() ); } MITK_DEBUG << "resize Vector"; long i=0; while (i < AND_Assamblage.size() && AND_Assamblage[i] != -1){ //-1 represents a placeholder in the array ++i; } AND_Assamblage.resize(i); MITK_DEBUG << "returning AND vector, size: " << AND_Assamblage.size(); return AND_Assamblage; // break; } case 1: { //OR std::vector OR_Assamblage = this->ExtractFiberIdSubset(pfcomp->getChildAt(0)); std::vector::iterator it; MITK_DEBUG << OR_Assamblage.size(); for (int i=1; igetNumberOfChildren(); ++i) { it = OR_Assamblage.end(); std::vector tmpChild = this->ExtractFiberIdSubset(pfcomp->getChildAt(i)); OR_Assamblage.insert(it, tmpChild.begin(), tmpChild.end()); MITK_DEBUG << "ROI " << i << " has fibers in ROI: " << tmpChild.size() << " OR Assamblage: " << OR_Assamblage.size(); } sort(OR_Assamblage.begin(), OR_Assamblage.end()); it = unique(OR_Assamblage.begin(), OR_Assamblage.end()); OR_Assamblage.resize( it - OR_Assamblage.begin() ); MITK_DEBUG << "returning OR vector, size: " << OR_Assamblage.size(); return OR_Assamblage; } case 2: { //NOT //get IDs of all fibers std::vector childResults; childResults.reserve(this->GetNumFibers()); vtkSmartPointer idSet = m_FiberIdDataSet->GetCellData()->GetArray(FIBER_ID_ARRAY); MITK_DEBUG << "m_NumOfFib: " << this->GetNumFibers() << " cellIdNum: " << idSet->GetNumberOfTuples(); for(long i=0; iGetNumFibers(); i++) { MITK_DEBUG << "i: " << i << " idset: " << idSet->GetTuple(i)[0]; childResults.push_back(idSet->GetTuple(i)[0]); } std::sort(childResults.begin(), childResults.end()); std::vector NOT_Assamblage(childResults.size()); //fill it with -1, otherwise 0 will be stored and 0 can also be an ID of fiber! fill(NOT_Assamblage.begin(), NOT_Assamblage.end(), -1); std::vector::iterator it; for (long i=0; igetNumberOfChildren(); ++i) { std::vector tmpChild = ExtractFiberIdSubset(pfcomp->getChildAt(i)); sort(tmpChild.begin(), tmpChild.end()); it = std::set_difference(childResults.begin(), childResults.end(), tmpChild.begin(), tmpChild.end(), NOT_Assamblage.begin() ); } MITK_DEBUG << "resize Vector"; long i=0; while (NOT_Assamblage[i] != -1){ //-1 represents a placeholder in the array ++i; } NOT_Assamblage.resize(i); return NOT_Assamblage; } default: MITK_DEBUG << "we have an UNDEFINED composition... ERROR" ; break; } } else { mitk::Geometry2D::ConstPointer pfgeometry = pf->GetGeometry2D(); const mitk::PlaneGeometry* planeGeometry = dynamic_cast (pfgeometry.GetPointer()); Vector3D planeNormal = planeGeometry->GetNormal(); planeNormal.Normalize(); Point3D planeOrigin = planeGeometry->GetOrigin(); MITK_DEBUG << "planeOrigin: " << planeOrigin[0] << " | " << planeOrigin[1] << " | " << planeOrigin[2] << endl; MITK_DEBUG << "planeNormal: " << planeNormal[0] << " | " << planeNormal[1] << " | " << planeNormal[2] << endl; std::vector PointsOnPlane; // contains all pointIds which are crossing the cutting plane std::vector PointsInROI; // based on PointsOnPlane, all ROI relevant point IDs are stored here /* Define cutting plane by ROI (PlanarFigure) */ vtkSmartPointer plane = vtkSmartPointer::New(); plane->SetOrigin(planeOrigin[0],planeOrigin[1],planeOrigin[2]); plane->SetNormal(planeNormal[0],planeNormal[1],planeNormal[2]); /* get all points/fibers cutting the plane */ MITK_DEBUG << "start clipping"; vtkSmartPointer clipper = vtkSmartPointer::New(); clipper->SetInput(m_FiberIdDataSet); clipper->SetClipFunction(plane); clipper->GenerateClipScalarsOn(); clipper->GenerateClippedOutputOn(); vtkSmartPointer clipperout = clipper->GetClippedOutput(); MITK_DEBUG << "end clipping"; MITK_DEBUG << "init and update clipperoutput"; clipperout->GetPointData()->Initialize(); clipperout->Update(); MITK_DEBUG << "init and update clipperoutput completed"; MITK_DEBUG << "STEP 1: find all points which have distance 0 to the given plane"; /*======STEP 1====== * extract all points, which are crossing the plane */ // Scalar values describe the distance between each remaining point to the given plane. Values sorted by point index vtkSmartPointer distanceList = clipperout->GetPointData()->GetScalars(); vtkIdType sizeOfList = distanceList->GetNumberOfTuples(); PointsOnPlane.reserve(sizeOfList); /* use reserve for high-performant push_back, no hidden copy procedures are processed then! * size of list can be optimized by reducing allocation, but be aware of iterator and vector size*/ for (int i=0; iGetTuple(i); // check if point is on plane. // 0.01 due to some approximation errors when calculating distance if (distance[0] >= -0.01 && distance[0] <= 0.01) PointsOnPlane.push_back(i); } MITK_DEBUG << "Num Of points on plane: " << PointsOnPlane.size(); MITK_DEBUG << "Step 2: extract Interesting points with respect to given extraction planarFigure"; PointsInROI.reserve(PointsOnPlane.size()); /*=======STEP 2===== * extract ROI relevant pointIds */ mitk::PlanarCircle::Pointer circleName = mitk::PlanarCircle::New(); mitk::PlanarPolygon::Pointer polyName = mitk::PlanarPolygon::New(); if ( pf->GetNameOfClass() == circleName->GetNameOfClass() ) { //calculate circle radius mitk::Point3D V1w = pf->GetWorldControlPoint(0); //centerPoint mitk::Point3D V2w = pf->GetWorldControlPoint(1); //radiusPoint double distPF = V1w.EuclideanDistanceTo(V2w); for (int i=0; iGetPoint(PointsOnPlane[i])[0] - V1w[0]) * (clipperout->GetPoint(PointsOnPlane[i])[0] - V1w[0]) + (clipperout->GetPoint(PointsOnPlane[i])[1] - V1w[1]) * (clipperout->GetPoint(PointsOnPlane[i])[1] - V1w[1]) + (clipperout->GetPoint(PointsOnPlane[i])[2] - V1w[2]) * (clipperout->GetPoint(PointsOnPlane[i])[2] - V1w[2])) ; if( XdistPnt <= distPF) PointsInROI.push_back(PointsOnPlane[i]); } } else if ( pf->GetNameOfClass() == polyName->GetNameOfClass() ) { //create vtkPolygon using controlpoints from planarFigure polygon vtkSmartPointer polygonVtk = vtkSmartPointer::New(); //get the control points from pf and insert them to vtkPolygon unsigned int nrCtrlPnts = pf->GetNumberOfControlPoints(); for (int i=0; iGetPoints()->InsertNextPoint((double)pf->GetWorldControlPoint(i)[0], (double)pf->GetWorldControlPoint(i)[1], (double)pf->GetWorldControlPoint(i)[2] ); } //prepare everything for using pointInPolygon function double n[3]; polygonVtk->ComputeNormal(polygonVtk->GetPoints()->GetNumberOfPoints(), static_cast(polygonVtk->GetPoints()->GetData()->GetVoidPointer(0)), n); double bounds[6]; polygonVtk->GetPoints()->GetBounds(bounds); for (int i=0; iGetPoint(PointsOnPlane[i])[0], clipperout->GetPoint(PointsOnPlane[i])[1], clipperout->GetPoint(PointsOnPlane[i])[2]}; int isInPolygon = polygonVtk->PointInPolygon(checkIn, polygonVtk->GetPoints()->GetNumberOfPoints() , static_cast(polygonVtk->GetPoints()->GetData()->GetVoidPointer(0)), bounds, n); if( isInPolygon ) PointsInROI.push_back(PointsOnPlane[i]); } } MITK_DEBUG << "Step3: Identify fibers"; // we need to access the fiberId Array, so make sure that this array is available if (!clipperout->GetCellData()->HasArray(FIBER_ID_ARRAY)) { MITK_DEBUG << "ERROR: FiberID array does not exist, no correlation between points and fiberIds possible! Make sure calling GenerateFiberIds()"; return FibersInROI; // FibersInRoi is empty then } if (PointsInROI.size()<=0) return FibersInROI; // prepare a structure where each point id is represented as an indexId. // vector looks like: | pntId | fiberIdx | std::vector< long > pointindexFiberMap; // walk through the whole subline section and create an vector sorted by point index vtkCellArray *clipperlines = clipperout->GetLines(); clipperlines->InitTraversal(); long numOfLineCells = clipperlines->GetNumberOfCells(); long numofClippedPoints = clipperout->GetNumberOfPoints(); pointindexFiberMap.resize(numofClippedPoints); //prepare resulting vector FibersInROI.reserve(PointsInROI.size()); MITK_DEBUG << "\n===== Pointindex based structure initialized ======\n"; // go through resulting "sub"lines which are stored as cells, "i" corresponds to current line id. for (int i=0, ic=0 ; iGetCell(ic, npts, pts); // go through point ids in hosting subline, "j" corresponds to current pointindex in current line i. eg. idx[0]=45; idx[1]=46 for (long j=0; jGetCellData()->GetArray(FIBER_ID_ARRAY)->GetTuple(i)[0] << " to pointId: " << pts[j]; pointindexFiberMap[ pts[j] ] = clipperout->GetCellData()->GetArray(FIBER_ID_ARRAY)->GetTuple(i)[0]; // MITK_DEBUG << "in array: " << pointindexFiberMap[ pts[j] ]; } } MITK_DEBUG << "\n===== Pointindex based structure finalized ======\n"; // get all Points in ROI with according fiberID for (long k = 0; k < PointsInROI.size(); k++) { //MITK_DEBUG << "point " << PointsInROI[k] << " belongs to fiber " << pointindexFiberMap[ PointsInROI[k] ]; if (pointindexFiberMap[ PointsInROI[k] ]<=GetNumFibers() && pointindexFiberMap[ PointsInROI[k] ]>=0) FibersInROI.push_back(pointindexFiberMap[ PointsInROI[k] ]); else MITK_INFO << "ERROR in ExtractFiberIdSubset; impossible fiber id detected"; } m_PointsRoi = PointsInROI; } // detecting fiberId duplicates MITK_DEBUG << "check for duplicates"; sort(FibersInROI.begin(), FibersInROI.end()); bool hasDuplicats = false; for(long i=0; i::iterator it; it = unique (FibersInROI.begin(), FibersInROI.end()); FibersInROI.resize( it - FibersInROI.begin() ); } return FibersInROI; } void mitk::FiberBundleX::UpdateFiberGeometry() { vtkSmartPointer cleaner = vtkSmartPointer::New(); cleaner->SetInput(m_FiberPolyData); cleaner->PointMergingOff(); cleaner->Update(); m_FiberPolyData = cleaner->GetOutput(); m_FiberLengths.clear(); m_MeanFiberLength = 0; m_MedianFiberLength = 0; m_LengthStDev = 0; m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (m_NumFibers<=0) // no fibers present; apply default geometry { m_MinFiberLength = 0; m_MaxFiberLength = 0; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetImageGeometry(true); float b[] = {0, 1, 0, 1, 0, 1}; geometry->SetFloatBounds(b); SetGeometry(geometry); return; } float min = itk::NumericTraits::NonpositiveMin(); float max = itk::NumericTraits::max(); float b[] = {max, min, max, min, max, min}; vtkCellArray* cells = m_FiberPolyData->GetLines(); cells->InitTraversal(); for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int p = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float length = 0; for (int j=0; jGetPoint(j, p1); if (p1[0]b[1]) b[1]=p1[0]; if (p1[1]b[3]) b[3]=p1[1]; if (p1[2]b[5]) b[5]=p1[2]; // calculate statistics if (jGetPoint(j+1, p2); float dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); length += dist; } } m_FiberLengths.push_back(length); m_MeanFiberLength += length; if (i==0) { m_MinFiberLength = length; m_MaxFiberLength = length; } else { if (lengthm_MaxFiberLength) m_MaxFiberLength = length; } } m_MeanFiberLength /= m_NumFibers; std::vector< float > sortedLengths = m_FiberLengths; std::sort(sortedLengths.begin(), sortedLengths.end()); for (int i=0; i1) m_LengthStDev /= (m_NumFibers-1); else m_LengthStDev = 0; m_LengthStDev = std::sqrt(m_LengthStDev); m_MedianFiberLength = sortedLengths.at(m_NumFibers/2); // provide some border margin for(int i=0; i<=4; i+=2) b[i] -=10; for(int i=1; i<=5; i+=2) b[i] +=10; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetFloatBounds(b); this->SetGeometry(geometry); } QStringList mitk::FiberBundleX::GetAvailableColorCodings() { QStringList availableColorCodings; int numColors = m_FiberPolyData->GetPointData()->GetNumberOfArrays(); for(int i=0; iGetPointData()->GetArrayName(i)); } //this controlstructure shall be implemented by the calling method if (availableColorCodings.isEmpty()) MITK_DEBUG << "no colorcodings available in fiberbundleX"; return availableColorCodings; } char* mitk::FiberBundleX::GetCurrentColorCoding() { return m_CurrentColorCoding; } void mitk::FiberBundleX::SetColorCoding(const char* requestedColorCoding) { if (requestedColorCoding==NULL) return; MITK_DEBUG << "SetColorCoding:" << requestedColorCoding; if( strcmp (COLORCODING_ORIENTATION_BASED,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_ORIENTATION_BASED; } else if( strcmp (COLORCODING_FA_BASED,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_FA_BASED; } else if( strcmp (COLORCODING_CUSTOM,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_CUSTOM; } else { MITK_DEBUG << "FIBERBUNDLE X: UNKNOWN COLORCODING in FIBERBUNDLEX Datastructure"; this->m_CurrentColorCoding = (char*) COLORCODING_CUSTOM; //will cause blank colorcoding of fibers } } void mitk::FiberBundleX::RotateAroundAxis(double x, double y, double z) { MITK_INFO << "Rotating fibers"; x = x*M_PI/180; y = y*M_PI/180; z = z*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; mitk::Geometry3D::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rotZ*rotY*rotX*dir; dir[0] += center[0]; dir[1] += center[1]; dir[2] += center[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::ScaleFibers(double x, double y, double z) { MITK_INFO << "Scaling fibers"; boost::progress_display disp(m_NumFibers); mitk::Geometry3D* geom = this->GetGeometry(); mitk::Point3D c = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); p[0] -= c[0]; p[1] -= c[1]; p[2] -= c[2]; p[0] *= x; p[1] *= y; p[2] *= z; p[0] += c[0]; p[1] += c[1]; p[2] += c[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::TranslateFibers(double x, double y, double z) { MITK_INFO << "Translating fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); p[0] += x; p[1] += y; p[2] += z; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::MirrorFibers(unsigned int axis) { if (axis>2) return; MITK_INFO << "Mirroring fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); p[axis] = -p[axis]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } bool mitk::FiberBundleX::ApplyCurvatureThreshold(float minRadius, bool deleteFibers) { if (minRadius<0) return true; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vtkOldCells = m_FiberPolyData->GetLines(); vtkOldCells->InitTraversal(); MITK_INFO << "Applying curvature threshold"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkIdType numPoints(0); vtkIdType* points(NULL); vtkOldCells->GetNextCell ( numPoints, points ); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(points[j], p1); double p2[3]; m_FiberPolyData->GetPoint(points[j+1], p2); double p3[3]; m_FiberPolyData->GetPoint(points[j+2], p3); vnl_vector_fixed< float, 3 > v1, v2, v3; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; v2[2] = p3[2]-p2[2]; v3[0] = p1[0]-p3[0]; v3[1] = p1[1]-p3[1]; v3[2] = p1[2]-p3[2]; float a = v1.magnitude(); float b = v2.magnitude(); float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); if (deleteFibers && rInsertNextPoint(p2); // container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); container = vtkSmartPointer::New(); } else if (j==numPoints-3) { id = vtkNewPoints->InsertNextPoint(p2); container->GetPointIds()->InsertNextId(id); id = vtkNewPoints->InsertNextPoint(p3); container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); } } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } bool mitk::FiberBundleX::RemoveShortFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMMm_MaxFiberLength) // can't remove all fibers return false; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); float min = m_MaxFiberLength; MITK_INFO << "Removing short fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, pointIds ); if (m_FiberLengths.at(i)>=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); if (m_FiberLengths.at(i)GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } bool mitk::FiberBundleX::RemoveLongFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMM>m_MaxFiberLength) return true; if (lengthInMM vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); MITK_INFO << "Removing long fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, pointIds ); if (m_FiberLengths.at(i)<=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } void mitk::FiberBundleX::DoFiberSmoothing(int pointsPerCm, double tension, double continuity, double bias ) { vtkSmartPointer vtkSmoothPoints = vtkSmartPointer::New(); //in smoothpoints the interpolated points representing a fiber are stored. //in vtkcells all polylines are stored, actually all id's of them are stored vtkSmartPointer vtkSmoothCells = vtkSmartPointer::New(); //cellcontainer for smoothed lines vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); vtkIdType pointHelperCnt = 0; MITK_INFO << "Resampling fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer points = vtkSmartPointer::New(); for (int j=0; jInsertNextPoint(m_FiberPolyData->GetPoint(pointIds[j])); float length = m_FiberLengths.at(i); length /=10; int sampling = pointsPerCm*length; vtkSmartPointer xSpline = vtkSmartPointer::New(); vtkSmartPointer ySpline = vtkSmartPointer::New(); vtkSmartPointer zSpline = vtkSmartPointer::New(); xSpline->SetDefaultBias(bias); xSpline->SetDefaultTension(tension); xSpline->SetDefaultContinuity(continuity); ySpline->SetDefaultBias(bias); ySpline->SetDefaultTension(tension); ySpline->SetDefaultContinuity(continuity); zSpline->SetDefaultBias(bias); zSpline->SetDefaultTension(tension); zSpline->SetDefaultContinuity(continuity); vtkSmartPointer spline = vtkSmartPointer::New(); spline->SetXSpline(xSpline); spline->SetYSpline(ySpline); spline->SetZSpline(zSpline); spline->SetPoints(points); vtkSmartPointer functionSource = vtkSmartPointer::New(); functionSource->SetParametricFunction(spline); functionSource->SetUResolution(sampling); functionSource->SetVResolution(sampling); functionSource->SetWResolution(sampling); functionSource->Update(); vtkPolyData* outputFunction = functionSource->GetOutput(); vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber vtkSmartPointer smoothLine = vtkSmartPointer::New(); smoothLine->GetPointIds()->SetNumberOfIds(tmpSmoothPnts->GetNumberOfPoints()); for (int j=0; jGetNumberOfPoints(); j++) { smoothLine->GetPointIds()->SetId(j, j+pointHelperCnt); vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); } vtkSmoothCells->InsertNextCell(smoothLine); pointHelperCnt += tmpSmoothPnts->GetNumberOfPoints(); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); UpdateColorCoding(); UpdateFiberGeometry(); m_FiberSampling = pointsPerCm; } void mitk::FiberBundleX::DoFiberSmoothing(int pointsPerCm) { DoFiberSmoothing(pointsPerCm, 0, 0, 0 ); } // Resample fiber to get equidistant points void mitk::FiberBundleX::ResampleFibers(float pointDistance) { if (pointDistance<=0.00001) return; vtkSmartPointer newPoly = vtkSmartPointer::New(); vtkSmartPointer newCellArray = vtkSmartPointer::New(); vtkSmartPointer newPoints = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); int numberOfLines = m_NumFibers; MITK_INFO << "Resampling fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, points ); vtkSmartPointer container = vtkSmartPointer::New(); double* point = m_FiberPolyData->GetPoint(points[0]); vtkIdType pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); float dtau = 0; int cur_p = 1; itk::Vector dR; float normdR = 0; for (;;) { while (dtau <= pointDistance && cur_p < numPoints) { itk::Vector v1; point = m_FiberPolyData->GetPoint(points[cur_p-1]); v1[0] = point[0]; v1[1] = point[1]; v1[2] = point[2]; itk::Vector v2; point = m_FiberPolyData->GetPoint(points[cur_p]); v2[0] = point[0]; v2[1] = point[1]; v2[2] = point[2]; dR = v2 - v1; normdR = std::sqrt(dR.GetSquaredNorm()); dtau += normdR; cur_p++; } if (dtau >= pointDistance) { itk::Vector v1; point = m_FiberPolyData->GetPoint(points[cur_p-1]); v1[0] = point[0]; v1[1] = point[1]; v1[2] = point[2]; itk::Vector v2 = v1 - dR*( (dtau-pointDistance)/normdR ); pointId = newPoints->InsertNextPoint(v2.GetDataPointer()); container->GetPointIds()->InsertNextId(pointId); } else { point = m_FiberPolyData->GetPoint(points[numPoints-1]); pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); break; } dtau = dtau-pointDistance; } newCellArray->InsertNextCell(container); } newPoly->SetPoints(newPoints); newPoly->SetLines(newCellArray); m_FiberPolyData = newPoly; UpdateFiberGeometry(); UpdateColorCoding(); m_FiberSampling = 10/pointDistance; } // reapply selected colorcoding in case polydata structure has changed void mitk::FiberBundleX::UpdateColorCoding() { char* cc = GetCurrentColorCoding(); if( strcmp (COLORCODING_ORIENTATION_BASED,cc) == 0 ) DoColorCodingOrientationBased(); else if( strcmp (COLORCODING_FA_BASED,cc) == 0 ) DoColorCodingFaBased(); } // reapply selected colorcoding in case polydata structure has changed bool mitk::FiberBundleX::Equals(mitk::FiberBundleX* fib) { if (fib==NULL) return false; mitk::FiberBundleX::Pointer tempFib = this->SubtractBundle(fib); mitk::FiberBundleX::Pointer tempFib2 = fib->SubtractBundle(this); if (tempFib.IsNull() && tempFib2.IsNull()) return true; return false; } /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */ void mitk::FiberBundleX::UpdateOutputInformation() { } void mitk::FiberBundleX::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::FiberBundleX::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::FiberBundleX::VerifyRequestedRegion() { return true; } void mitk::FiberBundleX::SetRequestedRegion( itk::DataObject *data ) { } diff --git a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper2D.cpp b/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper2D.cpp index 02046959d5..1a89089ba8 100644 --- a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper2D.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper2D.cpp @@ -1,288 +1,278 @@ /*=================================================================== 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. ===================================================================*/ /* * mitkFiberBundleMapper2D.cpp * mitk-all * * Created by HAL9000 on 1/17/11. * Copyright 2011 __MyCompanyName__. All rights reserved. * */ #include "mitkFiberBundleXMapper2D.h" #include #include #include #include #include //#include //#include #include #include #include #include #include #include #include #include //#include #include #include -#include +#include #include -#include -#include -#include +#include +#include +#include mitk::FiberBundleXMapper2D::FiberBundleXMapper2D() { m_lut = vtkLookupTable::New(); m_lut->Build(); } mitk::FiberBundleXMapper2D::~FiberBundleXMapper2D() { } mitk::FiberBundleX* mitk::FiberBundleXMapper2D::GetInput() { return dynamic_cast< mitk::FiberBundleX * > ( GetDataNode()->GetData() ); } void mitk::FiberBundleXMapper2D::Update(mitk::BaseRenderer * renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; MITK_DEBUG << "MapperFBX 2D update: "; // Calculate time step of the input data for the specified renderer (integer value) // this method is implemented in mitkMapper this->CalculateTimeStep( renderer ); //check if updates occured in the node or on the display FBXLocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); const DataNode *node = this->GetDataNode(); if ( (localStorage->m_LastUpdateTime < node->GetMTime()) || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) //was a property modified? || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) { // MITK_INFO << "UPDATE NEEDED FOR _ " << renderer->GetName(); this->GenerateDataForRenderer( renderer ); } if ((localStorage->m_LastUpdateTime < renderer->GetDisplayGeometry()->GetMTime()) ) //was the display geometry modified? e.g. zooming, panning) { this->UpdateShaderParameter(renderer); } } void mitk::FiberBundleXMapper2D::UpdateShaderParameter(mitk::BaseRenderer * renderer) { FBXLocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); //get information about current position of views mitk::SliceNavigationController::Pointer sliceContr = renderer->GetSliceNavigationController(); mitk::PlaneGeometry::ConstPointer planeGeo = sliceContr->GetCurrentPlaneGeometry(); //generate according cutting planes based on the view position float sliceN[3], planeOrigin[3]; // since shader uses camera coordinates, transform origin and normal from worldcoordinates to cameracoordinates planeOrigin[0] = (float) planeGeo->GetOrigin()[0]; planeOrigin[1] = (float) planeGeo->GetOrigin()[1]; planeOrigin[2] = (float) planeGeo->GetOrigin()[2]; sliceN[0] = planeGeo->GetNormal()[0]; sliceN[1] = planeGeo->GetNormal()[1]; sliceN[2] = planeGeo->GetNormal()[2]; float tmp1 = planeOrigin[0] * sliceN[0]; float tmp2 = planeOrigin[1] * sliceN[1]; float tmp3 = planeOrigin[2] * sliceN[2]; float d1 = tmp1 + tmp2 + tmp3; //attention, correct normalvector float plane1[4]; plane1[0] = sliceN[0]; plane1[1] = sliceN[1]; plane1[2] = sliceN[2]; plane1[3] = d1; float thickness = 2.0; if(!this->GetDataNode()->GetPropertyValue("Fiber2DSliceThickness",thickness)) MITK_INFO << "FIBER2D SLICE THICKNESS PROPERTY ERROR"; bool fiberfading = false; if(!this->GetDataNode()->GetPropertyValue("Fiber2DfadeEFX",fiberfading)) MITK_INFO << "FIBER2D SLICE FADE EFX PROPERTY ERROR"; int fiberfading_i = 1; if (!fiberfading) fiberfading_i = 0; // set Opacity float fiberOpacity; this->GetDataNode()->GetOpacity(fiberOpacity, NULL); localStorage->m_PointActor->GetProperty()->AddShaderVariable("slicingPlane",4, plane1); localStorage->m_PointActor->GetProperty()->AddShaderVariable("fiberThickness",1, &thickness); localStorage->m_PointActor->GetProperty()->AddShaderVariable("fiberFadingON",1, &fiberfading_i); localStorage->m_PointActor->GetProperty()->AddShaderVariable("fiberOpacity", 1, &fiberOpacity); } +mitk::IShaderRepository *mitk::FiberBundleXMapper2D::GetShaderRepository() +{ + ServiceReference serviceRef = GetModuleContext()->GetServiceReference(); + if (serviceRef) + { + return GetModuleContext()->GetService(serviceRef); + } + return NULL; +} + // ALL RAW DATA FOR VISUALIZATION IS GENERATED HERE. // vtkActors and Mappers are feeded here void mitk::FiberBundleXMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { //the handler of local storage gets feeded in this method with requested data for related renderwindow FBXLocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); //this procedure is depricated, //not needed after initializaton anymore mitk::DataNode* node = this->GetDataNode(); if ( node == NULL ) { MITK_INFO << "check DATANODE: ....[Fail] "; return; } /////////////////////////////////// ///THIS GET INPUT mitk::FiberBundleX* fbx = this->GetInput(); localStorage->m_PointMapper->ScalarVisibilityOn(); localStorage->m_PointMapper->SetScalarModeToUsePointFieldData(); localStorage->m_PointMapper->SetLookupTable(m_lut); //apply the properties after the slice was set localStorage->m_PointActor->GetProperty()->SetOpacity(0.999); // set color if (fbx->GetCurrentColorCoding() != NULL){ // localStorage->m_PointMapper->SelectColorArray(""); localStorage->m_PointMapper->SelectColorArray(fbx->GetCurrentColorCoding()); MITK_DEBUG << "MapperFBX 2D: " << fbx->GetCurrentColorCoding(); if(fbx->GetCurrentColorCoding() == fbx->COLORCODING_CUSTOM){ float temprgb[3]; this->GetDataNode()->GetColor( temprgb, NULL ); double trgb[3] = { (double) temprgb[0], (double) temprgb[1], (double) temprgb[2] }; localStorage->m_PointActor->GetProperty()->SetColor(trgb); } } localStorage->m_PointMapper->SetInput(fbx->GetFiberPolyData()); localStorage->m_PointActor->SetMapper(localStorage->m_PointMapper); localStorage->m_PointActor->GetProperty()->ShadingOn(); // Applying shading properties + if (IShaderRepository* shaderRepo = GetShaderRepository()) { - mitk::ShaderRepository::GetGlobalShaderRepository()->ApplyProperties(this->GetDataNode(),localStorage->m_PointActor,renderer, localStorage->m_LastUpdateTime); + shaderRepo->ApplyProperties(this->GetDataNode(),localStorage->m_PointActor,renderer, localStorage->m_LastUpdateTime); } this->UpdateShaderParameter(renderer); // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } vtkProp* mitk::FiberBundleXMapper2D::GetVtkProp(mitk::BaseRenderer *renderer) { //MITK_INFO << "FiberBundleMapper2D GetVtkProp(renderer)"; this->Update(renderer); return m_LSH.GetLocalStorage(renderer)->m_PointActor; } void mitk::FiberBundleXMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { //add shader to datano - - - //####### load shader from file ######### - QString applicationDir = QCoreApplication::applicationDirPath(); - - if (applicationDir.endsWith("bin")) - applicationDir.append("/"); - else if (applicationDir.endsWith("MacOS")) - { - //on osx, check if path for installer or MITK development is needed - applicationDir.append("/"); - QFile f( applicationDir+"FiberTrackingLUTBaryCoords.bin" ); - if( !f.exists() ) // if file does not exist, then look in MITK development build directory - applicationDir.append("../../../"); - }else - applicationDir.append("\\..\\"); - - mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( applicationDir.toStdString().c_str(), false ); - mitk::ShaderRepository::Pointer shaderRepository = mitk::ShaderRepository::GetGlobalShaderRepository(); - shaderRepository->LoadShader(mitk::StandardFileLocations::GetInstance()->FindFile("mitkShaderFiberClipping.xml")); - - - - //#################################################################### node->SetProperty("shader",mitk::ShaderProperty::New("mitkShaderFiberClipping")); - mitk::ShaderRepository::GetGlobalShaderRepository()->AddDefaultProperties(node,renderer,overwrite); + if (IShaderRepository* shaderRepo = GetShaderRepository()) + { + shaderRepo->AddDefaultProperties(node,renderer,overwrite); + } //add other parameters to propertylist node->AddProperty( "Fiber2DSliceThickness", mitk::FloatProperty::New(2.0f), renderer, overwrite ); node->AddProperty( "Fiber2DfadeEFX", mitk::BoolProperty::New(true), renderer, overwrite ); Superclass::SetDefaultProperties(node, renderer, overwrite); } mitk::FiberBundleXMapper2D::FBXLocalStorage::FBXLocalStorage() { m_PointActor = vtkSmartPointer::New(); m_PointMapper = vtkSmartPointer::New(); } diff --git a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper2D.h b/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper2D.h index 6381cb381d..59cc048edf 100644 --- a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper2D.h +++ b/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper2D.h @@ -1,107 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef FIBERBUNDLEXMAPPER2D_H_HEADER_INCLUDED #define FIBERBUNDLEXMAPPER2D_H_HEADER_INCLUDED //MITK Rendering #include #include //#include "FiberTrackingExports.h" #include #include #include class vtkActor; //class vtkPropAssembly; //lets see if we need it class mitkBaseRenderer; class vtkPolyDataMapper; class vtkCutter; class vtkPlane; class vtkPolyData; namespace mitk { + struct IShaderRepository; class FiberBundleXMapper2D : public VtkMapper { public: mitkClassMacro(FiberBundleXMapper2D, VtkMapper); itkNewMacro(Self); mitk::FiberBundleX* GetInput(); /** \brief Checks whether this mapper needs to update itself and generate * data. */ virtual void Update(mitk::BaseRenderer * renderer); static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = NULL, bool overwrite = false ); //### methods of MITK-VTK rendering pipeline virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); //### end of methods of MITK-VTK rendering pipeline class FBXLocalStorage : public mitk::Mapper::BaseLocalStorage { public: /** \brief Point Actor of a 2D render window. */ vtkSmartPointer m_PointActor; /** \brief Point Mapper of a 2D render window. */ vtkSmartPointer m_PointMapper; vtkSmartPointer m_SlicingPlane; //needed later when optimized 2D mapper vtkSmartPointer m_SlicedResult; //might be depricated in optimized 2D mapper /** \brief Timestamp of last update of stored data. */ itk::TimeStamp m_LastUpdateTime; /** \brief Constructor of the local storage. Do as much actions as possible in here to avoid double executions. */ FBXLocalStorage(); //if u copy&paste from this 2Dmapper, be aware that the implementation of this constructor is in the cpp file ~FBXLocalStorage() { } }; /** \brief This member holds all three LocalStorages for the three 2D render windows. */ mitk::Mapper::LocalStorageHandler m_LSH; protected: FiberBundleXMapper2D(); virtual ~FiberBundleXMapper2D(); /** Does the actual resampling, without rendering. */ virtual void GenerateDataForRenderer(mitk::BaseRenderer*); void UpdateShaderParameter(mitk::BaseRenderer*); + static IShaderRepository* GetShaderRepository(); + private: vtkSmartPointer m_lut; }; }//end namespace #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkShaderFiberClipping.xml b/Modules/DiffusionImaging/FiberTracking/Resources/Shaders/mitkShaderFiberClipping.xml similarity index 82% rename from Modules/DiffusionImaging/FiberTracking/Rendering/mitkShaderFiberClipping.xml rename to Modules/DiffusionImaging/FiberTracking/Resources/Shaders/mitkShaderFiberClipping.xml index ceedf961af..da3da5b910 100644 --- a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkShaderFiberClipping.xml +++ b/Modules/DiffusionImaging/FiberTracking/Resources/Shaders/mitkShaderFiberClipping.xml @@ -1,56 +1,56 @@ - - + + varying vec3 positionWorld; varying vec3 color; - - void main(void) + + void main(void) { color = gl_Color.rgb; positionWorld = vec3(gl_Vertex); gl_Position = ftransform(); } - + - + uniform vec4 slicingPlane; uniform float fiberThickness; uniform int fiberFadingON; uniform float fiberOpacity; - + varying vec3 positionWorld; varying vec3 color; - + void main(void) { float r1 = dot(positionWorld, slicingPlane.xyz) - slicingPlane.w; - + if ( abs(r1) > fiberThickness ) discard; - + if (fiberFadingON != 0) { float x = (r1+fiberThickness)/(fiberThickness*2.0); x = 1.0 - x; - gl_FragColor = vec4(color*x, fiberOpacity); + gl_FragColor = vec4(color*x, fiberOpacity); }else{ gl_FragColor = vec4(color, fiberOpacity); } - + } - + - + diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkAstroStickModel.cpp b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkAstroStickModel.cpp new file mode 100644 index 0000000000..753b8b9f20 --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkAstroStickModel.cpp @@ -0,0 +1,88 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#include +#include + +template< class ScalarType > +AstroStickModel< ScalarType >::AstroStickModel() + : m_Diffusivity(0.001) + , m_BValue(1000) + , m_NumSticks(42) + , m_RandomizeSticks(false) +{ + m_RandGen = ItkRandGenType::New(); + + vnl_matrix_fixed* sticks = itk::PointShell<42, vnl_matrix_fixed >::DistributePointShell(); + for (int i=0; iget(0,i); stick[1] = sticks->get(1,i); stick[2] = sticks->get(2,i); + stick.Normalize(); + m_Sticks.push_back(stick); + } +} + +template< class ScalarType > +AstroStickModel< ScalarType >::~AstroStickModel() +{ + +} + +template< class ScalarType > +typename AstroStickModel< ScalarType >::GradientType AstroStickModel< ScalarType >::GetRandomDirection() +{ + GradientType vec; + vec[0] = m_RandGen->GetNormalVariate(); + vec[1] = m_RandGen->GetNormalVariate(); + vec[2] = m_RandGen->GetNormalVariate(); + vec.Normalize(); + return vec; +} + +template< class ScalarType > +typename AstroStickModel< ScalarType >::PixelType AstroStickModel< ScalarType >::SimulateMeasurement() +{ + PixelType signal; + signal.SetSize(this->m_GradientList.size()); + double b = -m_BValue*m_Diffusivity; + + if (m_RandomizeSticks) + m_NumSticks = 30 + m_RandGen->GetIntegerVariate()%31; + + for( unsigned int i=0; im_GradientList.size(); i++) + { + GradientType g = this->m_GradientList[i]; + double bVal = g.GetNorm(); bVal *= bVal; + + if (bVal>0.0001) + { + for (int j=0; j +#include + +namespace mitk { + +/** + * \brief Generates the diffusion signal using an idealised cylinder with zero radius: e^(-bd(ng)²) + * + */ + +template< class ScalarType > +class AstroStickModel : public DiffusionSignalModel< ScalarType > +{ +public: + + AstroStickModel(); + ~AstroStickModel(); + + typedef typename DiffusionSignalModel< ScalarType >::PixelType PixelType; + typedef typename DiffusionSignalModel< ScalarType >::GradientType GradientType; + typedef typename DiffusionSignalModel< ScalarType >::GradientListType GradientListType; + typedef itk::Statistics::MersenneTwisterRandomVariateGenerator ItkRandGenType; + + /** Actual signal generation **/ + PixelType SimulateMeasurement(); + + void SetRandomizeSticks(bool randomize=true){ m_RandomizeSticks=randomize; } + void SetBvalue(float bValue) { m_BValue = bValue; } ///< b-value used to generate the artificial signal + void SetDiffusivity(float diffusivity) { m_Diffusivity = diffusivity; } ///< Scalar diffusion constant + void SetNumSticks(unsigned int order) + { + vnl_matrix sticks; + switch (order) + { + case 1: + m_NumSticks = 12; + sticks = itk::PointShell<12, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); + break; + case 2: + m_NumSticks = 42; + sticks = itk::PointShell<42, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); + break; + case 3: + m_NumSticks = 92; + sticks = itk::PointShell<92, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); + break; + case 4: + m_NumSticks = 162; + sticks = itk::PointShell<162, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); + break; + case 5: + m_NumSticks = 252; + sticks = itk::PointShell<252, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); + break; + default: + m_NumSticks = 42; + sticks = itk::PointShell<42, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); + break; + } + for (int i=0; i #include #include #include namespace mitk { /** * \brief Abstract class for diffusion signal models * */ template< class ScalarType > class DiffusionSignalModel { public: DiffusionSignalModel() : m_T2(100) + , m_Weight(1) {} ~DiffusionSignalModel(){} typedef itk::VariableLengthVector< ScalarType > PixelType; typedef itk::Vector GradientType; typedef std::vector GradientListType; /** Realizes actual signal generation. Has to be implemented in subclass. **/ virtual PixelType SimulateMeasurement() = 0; void SetFiberDirection(GradientType fiberDirection){ m_FiberDirection = fiberDirection; } void SetGradientList(GradientListType gradientList) { m_GradientList = gradientList; } void SetT2(double T2) { m_T2 = T2; } + void SetWeight(double Weight) { m_Weight = Weight; } + double GetWeight() { return m_Weight; } double GetT2() { return m_T2; } int GetNumGradients(){ return m_GradientList.size(); } std::vector< int > GetBaselineIndices() { std::vector< int > result; for( unsigned int i=0; im_GradientList.size(); i++) if (m_GradientList.at(i).GetNorm()<0.0001) result.push_back(i); return result; } int GetFirstBaselineIndex() { for( unsigned int i=0; im_GradientList.size(); i++) if (m_GradientList.at(i).GetNorm()<0.0001) return i; return -1; } + bool IsBaselineIndex(int idx) + { + if (m_GradientList.size()>idx && m_GradientList.at(idx).GetNorm()<0.0001) + return true; + } protected: GradientType m_FiberDirection; ///< Needed to generate anisotropc signal to determin direction of anisotropy GradientListType m_GradientList; ///< Diffusion gradient direction container double m_T2; ///< Tissue specific relaxation time + double m_Weight; }; } #endif diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.cpp similarity index 53% copy from Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h copy to Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.cpp index b96fd0fb6e..c1759751e0 100644 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.cpp @@ -1,40 +1,38 @@ /*=================================================================== 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 MITKPLUGINACTIVATOR_H -#define MITKPLUGINACTIVATOR_H +#include +#include -#include -#include +template< class ScalarType > +DotModel< ScalarType >::DotModel() +{ +} -namespace mitk { - - class MITK_LOCAL PluginActivator : - public QObject, public ctkPluginActivator - { - Q_OBJECT - Q_INTERFACES(ctkPluginActivator) - - public: - - void start(ctkPluginContext* context); - void stop(ctkPluginContext* context); - - }; // PluginActivator +template< class ScalarType > +DotModel< ScalarType >::~DotModel() +{ } -#endif // MITKPLUGINACTIVATOR_H +template< class ScalarType > +typename DotModel< ScalarType >::PixelType DotModel< ScalarType >::SimulateMeasurement() +{ + PixelType signal; + signal.SetSize(this->m_GradientList.size()); + signal.Fill(1); + return signal; +} diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.h new file mode 100644 index 0000000000..5a4cc038f0 --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.h @@ -0,0 +1,52 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef _MITK_DotModel_H +#define _MITK_DotModel_H + +#include + +namespace mitk { + +/** + * \brief Generates direction independent diffusion measurement employing a scalar diffusion constant d: e^(-bd) + * + */ + +template< class ScalarType > +class DotModel : public DiffusionSignalModel< ScalarType > +{ +public: + + DotModel(); + ~DotModel(); + + typedef typename DiffusionSignalModel< ScalarType >::PixelType PixelType; + typedef typename DiffusionSignalModel< ScalarType >::GradientType GradientType; + + /** Actual signal generation **/ + PixelType SimulateMeasurement(); + +protected: + +}; + +} + +#include "mitkDotModel.cpp" + +#endif + diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkKspaceArtifact.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkKspaceArtifact.h index 5c76a38364..a94d8dfb5d 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkKspaceArtifact.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkKspaceArtifact.h @@ -1,66 +1,67 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_KspaceArtifact_H #define _MITK_KspaceArtifact_H #include #include #include namespace mitk { /** * \brief Abstract class for diffusion noise models * */ template< class ScalarType > class KspaceArtifact { public: KspaceArtifact() : m_T2(2000) - , m_TE(20) - , m_T2star(50) + , m_TE(100) + , m_Tinhom(50) , m_LineReadoutTime(1) { } ~KspaceArtifact(){} typedef typename itk::FFTRealToComplexConjugateImageFilter< ScalarType, 2 >::OutputImageType ComplexSliceType; /** Adds artifact according to model to the input slice. Has to be implemented in subclass. **/ virtual typename ComplexSliceType::Pointer AddArtifact(typename ComplexSliceType::Pointer slice) = 0; - void SetTline(unsigned int LineReadoutTime){ m_LineReadoutTime=LineReadoutTime; } - void SetT2(unsigned int T2){ m_T2=T2; } - void SetTE(unsigned int TE){ m_TE=TE; } - void SetT2star(unsigned int T2star){ m_T2star=T2star; } + // all times stored internally in µ seconds, input in milliseconds + void SetTline(double LineReadoutTime){ m_LineReadoutTime=LineReadoutTime; } + void SetTE(double TE){ m_TE=TE; } + void SetT2(double T2){ m_T2=T2; } + void SetTinhom(unsigned int Tinhom){ m_Tinhom=Tinhom; } protected: - unsigned int m_T2star; - unsigned int m_T2; - unsigned int m_TE; - double m_LineReadoutTime; + double m_Tinhom; + double m_T2; + double m_TE; + double m_LineReadoutTime; }; } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkT2SmearingArtifact.cpp b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkSignalDecay.cpp similarity index 69% rename from Modules/DiffusionImaging/FiberTracking/SignalModels/mitkT2SmearingArtifact.cpp rename to Modules/DiffusionImaging/FiberTracking/SignalModels/mitkSignalDecay.cpp index 3c6d08c671..e68047ecad 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkT2SmearingArtifact.cpp +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkSignalDecay.cpp @@ -1,53 +1,53 @@ /*=================================================================== 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. ===================================================================*/ template< class ScalarType > -T2SmearingArtifact< ScalarType >::T2SmearingArtifact() +SignalDecay< ScalarType >::SignalDecay() { } template< class ScalarType > -T2SmearingArtifact< ScalarType >::~T2SmearingArtifact() +SignalDecay< ScalarType >::~SignalDecay() { } template< class ScalarType > -typename T2SmearingArtifact< ScalarType >::ComplexSliceType::Pointer T2SmearingArtifact< ScalarType >::AddArtifact(typename ComplexSliceType::Pointer slice) +typename SignalDecay< ScalarType >::ComplexSliceType::Pointer SignalDecay< ScalarType >::AddArtifact(typename ComplexSliceType::Pointer slice) { itk::ImageRegion<2> region = slice->GetLargestPossibleRegion(); - double dt = (double)this->m_LineReadoutTime/region.GetSize(0); + double dt = this->m_LineReadoutTime/region.GetSize(0); - double from90 = (double)this->m_TE - this->m_LineReadoutTime*(double)region.GetSize(1)/2; - double fromMaxEcho = - this->m_LineReadoutTime*(double)region.GetSize(1)/2; + double from90 = this->m_TE - this->m_LineReadoutTime*region.GetSize(1)/2; + double fromMaxEcho = - this->m_LineReadoutTime*region.GetSize(1)/2; for (int y=0; y pix = slice->GetPixel(idx); - double fact = exp(-from90/this->m_T2 -fabs(fromMaxEcho)/this->m_T2star); + double fact = exp(-from90/this->m_T2 -fabs(fromMaxEcho)/this->m_Tinhom); std::complex< double > newPix(fact*pix.real(), fact*pix.imag()); slice->SetPixel(idx, newPix); from90 += dt; fromMaxEcho += dt; } return slice; } diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkT2SmearingArtifact.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkSignalDecay.h similarity index 77% rename from Modules/DiffusionImaging/FiberTracking/SignalModels/mitkT2SmearingArtifact.h rename to Modules/DiffusionImaging/FiberTracking/SignalModels/mitkSignalDecay.h index 71d05dcc29..495e6a41d6 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkT2SmearingArtifact.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkSignalDecay.h @@ -1,53 +1,53 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef _MITK_T2SmearingArtifact_H -#define _MITK_T2SmearingArtifact_H +#ifndef _MITK_SignalDecay_H +#define _MITK_SignalDecay_H #include #include #include #include namespace mitk { /** * \brief Class to add gibbs ringing artifact to input complex slice * */ template< class ScalarType > -class T2SmearingArtifact : public KspaceArtifact< ScalarType > +class SignalDecay : public KspaceArtifact< ScalarType > { public: - T2SmearingArtifact(); - ~T2SmearingArtifact(); + SignalDecay(); + ~SignalDecay(); typedef typename KspaceArtifact< ScalarType >::ComplexSliceType ComplexSliceType; - /** Attenuate signal according to given T2 time. **/ + /** Attenuate signal according to given relaxation times. **/ typename ComplexSliceType::Pointer AddArtifact(typename ComplexSliceType::Pointer slice); protected: }; -#include "mitkT2SmearingArtifact.cpp" +#include "mitkSignalDecay.cpp" } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.cpp b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.cpp index b23d6d6443..28ee1cb38c 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.cpp +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.cpp @@ -1,115 +1,80 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include template< class ScalarType > TensorModel< ScalarType >::TensorModel() - : m_KernelFA(0.6) - , m_KernelADC(0.001) - , m_BValue(1000) + : m_BValue(1000) { m_KernelDirection[0]=1; m_KernelDirection[1]=0; m_KernelDirection[2]=0; - UpdateKernelTensor(); -} - -template< class ScalarType > -TensorModel< ScalarType >::~TensorModel() -{ - -} - -template< class ScalarType > -void TensorModel< ScalarType >::UpdateKernelTensor() -{ - ItkTensorType tensor; tensor.Fill(0.0); - float e1 = m_KernelADC*(1+2*m_KernelFA/sqrt(3-2*m_KernelFA*m_KernelFA)); - float e2 = m_KernelADC*(1-m_KernelFA/sqrt(3-2*m_KernelFA*m_KernelFA)); - tensor.SetElement(0, e1); - tensor.SetElement(3, e2); - tensor.SetElement(5, e2); - m_KernelTensorMatrix.fill(0.0); - m_KernelTensorMatrix[0][0] = e1; m_KernelTensorMatrix[1][1] = e2; m_KernelTensorMatrix[2][2] = e2; -} - -template< class ScalarType > -void TensorModel< ScalarType >::SetKernelFA(float FA) -{ - m_KernelFA = FA; - UpdateKernelTensor(); + m_KernelTensorMatrix[0][0] = 0.002; + m_KernelTensorMatrix[1][1] = 0.0005; + m_KernelTensorMatrix[2][2] = 0.0005; } template< class ScalarType > -void TensorModel< ScalarType >::SetKernelADC(float ADC) +TensorModel< ScalarType >::~TensorModel() { - m_KernelADC = ADC; - UpdateKernelTensor(); -} -template< class ScalarType > -void TensorModel< ScalarType >::SetKernelTensor(ItkTensorType& tensor) -{ - m_KernelTensorMatrix[0][0] = tensor[0]; m_KernelTensorMatrix[0][1] = tensor[1]; m_KernelTensorMatrix[0][2] = tensor[2]; - m_KernelTensorMatrix[1][0] = tensor[1]; m_KernelTensorMatrix[1][1] = tensor[3]; m_KernelTensorMatrix[1][2] = tensor[4]; - m_KernelTensorMatrix[2][0] = tensor[2]; m_KernelTensorMatrix[2][1] = tensor[4]; m_KernelTensorMatrix[2][2] = tensor[5]; } template< class ScalarType > typename TensorModel< ScalarType >::PixelType TensorModel< ScalarType >::SimulateMeasurement() { PixelType signal; signal.SetSize(this->m_GradientList.size()); signal.Fill(0.0); ItkTensorType tensor; tensor.Fill(0.0); this->m_FiberDirection.Normalize(); vnl_vector_fixed axis = itk::CrossProduct(m_KernelDirection, this->m_FiberDirection).GetVnlVector(); axis.normalize(); vnl_quaternion rotation(axis, acos(m_KernelDirection*this->m_FiberDirection)); rotation.normalize(); vnl_matrix_fixed matrix = rotation.rotation_matrix_transpose(); vnl_matrix_fixed tensorMatrix = matrix.transpose()*m_KernelTensorMatrix*matrix; tensor[0] = tensorMatrix[0][0]; tensor[1] = tensorMatrix[0][1]; tensor[2] = tensorMatrix[0][2]; tensor[3] = tensorMatrix[1][1]; tensor[4] = tensorMatrix[1][2]; tensor[5] = tensorMatrix[2][2]; for( unsigned int i=0; im_GradientList.size(); i++) { GradientType g = this->m_GradientList[i]; double bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) { itk::DiffusionTensor3D S; S[0] = g[0]*g[0]; S[1] = g[1]*g[0]; S[2] = g[2]*g[0]; S[3] = g[1]*g[1]; S[4] = g[2]*g[1]; S[5] = g[2]*g[2]; double D = tensor[0]*S[0] + tensor[1]*S[1] + tensor[2]*S[2] + tensor[1]*S[1] + tensor[3]*S[3] + tensor[4]*S[4] + tensor[2]*S[2] + tensor[4]*S[4] + tensor[5]*S[5]; // check for corrupted tensor and generate signal if (D>=0) signal[i] = exp ( -m_BValue * bVal * D ); } else signal[i] = 1; } return signal; } diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.h index fbb6b6eed2..0a94e5b860 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.h @@ -1,67 +1,64 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_TensorModel_H #define _MITK_TensorModel_H #include #include namespace mitk { /** * \brief Generates diffusion measurement employing a second rank tensor model: e^(-bg^TDg) * */ template< class ScalarType > class TensorModel : public DiffusionSignalModel< ScalarType > { public: TensorModel(); ~TensorModel(); typedef typename DiffusionSignalModel< ScalarType >::PixelType PixelType; typedef itk::DiffusionTensor3D< float > ItkTensorType; typedef typename DiffusionSignalModel< ScalarType >::GradientType GradientType; /** Actual signal generation **/ PixelType SimulateMeasurement(); - void SetKernelDirection(GradientType kernelDirection){ m_KernelDirection = kernelDirection; } - void SetKernelTensor(ItkTensorType& tensor); - void SetKernelFA(float FA); - void SetKernelADC(float ADC); void SetBvalue(float bValue) { m_BValue = bValue; } + void SetDiffusivity1(ScalarType d1){ m_KernelTensorMatrix[0][0] = d1; } + void SetDiffusivity2(ScalarType d2){ m_KernelTensorMatrix[1][1] = d2; } + void SetDiffusivity3(ScalarType d3){ m_KernelTensorMatrix[2][2] = d3; } protected: /** Calculates tensor matrix from FA and ADC **/ void UpdateKernelTensor(); - GradientType m_KernelDirection; ///< Direction of the kernel tensors principal eigenvector - vnl_matrix_fixed m_KernelTensorMatrix; ///< 3x3 matrix containing the kernel tensor values - float m_KernelFA; ///< FA of the kernel tensor - float m_KernelADC; ///< ADC of the kernel tensor - float m_BValue; ///< b-value used to generate the artificial signal + GradientType m_KernelDirection; ///< Direction of the kernel tensors principal eigenvector + vnl_matrix_fixed m_KernelTensorMatrix; ///< 3x3 matrix containing the kernel tensor values + float m_BValue; ///< b-value used to generate the artificial signal }; } #include "mitkTensorModel.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt index d6aa30bd5f..4d347cf758 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt @@ -1,5 +1,5 @@ MITK_CREATE_MODULE_TESTS() mitkAddCustomModuleTest(mitkFiberBundleXReaderWriterTest mitkFiberBundleXReaderWriterTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib) -mitkAddCustomModuleTest(mitkGibbsTrackingTest mitkGibbsTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/qBallImage.qbi ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/gibbsTrackingParameters.gtp ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib) +mitkAddCustomModuleTest(mitkGibbsTrackingTest mitkGibbsTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/qBallImage.qbi ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/gibbsTrackingParameters.gtp ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib) #mitkAddCustomModuleTest(mitkFiberBundleXTest mitkFiberBundleXTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib) diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkGibbsTrackingTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkGibbsTrackingTest.cpp index f21b2bcbb0..937e752d2a 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkGibbsTrackingTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkGibbsTrackingTest.cpp @@ -1,101 +1,99 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include using namespace mitk; /**Documentation * Test for gibbs tracking filter */ int mitkGibbsTrackingTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkGibbsTrackingTest"); - MITK_TEST_CONDITION_REQUIRED(argc>5,"check for input data") + MITK_TEST_CONDITION_REQUIRED(argc>4,"check for input data") QBallImage::Pointer mitkQballImage; Image::Pointer mitkMaskImage; mitk::FiberBundleX::Pointer fib1; try{ MITK_INFO << "Q-Ball image: " << argv[1]; MITK_INFO << "Mask image: " << argv[2]; MITK_INFO << "Parameter file: " << argv[3]; - MITK_INFO << "Lut path: " << argv[4]; - MITK_INFO << "Reference bundle: " << argv[5]; + MITK_INFO << "Reference bundle: " << argv[4]; RegisterDiffusionCoreObjectFactory(); RegisterFiberTrackingObjectFactory(); // test if fib1 can be read const std::string s1="", s2=""; std::vector infile = mitk::BaseDataIO::LoadBaseDataFromFile( argv[1], s1, s2, false ); mitkQballImage = dynamic_cast(infile.at(0).GetPointer()); MITK_TEST_CONDITION_REQUIRED(mitkQballImage.IsNotNull(),"check qball image") infile = mitk::BaseDataIO::LoadBaseDataFromFile( argv[2], s1, s2, false ); mitkMaskImage = dynamic_cast(infile.at(0).GetPointer()); MITK_TEST_CONDITION_REQUIRED(mitkMaskImage.IsNotNull(),"check mask image") - infile = mitk::BaseDataIO::LoadBaseDataFromFile( argv[5], s1, s2, false ); + infile = mitk::BaseDataIO::LoadBaseDataFromFile( argv[4], s1, s2, false ); fib1 = dynamic_cast(infile.at(0).GetPointer()); MITK_TEST_CONDITION_REQUIRED(fib1.IsNotNull(),"check fiber bundle") typedef itk::Vector OdfVectorType; typedef itk::Image OdfVectorImgType; typedef itk::Image MaskImgType; typedef itk::GibbsTrackingFilter GibbsTrackingFilterType; OdfVectorImgType::Pointer itk_qbi = OdfVectorImgType::New(); mitk::CastToItkImage(mitkQballImage, itk_qbi); MaskImgType::Pointer itk_mask = MaskImgType::New(); mitk::CastToItkImage(mitkMaskImage, itk_mask); GibbsTrackingFilterType::Pointer gibbsTracker = GibbsTrackingFilterType::New(); gibbsTracker->SetQBallImage(itk_qbi.GetPointer()); gibbsTracker->SetMaskImage(itk_mask); gibbsTracker->SetDuplicateImage(false); gibbsTracker->SetRandomSeed(1); gibbsTracker->SetLoadParameterFile(argv[3]); - gibbsTracker->SetLutPath(argv[4]); gibbsTracker->Update(); mitk::FiberBundleX::Pointer fib2 = mitk::FiberBundleX::New(gibbsTracker->GetFiberBundle()); MITK_TEST_CONDITION_REQUIRED(fib1->Equals(fib2), "check if gibbs tracking has changed"); gibbsTracker->SetRandomSeed(0); gibbsTracker->Update(); fib2 = mitk::FiberBundleX::New(gibbsTracker->GetFiberBundle()); MITK_TEST_CONDITION_REQUIRED(!fib1->Equals(fib2), "check if gibbs tracking has changed after wrong seed"); } catch(...) { return EXIT_FAILURE; } // always end with this! MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/FiberTracking/files.cmake b/Modules/DiffusionImaging/FiberTracking/files.cmake index 36e2eb59cf..dec7c0be87 100644 --- a/Modules/DiffusionImaging/FiberTracking/files.cmake +++ b/Modules/DiffusionImaging/FiberTracking/files.cmake @@ -1,88 +1,100 @@ set(CPP_FILES # DataStructures -> FiberBundleX IODataStructures/FiberBundleX/mitkFiberBundleX.cpp IODataStructures/FiberBundleX/mitkFiberBundleXWriter.cpp IODataStructures/FiberBundleX/mitkFiberBundleXReader.cpp IODataStructures/FiberBundleX/mitkFiberBundleXIOFactory.cpp IODataStructures/FiberBundleX/mitkFiberBundleXWriterFactory.cpp IODataStructures/FiberBundleX/mitkFiberBundleXSerializer.cpp IODataStructures/FiberBundleX/mitkFiberBundleXThreadMonitor.cpp # DataStructures -> PlanarFigureComposite IODataStructures/PlanarFigureComposite/mitkPlanarFigureComposite.cpp # DataStructures IODataStructures/mitkFiberTrackingObjectFactory.cpp # Rendering Rendering/mitkFiberBundleXMapper2D.cpp Rendering/mitkFiberBundleXMapper3D.cpp Rendering/mitkFiberBundleXThreadMonitorMapper3D.cpp #Rendering/mitkPlanarFigureMapper3D.cpp # Interactions Interactions/mitkFiberBundleInteractor.cpp # Algorithms Algorithms/mitkTractAnalyzer.cpp # Tractography Algorithms/GibbsTracking/mitkParticleGrid.cpp Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.cpp Algorithms/GibbsTracking/mitkEnergyComputer.cpp Algorithms/GibbsTracking/mitkGibbsEnergyComputer.cpp Algorithms/GibbsTracking/mitkFiberBuilder.cpp + Algorithms/GibbsTracking/mitkSphereInterpolator.cpp ) set(H_FILES # Rendering Rendering/mitkFiberBundleXMapper3D.h Rendering/mitkFiberBundleXMapper2D.h Rendering/mitkFiberBundleXThreadMonitorMapper3D.h #Rendering/mitkPlanarFigureMapper3D.h # DataStructures -> FiberBundleX IODataStructures/FiberBundleX/mitkFiberBundleX.h IODataStructures/FiberBundleX/mitkFiberBundleXWriter.h IODataStructures/FiberBundleX/mitkFiberBundleXReader.h IODataStructures/FiberBundleX/mitkFiberBundleXIOFactory.h IODataStructures/FiberBundleX/mitkFiberBundleXWriterFactory.h IODataStructures/FiberBundleX/mitkFiberBundleXSerializer.h IODataStructures/FiberBundleX/mitkFiberBundleXThreadMonitor.h IODataStructures/mitkFiberTrackingObjectFactory.h # Algorithms Algorithms/itkTractDensityImageFilter.h Algorithms/itkTractsToFiberEndingsImageFilter.h Algorithms/itkTractsToRgbaImageFilter.h Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h Algorithms/itkFibersFromPlanarFiguresFilter.h Algorithms/itkTractsToDWIImageFilter.h Algorithms/itkTractsToVectorImageFilter.h # (old) Tractography Algorithms/itkGibbsTrackingFilter.h Algorithms/itkStochasticTractographyFilter.h Algorithms/itkStreamlineTrackingFilter.h Algorithms/GibbsTracking/mitkParticle.h Algorithms/GibbsTracking/mitkParticleGrid.h Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.h Algorithms/GibbsTracking/mitkSimpSamp.h Algorithms/GibbsTracking/mitkEnergyComputer.h Algorithms/GibbsTracking/mitkGibbsEnergyComputer.h Algorithms/GibbsTracking/mitkSphereInterpolator.h Algorithms/GibbsTracking/mitkFiberBuilder.h # Signal Models SignalModels/mitkDiffusionSignalModel.h SignalModels/mitkTensorModel.h SignalModels/mitkBallModel.h + SignalModels/mitkDotModel.h + SignalModels/mitkAstroStickModel.h SignalModels/mitkStickModel.h SignalModels/mitkDiffusionNoiseModel.h SignalModels/mitkRicianNoiseModel.h SignalModels/mitkKspaceArtifact.h SignalModels/mitkGibbsRingingArtifact.h - SignalModels/mitkT2SmearingArtifact.h -) \ No newline at end of file + SignalModels/mitkSignalDecay.h +) + +set(RESOURCE_FILES + # Binary directory resources + FiberTrackingLUTBaryCoords.bin + FiberTrackingLUTIndices.bin + + # Shaders + Shaders/mitkShaderFiberClipping.xml +) diff --git a/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp b/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp index 7f219f419c..6aefa6ee3c 100644 --- a/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp +++ b/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp @@ -1,1184 +1,1215 @@ /*=================================================================== 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 "mitkImageStatisticsCalculator.h" #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" #include "mitkExtractImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if ( ( VTK_MAJOR_VERSION <= 5 ) && ( VTK_MINOR_VERSION<=8) ) #include "mitkvtkLassoStencilSource.h" #else #include "vtkLassoStencilSource.h" #endif #include #include namespace mitk { ImageStatisticsCalculator::ImageStatisticsCalculator() : m_MaskingMode( MASKING_MODE_NONE ), m_MaskingModeChanged( false ), m_IgnorePixelValue(0.0), m_DoIgnorePixelValue(false), - m_IgnorePixelValueChanged(false) + m_IgnorePixelValueChanged(false), + m_PlanarFigureAxis (0), + m_PlanarFigureSlice (0), + m_PlanarFigureCoordinate0 (0), + m_PlanarFigureCoordinate1 (0) { m_EmptyHistogram = HistogramType::New(); HistogramType::SizeType histogramSize; histogramSize.Fill( 256 ); m_EmptyHistogram->Initialize( histogramSize ); m_EmptyStatistics.Reset(); } ImageStatisticsCalculator::~ImageStatisticsCalculator() { } void ImageStatisticsCalculator::SetImage( const mitk::Image *image ) { if ( m_Image != image ) { m_Image = image; this->Modified(); unsigned int numberOfTimeSteps = image->GetTimeSteps(); // Initialize vectors to time-size of this image m_ImageHistogramVector.resize( numberOfTimeSteps ); m_MaskedImageHistogramVector.resize( numberOfTimeSteps ); m_PlanarFigureHistogramVector.resize( numberOfTimeSteps ); m_ImageStatisticsVector.resize( numberOfTimeSteps ); m_MaskedImageStatisticsVector.resize( numberOfTimeSteps ); m_PlanarFigureStatisticsVector.resize( numberOfTimeSteps ); m_ImageStatisticsTimeStampVector.resize( numberOfTimeSteps ); m_MaskedImageStatisticsTimeStampVector.resize( numberOfTimeSteps ); m_PlanarFigureStatisticsTimeStampVector.resize( numberOfTimeSteps ); m_ImageStatisticsCalculationTriggerVector.resize( numberOfTimeSteps ); m_MaskedImageStatisticsCalculationTriggerVector.resize( numberOfTimeSteps ); m_PlanarFigureStatisticsCalculationTriggerVector.resize( numberOfTimeSteps ); for ( unsigned int t = 0; t < image->GetTimeSteps(); ++t ) { m_ImageStatisticsTimeStampVector[t].Modified(); m_ImageStatisticsCalculationTriggerVector[t] = true; } } } void ImageStatisticsCalculator::SetImageMask( const mitk::Image *imageMask ) { if ( m_Image.IsNull() ) { itkExceptionMacro( << "Image needs to be set first!" ); } if ( m_Image->GetTimeSteps() != imageMask->GetTimeSteps() ) { itkExceptionMacro( << "Image and image mask need to have equal number of time steps!" ); } if ( m_ImageMask != imageMask ) { m_ImageMask = imageMask; this->Modified(); for ( unsigned int t = 0; t < m_Image->GetTimeSteps(); ++t ) { m_MaskedImageStatisticsTimeStampVector[t].Modified(); m_MaskedImageStatisticsCalculationTriggerVector[t] = true; } } } void ImageStatisticsCalculator::SetPlanarFigure( mitk::PlanarFigure *planarFigure ) { if ( m_Image.IsNull() ) { itkExceptionMacro( << "Image needs to be set first!" ); } if ( m_PlanarFigure != planarFigure ) { m_PlanarFigure = planarFigure; this->Modified(); for ( unsigned int t = 0; t < m_Image->GetTimeSteps(); ++t ) { m_PlanarFigureStatisticsTimeStampVector[t].Modified(); m_PlanarFigureStatisticsCalculationTriggerVector[t] = true; } } } void ImageStatisticsCalculator::SetMaskingMode( unsigned int mode ) { if ( m_MaskingMode != mode ) { m_MaskingMode = mode; m_MaskingModeChanged = true; this->Modified(); } } void ImageStatisticsCalculator::SetMaskingModeToNone() { if ( m_MaskingMode != MASKING_MODE_NONE ) { m_MaskingMode = MASKING_MODE_NONE; m_MaskingModeChanged = true; this->Modified(); } } void ImageStatisticsCalculator::SetMaskingModeToImage() { if ( m_MaskingMode != MASKING_MODE_IMAGE ) { m_MaskingMode = MASKING_MODE_IMAGE; m_MaskingModeChanged = true; this->Modified(); } } void ImageStatisticsCalculator::SetMaskingModeToPlanarFigure() { if ( m_MaskingMode != MASKING_MODE_PLANARFIGURE ) { m_MaskingMode = MASKING_MODE_PLANARFIGURE; m_MaskingModeChanged = true; this->Modified(); } } void ImageStatisticsCalculator::SetIgnorePixelValue(double value) { if ( m_IgnorePixelValue != value ) { m_IgnorePixelValue = value; if(m_DoIgnorePixelValue) { m_IgnorePixelValueChanged = true; } this->Modified(); } } double ImageStatisticsCalculator::GetIgnorePixelValue() { return m_IgnorePixelValue; } void ImageStatisticsCalculator::SetDoIgnorePixelValue(bool value) { if ( m_DoIgnorePixelValue != value ) { m_DoIgnorePixelValue = value; m_IgnorePixelValueChanged = true; this->Modified(); } } bool ImageStatisticsCalculator::GetDoIgnorePixelValue() { return m_DoIgnorePixelValue; } bool ImageStatisticsCalculator::ComputeStatistics( unsigned int timeStep ) { if (m_Image.IsNull() ) { mitkThrow() << "Image not set!"; } if (!m_Image->IsInitialized()) { mitkThrow() << "Image not initialized!"; } if ( m_Image->GetReferenceCount() == 1 ) { // Image no longer valid; we are the only ones to still hold a reference on it return false; } if ( timeStep >= m_Image->GetTimeSteps() ) { throw std::runtime_error( "Error: invalid time step!" ); } // If a mask was set but we are the only ones to still hold a reference on // it, delete it. if ( m_ImageMask.IsNotNull() && (m_ImageMask->GetReferenceCount() == 1) ) { m_ImageMask = NULL; } // Check if statistics is already up-to-date unsigned long imageMTime = m_ImageStatisticsTimeStampVector[timeStep].GetMTime(); unsigned long maskedImageMTime = m_MaskedImageStatisticsTimeStampVector[timeStep].GetMTime(); unsigned long planarFigureMTime = m_PlanarFigureStatisticsTimeStampVector[timeStep].GetMTime(); bool imageStatisticsCalculationTrigger = m_ImageStatisticsCalculationTriggerVector[timeStep]; bool maskedImageStatisticsCalculationTrigger = m_MaskedImageStatisticsCalculationTriggerVector[timeStep]; bool planarFigureStatisticsCalculationTrigger = m_PlanarFigureStatisticsCalculationTriggerVector[timeStep]; if ( !m_IgnorePixelValueChanged && ((m_MaskingMode != MASKING_MODE_NONE) || (imageMTime > m_Image->GetMTime() && !imageStatisticsCalculationTrigger)) && ((m_MaskingMode != MASKING_MODE_IMAGE) || (maskedImageMTime > m_ImageMask->GetMTime() && !maskedImageStatisticsCalculationTrigger)) && ((m_MaskingMode != MASKING_MODE_PLANARFIGURE) || (planarFigureMTime > m_PlanarFigure->GetMTime() && !planarFigureStatisticsCalculationTrigger)) ) { // Statistics is up to date! if ( m_MaskingModeChanged ) { m_MaskingModeChanged = false; return true; } else { return false; } } // Reset state changed flag m_MaskingModeChanged = false; m_IgnorePixelValueChanged = false; // Depending on masking mode, extract and/or generate the required image // and mask data from the user input this->ExtractImageAndMask( timeStep ); StatisticsContainer *statisticsContainer; HistogramContainer *histogramContainer; switch ( m_MaskingMode ) { case MASKING_MODE_NONE: default: if(!m_DoIgnorePixelValue) { statisticsContainer = &m_ImageStatisticsVector[timeStep]; histogramContainer = &m_ImageHistogramVector[timeStep]; m_ImageStatisticsTimeStampVector[timeStep].Modified(); m_ImageStatisticsCalculationTriggerVector[timeStep] = false; } else { statisticsContainer = &m_MaskedImageStatisticsVector[timeStep]; histogramContainer = &m_MaskedImageHistogramVector[timeStep]; m_MaskedImageStatisticsTimeStampVector[timeStep].Modified(); m_MaskedImageStatisticsCalculationTriggerVector[timeStep] = false; } break; case MASKING_MODE_IMAGE: statisticsContainer = &m_MaskedImageStatisticsVector[timeStep]; histogramContainer = &m_MaskedImageHistogramVector[timeStep]; m_MaskedImageStatisticsTimeStampVector[timeStep].Modified(); m_MaskedImageStatisticsCalculationTriggerVector[timeStep] = false; break; case MASKING_MODE_PLANARFIGURE: statisticsContainer = &m_PlanarFigureStatisticsVector[timeStep]; histogramContainer = &m_PlanarFigureHistogramVector[timeStep]; m_PlanarFigureStatisticsTimeStampVector[timeStep].Modified(); m_PlanarFigureStatisticsCalculationTriggerVector[timeStep] = false; break; } // Calculate statistics and histogram(s) if ( m_InternalImage->GetDimension() == 3 ) { if ( m_MaskingMode == MASKING_MODE_NONE && !m_DoIgnorePixelValue ) { AccessFixedDimensionByItk_2( m_InternalImage, InternalCalculateStatisticsUnmasked, 3, statisticsContainer, histogramContainer ); } else { AccessFixedDimensionByItk_3( m_InternalImage, InternalCalculateStatisticsMasked, 3, m_InternalImageMask3D.GetPointer(), statisticsContainer, histogramContainer ); } } else if ( m_InternalImage->GetDimension() == 2 ) { if ( m_MaskingMode == MASKING_MODE_NONE && !m_DoIgnorePixelValue ) { AccessFixedDimensionByItk_2( m_InternalImage, InternalCalculateStatisticsUnmasked, 2, statisticsContainer, histogramContainer ); } else { AccessFixedDimensionByItk_3( m_InternalImage, InternalCalculateStatisticsMasked, 2, m_InternalImageMask2D.GetPointer(), statisticsContainer, histogramContainer ); } } else { MITK_ERROR << "ImageStatistics: Image dimension not supported!"; } // Release unused image smart pointers to free memory m_InternalImage = mitk::Image::ConstPointer(); m_InternalImageMask3D = MaskImage3DType::Pointer(); m_InternalImageMask2D = MaskImage2DType::Pointer(); return true; } const ImageStatisticsCalculator::HistogramType * ImageStatisticsCalculator::GetHistogram( unsigned int timeStep, unsigned int label ) const { if ( m_Image.IsNull() || (timeStep >= m_Image->GetTimeSteps()) ) { return NULL; } switch ( m_MaskingMode ) { case MASKING_MODE_NONE: default: { if(m_DoIgnorePixelValue) return m_MaskedImageHistogramVector[timeStep][label]; return m_ImageHistogramVector[timeStep][label]; } case MASKING_MODE_IMAGE: return m_MaskedImageHistogramVector[timeStep][label]; case MASKING_MODE_PLANARFIGURE: return m_PlanarFigureHistogramVector[timeStep][label]; } } const ImageStatisticsCalculator::HistogramContainer & ImageStatisticsCalculator::GetHistogramVector( unsigned int timeStep ) const { if ( m_Image.IsNull() || (timeStep >= m_Image->GetTimeSteps()) ) { return m_EmptyHistogramContainer; } switch ( m_MaskingMode ) { case MASKING_MODE_NONE: default: { if(m_DoIgnorePixelValue) return m_MaskedImageHistogramVector[timeStep]; return m_ImageHistogramVector[timeStep]; } case MASKING_MODE_IMAGE: return m_MaskedImageHistogramVector[timeStep]; case MASKING_MODE_PLANARFIGURE: return m_PlanarFigureHistogramVector[timeStep]; } } const ImageStatisticsCalculator::Statistics & ImageStatisticsCalculator::GetStatistics( unsigned int timeStep, unsigned int label ) const { if ( m_Image.IsNull() || (timeStep >= m_Image->GetTimeSteps()) ) { return m_EmptyStatistics; } switch ( m_MaskingMode ) { case MASKING_MODE_NONE: default: { if(m_DoIgnorePixelValue) return m_MaskedImageStatisticsVector[timeStep][label]; return m_ImageStatisticsVector[timeStep][label]; } case MASKING_MODE_IMAGE: return m_MaskedImageStatisticsVector[timeStep][label]; case MASKING_MODE_PLANARFIGURE: return m_PlanarFigureStatisticsVector[timeStep][label]; } } const ImageStatisticsCalculator::StatisticsContainer & ImageStatisticsCalculator::GetStatisticsVector( unsigned int timeStep ) const { if ( m_Image.IsNull() || (timeStep >= m_Image->GetTimeSteps()) ) { return m_EmptyStatisticsContainer; } switch ( m_MaskingMode ) { case MASKING_MODE_NONE: default: { if(m_DoIgnorePixelValue) return m_MaskedImageStatisticsVector[timeStep]; return m_ImageStatisticsVector[timeStep]; } case MASKING_MODE_IMAGE: return m_MaskedImageStatisticsVector[timeStep]; case MASKING_MODE_PLANARFIGURE: return m_PlanarFigureStatisticsVector[timeStep]; } } void ImageStatisticsCalculator::ExtractImageAndMask( unsigned int timeStep ) { if ( m_Image.IsNull() ) { throw std::runtime_error( "Error: image empty!" ); } if ( timeStep >= m_Image->GetTimeSteps() ) { throw std::runtime_error( "Error: invalid time step!" ); } ImageTimeSelector::Pointer imageTimeSelector = ImageTimeSelector::New(); imageTimeSelector->SetInput( m_Image ); imageTimeSelector->SetTimeNr( timeStep ); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image *timeSliceImage = imageTimeSelector->GetOutput(); switch ( m_MaskingMode ) { case MASKING_MODE_NONE: { m_InternalImage = timeSliceImage; m_InternalImageMask2D = NULL; m_InternalImageMask3D = NULL; if(m_DoIgnorePixelValue) { if( m_InternalImage->GetDimension() == 3 ) { CastToItkImage( timeSliceImage, m_InternalImageMask3D ); m_InternalImageMask3D->FillBuffer(1); } if( m_InternalImage->GetDimension() == 2 ) { CastToItkImage( timeSliceImage, m_InternalImageMask2D ); m_InternalImageMask2D->FillBuffer(1); } } break; } case MASKING_MODE_IMAGE: { if ( m_ImageMask.IsNotNull() && (m_ImageMask->GetReferenceCount() > 1) ) { if ( timeStep < m_ImageMask->GetTimeSteps() ) { ImageTimeSelector::Pointer maskedImageTimeSelector = ImageTimeSelector::New(); maskedImageTimeSelector->SetInput( m_ImageMask ); maskedImageTimeSelector->SetTimeNr( timeStep ); maskedImageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image *timeSliceMaskedImage = maskedImageTimeSelector->GetOutput(); m_InternalImage = timeSliceImage; CastToItkImage( timeSliceMaskedImage, m_InternalImageMask3D ); } else { throw std::runtime_error( "Error: image mask has not enough time steps!" ); } } else { throw std::runtime_error( "Error: image mask empty!" ); } break; } case MASKING_MODE_PLANARFIGURE: { m_InternalImageMask2D = NULL; if ( m_PlanarFigure.IsNull() ) { throw std::runtime_error( "Error: planar figure empty!" ); } if ( !m_PlanarFigure->IsClosed() ) { throw std::runtime_error( "Masking not possible for non-closed figures" ); } const Geometry3D *imageGeometry = timeSliceImage->GetGeometry(); if ( imageGeometry == NULL ) { throw std::runtime_error( "Image geometry invalid!" ); } const Geometry2D *planarFigureGeometry2D = m_PlanarFigure->GetGeometry2D(); if ( planarFigureGeometry2D == NULL ) { throw std::runtime_error( "Planar-Figure not yet initialized!" ); } const PlaneGeometry *planarFigureGeometry = dynamic_cast< const PlaneGeometry * >( planarFigureGeometry2D ); if ( planarFigureGeometry == NULL ) { throw std::runtime_error( "Non-planar planar figures not supported!" ); } // Find principal direction of PlanarFigure in input image unsigned int axis; if ( !this->GetPrincipalAxis( imageGeometry, planarFigureGeometry->GetNormal(), axis ) ) { throw std::runtime_error( "Non-aligned planar figures not supported!" ); } + m_PlanarFigureAxis = axis; // Find slice number corresponding to PlanarFigure in input image MaskImage3DType::IndexType index; imageGeometry->WorldToIndex( planarFigureGeometry->GetOrigin(), index ); unsigned int slice = index[axis]; + m_PlanarFigureSlice = slice; // Extract slice with given position and direction from image ExtractImageFilter::Pointer imageExtractor = ExtractImageFilter::New(); imageExtractor->SetInput( timeSliceImage ); imageExtractor->SetSliceDimension( axis ); imageExtractor->SetSliceIndex( slice ); imageExtractor->Update(); m_InternalImage = imageExtractor->GetOutput(); // Compute mask from PlanarFigure AccessFixedDimensionByItk_1( m_InternalImage, InternalCalculateMaskFromPlanarFigure, 2, axis ); } } if(m_DoIgnorePixelValue) { if ( m_InternalImage->GetDimension() == 3 ) { AccessFixedDimensionByItk_1( m_InternalImage, InternalMaskIgnoredPixels, 3, m_InternalImageMask3D.GetPointer() ); } else if ( m_InternalImage->GetDimension() == 2 ) { AccessFixedDimensionByItk_1( m_InternalImage, InternalMaskIgnoredPixels, 2, m_InternalImageMask2D.GetPointer() ); } } } bool ImageStatisticsCalculator::GetPrincipalAxis( const Geometry3D *geometry, Vector3D vector, unsigned int &axis ) { vector.Normalize(); for ( unsigned int i = 0; i < 3; ++i ) { Vector3D axisVector = geometry->GetAxisVector( i ); axisVector.Normalize(); if ( fabs( fabs( axisVector * vector ) - 1.0) < mitk::eps ) { axis = i; return true; } } return false; } template < typename TPixel, unsigned int VImageDimension > void ImageStatisticsCalculator::InternalCalculateStatisticsUnmasked( const itk::Image< TPixel, VImageDimension > *image, StatisticsContainer *statisticsContainer, HistogramContainer* histogramContainer ) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< unsigned short, VImageDimension > MaskImageType; typedef typename ImageType::IndexType IndexType; typedef itk::Statistics::ScalarImageToHistogramGenerator< ImageType > HistogramGeneratorType; statisticsContainer->clear(); histogramContainer->clear(); // Progress listening... typedef itk::SimpleMemberCommand< ImageStatisticsCalculator > ITKCommandType; ITKCommandType::Pointer progressListener; progressListener = ITKCommandType::New(); progressListener->SetCallbackFunction( this, &ImageStatisticsCalculator::UnmaskedStatisticsProgressUpdate ); // Issue 100 artificial progress events since ScalarIMageToHistogramGenerator // does not (yet?) support progress reporting this->InvokeEvent( itk::StartEvent() ); for ( unsigned int i = 0; i < 100; ++i ) { this->UnmaskedStatisticsProgressUpdate(); } // Calculate statistics (separate filter) typedef itk::StatisticsImageFilter< ImageType > StatisticsFilterType; typename StatisticsFilterType::Pointer statisticsFilter = StatisticsFilterType::New(); statisticsFilter->SetInput( image ); unsigned long observerTag = statisticsFilter->AddObserver( itk::ProgressEvent(), progressListener ); statisticsFilter->Update(); statisticsFilter->RemoveObserver( observerTag ); this->InvokeEvent( itk::EndEvent() ); // Calculate minimum and maximum typedef itk::MinimumMaximumImageCalculator< ImageType > MinMaxFilterType; typename MinMaxFilterType::Pointer minMaxFilter = MinMaxFilterType::New(); minMaxFilter->SetImage( image ); unsigned long observerTag2 = minMaxFilter->AddObserver( itk::ProgressEvent(), progressListener ); minMaxFilter->Compute(); minMaxFilter->RemoveObserver( observerTag2 ); this->InvokeEvent( itk::EndEvent() ); Statistics statistics; statistics.Reset(); statistics.Label = 1; statistics.N = image->GetBufferedRegion().GetNumberOfPixels(); statistics.Min = statisticsFilter->GetMinimum(); statistics.Max = statisticsFilter->GetMaximum(); statistics.Mean = statisticsFilter->GetMean(); statistics.Median = 0.0; statistics.Sigma = statisticsFilter->GetSigma(); statistics.RMS = sqrt( statistics.Mean * statistics.Mean + statistics.Sigma * statistics.Sigma ); statistics.MinIndex.set_size(image->GetImageDimension()); statistics.MaxIndex.set_size(image->GetImageDimension()); for (int i=0; iGetIndexOfMaximum()[i]; statistics.MinIndex[i] = minMaxFilter->GetIndexOfMinimum()[i]; } statisticsContainer->push_back( statistics ); // Calculate histogram typename HistogramGeneratorType::Pointer histogramGenerator = HistogramGeneratorType::New(); histogramGenerator->SetInput( image ); histogramGenerator->SetMarginalScale( 100 ); histogramGenerator->SetNumberOfBins( 768 ); histogramGenerator->SetHistogramMin( statistics.Min ); histogramGenerator->SetHistogramMax( statistics.Max ); histogramGenerator->Compute(); histogramContainer->push_back( histogramGenerator->GetOutput() ); } template < typename TPixel, unsigned int VImageDimension > void ImageStatisticsCalculator::InternalMaskIgnoredPixels( const itk::Image< TPixel, VImageDimension > *image, itk::Image< unsigned short, VImageDimension > *maskImage ) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< unsigned short, VImageDimension > MaskImageType; itk::ImageRegionIterator itmask(maskImage, maskImage->GetLargestPossibleRegion()); itk::ImageRegionConstIterator itimage(image, image->GetLargestPossibleRegion()); itmask = itmask.Begin(); itimage = itimage.Begin(); while( !itmask.IsAtEnd() ) { if(m_IgnorePixelValue == itimage.Get()) { itmask.Set(0); } ++itmask; ++itimage; } } template < typename TPixel, unsigned int VImageDimension > void ImageStatisticsCalculator::InternalCalculateStatisticsMasked( const itk::Image< TPixel, VImageDimension > *image, itk::Image< unsigned short, VImageDimension > *maskImage, StatisticsContainer* statisticsContainer, HistogramContainer* histogramContainer ) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< unsigned short, VImageDimension > MaskImageType; typedef typename ImageType::IndexType IndexType; typedef typename ImageType::PointType PointType; typedef typename ImageType::SpacingType SpacingType; typedef itk::LabelStatisticsImageFilter< ImageType, MaskImageType > LabelStatisticsFilterType; typedef itk::ChangeInformationImageFilter< MaskImageType > ChangeInformationFilterType; typedef itk::ExtractImageFilter< ImageType, ImageType > ExtractImageFilterType; statisticsContainer->clear(); histogramContainer->clear(); // Make sure that mask is set if ( maskImage == NULL ) { itkExceptionMacro( << "Mask image needs to be set!" ); } // Make sure that spacing of mask and image are the same SpacingType imageSpacing = image->GetSpacing(); SpacingType maskSpacing = maskImage->GetSpacing(); PointType zeroPoint; zeroPoint.Fill( 0.0 ); if ( (zeroPoint + imageSpacing).SquaredEuclideanDistanceTo( (zeroPoint + maskSpacing) ) > mitk::eps ) { itkExceptionMacro( << "Mask needs to have same spacing as image! (Image spacing: " << imageSpacing << "; Mask spacing: " << maskSpacing << ")" ); } // Make sure that orientation of mask and image are the same typedef typename ImageType::DirectionType DirectionType; DirectionType imageDirection = image->GetDirection(); DirectionType maskDirection = maskImage->GetDirection(); for( int i = 0; i < imageDirection.ColumnDimensions; ++i ) { for( int j = 0; j < imageDirection.ColumnDimensions; ++j ) { double differenceDirection = imageDirection[i][j] - maskDirection[i][j]; if ( fabs( differenceDirection ) > mitk::eps ) { itkExceptionMacro( << "Mask needs to have same direction as image! (Image direction: " << imageDirection << "; Mask direction: " << maskDirection << ")" ); } } } // Make sure that the voxels of mask and image are correctly "aligned", i.e., voxel boundaries are the same in both images PointType imageOrigin = image->GetOrigin(); PointType maskOrigin = maskImage->GetOrigin(); long offset[ImageType::ImageDimension]; typedef itk::ContinuousIndex ContinousIndexType; ContinousIndexType maskOriginContinousIndex, imageOriginContinousIndex; image->TransformPhysicalPointToContinuousIndex(maskOrigin, maskOriginContinousIndex); image->TransformPhysicalPointToContinuousIndex(imageOrigin, imageOriginContinousIndex); for ( unsigned int i = 0; i < ImageType::ImageDimension; ++i ) { double misalignment = maskOriginContinousIndex[i] - floor( maskOriginContinousIndex[i] + 0.5 ); if ( fabs( misalignment ) > mitk::eps ) { itkExceptionMacro( << "Pixels/voxels of mask and image are not sufficiently aligned! (Misalignment: " << misalignment << ")" ); } double indexCoordDistance = maskOriginContinousIndex[i] - imageOriginContinousIndex[i]; offset[i] = (int) indexCoordDistance + image->GetBufferedRegion().GetIndex()[i]; } // Adapt the origin and region (index/size) of the mask so that the origin of both are the same typename ChangeInformationFilterType::Pointer adaptMaskFilter; adaptMaskFilter = ChangeInformationFilterType::New(); adaptMaskFilter->ChangeOriginOn(); adaptMaskFilter->ChangeRegionOn(); adaptMaskFilter->SetInput( maskImage ); adaptMaskFilter->SetOutputOrigin( image->GetOrigin() ); adaptMaskFilter->SetOutputOffset( offset ); adaptMaskFilter->Update(); typename MaskImageType::Pointer adaptedMaskImage = adaptMaskFilter->GetOutput(); // Make sure that mask region is contained within image region if ( !image->GetLargestPossibleRegion().IsInside( adaptedMaskImage->GetLargestPossibleRegion() ) ) { itkExceptionMacro( << "Mask region needs to be inside of image region! (Image region: " << image->GetLargestPossibleRegion() << "; Mask region: " << adaptedMaskImage->GetLargestPossibleRegion() << ")" ); } // If mask region is smaller than image region, extract the sub-sampled region from the original image typename ImageType::SizeType imageSize = image->GetBufferedRegion().GetSize(); typename ImageType::SizeType maskSize = maskImage->GetBufferedRegion().GetSize(); bool maskSmallerImage = false; for ( unsigned int i = 0; i < ImageType::ImageDimension; ++i ) { if ( maskSize[i] < imageSize[i] ) { maskSmallerImage = true; } } typename ImageType::ConstPointer adaptedImage; if ( maskSmallerImage ) { typename ExtractImageFilterType::Pointer extractImageFilter = ExtractImageFilterType::New(); extractImageFilter->SetInput( image ); extractImageFilter->SetExtractionRegion( adaptedMaskImage->GetBufferedRegion() ); extractImageFilter->Update(); adaptedImage = extractImageFilter->GetOutput(); } else { adaptedImage = image; } // Initialize Filter typedef itk::StatisticsImageFilter< ImageType > StatisticsFilterType; typename StatisticsFilterType::Pointer statisticsFilter = StatisticsFilterType::New(); statisticsFilter->SetInput( adaptedImage ); statisticsFilter->Update(); int numberOfBins = ( m_DoIgnorePixelValue && (m_MaskingMode == MASKING_MODE_NONE) ) ? 768 : 384; typename LabelStatisticsFilterType::Pointer labelStatisticsFilter; labelStatisticsFilter = LabelStatisticsFilterType::New(); labelStatisticsFilter->SetInput( adaptedImage ); labelStatisticsFilter->SetLabelInput( adaptedMaskImage ); labelStatisticsFilter->UseHistogramsOn(); labelStatisticsFilter->SetHistogramParameters( numberOfBins, statisticsFilter->GetMinimum(), statisticsFilter->GetMaximum() ); // Add progress listening typedef itk::SimpleMemberCommand< ImageStatisticsCalculator > ITKCommandType; ITKCommandType::Pointer progressListener; progressListener = ITKCommandType::New(); progressListener->SetCallbackFunction( this, &ImageStatisticsCalculator::MaskedStatisticsProgressUpdate ); unsigned long observerTag = labelStatisticsFilter->AddObserver( itk::ProgressEvent(), progressListener ); // Execute filter this->InvokeEvent( itk::StartEvent() ); // Make sure that only the mask region is considered (otherwise, if the mask region is smaller // than the image region, the Update() would result in an exception). labelStatisticsFilter->GetOutput()->SetRequestedRegion( adaptedMaskImage->GetLargestPossibleRegion() ); // Execute the filter labelStatisticsFilter->Update(); this->InvokeEvent( itk::EndEvent() ); labelStatisticsFilter->RemoveObserver( observerTag ); // Find all relevant labels of mask (other than 0) std::list< int > relevantLabels; bool maskNonEmpty = false; unsigned int i; for ( i = 1; i < 4096; ++i ) { if ( labelStatisticsFilter->HasLabel( i ) ) { relevantLabels.push_back( i ); maskNonEmpty = true; } } if ( maskNonEmpty ) { std::list< int >::iterator it; for ( it = relevantLabels.begin(), i = 0; it != relevantLabels.end(); ++it, ++i ) { histogramContainer->push_back( HistogramType::ConstPointer( labelStatisticsFilter->GetHistogram( (*it) ) ) ); Statistics statistics; statistics.Label = (*it); statistics.N = labelStatisticsFilter->GetCount( *it ); statistics.Min = labelStatisticsFilter->GetMinimum( *it ); statistics.Max = labelStatisticsFilter->GetMaximum( *it ); statistics.Mean = labelStatisticsFilter->GetMean( *it ); statistics.Median = labelStatisticsFilter->GetMedian( *it ); statistics.Sigma = labelStatisticsFilter->GetSigma( *it ); statistics.RMS = sqrt( statistics.Mean * statistics.Mean + statistics.Sigma * statistics.Sigma ); // restrict image to mask area for min/max index calculation typedef itk::MaskImageFilter< ImageType, MaskImageType, ImageType > MaskImageFilterType; typename MaskImageFilterType::Pointer masker = MaskImageFilterType::New(); masker->SetOutsideValue( (statistics.Min+statistics.Max)/2 ); masker->SetInput1(adaptedImage); masker->SetInput2(adaptedMaskImage); masker->Update(); // get index of minimum and maximum typedef itk::MinimumMaximumImageCalculator< ImageType > MinMaxFilterType; typename MinMaxFilterType::Pointer minMaxFilter = MinMaxFilterType::New(); minMaxFilter->SetImage( masker->GetOutput() ); unsigned long observerTag2 = minMaxFilter->AddObserver( itk::ProgressEvent(), progressListener ); minMaxFilter->Compute(); minMaxFilter->RemoveObserver( observerTag2 ); this->InvokeEvent( itk::EndEvent() ); statistics.MinIndex.set_size(adaptedImage->GetImageDimension()); statistics.MaxIndex.set_size(adaptedImage->GetImageDimension()); - for (int i=0; iGetIndexOfMaximum(); + typename MinMaxFilterType::IndexType tempMinIndex = minMaxFilter->GetIndexOfMinimum(); + +// FIX BUG 14644 + //If a PlanarFigure is used for segmentation the + //adaptedImage is a single slice (2D). Adding the + // 3. dimension. + if (m_MaskingMode == MASKING_MODE_PLANARFIGURE && m_Image->GetDimension()==3) + { + statistics.MaxIndex.set_size(m_Image->GetDimension()); + statistics.MaxIndex[m_PlanarFigureCoordinate0]=tempMaxIndex[0]; + statistics.MaxIndex[m_PlanarFigureCoordinate1]=tempMaxIndex[1]; + statistics.MaxIndex[m_PlanarFigureAxis]=m_PlanarFigureSlice; + + statistics.MinIndex.set_size(m_Image->GetDimension()); + statistics.MinIndex[m_PlanarFigureCoordinate0]=tempMinIndex[0]; + statistics.MinIndex[m_PlanarFigureCoordinate1]=tempMinIndex[1]; + statistics.MinIndex[m_PlanarFigureAxis]=m_PlanarFigureSlice; + } else { - statistics.MaxIndex[i] = minMaxFilter->GetIndexOfMaximum()[i]; - statistics.MinIndex[i] = minMaxFilter->GetIndexOfMinimum()[i]; + for (int i = 0; ipush_back( statistics ); } } else { histogramContainer->push_back( HistogramType::ConstPointer( m_EmptyHistogram ) ); statisticsContainer->push_back( Statistics() );; } } template < typename TPixel, unsigned int VImageDimension > void ImageStatisticsCalculator::InternalCalculateMaskFromPlanarFigure( const itk::Image< TPixel, VImageDimension > *image, unsigned int axis ) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::CastImageFilter< ImageType, MaskImage2DType > CastFilterType; // Generate mask image as new image with same header as input image and // initialize with "1". typename CastFilterType::Pointer castFilter = CastFilterType::New(); castFilter->SetInput( image ); castFilter->Update(); castFilter->GetOutput()->FillBuffer( 1 ); // all PolylinePoints of the PlanarFigure are stored in a vtkPoints object. // These points are used by the vtkLassoStencilSource to create // a vtkImageStencil. const mitk::Geometry2D *planarFigureGeometry2D = m_PlanarFigure->GetGeometry2D(); const typename PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 ); const mitk::Geometry3D *imageGeometry3D = m_Image->GetGeometry( 0 ); // Determine x- and y-dimensions depending on principal axis int i0, i1; switch ( axis ) { case 0: i0 = 1; i1 = 2; break; case 1: i0 = 0; i1 = 2; break; case 2: default: i0 = 0; i1 = 1; break; } + m_PlanarFigureCoordinate0= i0; + m_PlanarFigureCoordinate1= i1; // store the polyline contour as vtkPoints object bool outOfBounds = false; vtkSmartPointer points = vtkSmartPointer::New(); typename PlanarFigure::PolyLineType::const_iterator it; for ( it = planarFigurePolyline.begin(); it != planarFigurePolyline.end(); ++it ) { Point3D point3D; // Convert 2D point back to the local index coordinates of the selected // image planarFigureGeometry2D->Map( it->Point, point3D ); // Polygons (partially) outside of the image bounds can not be processed // further due to a bug in vtkPolyDataToImageStencil if ( !imageGeometry3D->IsInside( point3D ) ) { outOfBounds = true; } imageGeometry3D->WorldToIndex( point3D, point3D ); points->InsertNextPoint( point3D[i0], point3D[i1], 0 ); } // mark a malformed 2D planar figure ( i.e. area = 0 ) as out of bounds // this can happen when all control points of a rectangle lie on the same line = two of the three extents are zero double bounds[6] = {0, 0, 0, 0, 0, 0}; points->GetBounds( bounds ); bool extent_x = (fabs(bounds[0] - bounds[1])) < mitk::eps; bool extent_y = (fabs(bounds[2] - bounds[3])) < mitk::eps; bool extent_z = (fabs(bounds[4] - bounds[5])) < mitk::eps; // throw an exception if a closed planar figure is deformed, i.e. has only one non-zero extent if ( m_PlanarFigure->IsClosed() && ((extent_x && extent_y) || (extent_x && extent_z) || (extent_y && extent_z))) { mitkThrow() << "Figure has a zero area and cannot be used for masking."; } if ( outOfBounds ) { throw std::runtime_error( "Figure at least partially outside of image bounds!" ); } // create a vtkLassoStencilSource and set the points of the Polygon vtkSmartPointer lassoStencil = vtkSmartPointer::New(); lassoStencil->SetShapeToPolygon(); lassoStencil->SetPoints( points ); // Export from ITK to VTK (to use a VTK filter) typedef itk::VTKImageImport< MaskImage2DType > ImageImportType; typedef itk::VTKImageExport< MaskImage2DType > ImageExportType; typename ImageExportType::Pointer itkExporter = ImageExportType::New(); itkExporter->SetInput( castFilter->GetOutput() ); vtkSmartPointer vtkImporter = vtkSmartPointer::New(); this->ConnectPipelines( itkExporter, vtkImporter ); // Apply the generated image stencil to the input image vtkSmartPointer imageStencilFilter = vtkSmartPointer::New(); imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() ); imageStencilFilter->SetStencil( lassoStencil->GetOutput() ); imageStencilFilter->ReverseStencilOff(); imageStencilFilter->SetBackgroundValue( 0 ); imageStencilFilter->Update(); // Export from VTK back to ITK vtkSmartPointer vtkExporter = vtkImageExport::New(); // TODO: this is WRONG, should be vtkSmartPointer::New(), but bug # 14455 vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() ); vtkExporter->Update(); typename ImageImportType::Pointer itkImporter = ImageImportType::New(); this->ConnectPipelines( vtkExporter, itkImporter ); itkImporter->Update(); // Store mask m_InternalImageMask2D = itkImporter->GetOutput(); } void ImageStatisticsCalculator::UnmaskedStatisticsProgressUpdate() { // Need to throw away every second progress event to reach a final count of // 100 since two consecutive filters are used in this case static int updateCounter = 0; if ( updateCounter++ % 2 == 0 ) { this->InvokeEvent( itk::ProgressEvent() ); } } void ImageStatisticsCalculator::MaskedStatisticsProgressUpdate() { this->InvokeEvent( itk::ProgressEvent() ); } } diff --git a/Modules/ImageStatistics/mitkImageStatisticsCalculator.h b/Modules/ImageStatistics/mitkImageStatisticsCalculator.h index fa2ef0ea85..34288e8ca7 100644 --- a/Modules/ImageStatistics/mitkImageStatisticsCalculator.h +++ b/Modules/ImageStatistics/mitkImageStatisticsCalculator.h @@ -1,322 +1,328 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_IMAGESTATISTICSCALCULATOR_H #define _MITK_IMAGESTATISTICSCALCULATOR_H #include #include "ImageStatisticsExports.h" #include #include #ifndef __itkHistogram_h #include #endif #include "mitkImage.h" #include "mitkImageTimeSelector.h" #include "mitkPlanarFigure.h" #include namespace mitk { /** * \brief Class for calculating statistics and histogram for an (optionally * masked) image. * * Images can be masked by either a label image (of the same dimensions as * the original image) or by a closed mitk::PlanarFigure, e.g. a circle or * polygon. When masking with a planar figure, the slice corresponding to the * plane containing the figure is extracted and then clipped with contour * defined by the figure. Planar figures need to be aligned along the main axes * of the image (axial, sagittal, coronal). Planar figures on arbitrary * rotated planes are not supported. * * For each operating mode (no masking, masking by image, masking by planar * figure), the calculated statistics and histogram are cached so that, when * switching back and forth between operation modes without modifying mask or * image, the information doesn't need to be recalculated. * * Note: currently time-resolved and multi-channel pictures are not properly * supported. */ class ImageStatistics_EXPORT ImageStatisticsCalculator : public itk::Object { public: enum { MASKING_MODE_NONE = 0, MASKING_MODE_IMAGE, MASKING_MODE_PLANARFIGURE }; typedef itk::Statistics::Histogram HistogramType; typedef HistogramType::ConstIterator HistogramConstIteratorType; struct Statistics { int Label; unsigned int N; double Min; double Max; double Mean; double Median; double Variance; double Sigma; double RMS; vnl_vector< int > MinIndex; vnl_vector< int > MaxIndex; void Reset() { Label = 0; N = 0; Min = 0.0; Max = 0.0; Mean = 0.0; Median = 0.0; Variance = 0.0; Sigma = 0.0; RMS = 0.0; } }; typedef std::vector< HistogramType::ConstPointer > HistogramContainer; typedef std::vector< Statistics > StatisticsContainer; mitkClassMacro( ImageStatisticsCalculator, itk::Object ); itkNewMacro( ImageStatisticsCalculator ); /** \brief Set image from which to compute statistics. */ void SetImage( const mitk::Image *image ); /** \brief Set image for masking. */ void SetImageMask( const mitk::Image *imageMask ); /** \brief Set planar figure for masking. */ void SetPlanarFigure( mitk::PlanarFigure *planarFigure ); /** \brief Set/Get operation mode for masking */ void SetMaskingMode( unsigned int mode ); /** \brief Set/Get operation mode for masking */ itkGetMacro( MaskingMode, unsigned int ); /** \brief Set/Get operation mode for masking */ void SetMaskingModeToNone(); /** \brief Set/Get operation mode for masking */ void SetMaskingModeToImage(); /** \brief Set/Get operation mode for masking */ void SetMaskingModeToPlanarFigure(); /** \brief Set a pixel value for pixels that will be ignored in the statistics */ void SetIgnorePixelValue(double value); /** \brief Get the pixel value for pixels that will be ignored in the statistics */ double GetIgnorePixelValue(); /** \brief Set wether a pixel value should be ignored in the statistics */ void SetDoIgnorePixelValue(bool doit); /** \brief Get wether a pixel value will be ignored in the statistics */ bool GetDoIgnorePixelValue(); /** \brief Compute statistics (together with histogram) for the current * masking mode. * * Computation is not executed if statistics is already up to date. In this * case, false is returned; otherwise, true.*/ virtual bool ComputeStatistics( unsigned int timeStep = 0 ); /** \brief Retrieve the histogram depending on the current masking mode. * * \param label The label for which to retrieve the histogram in multi-label situations (ascending order). */ const HistogramType *GetHistogram( unsigned int timeStep = 0, unsigned int label = 0 ) const; /** \brief Retrieve the histogram depending on the current masking mode (for all image labels. */ const HistogramContainer &GetHistogramVector( unsigned int timeStep = 0 ) const; /** \brief Retrieve statistics depending on the current masking mode. * * \param label The label for which to retrieve the statistics in multi-label situations (ascending order). */ const Statistics &GetStatistics( unsigned int timeStep = 0, unsigned int label = 0 ) const; /** \brief Retrieve statistics depending on the current masking mode (for all image labels). */ const StatisticsContainer &GetStatisticsVector( unsigned int timeStep = 0 ) const; protected: typedef std::vector< HistogramContainer > HistogramVector; typedef std::vector< StatisticsContainer > StatisticsVector; typedef std::vector< itk::TimeStamp > TimeStampVectorType; typedef std::vector< bool > BoolVectorType; typedef itk::Image< unsigned short, 3 > MaskImage3DType; typedef itk::Image< unsigned short, 2 > MaskImage2DType; ImageStatisticsCalculator(); virtual ~ImageStatisticsCalculator(); /** \brief Depending on the masking mode, the image and mask from which to * calculate statistics is extracted from the original input image and mask * data. * * For example, a when using a PlanarFigure as mask, the 2D image slice * corresponding to the PlanarFigure will be extracted from the original * image. If masking is disabled, the original image is simply passed * through. */ void ExtractImageAndMask( unsigned int timeStep = 0 ); /** \brief If the passed vector matches any of the three principal axes * of the passed geometry, the ínteger value corresponding to the axis * is set and true is returned. */ bool GetPrincipalAxis( const Geometry3D *geometry, Vector3D vector, unsigned int &axis ); template < typename TPixel, unsigned int VImageDimension > void InternalCalculateStatisticsUnmasked( const itk::Image< TPixel, VImageDimension > *image, StatisticsContainer* statisticsContainer, HistogramContainer *histogramContainer ); template < typename TPixel, unsigned int VImageDimension > void InternalCalculateStatisticsMasked( const itk::Image< TPixel, VImageDimension > *image, itk::Image< unsigned short, VImageDimension > *maskImage, StatisticsContainer* statisticsContainer, HistogramContainer* histogramContainer ); template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( const itk::Image< TPixel, VImageDimension > *image, unsigned int axis ); template < typename TPixel, unsigned int VImageDimension > void InternalMaskIgnoredPixels( const itk::Image< TPixel, VImageDimension > *image, itk::Image< unsigned short, VImageDimension > *maskImage ); /** Connection from ITK to VTK */ template void ConnectPipelines(ITK_Exporter exporter, vtkSmartPointer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } /** Connection from VTK to ITK */ template void ConnectPipelines(vtkSmartPointer exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } void UnmaskedStatisticsProgressUpdate(); void MaskedStatisticsProgressUpdate(); /** m_Image contains the input image (e.g. 2D, 3D, 3D+t)*/ mitk::Image::ConstPointer m_Image; mitk::Image::ConstPointer m_ImageMask; mitk::PlanarFigure::Pointer m_PlanarFigure; HistogramVector m_ImageHistogramVector; HistogramVector m_MaskedImageHistogramVector; HistogramVector m_PlanarFigureHistogramVector; HistogramType::Pointer m_EmptyHistogram; HistogramContainer m_EmptyHistogramContainer; StatisticsVector m_ImageStatisticsVector; StatisticsVector m_MaskedImageStatisticsVector; StatisticsVector m_PlanarFigureStatisticsVector; Statistics m_EmptyStatistics; StatisticsContainer m_EmptyStatisticsContainer; unsigned int m_MaskingMode; bool m_MaskingModeChanged; /** m_InternalImage contains a image volume at one time step (e.g. 2D, 3D)*/ mitk::Image::ConstPointer m_InternalImage; MaskImage3DType::Pointer m_InternalImageMask3D; MaskImage2DType::Pointer m_InternalImageMask2D; TimeStampVectorType m_ImageStatisticsTimeStampVector; TimeStampVectorType m_MaskedImageStatisticsTimeStampVector; TimeStampVectorType m_PlanarFigureStatisticsTimeStampVector; BoolVectorType m_ImageStatisticsCalculationTriggerVector; BoolVectorType m_MaskedImageStatisticsCalculationTriggerVector; BoolVectorType m_PlanarFigureStatisticsCalculationTriggerVector; double m_IgnorePixelValue; bool m_DoIgnorePixelValue; bool m_IgnorePixelValueChanged; + + unsigned int m_PlanarFigureAxis; // Normal axis for PlanarFigure + unsigned int m_PlanarFigureSlice; // Slice which contains PlanarFigure + int m_PlanarFigureCoordinate0; // First plane-axis for PlanarFigure + int m_PlanarFigureCoordinate1; // Second plane-axis for PlanarFigure + }; } #endif // #define _MITK_IMAGESTATISTICSCALCULATOR_H diff --git a/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.cpp b/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.cpp index b0646e5a65..b13cf0477b 100644 --- a/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.cpp +++ b/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.cpp @@ -1,227 +1,235 @@ /*=================================================================== 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. ===================================================================*/ #if(_MSC_VER==1200) #include #include #include #endif #include "mitkBoundingObjectCutter.h" #include "mitkBoundingObjectCutter.txx" #include "mitkTimeHelper.h" #include "mitkImageAccessByItk.h" #include "mitkBoundingObject.h" #include "mitkGeometry3D.h" //#include "itkImageRegionIteratorWithIndex.h" namespace mitk { void BoundingObjectCutter::SetBoundingObject( const mitk::BoundingObject* boundingObject ) { m_BoundingObject = const_cast(boundingObject); // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(1, const_cast< mitk::BoundingObject * >( boundingObject ) ); } const mitk::BoundingObject* BoundingObjectCutter::GetBoundingObject() const { return m_BoundingObject.GetPointer(); } BoundingObjectCutter::BoundingObjectCutter() : m_BoundingObject(NULL), m_InsideValue(1), m_OutsideValue(0), m_AutoOutsideValue(false), m_UseInsideValue(false), m_OutsidePixelCount(0), m_InsidePixelCount(0), m_UseWholeInputRegion(false) { this->SetNumberOfInputs(2); this->SetNumberOfRequiredInputs(2); m_InputTimeSelector = mitk::ImageTimeSelector::New(); m_OutputTimeSelector = mitk::ImageTimeSelector::New(); } BoundingObjectCutter::~BoundingObjectCutter() { } const mitk::PixelType BoundingObjectCutter::GetOutputPixelType() { return this->GetInput()->GetPixelType(); } void BoundingObjectCutter::GenerateInputRequestedRegion() { mitk::Image* output = this->GetOutput(); if((output->IsInitialized()==false) || (m_BoundingObject.IsNull()) || (m_BoundingObject->GetTimeSlicedGeometry()->GetTimeSteps() == 0)) return; // we have already calculated the spatial part of the // input-requested-region in m_InputRequestedRegion in // GenerateOutputInformation (which is called before // GenerateInputRequestedRegion). GenerateTimeInInputRegion(output, const_cast< mitk::Image * > ( this->GetInput() )); GenerateTimeInInputRegion(output, m_BoundingObject.GetPointer()); } void BoundingObjectCutter::GenerateOutputInformation() { mitk::Image::Pointer output = this->GetOutput(); if ((output->IsInitialized()) && (output->GetPipelineMTime() <= m_TimeOfHeaderInitialization.GetMTime())) return; mitk::Image::Pointer input = const_cast< mitk::Image * > ( this->GetInput() ); + if(input.IsNull()) + { + MITK_WARN << "Input is not a mitk::Image"; + return; + } itkDebugMacro(<<"GenerateOutputInformation()"); + unsigned int dimension = input->GetDimension(); - if(input.IsNull()) + if (dimension < 3) + { + MITK_WARN << "ImageCropper cannot handle 1D or 2D Objects. Operation aborted."; return; + } if((m_BoundingObject.IsNull()) || (m_BoundingObject->GetTimeSlicedGeometry()->GetTimeSteps() == 0)) return; mitk::Geometry3D* boGeometry = m_BoundingObject->GetGeometry(); mitk::Geometry3D* inputImageGeometry = input->GetSlicedGeometry(); // calculate bounding box of bounding-object relative to the geometry // of the input image. The result is in pixel coordinates of the input // image (because the m_IndexToWorldTransform includes the spacing). mitk::BoundingBox::Pointer boBoxRelativeToImage = boGeometry->CalculateBoundingBoxRelativeToTransform( inputImageGeometry->GetIndexToWorldTransform() ); // PART I: initialize input requested region. We do this already here (and not // later when GenerateInputRequestedRegion() is called), because we // also need the information to setup the output. // pre-initialize input-requested-region to largest-possible-region // and correct time-region; spatial part will be cropped by // bounding-box of bounding-object below m_InputRequestedRegion = input->GetLargestPossibleRegion(); // build region out of bounding-box of bounding-object mitk::SlicedData::IndexType index=m_InputRequestedRegion.GetIndex(); //init times and channels mitk::BoundingBox::PointType min = boBoxRelativeToImage->GetMinimum(); - index[0] = (mitk::SlicedData::IndexType::IndexValueType)(min[0]+0.5); - index[1] = (mitk::SlicedData::IndexType::IndexValueType)(min[1]+0.5); - index[2] = (mitk::SlicedData::IndexType::IndexValueType)(min[2]+0.5); + index[0] = (mitk::SlicedData::IndexType::IndexValueType)(min[0]); + index[1] = (mitk::SlicedData::IndexType::IndexValueType)(min[1]); + index[2] = (mitk::SlicedData::IndexType::IndexValueType)(min[2]); mitk::SlicedData::SizeType size = m_InputRequestedRegion.GetSize(); //init times and channels mitk::BoundingBox::PointType max = boBoxRelativeToImage->GetMaximum(); - size[0] = (mitk::SlicedData::SizeType::SizeValueType)(max[0]+0.5)-index[0]; - size[1] = (mitk::SlicedData::SizeType::SizeValueType)(max[1]+0.5)-index[1]; - size[2] = (mitk::SlicedData::SizeType::SizeValueType)(max[2]+0.5)-index[2]; + size[0] = (mitk::SlicedData::SizeType::SizeValueType)(max[0])-index[0]; + size[1] = (mitk::SlicedData::SizeType::SizeValueType)(max[1])-index[1]; + size[2] = (mitk::SlicedData::SizeType::SizeValueType)(max[2])-index[2]; mitk::SlicedData::RegionType boRegion(index, size); if(m_UseWholeInputRegion == false) { // crop input-requested-region with region of bounding-object if(m_InputRequestedRegion.Crop(boRegion)==false) { // crop not possible => do nothing: set time size to 0. size.Fill(0); m_InputRequestedRegion.SetSize(size); boRegion.SetSize(size); m_BoundingObject->SetRequestedRegion(&boRegion); return; } } // set input-requested-region, because we access it later in // GenerateInputRequestedRegion (there we just set the time) input->SetRequestedRegion(&m_InputRequestedRegion); // PART II: initialize output image - unsigned int dimension = input->GetDimension(); unsigned int *dimensions = new unsigned int [dimension]; itk2vtk(m_InputRequestedRegion.GetSize(), dimensions); if(dimension>3) memcpy(dimensions+3, input->GetDimensions()+3, (dimension-3)*sizeof(unsigned int)); output->Initialize(mitk::PixelType(GetOutputPixelType()), dimension, dimensions); delete [] dimensions; // now we have everything to initialize the transform of the output mitk::SlicedGeometry3D* slicedGeometry = output->GetSlicedGeometry(); // set the transform: use the transform of the input; // the origin will be replaced afterwards AffineTransform3D::Pointer indexToWorldTransform = AffineTransform3D::New(); indexToWorldTransform->SetParameters(input->GetSlicedGeometry()->GetIndexToWorldTransform()->GetParameters()); slicedGeometry->SetIndexToWorldTransform(indexToWorldTransform); // Position the output Image to match the corresponding region of the input image const mitk::SlicedData::IndexType& start = m_InputRequestedRegion.GetIndex(); mitk::Point3D origin; vtk2itk(start, origin); inputImageGeometry->IndexToWorld(origin, origin); slicedGeometry->SetOrigin(origin); mitk::TimeSlicedGeometry* timeSlicedGeometry = output->GetTimeSlicedGeometry(); timeSlicedGeometry->InitializeEvenlyTimed(slicedGeometry, output->GetDimension(3)); timeSlicedGeometry->CopyTimes(input->GetTimeSlicedGeometry()); m_TimeOfHeaderInitialization.Modified(); } void BoundingObjectCutter::ComputeData(mitk::Image* input3D, int boTimeStep) { AccessFixedDimensionByItk_2(input3D, CutImage, 3, this, boTimeStep); } void BoundingObjectCutter::GenerateData() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if(input.IsNull()) return; if((output->IsInitialized()==false) || (m_BoundingObject.IsNull()) || (m_BoundingObject->GetTimeSlicedGeometry()->GetTimeSteps() == 0)) return; m_InputTimeSelector->SetInput(input); m_OutputTimeSelector->SetInput(this->GetOutput()); mitk::Surface::RegionType outputRegion = output->GetRequestedRegion(); const mitk::TimeSlicedGeometry *outputTimeGeometry = output->GetTimeSlicedGeometry(); const mitk::TimeSlicedGeometry *inputTimeGeometry = input->GetTimeSlicedGeometry(); const mitk::TimeSlicedGeometry *boundingObjectTimeGeometry = m_BoundingObject->GetTimeSlicedGeometry(); ScalarType timeInMS; int timestep=0; int tstart=outputRegion.GetIndex(3); int tmax=tstart+outputRegion.GetSize(3); int t; for(t=tstart;tTimeStepToMS( t ); timestep = inputTimeGeometry->MSToTimeStep( timeInMS ); m_InputTimeSelector->SetTimeNr(timestep); m_InputTimeSelector->UpdateLargestPossibleRegion(); m_OutputTimeSelector->SetTimeNr(t); m_OutputTimeSelector->UpdateLargestPossibleRegion(); timestep = boundingObjectTimeGeometry->MSToTimeStep( timeInMS ); ComputeData(m_InputTimeSelector->GetOutput(), timestep); } m_InputTimeSelector->SetInput(NULL); m_OutputTimeSelector->SetInput(NULL); m_TimeOfHeaderInitialization.Modified(); } } // of namespace mitk diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h b/Modules/MitkExt/Controllers/mitkIPythonService.cpp similarity index 53% copy from Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h copy to Modules/MitkExt/Controllers/mitkIPythonService.cpp index b96fd0fb6e..3138baee1a 100644 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h +++ b/Modules/MitkExt/Controllers/mitkIPythonService.cpp @@ -1,40 +1,21 @@ /*=================================================================== 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 MITKPLUGINACTIVATOR_H -#define MITKPLUGINACTIVATOR_H -#include -#include - - -namespace mitk { - - class MITK_LOCAL PluginActivator : - public QObject, public ctkPluginActivator - { - Q_OBJECT - Q_INTERFACES(ctkPluginActivator) - - public: - - void start(ctkPluginContext* context); - void stop(ctkPluginContext* context); - - }; // PluginActivator +#include "mitkIPythonService.h" +mitk::IPythonService::~IPythonService() +{ } - -#endif // MITKPLUGINACTIVATOR_H diff --git a/Modules/MitkExt/Controllers/mitkIPythonService.h b/Modules/MitkExt/Controllers/mitkIPythonService.h new file mode 100644 index 0000000000..5e34bd6abc --- /dev/null +++ b/Modules/MitkExt/Controllers/mitkIPythonService.h @@ -0,0 +1,141 @@ +/*=================================================================== + +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 mitkIPythonService_h +#define mitkIPythonService_h + +// mitk +#include "MitkExtExports.h" +#include "mitkImage.h" +//for microservices +#include +#include "mitkSurface.h" +#include + +namespace mitk +{ + /// + /// describes a python variable (data container) + /// \see IPythonService::GetVariableStack() + /// + struct PythonVariable + { + std::string m_Name; + std::string m_Type; + std::string m_Value; + }; + + /// + /// a PythonCommandObserver gets informed as soon as a python command was issued + /// \see IPythonService::AddPythonCommandObserver() + /// + class PythonCommandObserver + { + public: + virtual void CommandExecuted(const std::string& pythonCommand) = 0; + }; + + /// + /// The central service for issuing Python Code + /// The class also enables to transfer mitk images to python as itk::Image and vice versa + /// \see IPythonService::GetVariableStack() + /// + class MitkExt_EXPORT IPythonService + { + public: + /// + /// Constant representing a single line command + /// \see IPythonService::Execute() + static const int SINGLE_LINE_COMMAND = 0; + /// + /// Constant representing a command in which the commands are seperated by new lines, i.e. "\\n" + /// \see IPythonService::Execute() + static const int MULTI_LINE_COMMAND = 1; + /// + /// Constant representing a single line command x which is run as "eval(x)" + /// \see IPythonService::Execute() + static const int EVAL_COMMAND = 2; + + /// + /// Executes a python command. + /// \return A variant containing the return value as string of the python code (if any) + virtual std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ) = 0; + /// + /// Executes a python script. + virtual void ExecuteScript( const std::string& pathToPythonScript ) = 0; + /// + /// \return true if the last call to Execute...() resulted in an error, false otherwise + virtual bool PythonErrorOccured() const = 0; + /// + /// \return The list of variables in the __main__ namespace + virtual std::vector GetVariableStack() const = 0; + /// + /// \return true if a variable with this name is defined in the __main__ namespace, false otherwise + virtual bool DoesVariableExist(const std::string& name) const = 0; + /// + /// adds a command observer which is informed after a command was issued with "Execute" + virtual void AddPythonCommandObserver( PythonCommandObserver* observer ) = 0; + /// + /// removes a specific command observer + virtual void RemovePythonCommandObserver( PythonCommandObserver* observer ) = 0; + /// + /// notify all observer. this should only be used if it can be garantueed that the + /// current python interpreter instance got another command from anywhere else + /// the the Execute() method of this service, e.g. the shell widget uses this function + /// since it does not use Execute() + virtual void NotifyObserver( const std::string& command ) = 0; + + /// + /// \return true, if itk wrapping is available, false otherwise + virtual bool IsItkPythonWrappingAvailable() = 0; + /// + /// copies an mitk image as itk image into the python interpreter process + /// the image will be available as "varName" in python if everythin worked + /// \return true if image was copied, else false + virtual bool CopyToPythonAsItkImage( mitk::Image* image, const std::string& varName ) = 0; + /// + /// copies an itk image from the python process that is named "varName" + /// \return the image or 0 if copying was not possible + virtual mitk::Image::Pointer CopyItkImageFromPython( const std::string& varName ) = 0; + + /// + /// \return true, if OpenCv wrapping is available, false otherwise + virtual bool IsOpenCvPythonWrappingAvailable() = 0; + /// + /// \see CopyToPythonAsItkImage() + virtual bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ) = 0; + /// + /// \see CopyCvImageFromPython() + virtual mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ) = 0; + + /// + /// \return true, if vtk wrapping is available, false otherwise + virtual bool IsVtkPythonWrappingAvailable() = 0; + /// + /// \see CopyToPythonAsItkImage() + virtual bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ) = 0; + /// + /// \see CopyCvImageFromPython() + virtual mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ) = 0; + + /// + /// nothing to do here + virtual ~IPythonService(); // leer in mitkIPythonService.cpp implementieren + }; +} + +US_DECLARE_SERVICE_INTERFACE(mitk::IPythonService, "org.mitk.services.IPythonService") + +#endif diff --git a/Modules/MitkExt/Controllers/mitkToolManager.cpp b/Modules/MitkExt/Controllers/mitkToolManager.cpp index 74650a2092..02ba2ad59b 100644 --- a/Modules/MitkExt/Controllers/mitkToolManager.cpp +++ b/Modules/MitkExt/Controllers/mitkToolManager.cpp @@ -1,528 +1,576 @@ /*=================================================================== 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 "mitkToolManager.h" #include "mitkGlobalInteraction.h" #include "mitkCoreObjectFactory.h" #include #include #include +#include "mitkInteractionEventObserver.h" +#include "mitkDisplayInteractor.h" +// MicroServices +#include "mitkGetModuleContext.h" +#include "mitkModule.h" +#include "mitkModuleRegistry.h" + + mitk::ToolManager::ToolManager(DataStorage* storage) :m_ActiveTool(NULL), m_ActiveToolID(-1), m_RegisteredClients(0), m_DataStorage(storage) { CoreObjectFactory::GetInstance(); // to make sure a CoreObjectFactory was instantiated (and in turn, possible tools are registered) - bug 1029 // get a list of all known mitk::Tools std::list thingsThatClaimToBeATool = itk::ObjectFactoryBase::CreateAllInstance("mitkTool"); // remember these tools for ( std::list::iterator iter = thingsThatClaimToBeATool.begin(); iter != thingsThatClaimToBeATool.end(); ++iter ) { if ( Tool* tool = dynamic_cast( iter->GetPointer() ) ) { tool->SetToolManager(this); // important to call right after instantiation tool->ErrorMessage += MessageDelegate1( this, &ToolManager::OnToolErrorMessage ); tool->GeneralMessage += MessageDelegate1( this, &ToolManager::OnGeneralToolMessage ); m_Tools.push_back( tool ); } } //ActivateTool(0); // first one is default } mitk::ToolManager::~ToolManager() { for (DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter) (*dataIter)->RemoveObserver(m_WorkingDataObserverTags[(*dataIter)]); if(this->GetDataStorage() != NULL) this->GetDataStorage()->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1 ( this, &ToolManager::OnNodeRemoved )); if (m_ActiveTool) { m_ActiveTool->Deactivated(); GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); m_ActiveTool = NULL; m_ActiveToolID = -1; // no tool active ActiveToolChanged.Send(); } for ( NodeTagMapType::iterator observerTagMapIter = m_ReferenceDataObserverTags.begin(); observerTagMapIter != m_ReferenceDataObserverTags.end(); ++observerTagMapIter ) { observerTagMapIter->first->RemoveObserver( observerTagMapIter->second ); } } void mitk::ToolManager::OnToolErrorMessage(std::string s) { this->ToolErrorMessage(s); } void mitk::ToolManager::OnGeneralToolMessage(std::string s) { this->GeneralToolMessage(s); } const mitk::ToolManager::ToolVectorTypeConst mitk::ToolManager::GetTools() { ToolVectorTypeConst resultList; for ( ToolVectorType::iterator iter = m_Tools.begin(); iter != m_Tools.end(); ++iter ) { resultList.push_back( iter->GetPointer() ); } return resultList; } mitk::Tool* mitk::ToolManager::GetToolById(int id) { try { return m_Tools.at(id); } catch(std::exception&) { return NULL; } } bool mitk::ToolManager::ActivateTool(int id) { if(this->GetDataStorage()) { this->GetDataStorage()->RemoveNodeEvent.AddListener( mitk::MessageDelegate1 ( this, &ToolManager::OnNodeRemoved ) ); } //MITK_INFO << "ToolManager::ActivateTool("<SetEventNotificationPolicy(GlobalInteraction::INFORM_MULTIPLE); + // Re-enabling InteractionEventObservers that have been previously disabled for legacy handling of Tools + // in new interaction framework + std::list listEventObserver; + ServiceTracker* eventObserverTracker= new ServiceTracker(GetModuleContext()); + eventObserverTracker->Open(); + eventObserverTracker->GetServiceReferences(listEventObserver); // query all registered interaction event observer + for (std::list::iterator it = listEventObserver.begin(); it != listEventObserver.end(); ++it) + { + InteractionEventObserver* interactionEventObserver = eventObserverTracker->GetService(*it); + if (interactionEventObserver != NULL) { + DisplayInteractor* displayInteractor = dynamic_cast(interactionEventObserver); + if (displayInteractor != NULL) { + // here the regular configuration is loaded again + displayInteractor->LoadEventConfig("DisplayConfigMITK.xml","Mitk"); + } + } + } + eventObserverTracker->Close(); + delete eventObserverTracker; + } if ( GetToolById( id ) == m_ActiveTool ) return true; // no change needed static int nextTool = -1; nextTool = id; //MITK_INFO << "ToolManager::ActivateTool("<Deactivated(); GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); } m_ActiveTool = GetToolById( nextTool ); m_ActiveToolID = m_ActiveTool ? nextTool : -1; // current ID if tool is valid, otherwise -1 ActiveToolChanged.Send(); if (m_ActiveTool) { if (m_RegisteredClients > 0) { m_ActiveTool->Activated(); GlobalInteraction::GetInstance()->AddListener( m_ActiveTool ); //If a tool is activated set event notification policy to one GlobalInteraction::GetInstance()->SetEventNotificationPolicy(GlobalInteraction::INFORM_ONE); + // As a legacy solution the display interaction of the new interaction framework is disabled here to avoid conflicts with tools + // Note: this only affects InteractionEventObservers (formerly known as Listeners) all DataNode specific interaction will still be enabled + std::list listEventObserver; + ServiceTracker* eventObserverTracker= new ServiceTracker(GetModuleContext()); + eventObserverTracker->Open(); + eventObserverTracker->GetServiceReferences(listEventObserver); + for (std::list::iterator it = listEventObserver.begin(); it != listEventObserver.end(); ++it) + { + InteractionEventObserver* interactionEventObserver = eventObserverTracker->GetService(*it); + if (interactionEventObserver != NULL) { + DisplayInteractor* displayInteractor = dynamic_cast(interactionEventObserver); + if (displayInteractor != NULL) { + // here the regular configuration is loaded again + displayInteractor->LoadEventConfig("Legacy/DisplayConfigMITKTools.xml","Mitk"); + } + } + } + eventObserverTracker->Close(); + delete eventObserverTracker; } } } inActivateTool = false; return (m_ActiveTool != NULL); } void mitk::ToolManager::SetReferenceData(DataVectorType data) { if (data != m_ReferenceData) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_ReferenceDataObserverTags.find( *dataIter ); if ( searchIter != m_ReferenceDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_ReferenceData = data; // TODO tell active tool? // attach new observers m_ReferenceDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheReferenceDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheReferenceDataDeletedConst ); m_ReferenceDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } ReferenceDataChanged.Send(); } } void mitk::ToolManager::OnOneOfTheReferenceDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheReferenceDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheReferenceDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from reference data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_ReferenceDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetReferenceData( v ); } void mitk::ToolManager::SetReferenceData(DataNode* data) { //MITK_INFO << "ToolManager::SetReferenceData(" << (void*)data << ")" << std::endl; DataVectorType v; if (data) { v.push_back(data); } SetReferenceData(v); } void mitk::ToolManager::SetWorkingData(DataVectorType data) { if ( data != m_WorkingData ) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_WorkingDataObserverTags.find( *dataIter ); if ( searchIter != m_WorkingDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_WorkingData = data; // TODO tell active tool? // attach new observers m_WorkingDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheWorkingDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheWorkingDataDeletedConst ); m_WorkingDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } WorkingDataChanged.Send(); } } void mitk::ToolManager::OnOneOfTheWorkingDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheWorkingDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheWorkingDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from reference data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_WorkingDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetWorkingData( v ); } void mitk::ToolManager::SetWorkingData(DataNode* data) { DataVectorType v; if (data) // don't allow for NULL nodes { v.push_back(data); } SetWorkingData(v); } void mitk::ToolManager::SetRoiData(DataVectorType data) { if (data != m_RoiData) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_RoiDataObserverTags.find( *dataIter ); if ( searchIter != m_RoiDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_RoiData = data; // TODO tell active tool? // attach new observers m_RoiDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheRoiDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheRoiDataDeletedConst ); m_RoiDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } RoiDataChanged.Send(); } } void mitk::ToolManager::SetRoiData(DataNode* data) { DataVectorType v; if(data) { v.push_back(data); } this->SetRoiData(v); } void mitk::ToolManager::OnOneOfTheRoiDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheRoiDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheRoiDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from roi data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_RoiDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetRoiData( v ); } mitk::ToolManager::DataVectorType mitk::ToolManager::GetReferenceData() { return m_ReferenceData; } mitk::DataNode* mitk::ToolManager::GetReferenceData(int idx) { try { return m_ReferenceData.at(idx); } catch(std::exception&) { return NULL; } } mitk::ToolManager::DataVectorType mitk::ToolManager::GetWorkingData() { return m_WorkingData; } mitk::ToolManager::DataVectorType mitk::ToolManager::GetRoiData() { return m_RoiData; } mitk::DataNode* mitk::ToolManager::GetRoiData(int idx) { try { return m_RoiData.at(idx); } catch(std::exception&) { return NULL; } } mitk::DataStorage* mitk::ToolManager::GetDataStorage() { if ( m_DataStorage.IsNotNull() ) { return m_DataStorage; } else { return NULL; } } void mitk::ToolManager::SetDataStorage(DataStorage& storage) { m_DataStorage = &storage; } mitk::DataNode* mitk::ToolManager::GetWorkingData(int idx) { try { return m_WorkingData.at(idx); } catch(std::exception&) { return NULL; } } int mitk::ToolManager::GetActiveToolID() { return m_ActiveToolID; } mitk::Tool* mitk::ToolManager::GetActiveTool() { return m_ActiveTool; } void mitk::ToolManager::RegisterClient() { if ( m_RegisteredClients < 1 ) { if ( m_ActiveTool ) { m_ActiveTool->Activated(); GlobalInteraction::GetInstance()->AddListener( m_ActiveTool ); } } ++m_RegisteredClients; } void mitk::ToolManager::UnregisterClient() { if ( m_RegisteredClients < 1) return; --m_RegisteredClients; if ( m_RegisteredClients < 1 ) { if ( m_ActiveTool ) { m_ActiveTool->Deactivated(); GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); } } } int mitk::ToolManager::GetToolID( const Tool* tool ) { int id(0); for ( ToolVectorType::iterator iter = m_Tools.begin(); iter != m_Tools.end(); ++iter, ++id ) { if ( tool == iter->GetPointer() ) { return id; } } return -1; } void mitk::ToolManager::OnNodeRemoved(const mitk::DataNode* node) { //check if the data of the node is typeof Image /*if(dynamic_cast(node->GetData())) {*/ //check all storage vectors OnOneOfTheReferenceDataDeleted(const_cast(node), itk::DeleteEvent()); OnOneOfTheRoiDataDeleted(const_cast(node),itk::DeleteEvent()); OnOneOfTheWorkingDataDeleted(const_cast(node),itk::DeleteEvent()); //} } diff --git a/Modules/MitkExt/DataManagement/mitkBoundingObject.cpp b/Modules/MitkExt/DataManagement/mitkBoundingObject.cpp index 4ce86e110d..5ddd75745b 100644 --- a/Modules/MitkExt/DataManagement/mitkBoundingObject.cpp +++ b/Modules/MitkExt/DataManagement/mitkBoundingObject.cpp @@ -1,68 +1,72 @@ /*=================================================================== 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 "mitkBoundingObject.h" #include "mitkBaseProcess.h" mitk::BoundingObject::BoundingObject() : Surface(), m_Positive(true) { // Initialize(1); /* bounding box around the unscaled bounding object */ ScalarType bounds[6]={-1,1,-1,1,-1,1}; //{xmin,x_max, ymin,y_max,zmin,z_max} GetGeometry()->SetBounds(bounds); GetTimeSlicedGeometry()->UpdateInformation(); } mitk::BoundingObject::~BoundingObject() { } mitk::ScalarType mitk::BoundingObject::GetVolume() { return 0.0; } void mitk::BoundingObject::FitGeometry(mitk::Geometry3D* aGeometry3D) { // Adjusted this function to fix // BUG 6951 - Image Cropper - Bounding Box is strange // Still, the behavior of the BoundingObject is really strange. // One would think that writing "setGeometry(aGeometry3D)" here would do the job. // But apparently the boundingObject can only be handled correctly, when it's // indexBounds are from -1 to 1 in all axis (so it is only 2x2x2 Pixels big) and the spacing // specifies it's actual bounds. This behavior needs to be analyzed and maybe changed. // Check also BUG 11406 - if (aGeometry3D->GetImageGeometry()) - { - aGeometry3D->ChangeImageGeometryConsideringOriginOffset(false); - } GetGeometry()->SetIdentity(); GetGeometry()->Compose(aGeometry3D->GetIndexToWorldTransform()); - GetGeometry()->SetOrigin(aGeometry3D->GetCenter()); + // Since aGeometry (which should actually be const), is an imagegeometry and boundingObject is NOT an image, + // we have to adjust the Origin by shifting it half pixel + mitk::Point3D myOrigin = aGeometry3D->GetCenter(); + myOrigin[0] -= (aGeometry3D->GetSpacing()[0] / 2.0); + myOrigin[1] -= (aGeometry3D->GetSpacing()[1] / 2.0); + myOrigin[2] -= (aGeometry3D->GetSpacing()[2] / 2.0); + + GetGeometry()->SetOrigin(myOrigin); mitk::Vector3D size; for(unsigned int i=0; i < 3; ++i) - size[i] = (aGeometry3D->GetExtentInMM(i)/2.0) -1; + size[i] = (aGeometry3D->GetExtentInMM(i)/2.0); GetGeometry()->SetSpacing( size ); GetTimeSlicedGeometry()->UpdateInformation(); + } diff --git a/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp b/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp index 2d66b1637b..9d79d2139c 100644 --- a/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp +++ b/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp @@ -1,708 +1,708 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define GPU_INFO MITK_INFO("mapper.vr") #define GPU_WARN MITK_WARN("mapper.vr") #define GPU_ERROR MITK_ERROR("mapper.vr") #include "mitkGPUVolumeMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkLevelWindow.h" #include "mitkColorProperty.h" #include "mitkLevelWindowProperty.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunctionProperty.h" #include "mitkTransferFunctionInitializer.h" #include "mitkColorProperty.h" #include "mitkVtkPropRenderer.h" #include "mitkRenderingManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) #include "vtkMitkGPUVolumeRayCastMapper.h" #endif #include "vtkOpenGLGPUVolumeRayCastMapper.h" #include "vtkMitkOpenGLVolumeTextureMapper3D.h" const mitk::Image* mitk::GPUVolumeMapper3D::GetInput() { return static_cast ( GetDataNode()->GetData() ); } void mitk::GPUVolumeMapper3D::MitkRenderVolumetricGeometry(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); VtkMapper::MitkRenderVolumetricGeometry(renderer); if(ls->m_gpuInitialized) ls->m_MapperGPU->UpdateMTime(); } bool mitk::GPUVolumeMapper3D::InitGPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_gpuInitialized) return ls->m_gpuSupported; GPU_INFO << "initializing gpu-slicing-vr (vtkMitkOpenGLVolumeTextureMapper3D)"; ls->m_MapperGPU = vtkSmartPointer::New(); ls->m_MapperGPU->SetUseCompressedTexture(false); ls->m_MapperGPU->SetSampleDistance(1.0); ls->m_VolumePropertyGPU = vtkSmartPointer::New(); ls->m_VolumePropertyGPU->ShadeOn(); ls->m_VolumePropertyGPU->SetAmbient (0.25f); //0.05f ls->m_VolumePropertyGPU->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyGPU->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyGPU->SetSpecularPower(16.0f); ls->m_VolumePropertyGPU->SetInterpolationTypeToLinear(); ls->m_VolumeGPU = vtkSmartPointer::New(); ls->m_VolumeGPU->SetMapper( ls->m_MapperGPU ); ls->m_VolumeGPU->SetProperty( ls->m_VolumePropertyGPU ); ls->m_VolumeGPU->VisibilityOn(); ls->m_MapperGPU->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); ls->m_gpuSupported = ls->m_MapperGPU->IsRenderSupported(renderer->GetVtkRenderer(),ls->m_VolumePropertyGPU); ls->m_gpuInitialized = true; return ls->m_gpuSupported; } void mitk::GPUVolumeMapper3D::InitCPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_cpuInitialized) return; int numThreads = itk::MultiThreader::GetGlobalDefaultNumberOfThreads(); GPU_INFO << "initializing cpu-raycast-vr (vtkFixedPointVolumeRayCastMapper) (" << numThreads << " threads)"; ls->m_MapperCPU = vtkSmartPointer::New(); ls->m_MapperCPU->SetSampleDistance(1.0); // ls->m_MapperCPU->LockSampleDistanceToInputSpacingOn(); ls->m_MapperCPU->SetImageSampleDistance(1.0); ls->m_MapperCPU->IntermixIntersectingGeometryOn(); ls->m_MapperCPU->SetAutoAdjustSampleDistances(0); ls->m_MapperCPU->SetNumberOfThreads( numThreads ); ls->m_VolumePropertyCPU = vtkSmartPointer::New(); ls->m_VolumePropertyCPU->ShadeOn(); ls->m_VolumePropertyCPU->SetAmbient (0.10f); //0.05f ls->m_VolumePropertyCPU->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyCPU->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyCPU->SetSpecularPower(16.0f); ls->m_VolumePropertyCPU->SetInterpolationTypeToLinear(); ls->m_VolumeCPU = vtkSmartPointer::New(); ls->m_VolumeCPU->SetMapper( ls->m_MapperCPU ); ls->m_VolumeCPU->SetProperty( ls->m_VolumePropertyCPU ); ls->m_VolumeCPU->VisibilityOn(); ls->m_MapperCPU->SetInput( m_UnitSpacingImageFilter->GetOutput() );//m_Resampler->GetOutput()); ls->m_cpuInitialized=true; } void mitk::GPUVolumeMapper3D::DeinitGPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_gpuInitialized) { GPU_INFO << "deinitializing gpu-slicing-vr"; ls->m_VolumePropertyGPU = NULL; ls->m_MapperGPU = NULL; ls->m_VolumeGPU = NULL; ls->m_gpuInitialized=false; } } void mitk::GPUVolumeMapper3D::DeinitCPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(!ls->m_cpuInitialized) return; GPU_INFO << "deinitializing cpu-raycast-vr"; ls->m_VolumePropertyCPU = NULL; ls->m_MapperCPU = NULL; ls->m_VolumeCPU = NULL; ls->m_cpuInitialized=false; } mitk::GPUVolumeMapper3D::GPUVolumeMapper3D() { m_VolumeNULL=0; m_commonInitialized=false; } mitk::GPUVolumeMapper3D::~GPUVolumeMapper3D() { DeinitCommon(); } void mitk::GPUVolumeMapper3D::InitCommon() { if(m_commonInitialized) return; m_UnitSpacingImageFilter = vtkSmartPointer::New(); m_UnitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); CreateDefaultTransferFunctions(); m_commonInitialized=true; } void mitk::GPUVolumeMapper3D::DeinitCommon() { if(!m_commonInitialized) return; m_commonInitialized=false; } bool mitk::GPUVolumeMapper3D::IsRenderable(mitk::BaseRenderer* renderer) { if(!GetDataNode()) return false; DataNode* node = GetDataNode(); bool visible = true; node->GetVisibility(visible, renderer, "visible"); if(!visible) return false; bool value = false; - if(!node->GetBoolProperty("volumerendering",value,renderer)); + if(!node->GetBoolProperty("volumerendering",value,renderer)) return false; if(!value) return false; mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); if ( !input || !input->IsInitialized() ) return false; vtkImageData *inputData = input->GetVtkImageData( this->GetTimestep() ); if(inputData==NULL) return false; return true; } void mitk::GPUVolumeMapper3D::InitVtkMapper(mitk::BaseRenderer* renderer) { // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(IsRAYEnabled(renderer)) { DeinitCPU(renderer); DeinitGPU(renderer); if(!InitRAY(renderer)) { GPU_WARN << "hardware renderer can't initialize ... falling back to software renderer"; goto fallback; } } else #endif if(IsGPUEnabled(renderer)) { DeinitCPU(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) DeinitRAY(renderer); #endif if(!InitGPU(renderer)) { GPU_WARN << "hardware renderer can't initialize ... falling back to software renderer"; goto fallback; } } else { fallback: DeinitGPU(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) DeinitRAY(renderer); #endif InitCPU(renderer); } } vtkProp *mitk::GPUVolumeMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { if(!IsRenderable(renderer)) { if(!m_VolumeNULL) { m_VolumeNULL = vtkSmartPointer::New(); m_VolumeNULL->VisibilityOff(); } return m_VolumeNULL; } InitCommon(); InitVtkMapper( renderer ); LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) return ls->m_VolumeRAY; #endif if(ls->m_gpuInitialized) return ls->m_VolumeGPU; return ls->m_VolumeCPU; } void mitk::GPUVolumeMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { if(!IsRenderable(renderer)) return; InitCommon(); InitVtkMapper( renderer ); mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); vtkImageData *inputData = input->GetVtkImageData( this->GetTimestep() ); m_UnitSpacingImageFilter->SetInput( inputData ); LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) { GenerateDataRAY(renderer); } else #endif if(ls->m_gpuInitialized) { GenerateDataGPU(renderer); } else { GenerateDataCPU(renderer); } // UpdateTransferFunctions UpdateTransferFunctions( renderer ); } void mitk::GPUVolumeMapper3D::GenerateDataGPU( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool useCompression = false; GetDataNode()->GetBoolProperty("volumerendering.gpu.usetexturecompression",useCompression,renderer); ls->m_MapperGPU->SetUseCompressedTexture(useCompression); if( IsLODEnabled(renderer) && mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) == 0 ) ls->m_MapperGPU->SetSampleDistance(2.0); else ls->m_MapperGPU->SetSampleDistance(1.0); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.gpu.ambient",value,renderer)) ls->m_VolumePropertyGPU->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.diffuse",value,renderer)) ls->m_VolumePropertyGPU->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.specular",value,renderer)) ls->m_VolumePropertyGPU->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.specular.power",value,renderer)) ls->m_VolumePropertyGPU->SetSpecularPower(value); } } void mitk::GPUVolumeMapper3D::GenerateDataCPU( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); int nextLod = mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ); if( IsLODEnabled(renderer) && nextLod == 0 ) { ls->m_MapperCPU->SetImageSampleDistance(3.5); ls->m_MapperCPU->SetSampleDistance(1.25); ls->m_VolumePropertyCPU->SetInterpolationTypeToNearest(); } else { ls->m_MapperCPU->SetImageSampleDistance(1.0); ls->m_MapperCPU->SetSampleDistance(1.0); ls->m_VolumePropertyCPU->SetInterpolationTypeToLinear(); } // Check raycasting mode if(IsMIPEnabled(renderer)) ls->m_MapperCPU->SetBlendModeToMaximumIntensity(); else ls->m_MapperCPU->SetBlendModeToComposite(); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.cpu.ambient",value,renderer)) ls->m_VolumePropertyCPU->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.diffuse",value,renderer)) ls->m_VolumePropertyCPU->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.specular",value,renderer)) ls->m_VolumePropertyCPU->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.specular.power",value,renderer)) ls->m_VolumePropertyCPU->SetSpecularPower(value); } } void mitk::GPUVolumeMapper3D::CreateDefaultTransferFunctions() { m_DefaultOpacityTransferFunction = vtkSmartPointer::New(); m_DefaultOpacityTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultOpacityTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultOpacityTransferFunction->ClampingOn(); m_DefaultGradientTransferFunction = vtkSmartPointer::New(); m_DefaultGradientTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultGradientTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultGradientTransferFunction->ClampingOn(); m_DefaultColorTransferFunction = vtkSmartPointer::New(); m_DefaultColorTransferFunction->AddRGBPoint( 0.0, 0.0, 0.0, 0.0 ); m_DefaultColorTransferFunction->AddRGBPoint( 127.5, 1, 1, 0.0 ); m_DefaultColorTransferFunction->AddRGBPoint( 255.0, 0.8, 0.2, 0 ); m_DefaultColorTransferFunction->ClampingOn(); m_BinaryOpacityTransferFunction = vtkSmartPointer::New(); m_BinaryOpacityTransferFunction->AddPoint( 0, 0.0 ); m_BinaryOpacityTransferFunction->AddPoint( 1, 1.0 ); m_BinaryGradientTransferFunction = vtkSmartPointer::New(); m_BinaryGradientTransferFunction->AddPoint( 0.0, 1.0 ); m_BinaryColorTransferFunction = vtkSmartPointer::New(); } void mitk::GPUVolumeMapper3D::UpdateTransferFunctions( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); vtkPiecewiseFunction *opacityTransferFunction = m_DefaultOpacityTransferFunction; vtkPiecewiseFunction *gradientTransferFunction = m_DefaultGradientTransferFunction; vtkColorTransferFunction *colorTransferFunction = m_DefaultColorTransferFunction; bool isBinary = false; GetDataNode()->GetBoolProperty("binary", isBinary, renderer); if(isBinary) { opacityTransferFunction = m_BinaryOpacityTransferFunction; gradientTransferFunction = m_BinaryGradientTransferFunction; colorTransferFunction = m_BinaryColorTransferFunction; colorTransferFunction->RemoveAllPoints(); float rgb[3]; if( !GetDataNode()->GetColor( rgb,renderer ) ) rgb[0]=rgb[1]=rgb[2]=1; colorTransferFunction->AddRGBPoint( 0,rgb[0],rgb[1],rgb[2] ); colorTransferFunction->Modified(); } else { mitk::TransferFunctionProperty *transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction",renderer)); if( transferFunctionProp ) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } } if(ls->m_gpuInitialized) { ls->m_VolumePropertyGPU->SetColor( colorTransferFunction ); ls->m_VolumePropertyGPU->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyGPU->SetGradientOpacity( gradientTransferFunction ); } // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) { ls->m_VolumePropertyRAY->SetColor( colorTransferFunction ); ls->m_VolumePropertyRAY->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyRAY->SetGradientOpacity( gradientTransferFunction ); } #endif if(ls->m_cpuInitialized) { ls->m_VolumePropertyCPU->SetColor( colorTransferFunction ); ls->m_VolumePropertyCPU->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyCPU->SetGradientOpacity( gradientTransferFunction ); } } void mitk::GPUVolumeMapper3D::ApplyProperties(vtkActor* /*actor*/, mitk::BaseRenderer* /*renderer*/) { //GPU_INFO << "ApplyProperties"; } void mitk::GPUVolumeMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { //GPU_INFO << "SetDefaultProperties"; node->AddProperty( "volumerendering", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.usemip", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.uselod", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.ambient", mitk::FloatProperty::New( 0.10f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); bool usegpu = true; #ifdef __APPLE__ usegpu = false; node->AddProperty( "volumerendering.uselod", mitk::BoolProperty::New( true ), renderer, overwrite ); #endif node->AddProperty( "volumerendering.usegpu", mitk::BoolProperty::New( usegpu ), renderer, overwrite ); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) node->AddProperty( "volumerendering.useray", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.ambient", mitk::FloatProperty::New( 0.25f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); #endif node->AddProperty( "volumerendering.gpu.ambient", mitk::FloatProperty::New( 0.25f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.usetexturecompression", mitk::BoolProperty ::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.reducesliceartifacts" , mitk::BoolProperty ::New( false ), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if(image.IsNotNull() && image->IsInitialized()) { if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) { mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetAuto( image ); levWinProp->SetLevelWindow( levelwindow ); node->SetProperty( "levelwindow", levWinProp, renderer ); } if((overwrite) || (node->GetProperty("TransferFunction", renderer)==NULL)) { // add a default transfer function mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(tf); tfInit->SetTransferFunctionMode(0); node->SetProperty ( "TransferFunction", mitk::TransferFunctionProperty::New ( tf.GetPointer() ) ); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } bool mitk::GPUVolumeMapper3D::IsLODEnabled( mitk::BaseRenderer * renderer ) const { bool value = false; return GetDataNode()->GetBoolProperty("volumerendering.uselod",value,renderer) && value; } bool mitk::GPUVolumeMapper3D::IsMIPEnabled( mitk::BaseRenderer * renderer ) { bool value = false; return GetDataNode()->GetBoolProperty("volumerendering.usemip",value,renderer) && value; } bool mitk::GPUVolumeMapper3D::IsGPUEnabled( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool value = false; return ls->m_gpuSupported && GetDataNode()->GetBoolProperty("volumerendering.usegpu",value,renderer) && value; } // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) bool mitk::GPUVolumeMapper3D::InitRAY(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_rayInitialized) return ls->m_raySupported; GPU_INFO << "initializing gpu-raycast-vr (vtkOpenGLGPUVolumeRayCastMapper)"; ls->m_MapperRAY = vtkSmartPointer::New(); ls->m_MapperRAY->SetAutoAdjustSampleDistances(0); ls->m_MapperRAY->SetSampleDistance(1.0); ls->m_VolumePropertyRAY = vtkSmartPointer::New(); ls->m_VolumePropertyRAY->ShadeOn(); ls->m_VolumePropertyRAY->SetAmbient (0.25f); //0.05f ls->m_VolumePropertyRAY->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyRAY->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyRAY->SetSpecularPower(16.0f); ls->m_VolumePropertyRAY->SetInterpolationTypeToLinear(); ls->m_VolumeRAY = vtkSmartPointer::New(); ls->m_VolumeRAY->SetMapper( ls->m_MapperRAY ); ls->m_VolumeRAY->SetProperty( ls->m_VolumePropertyRAY ); ls->m_VolumeRAY->VisibilityOn(); ls->m_MapperRAY->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); ls->m_raySupported = ls->m_MapperRAY->IsRenderSupported(renderer->GetRenderWindow(),ls->m_VolumePropertyRAY); ls->m_rayInitialized = true; return ls->m_raySupported; } void mitk::GPUVolumeMapper3D::DeinitRAY(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_rayInitialized) { GPU_INFO << "deinitializing gpu-raycast-vr"; ls->m_MapperRAY = NULL; ls->m_VolumePropertyRAY = NULL; //Here ReleaseGraphicsResources has to be called to avoid VTK error messages. //This seems like a VTK bug, because ReleaseGraphicsResources() is ment for internal use, //but you cannot just delete the object (last smartpointer reference) without getting the //VTK error. ls->m_VolumeRAY->ReleaseGraphicsResources(renderer->GetVtkRenderer()->GetRenderWindow()); ls->m_VolumeRAY = NULL; ls->m_rayInitialized=false; } } void mitk::GPUVolumeMapper3D::GenerateDataRAY( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if( IsLODEnabled(renderer) && mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) == 0 ) ls->m_MapperRAY->SetImageSampleDistance(4.0); else ls->m_MapperRAY->SetImageSampleDistance(1.0); // Check raycasting mode if(IsMIPEnabled(renderer)) ls->m_MapperRAY->SetBlendModeToMaximumIntensity(); else ls->m_MapperRAY->SetBlendModeToComposite(); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.ray.ambient",value,renderer)) ls->m_VolumePropertyRAY->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.diffuse",value,renderer)) ls->m_VolumePropertyRAY->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.specular",value,renderer)) ls->m_VolumePropertyRAY->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.specular.power",value,renderer)) ls->m_VolumePropertyRAY->SetSpecularPower(value); } } bool mitk::GPUVolumeMapper3D::IsRAYEnabled( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool value = false; return ls->m_raySupported && GetDataNode()->GetBoolProperty("volumerendering.useray",value,renderer) && value; } #endif diff --git a/Modules/MitkExt/files.cmake b/Modules/MitkExt/files.cmake index 1f2936e157..4061c11ef5 100644 --- a/Modules/MitkExt/files.cmake +++ b/Modules/MitkExt/files.cmake @@ -1,150 +1,151 @@ set(CPP_FILES Algorithms/mitkMaskAndCutRoiImageFilter.cpp Algorithms/mitkBoundingObjectToSegmentationFilter.cpp Algorithms/vtkPointSetSlicer.cxx Algorithms/mitkCoreExtObjectFactory.cpp Algorithms/mitkAngleCorrectByPointFilter.cpp Algorithms/mitkAutoCropImageFilter.cpp Algorithms/mitkBoundingObjectCutter.cpp Algorithms/mitkCylindricToCartesianFilter.cpp Algorithms/mitkDopplerToStrainRateFilter.cpp Algorithms/mitkGeometryClipImageFilter.cpp Algorithms/mitkGeometryDataSource.cpp Algorithms/mitkHeightFieldSurfaceClipImageFilter.cpp Algorithms/mitkImageToLookupTableFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkInterpolateLinesFilter.cpp Algorithms/mitkLabeledImageToSurfaceFilter.cpp Algorithms/mitkLabeledImageVolumeCalculator.cpp Algorithms/mitkLookupTableSource.cpp Algorithms/mitkMaskImageFilter.cpp Algorithms/mitkMeshSource.cpp Algorithms/mitkNonBlockingAlgorithm.cpp Algorithms/mitkPadImageFilter.cpp Algorithms/mitkPlaneCutFilter.cpp Algorithms/mitkPlaneFit.cpp Algorithms/mitkPlanesPerpendicularToLinesFilter.cpp Algorithms/mitkPointLocator.cpp Algorithms/mitkPointSetToCurvedGeometryFilter.cpp Algorithms/mitkPointSetToGeometryDataFilter.cpp Algorithms/mitkPointSetIndexToWorldTransformFilter.cpp Algorithms/mitkSurfaceIndexToWorldTransformFilter.cpp Algorithms/mitkPolygonToRingFilter.cpp Algorithms/mitkProbeFilter.cpp Algorithms/mitkSimpleHistogram.cpp Algorithms/mitkSimpleUnstructuredGridHistogram.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkUnstructuredGridHistogram.cpp Algorithms/mitkUnstructuredGridSource.cpp Algorithms/mitkVolumeVisualizationImagePreprocessor.cpp + Controllers/mitkIPythonService.cpp Controllers/mitkMovieGenerator.cpp Controllers/mitkMultiStepper.cpp Controllers/mitkToolManager.cpp DataManagement/mitkAffineTransformationOperation.cpp DataManagement/mitkApplyDiffImageOperation.cpp DataManagement/mitkBoundingObject.cpp DataManagement/mitkBoundingObjectGroup.cpp DataManagement/mitkCellOperation.cpp DataManagement/mitkColorConversions.cpp DataManagement/mitkColorSequence.cpp DataManagement/mitkColorSequenceCycleH.cpp DataManagement/mitkColorSequenceHalfTones.cpp DataManagement/mitkColorSequenceRainbow.cpp DataManagement/mitkCompressedImageContainer.cpp DataManagement/mitkCone.cpp DataManagement/mitkCuboid.cpp DataManagement/mitkCylinder.cpp DataManagement/mitkDataStorageSelection.cpp DataManagement/mitkDelegateManager.cpp DataManagement/mitkDrawOperation.cpp DataManagement/mitkEllipsoid.cpp DataManagement/mitkExternAbstractTransformGeometry.cpp DataManagement/mitkFrameOfReferenceUIDManager.cpp DataManagement/mitkGridRepresentationProperty.cpp DataManagement/mitkGridVolumeMapperProperty.cpp DataManagement/mitkItkBaseDataAdapter.cpp DataManagement/mitkLabeledImageLookupTable.cpp DataManagement/mitkLineOperation.cpp DataManagement/mitkMesh.cpp DataManagement/mitkObjectSet.cpp DataManagement/mitkOrganTypeProperty.cpp DataManagement/mitkPlaneLandmarkProjector.cpp DataManagement/mitkPlane.cpp DataManagement/mitkPropertyManager.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkSeedsImage.cpp DataManagement/mitkSeedsImageLookupTableSource.cpp DataManagement/mitkSphereLandmarkProjector.cpp # DataManagement/mitkUSLookupTableSource.cpp DataManagement/mitkUnstructuredGrid.cpp DataManagement/mitkVideoSource.cpp DataManagement/vtkObjectSet.cpp IO/mitkObjFileIOFactory.cpp IO/mitkObjFileReader.cpp IO/mitkPACSPlugin.cpp IO/mitkParRecFileIOFactory.cpp IO/mitkParRecFileReader.cpp IO/mitkStlVolumeTimeSeriesIOFactory.cpp IO/mitkStlVolumeTimeSeriesReader.cpp IO/mitkUnstructuredGridVtkWriter.cpp IO/mitkUnstructuredGridVtkWriterFactory.cpp IO/mitkVtkUnstructuredGridIOFactory.cpp IO/mitkVtkUnstructuredGridReader.cpp IO/mitkVtkVolumeTimeSeriesIOFactory.cpp IO/mitkVtkVolumeTimeSeriesReader.cpp Interactions/mitkConferenceEventMapper.cpp Interactions/mitkConnectPointsInteractor.cpp #Interactions/mitkCoordinateSupplier.cpp #Interactions/mitkDisplayCoordinateOperation.cpp #Interactions/mitkDisplayInteractor.cpp Interactions/mitkAffineInteractor3D.cpp Interactions/mitkDisplayPointSetInteractor.cpp #Interactions/mitkDisplayVectorInteractor.cpp Interactions/mitkInteractionDebug.cpp Interactions/mitkInteractionDebugger.cpp Interactions/mitkPointInteractor.cpp Interactions/mitkPointSelectorInteractor.cpp #Interactions/mitkPositionTracker.cpp Interactions/mitkSeedsInteractor.cpp Interactions/mitkSocketClient.cpp Interactions/mitkSurfaceDeformationInteractor3D.cpp Interactions/mitkSurfaceInteractor.cpp Interactions/mitkTool.cpp # Interactions/mitkCreateSurfaceTool.cpp Interactions/mitkMorphologicTool.cpp Interactions/mitkErodeTool.cpp Interactions/mitkDilateTool.cpp Interactions/mitkOpeningTool.cpp Interactions/mitkClosingTool.cpp Interactions/mitkPixelManipulationTool.cpp Rendering/mitkEnhancedPointSetVtkMapper3D.cpp Rendering/mitkImageBackground2D.cpp Rendering/mitkLineMapper2D.cpp # Rendering/mitkLineVtkMapper3D.cpp Rendering/mitkMeshMapper2D.cpp Rendering/mitkMeshVtkMapper3D.cpp Rendering/mitkNativeRenderWindowInteractor.cpp Rendering/mitkSplineMapper2D.cpp Rendering/mitkSplineVtkMapper3D.cpp Rendering/mitkUnstructuredGridMapper2D.cpp Rendering/mitkUnstructuredGridVtkMapper3D.cpp Rendering/mitkVectorImageMapper2D.cpp Rendering/vtkUnstructuredGridMapper.cpp Rendering/vtkMaskedGlyph2D.cpp Rendering/vtkMaskedGlyph3D.cpp Rendering/vtkMitkVolumeTextureMapper3D.cpp Rendering/vtkMitkOpenGLVolumeTextureMapper3D.cpp Rendering/mitkGPUVolumeMapper3D.cpp Rendering/vtkMitkGPUVolumeRayCastMapper.cpp ) if(WIN32 AND NOT MINGW) set(CPP_FILES Controllers/mitkMovieGeneratorWin32.cpp ${CPP_FILES} ) endif(WIN32 AND NOT MINGW) diff --git a/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.cpp b/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.cpp index 9f77172bcf..9eb5967c04 100644 --- a/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.cpp +++ b/Modules/PlanarFigure/Rendering/mitkPlanarFigureMapper2D.cpp @@ -1,754 +1,754 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarFigureMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkGL.h" #include "mitkVtkPropRenderer.h" #define _USE_MATH_DEFINES #include // offset which moves the planarfigures on top of the other content // the crosshair is rendered into the z = 1 layer. static const float PLANAR_OFFSET = 0.5f; mitk::PlanarFigureMapper2D::PlanarFigureMapper2D() { this->InitializeDefaultPlanarFigureProperties(); } mitk::PlanarFigureMapper2D::~PlanarFigureMapper2D() { } void mitk::PlanarFigureMapper2D::Paint( mitk::BaseRenderer *renderer ) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; // Get PlanarFigure from input mitk::PlanarFigure *planarFigure = const_cast< mitk::PlanarFigure * >( static_cast< const mitk::PlanarFigure * >( GetDataNode()->GetData() ) ); // Check if PlanarFigure has already been placed; otherwise, do nothing if ( !planarFigure->IsPlaced() ) { return; } // Get 2D geometry frame of PlanarFigure mitk::Geometry2D *planarFigureGeometry2D = dynamic_cast< Geometry2D * >( planarFigure->GetGeometry( 0 ) ); if ( planarFigureGeometry2D == NULL ) { MITK_ERROR << "PlanarFigure does not have valid Geometry2D!"; return; } // Get current world 2D geometry from renderer const mitk::Geometry2D *rendererGeometry2D = renderer->GetCurrentWorldGeometry2D(); // If the PlanarFigure geometry is a plane geometry, check if current // world plane is parallel to and within the planar figure geometry bounds // (otherwise, display nothing) mitk::PlaneGeometry *planarFigurePlaneGeometry = dynamic_cast< PlaneGeometry * >( planarFigureGeometry2D ); const mitk::PlaneGeometry *rendererPlaneGeometry = dynamic_cast< const PlaneGeometry * >( rendererGeometry2D ); if ( (planarFigurePlaneGeometry != NULL) && (rendererPlaneGeometry != NULL) ) { double planeThickness = planarFigurePlaneGeometry->GetExtentInMM( 2 ); if ( !planarFigurePlaneGeometry->IsParallel( rendererPlaneGeometry ) || !(planarFigurePlaneGeometry->DistanceFromPlane( rendererPlaneGeometry ) < planeThickness / 3.0) ) { // Planes are not parallel or renderer plane is not within PlanarFigure // geometry bounds --> exit return; } } else { // Plane is not valid (curved reformations are not possible yet) return; } // Get display geometry mitk::DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry(); assert( displayGeometry != NULL ); // Apply visual appearance properties from the PropertyList ApplyColorAndOpacityProperties( renderer ); // Enable line antialiasing glEnable( GL_LINE_SMOOTH ); glHint( GL_LINE_SMOOTH_HINT, GL_NICEST ); glEnable(GL_DEPTH_TEST); // Get properties from node (if present) const mitk::DataNode* node=this->GetDataNode(); this->InitializePlanarFigurePropertiesFromDataNode( node ); PlanarFigureDisplayMode lineDisplayMode = PF_DEFAULT; if ( m_IsSelected ) { lineDisplayMode = PF_SELECTED; } else if ( m_IsHovering ) { lineDisplayMode = PF_HOVER; } mitk::Point2D firstPoint; firstPoint[0] = 0; firstPoint[1] = 1; if ( m_DrawOutline ) { // Draw the outline for all polylines if requested this->DrawMainLines( planarFigure, m_OutlineColor[lineDisplayMode], m_OutlineOpacity[lineDisplayMode], m_DrawShadow, m_OutlineWidth, m_ShadowWidthFactor, firstPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); // Draw the outline for all helper objects if requested this->DrawHelperLines( planarFigure, m_OutlineColor[lineDisplayMode], m_OutlineOpacity[lineDisplayMode], m_DrawShadow, m_OutlineWidth, m_ShadowWidthFactor, firstPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } // Draw the main line for all polylines this->DrawMainLines( planarFigure, m_LineColor[lineDisplayMode], m_LineOpacity[lineDisplayMode], m_DrawShadow, m_LineWidth, m_ShadowWidthFactor, firstPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); double annotationOffset = 0.0; //Get Global Opacity float globalOpacity = 1.0; node->GetFloatProperty("opacity", globalOpacity); // draw name near the first point (if present) std::string name = node->GetName(); if ( m_DrawName && !name.empty() ) { mitk::VtkPropRenderer* openGLrenderer = dynamic_cast( renderer ); if ( openGLrenderer ) { openGLrenderer->WriteSimpleText( name, firstPoint[0] + 6.0, firstPoint[1] + 4.0, 0, 0, 0, globalOpacity ); //this is a shadow openGLrenderer->WriteSimpleText( name, firstPoint[0] + 5.0, firstPoint[1] + 5.0, m_LineColor[lineDisplayMode][0], m_LineColor[lineDisplayMode][1], m_LineColor[lineDisplayMode][2], globalOpacity ); // If drawing is successful, add approximate height to annotation offset annotationOffset -= 15.0; } } // draw feature quantities (if requested) new the first point if ( m_DrawQuantities ) { std::stringstream quantityString; quantityString.setf( ios::fixed, ios::floatfield ); quantityString.precision( 1 ); bool firstActiveFeature = true; for ( unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i ) { if( planarFigure->IsFeatureActive(i) && planarFigure->IsFeatureVisible( i ) ) { if ( ! firstActiveFeature ) { quantityString << " x "; } quantityString << planarFigure->GetQuantity( i ) << " "; quantityString << planarFigure->GetFeatureUnit( i ); firstActiveFeature = false; } } mitk::VtkPropRenderer* openGLrenderer = dynamic_cast( renderer ); if ( openGLrenderer ) { openGLrenderer->WriteSimpleText( quantityString.str().c_str(), firstPoint[0] + 6.0, firstPoint[1] + 4.0 + annotationOffset, 0, 0, 0, globalOpacity ); //this is a shadow openGLrenderer->WriteSimpleText( quantityString.str().c_str(), firstPoint[0] + 5.0, firstPoint[1] + 5.0 + annotationOffset, m_LineColor[lineDisplayMode][0], m_LineColor[lineDisplayMode][1], m_LineColor[lineDisplayMode][2], globalOpacity ); // If drawing is successful, add approximate height to annotation offset annotationOffset -= 15.0; } } // Draw helper objects this->DrawHelperLines( planarFigure, m_HelperlineColor[lineDisplayMode], m_HelperlineOpacity[lineDisplayMode], m_DrawShadow, m_LineWidth, m_ShadowWidthFactor, firstPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); if ( m_DrawControlPoints ) { // Draw markers at control points (selected control point will be colored) for ( unsigned int i = 0; i < planarFigure->GetNumberOfControlPoints(); ++i ) { bool isEditable = true; m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable ); PlanarFigureDisplayMode pointDisplayMode = PF_DEFAULT; // Only if planar figure is marked as editable: display markers (control points) in a // different style if mouse is over them or they are selected if ( isEditable ) { if ( i == (unsigned int) planarFigure->GetSelectedControlPoint() ) { pointDisplayMode = PF_SELECTED; } else if ( m_IsHovering ) { pointDisplayMode = PF_HOVER; } } if ( m_DrawOutline ) { // draw outlines for markers as well // linewidth for the contour is only half, as full width looks // much too thick! this->DrawMarker( planarFigure->GetControlPoint( i ), m_OutlineColor[lineDisplayMode], m_MarkerlineOpacity[pointDisplayMode], m_OutlineColor[lineDisplayMode], m_MarkerOpacity[pointDisplayMode], m_OutlineWidth/2, m_ControlPointShape, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } this->DrawMarker( planarFigure->GetControlPoint( i ), m_MarkerlineColor[pointDisplayMode], m_MarkerlineOpacity[pointDisplayMode], m_MarkerColor[pointDisplayMode], m_MarkerOpacity[pointDisplayMode], m_LineWidth, m_ControlPointShape, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } if ( planarFigure->IsPreviewControlPointVisible() ) { this->DrawMarker( planarFigure->GetPreviewControlPoint(), m_MarkerlineColor[PF_HOVER], m_MarkerlineOpacity[PF_HOVER], m_MarkerColor[PF_HOVER], m_MarkerOpacity[PF_HOVER], m_LineWidth, m_ControlPointShape, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } } glLineWidth( 1.0f ); } void mitk::PlanarFigureMapper2D::PaintPolyLine( mitk::PlanarFigure::PolyLineType vertices, bool closed, float* color, float opacity, float lineWidth, Point2D& firstPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry) { glColor4f( color[0], color[1], color[2], opacity ); glLineWidth(lineWidth); glBegin( GL_LINE_STRIP ); for ( PlanarFigure::PolyLineType::iterator iter = vertices.begin(); iter!=vertices.end(); iter++ ) { // Draw this 2D point as OpenGL vertex mitk::Point2D displayPoint; this->TransformObjectToDisplay( iter->Point, displayPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); if(iter == vertices.begin()) firstPoint = displayPoint; glVertex3f( displayPoint[0], displayPoint[1], PLANAR_OFFSET ); } - if(closed) + if(closed && (vertices.begin() != vertices.end())) { // complete line loop to the first point again mitk::Point2D displayPoint; this->TransformObjectToDisplay( vertices.begin()->Point, displayPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); glVertex3f( displayPoint[0], displayPoint[1], PLANAR_OFFSET ); } glEnd(); } void mitk::PlanarFigureMapper2D::DrawMainLines( mitk::PlanarFigure* figure, float* color, float opacity, bool drawShadow, float lineWidth, float shadowWidthFactor, Point2D& firstPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry) { for ( unsigned short loop = 0; loop < figure->GetPolyLinesSize(); ++loop ) { PlanarFigure::PolyLineType polyline = figure->GetPolyLine(loop); if ( drawShadow ) { float* shadow = new float[3]; shadow[0] = 0; shadow[1] = 0; shadow[2] = 0; //set shadow opacity float shadowOpacity = 0.0f; if( opacity > 0.2f ) shadowOpacity = opacity - 0.2f; this->PaintPolyLine( polyline, figure->IsClosed(), shadow, shadowOpacity, lineWidth*shadowWidthFactor, firstPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); delete shadow; } this->PaintPolyLine( polyline, figure->IsClosed(), color, opacity, lineWidth, firstPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } } void mitk::PlanarFigureMapper2D::DrawHelperLines( mitk::PlanarFigure* figure, float* color, float opacity, bool drawShadow, float lineWidth, float shadowWidthFactor, Point2D& firstPoint, const Geometry2D* planarFigureGeometry2D, const Geometry2D* rendererGeometry2D, const DisplayGeometry* displayGeometry) { // Draw helper objects for ( unsigned int loop = 0; loop < figure->GetHelperPolyLinesSize(); ++loop ) { const mitk::PlanarFigure::PolyLineType helperPolyLine = figure->GetHelperPolyLine(loop, displayGeometry->GetScaleFactorMMPerDisplayUnit(), displayGeometry->GetDisplayHeight() ); // Check if the current helper objects is to be painted if ( !figure->IsHelperToBePainted( loop ) ) { continue; } // check if shadow shall be painted around the figure if ( drawShadow ) { float* shadow = new float[3]; shadow[0] = 0; shadow[1] = 0; shadow[2] = 0; //set shadow opacity float shadowOpacity = 0.0f; if( opacity > 0.2f ) shadowOpacity = opacity - 0.2f; // paint shadow by painting the figure twice // one in black with a slightly broader line-width ... this->PaintPolyLine( helperPolyLine, false, shadow, shadowOpacity, lineWidth*shadowWidthFactor, firstPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); delete shadow; } // ... and once normally above the shadow. this->PaintPolyLine( helperPolyLine, false, color, opacity, lineWidth, firstPoint, planarFigureGeometry2D, rendererGeometry2D, displayGeometry ); } } void mitk::PlanarFigureMapper2D::TransformObjectToDisplay( const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ) { mitk::Point3D point3D; // Map circle point from local 2D geometry into 3D world space objectGeometry->Map( point2D, point3D ); // Project 3D world point onto display geometry rendererGeometry->Map( point3D, displayPoint ); displayGeometry->WorldToDisplay( displayPoint, displayPoint ); } void mitk::PlanarFigureMapper2D::DrawMarker( const mitk::Point2D &point, float* lineColor, float lineOpacity, float* markerColor, float markerOpacity, float lineWidth, PlanarFigureControlPointStyleProperty::Shape shape, const mitk::Geometry2D *objectGeometry, const mitk::Geometry2D *rendererGeometry, const mitk::DisplayGeometry *displayGeometry ) { mitk::Point2D displayPoint; if ( markerOpacity == 0 && lineOpacity == 0 ) return; this->TransformObjectToDisplay( point, displayPoint, objectGeometry, rendererGeometry, displayGeometry ); glColor4f( markerColor[0], markerColor[1], markerColor[2], markerOpacity ); glLineWidth( lineWidth ); switch ( shape ) { case PlanarFigureControlPointStyleProperty::Square: default: // Paint filled square // Disable line antialiasing (does not look nice for squares) glDisable( GL_LINE_SMOOTH ); glRectf( displayPoint[0] - 4, displayPoint[1] - 4, displayPoint[0] + 4, displayPoint[1] + 4 ); // Paint outline glColor4f( lineColor[0], lineColor[1], lineColor[2], lineOpacity ); glBegin( GL_LINE_LOOP ); glVertex3f( displayPoint[0] - 4, displayPoint[1] - 4, PLANAR_OFFSET ); glVertex3f( displayPoint[0] - 4, displayPoint[1] + 4, PLANAR_OFFSET ); glVertex3f( displayPoint[0] + 4, displayPoint[1] + 4, PLANAR_OFFSET ); glVertex3f( displayPoint[0] + 4, displayPoint[1] - 4, PLANAR_OFFSET ); glEnd(); break; case PlanarFigureControlPointStyleProperty::Circle: // Paint filled circle glBegin( GL_POLYGON ); float radius = 4.0; for ( int angle = 0; angle < 8; ++angle ) { float angleRad = angle * (float) 3.14159 / 4.0; float x = displayPoint[0] + radius * (float)cos( angleRad ); float y = displayPoint[1] + radius * (float)sin( angleRad ); glVertex3f(x, y, PLANAR_OFFSET); } glEnd(); // Paint outline glColor4f( lineColor[0], lineColor[1], lineColor[2], lineOpacity ); glBegin( GL_LINE_LOOP ); for ( int angle = 0; angle < 8; ++angle ) { float angleRad = angle * (float) 3.14159 / 4.0; float x = displayPoint[0] + radius * (float)cos( angleRad ); float y = displayPoint[1] + radius * (float)sin( angleRad ); glVertex3f(x, y, PLANAR_OFFSET); } glEnd(); break; } // end switch } void mitk::PlanarFigureMapper2D::InitializeDefaultPlanarFigureProperties() { m_IsSelected = false; m_IsHovering = false; m_DrawOutline = false; m_DrawQuantities = false; m_DrawShadow = false; m_DrawControlPoints = false; m_DrawName = true; m_ShadowWidthFactor = 1.2; m_LineWidth = 1.0; m_OutlineWidth = 4.0; m_HelperlineWidth = 2.0; m_ControlPointShape = PlanarFigureControlPointStyleProperty::Square; this->SetColorProperty( m_LineColor, PF_DEFAULT, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_LineOpacity, PF_DEFAULT, 1.0 ); this->SetColorProperty( m_OutlineColor, PF_DEFAULT, 0.0, 0.0, 1.0 ); this->SetFloatProperty( m_OutlineOpacity, PF_DEFAULT, 1.0 ); this->SetColorProperty( m_HelperlineColor, PF_DEFAULT, 0.4, 0.8, 0.2 ); this->SetFloatProperty( m_HelperlineOpacity, PF_DEFAULT, 0.4 ); this->SetColorProperty( m_MarkerlineColor, PF_DEFAULT, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_MarkerlineOpacity, PF_DEFAULT, 1.0 ); this->SetColorProperty( m_MarkerColor, PF_DEFAULT, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_MarkerOpacity, PF_DEFAULT, 0.0 ); this->SetColorProperty( m_LineColor, PF_HOVER, 1.0, 0.7, 0.0 ); this->SetFloatProperty( m_LineOpacity, PF_HOVER, 1.0 ); this->SetColorProperty( m_OutlineColor, PF_HOVER, 0.0, 0.0, 1.0 ); this->SetFloatProperty( m_OutlineOpacity, PF_HOVER, 1.0 ); this->SetColorProperty( m_HelperlineColor, PF_HOVER, 0.4, 0.8, 0.2 ); this->SetFloatProperty( m_HelperlineOpacity, PF_HOVER, 0.4 ); this->SetColorProperty( m_MarkerlineColor, PF_HOVER, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_MarkerlineOpacity, PF_HOVER, 1.0 ); this->SetColorProperty( m_MarkerColor, PF_HOVER, 1.0, 0.6, 0.0 ); this->SetFloatProperty( m_MarkerOpacity, PF_HOVER, 0.2 ); this->SetColorProperty( m_LineColor, PF_SELECTED, 1.0, 0.0, 0.0 ); this->SetFloatProperty( m_LineOpacity, PF_SELECTED, 1.0 ); this->SetColorProperty( m_OutlineColor, PF_SELECTED, 0.0, 0.0, 1.0 ); this->SetFloatProperty( m_OutlineOpacity, PF_SELECTED, 1.0 ); this->SetColorProperty( m_HelperlineColor, PF_SELECTED, 0.4, 0.8, 0.2 ); this->SetFloatProperty( m_HelperlineOpacity, PF_SELECTED, 0.4 ); this->SetColorProperty( m_MarkerlineColor, PF_SELECTED, 1.0, 1.0, 1.0 ); this->SetFloatProperty( m_MarkerlineOpacity, PF_SELECTED, 1.0 ); this->SetColorProperty( m_MarkerColor, PF_SELECTED, 1.0, 0.6, 0.0 ); this->SetFloatProperty( m_MarkerOpacity, PF_SELECTED, 1.0 ); } void mitk::PlanarFigureMapper2D::InitializePlanarFigurePropertiesFromDataNode( const mitk::DataNode* node ) { if ( node == NULL ) { return; } //Get Global Opacity float globalOpacity = 1.0; node->GetFloatProperty("opacity", globalOpacity); node->GetBoolProperty( "selected", m_IsSelected ); node->GetBoolProperty( "planarfigure.ishovering", m_IsHovering ); node->GetBoolProperty( "planarfigure.drawoutline", m_DrawOutline ); node->GetBoolProperty( "planarfigure.drawshadow", m_DrawShadow ); node->GetBoolProperty( "planarfigure.drawquantities", m_DrawQuantities ); node->GetBoolProperty( "planarfigure.drawcontrolpoints", m_DrawControlPoints ); node->GetBoolProperty( "planarfigure.drawname", m_DrawName ); node->GetFloatProperty( "planarfigure.line.width", m_LineWidth ); node->GetFloatProperty( "planarfigure.shadow.widthmodifier", m_ShadowWidthFactor ); node->GetFloatProperty( "planarfigure.outline.width", m_OutlineWidth ); node->GetFloatProperty( "planarfigure.helperline.width", m_HelperlineWidth ); PlanarFigureControlPointStyleProperty::Pointer styleProperty = dynamic_cast< PlanarFigureControlPointStyleProperty* >( node->GetProperty( "planarfigure.controlpointshape" ) ); if ( styleProperty.IsNotNull() ) { m_ControlPointShape = styleProperty->GetShape(); } //Set default color and opacity //If property "planarfigure.default.*.color" exists, then use that color. Otherwise global "color" property is used. if( !node->GetColor( m_LineColor[PF_DEFAULT], NULL, "planarfigure.default.line.color")) { node->GetColor( m_LineColor[PF_DEFAULT], NULL, "color" ); } node->GetFloatProperty( "planarfigure.default.line.opacity", m_LineOpacity[PF_DEFAULT] ); if( !node->GetColor( m_OutlineColor[PF_DEFAULT], NULL, "planarfigure.default.outline.color")) { node->GetColor( m_OutlineColor[PF_DEFAULT], NULL, "color" ); } node->GetFloatProperty( "planarfigure.default.outline.opacity", m_OutlineOpacity[PF_DEFAULT] ); if( !node->GetColor( m_HelperlineColor[PF_DEFAULT], NULL, "planarfigure.default.helperline.color")) { node->GetColor( m_HelperlineColor[PF_DEFAULT], NULL, "color" ); } node->GetFloatProperty( "planarfigure.default.helperline.opacity", m_HelperlineOpacity[PF_DEFAULT] ); node->GetColor( m_MarkerlineColor[PF_DEFAULT], NULL, "planarfigure.default.markerline.color" ); node->GetFloatProperty( "planarfigure.default.markerline.opacity", m_MarkerlineOpacity[PF_DEFAULT] ); node->GetColor( m_MarkerColor[PF_DEFAULT], NULL, "planarfigure.default.marker.color" ); node->GetFloatProperty( "planarfigure.default.marker.opacity", m_MarkerOpacity[PF_DEFAULT] ); //Set hover color and opacity node->GetColor( m_LineColor[PF_HOVER], NULL, "planarfigure.hover.line.color" ); node->GetFloatProperty( "planarfigure.hover.line.opacity", m_LineOpacity[PF_HOVER] ); node->GetColor( m_OutlineColor[PF_HOVER], NULL, "planarfigure.hover.outline.color" ); node->GetFloatProperty( "planarfigure.hover.outline.opacity", m_OutlineOpacity[PF_HOVER] ); node->GetColor( m_HelperlineColor[PF_HOVER], NULL, "planarfigure.hover.helperline.color" ); node->GetFloatProperty( "planarfigure.hover.helperline.opacity", m_HelperlineOpacity[PF_HOVER] ); node->GetColor( m_MarkerlineColor[PF_HOVER], NULL, "planarfigure.hover.markerline.color" ); node->GetFloatProperty( "planarfigure.hover.markerline.opacity", m_MarkerlineOpacity[PF_HOVER] ); node->GetColor( m_MarkerColor[PF_HOVER], NULL, "planarfigure.hover.marker.color" ); node->GetFloatProperty( "planarfigure.hover.marker.opacity", m_MarkerOpacity[PF_HOVER] ); //Set selected color and opacity node->GetColor( m_LineColor[PF_SELECTED], NULL, "planarfigure.selected.line.color" ); node->GetFloatProperty( "planarfigure.selected.line.opacity", m_LineOpacity[PF_SELECTED] ); node->GetColor( m_OutlineColor[PF_SELECTED], NULL, "planarfigure.selected.outline.color" ); node->GetFloatProperty( "planarfigure.selected.outline.opacity", m_OutlineOpacity[PF_SELECTED] ); node->GetColor( m_HelperlineColor[PF_SELECTED], NULL, "planarfigure.selected.helperline.color" ); node->GetFloatProperty( "planarfigure.selected.helperline.opacity", m_HelperlineOpacity[PF_SELECTED] ); node->GetColor( m_MarkerlineColor[PF_SELECTED], NULL, "planarfigure.selected.markerline.color" ); node->GetFloatProperty( "planarfigure.selected.markerline.opacity", m_MarkerlineOpacity[PF_SELECTED] ); node->GetColor( m_MarkerColor[PF_SELECTED], NULL, "planarfigure.selected.marker.color" ); node->GetFloatProperty( "planarfigure.selected.marker.opacity", m_MarkerOpacity[PF_SELECTED] ); //adapt opacity values to global "opacity" property for( unsigned int i = 0; i < PF_COUNT; ++i ) { m_LineOpacity[i] *= globalOpacity; m_OutlineOpacity[i] *= globalOpacity; m_HelperlineOpacity[i] *= globalOpacity; m_MarkerlineOpacity[i] *= globalOpacity; m_MarkerOpacity[i] *= globalOpacity; } } void mitk::PlanarFigureMapper2D::SetDefaultProperties( mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite ) { node->AddProperty( "visible", mitk::BoolProperty::New(true), renderer, overwrite ); //node->SetProperty("planarfigure.iseditable",mitk::BoolProperty::New(true)); //node->SetProperty("planarfigure.isextendable",mitk::BoolProperty::New(true)); //node->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawoutline", mitk::BoolProperty::New(true) ); //node->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawcontrolpoints", mitk::BoolProperty::New(true) ); node->AddProperty( "planarfigure.drawname", mitk::BoolProperty::New(true) ); node->AddProperty("planarfigure.line.width", mitk::FloatProperty::New(2.0) ); node->AddProperty("planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0) ); node->AddProperty("planarfigure.outline.width", mitk::FloatProperty::New(2.0) ); node->AddProperty("planarfigure.helperline.width", mitk::FloatProperty::New(2.0) ); node->AddProperty( "planarfigure.default.line.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.default.outline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.default.helperline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); node->AddProperty( "planarfigure.default.markerline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); node->AddProperty( "planarfigure.default.marker.opacity",mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.line.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.outline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.markerline.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.hover.marker.color", mitk::ColorProperty::New(0.0,1.0,0.0) ); node->AddProperty( "planarfigure.hover.marker.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.selected.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.line.opacity",mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.outline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty( "planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.helperline.opacity",mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(1.0) ); node->AddProperty( "planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); node->AddProperty( "planarfigure.selected.marker.opacity",mitk::FloatProperty::New(1.0)); } diff --git a/Modules/Python/CMakeLists.txt b/Modules/Python/CMakeLists.txt new file mode 100644 index 0000000000..1076f2bde9 --- /dev/null +++ b/Modules/Python/CMakeLists.txt @@ -0,0 +1,13 @@ +if( MITK_USE_Python ) + + MITK_CREATE_MODULE(mitkPython + DEPENDS MitkExt + EXPORT_DEFINE MITK_PYTHON_EXPORT + PACKAGE_DEPENDS QT CTK PythonLibs + QT_MODULE + ) + configure_file(PythonPath.h.in + "${CMAKE_CURRENT_BINARY_DIR}/PythonPath.h" @ONLY) + + add_subdirectory(Testing) +endif() \ No newline at end of file diff --git a/Modules/Python/PythonPath.h.in b/Modules/Python/PythonPath.h.in new file mode 100644 index 0000000000..384811cc81 --- /dev/null +++ b/Modules/Python/PythonPath.h.in @@ -0,0 +1,19 @@ +#ifdef _DEBUG +#define PYTHON_PATH_BUILD_TYPE "/Debug" +#else +#define PYTHON_PATH_BUILD_TYPE "/Release" +#endif + +#define PYTHONPATH_COMMAND "import sys\n"\ +"sys.path.append('@ITK_LIBRARY_DIRS@')\n"\ +"sys.path.append('@ITK_DIR@/Wrapping/WrapITK/Python')\n"\ +"sys.path.append('@ITK_LIBRARY_DIRS@" PYTHON_PATH_BUILD_TYPE "')\n"\ +"sys.path.append('@ITK_DIR@/Wrapping/WrapITK/Python" PYTHON_PATH_BUILD_TYPE "')\n"\ +"sys.path.append('@VTK_LIBRARY_DIRS@')\n"\ +"sys.path.append('@VTK_DIR@/Wrapping/Python')\n"\ +"sys.path.append('@VTK_DIR@/bin" PYTHON_PATH_BUILD_TYPE "')\n"\ +"sys.path.append('@VTK_DIR@/Wrapping/Python')\n"\ +"sys.path.append('@OpenCV_DIR@/lib" PYTHON_PATH_BUILD_TYPE "')\n"\ +"sys.path.append('@OpenCV_DIR@/lib')\n"\ +"sys.path.append('@OpenCV_DIR@/bin')\n"\ +"sys.path.append('@OpenCV_DIR@/bin" PYTHON_PATH_BUILD_TYPE "')" diff --git a/Modules/Python/QmitkCtkPythonShell.cpp b/Modules/Python/QmitkCtkPythonShell.cpp new file mode 100644 index 0000000000..c87c39f85d --- /dev/null +++ b/Modules/Python/QmitkCtkPythonShell.cpp @@ -0,0 +1,91 @@ +/*=================================================================== + +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 "QmitkCtkPythonShell.h" + +#include +#include +#include +#include +#include +#include "mitkPythonService.h" +#include +#include +#include + +struct QmitkCtkPythonShellData +{ + mitk::PythonService* m_PythonService; + mitk::ServiceReference m_PythonServiceRef; +}; + +QmitkCtkPythonShell::QmitkCtkPythonShell(QWidget* parent) + : ctkPythonConsole(parent), d( new QmitkCtkPythonShellData ) +{ + MITK_DEBUG("QmitkCtkPythonShell") << "retrieving IPythonService"; + mitk::ModuleContext* context = mitk::GetModuleContext(); + d->m_PythonServiceRef = context->GetServiceReference(); + d->m_PythonService = dynamic_cast ( context->GetService(d->m_PythonServiceRef) ); + + MITK_DEBUG("QmitkCtkPythonShell") << "checking IPythonService"; + Q_ASSERT( d->m_PythonService ); + + MITK_DEBUG("QmitkCtkPythonShell") << "initialize m_PythonService"; + this->initialize( d->m_PythonService->GetPythonManager() ); + + MITK_DEBUG("QmitkCtkPythonShell") << "m_PythonService initialized"; +} + +QmitkCtkPythonShell::~QmitkCtkPythonShell() +{ + mitk::ModuleContext* context = mitk::GetModuleContext(); + context->UngetService( d->m_PythonServiceRef ); + delete d; +} + +void QmitkCtkPythonShell::dragEnterEvent(QDragEnterEvent *event) +{ + event->accept(); +} +void QmitkCtkPythonShell::dropEvent(QDropEvent *event) +{ + QList urls = event->mimeData()->urls(); + for(int i = 0; i < urls.size(); i++) + { + d->m_PythonService->Execute( urls[i].toString().toStdString(), mitk::IPythonService::SINGLE_LINE_COMMAND ); + } +} + +bool QmitkCtkPythonShell::canInsertFromMimeData( const QMimeData *source ) const +{ + return true; +} + +void QmitkCtkPythonShell::executeCommand(const QString& command) +{ + MITK_DEBUG("QmitkCtkPythonShell") << "executing command " << command.toStdString(); + ctkPythonConsole::executeCommand(command); + d->m_PythonService->NotifyObserver(command.toStdString()); +} + +void QmitkCtkPythonShell::Paste(const QString &command) +{ + if( this->isVisible() ) + { + this->exec( command ); + //this->executeCommand( command ); + } +} diff --git a/Modules/Python/QmitkCtkPythonShell.h b/Modules/Python/QmitkCtkPythonShell.h new file mode 100644 index 0000000000..1e50cf4d2d --- /dev/null +++ b/Modules/Python/QmitkCtkPythonShell.h @@ -0,0 +1,60 @@ +/*=================================================================== + +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 QmitkCtkPythonShell_h +#define QmitkCtkPythonShell_h + +#include +#include +#include "mitkPythonExports.h" + +/// +/// forward declarations +/// +struct QmitkCtkPythonShellData; +class ctkAbstractPythonManager; +class QDragEnterEvent; +class QDropEvent; +class QMimeData; + +/// +/// Reimplements the ctkPythonConsole with drag and drop functionality for text +/// Furthermore it calls NotifyObserver() on the IPythonService to inform listeners +/// +class MITK_PYTHON_EXPORT QmitkCtkPythonShell : public ctkPythonConsole +{ + Q_OBJECT + +public: + QmitkCtkPythonShell(QWidget* parent = 0); + ~QmitkCtkPythonShell(); +public slots: + void Paste( const QString& command ); +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + bool canInsertFromMimeData( const QMimeData *source ) const; + void executeCommand(const QString& command); + +private: + QmitkCtkPythonShellData* d; +}; + + + + +#endif // QmitkCtkPythonShell_h + diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditorHighlighter.cpp b/Modules/Python/QmitkPythonScriptEditorHighlighter.cpp similarity index 100% rename from Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditorHighlighter.cpp rename to Modules/Python/QmitkPythonScriptEditorHighlighter.cpp diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditorHighlighter.h b/Modules/Python/QmitkPythonScriptEditorHighlighter.h similarity index 63% rename from Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditorHighlighter.h rename to Modules/Python/QmitkPythonScriptEditorHighlighter.h index c97d0da45f..cf97e58248 100644 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditorHighlighter.h +++ b/Modules/Python/QmitkPythonScriptEditorHighlighter.h @@ -1,44 +1,40 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKPYTHONSCRIPTEDITORHIGHLIGHTER_H_ -#define QMITKPYTHONSCRIPTEDITORHIGHLIGHTER_H_ +#ifndef QmitkPythonScriptEditorHighlighter_h +#define QmitkPythonScriptEditorHighlighter_h -#include #include +#include "mitkPythonExports.h" -class QmitkPythonScriptEditorHighlighter : public QSyntaxHighlighter +/// +/// A script highlighter for Python Scripts +class MITK_PYTHON_EXPORT QmitkPythonScriptEditorHighlighter : public QSyntaxHighlighter { - // 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: QmitkPythonScriptEditorHighlighter(QTextDocument *parent); virtual ~QmitkPythonScriptEditorHighlighter(); -signals: - -protected slots: - protected: - virtual void highlightBlock(const QString &text); + void highlightBlock(const QString &text); void highlightComments(const QString &text); private: }; -#endif +#endif // QmitkPythonScriptEditorHighlighter_h diff --git a/Modules/Python/QmitkPythonSnippets.cpp b/Modules/Python/QmitkPythonSnippets.cpp new file mode 100644 index 0000000000..975944557c --- /dev/null +++ b/Modules/Python/QmitkPythonSnippets.cpp @@ -0,0 +1,483 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkPythonSnippets.h" +#include "QmitkPythonScriptEditorHighlighter.h" +#include +#include +#include + +struct QmitkPythonSnippetsData +{ + QString m_AutoSaveFileName; + QString m_SaveFileName; + + QAction* m_PasteSnippet; + QAction* m_RemoveSnippet; + QAction* m_RenameSnippet; + QAction* m_AddSnippet; + QAction* m_RestoreDefaultSnippets; + QAction* m_LoadSnippets; + QAction* m_SaveSnippets; + + QToolBar* m_Toolbar; + + QComboBox* m_Name; + + QTextEdit* m_Content; + + QGridLayout* m_Layout; + + QmitkPythonSnippets::QStringMap m_Snippets; +}; + +const QString QmitkPythonSnippets::DEFAULT_SNIPPET_FILE( ":/mitkPython/PythonSnippets.xml" ); +const QString QmitkPythonSnippets::SNIPPETS_ROOT_XML_ELEMENT_NAME( "PythonSnippets" ); +const QString QmitkPythonSnippets::SNIPPETS_XML_ELEMENT_NAME( "PythonSnippet" ); + +QmitkPythonSnippets::QmitkPythonSnippets( const QString& _AutoSaveFileName, QWidget* parent ) +: QWidget(parent), d(new QmitkPythonSnippetsData) +{ + d->m_SaveFileName = QDir::currentPath(); + d->m_AutoSaveFileName = _AutoSaveFileName; + + if( !this->LoadStringMap( d->m_AutoSaveFileName, d->m_Snippets ) ) + { + this->LoadStringMap( DEFAULT_SNIPPET_FILE, d->m_Snippets ); + } + + d->m_PasteSnippet = new QAction(this); + d->m_PasteSnippet->setObjectName(QString::fromUtf8("PasteSnippet")); + QIcon icon; + icon.addFile(QString::fromUtf8(":/mitkPython/edit-paste.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_PasteSnippet->setIcon(icon); + d->m_PasteSnippet->setToolTip("Paste snippet!"); + d->m_PasteSnippet->setEnabled(false); + + d->m_RemoveSnippet = new QAction(this); + d->m_RemoveSnippet->setObjectName(QString::fromUtf8("RemoveSnippet")); + QIcon icon1; + icon1.addFile(QString::fromUtf8(":/mitkPython/edit-delete.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_RemoveSnippet->setIcon(icon1); + d->m_RemoveSnippet->setToolTip("Remove snippet."); + d->m_RemoveSnippet->setEnabled(false); + + d->m_RenameSnippet = new QAction(this); + d->m_RenameSnippet->setObjectName(QString::fromUtf8("RenameSnippet")); + QIcon icon2; + icon2.addFile(QString::fromUtf8(":/mitkPython/edit-find-replace.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_RenameSnippet->setIcon(icon2); + d->m_RenameSnippet->setToolTip("Rename snippet."); + d->m_RenameSnippet->setEnabled(false); + + d->m_AddSnippet = new QAction(this); + d->m_AddSnippet->setObjectName(QString::fromUtf8("AddSnippet")); + QIcon icon3; + icon3.addFile(QString::fromUtf8(":/mitkPython/document-new.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_AddSnippet->setIcon(icon3); + d->m_AddSnippet->setToolTip("Add snippet."); + + d->m_RestoreDefaultSnippets = new QAction(this); + d->m_RestoreDefaultSnippets->setObjectName(QString::fromUtf8("RestoreDefaultSnippets")); + QIcon icon4; + icon4.addFile(QString::fromUtf8(":/mitkPython/edit-clear.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_RestoreDefaultSnippets->setIcon(icon4); + d->m_RestoreDefaultSnippets->setToolTip("Restore default snippets"); + + d->m_LoadSnippets = new QAction(this); + d->m_LoadSnippets->setToolTip("Load Snippets from disk."); + d->m_LoadSnippets->setObjectName(QString::fromUtf8("LoadSnippets")); + QIcon icon5; + icon5.addFile(QString::fromUtf8(":/mitkPython/document-open.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_LoadSnippets->setIcon(icon5); + + d->m_SaveSnippets = new QAction(this); + d->m_SaveSnippets->setToolTip("Save Snippets to disk."); + d->m_SaveSnippets->setObjectName(QString::fromUtf8("SaveSnippets")); + QIcon icon6; + icon6.addFile(QString::fromUtf8(":/mitkPython/document-save.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_SaveSnippets->setIcon(icon6); + d->m_SaveSnippets->setEnabled(false); + + d->m_Toolbar = new QToolBar; + d->m_Toolbar->addAction( d->m_PasteSnippet ); + d->m_Toolbar->addAction( d->m_AddSnippet ); + d->m_Toolbar->addAction( d->m_RemoveSnippet ); + d->m_Toolbar->addAction( d->m_RenameSnippet ); + d->m_Toolbar->addAction( d->m_RestoreDefaultSnippets ); + d->m_Toolbar->addAction( d->m_SaveSnippets ); + d->m_Toolbar->addAction( d->m_LoadSnippets ); + + d->m_Name = new QComboBox; + d->m_Name->setObjectName(QString::fromUtf8("Name")); + + d->m_Content = new QTextEdit(this); + d->m_Content->setObjectName(QString::fromUtf8("Content")); + d->m_Content->setEnabled(false); + + QmitkPythonScriptEditorHighlighter* highlighter = + new QmitkPythonScriptEditorHighlighter( d->m_Content->document() ); + + d->m_Layout = new QGridLayout; + d->m_Layout->addWidget( d->m_Toolbar, 0, 0, 1, 1 ); + d->m_Layout->addWidget( d->m_Name, 1, 0, 1, 1 ); + d->m_Layout->addWidget( d->m_Content, 2, 0, 1, 1 ); + d->m_Layout->setContentsMargins(2,2,2,2); + + this->setLayout(d->m_Layout); + QMetaObject::connectSlotsByName(this); + + this->Update(); +} + +QmitkPythonSnippets::~QmitkPythonSnippets() +{ + delete d; +} + +void QmitkPythonSnippets::on_PasteSnippet_triggered( bool ) +{ + emit PasteCommandRequested( d->m_Content->toPlainText() ); +} + +void QmitkPythonSnippets::on_RenameSnippet_triggered(bool) +{ + QString oldname = d->m_Name->currentText(); + QString name = oldname; + bool ok = false; + while( true ) + { + name = QInputDialog::getText(this, + tr("Add new snippet"), + tr("Name of snippet:"), + QLineEdit::Normal, + name, + &ok); + + if (ok) + { + if ( d->m_Snippets.contains(name) ) + { + QMessageBox::warning(this, + tr("Duplicate name."), + tr("The entered name already exists. Enter another one or cancel the operation."), + QMessageBox::Ok, + QMessageBox::Ok ); + } + else + { + QString tmpSnippet = d->m_Snippets[oldname]; + d->m_Snippets.remove(oldname); + d->m_Snippets[name] = tmpSnippet; + this->Update(name); + this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); + break; + } + } + else + { + break; + } + } +} + +void QmitkPythonSnippets::on_AddSnippet_triggered(bool) +{ + bool ok; + QString name = QInputDialog::getText(this, + tr("Add new snippet"), + tr("Name of snippet:"), + QLineEdit::Normal, + "newSnippet", + &ok); + if (ok && !name.isEmpty()) + { + MITK_DEBUG("QmitkPythonSnippets") << "creating unique name for " << name.toStdString(); + name = this->CreateUniqueName(name); + + MITK_DEBUG("QmitkPythonSnippets") << "creating snippet " << name.toStdString(); + d->m_Snippets[name] = ""; + this->Update(name); + this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); + } +} + +QString QmitkPythonSnippets::CreateUniqueName( const QString& name ) const +{ + QString newName = name; + size_t i = 2; + while( d->m_Snippets.contains(name) ) + { + newName = name + QString("_%1").arg(i); + ++i; + } + + return newName; +} + +void QmitkPythonSnippets::on_RemoveSnippet_triggered(bool) +{ + QString name = d->m_Name->currentText(); + QString question = QString("Really remove Snippet %1?").arg(name); + int remove = QMessageBox::question( this, + QString("Confirm removal"), + question, + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No ); + + if( remove == QMessageBox::Yes || remove == QMessageBox::Ok ) + { + d->m_Snippets.remove(name); + this->Update(); + this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); + } +} + +void QmitkPythonSnippets::on_RestoreDefaultSnippets_triggered(bool) +{ + QString question = QString("Really restore default Snippets?"); + int remove = QMessageBox::question( this, + QString("Confirm restoring"), + question, + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No ); + if( remove == QMessageBox::Yes || remove == QMessageBox::Ok ) + { + this->LoadStringMap( DEFAULT_SNIPPET_FILE, d->m_Snippets ); + this->Update(); + this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); + } +} + +void QmitkPythonSnippets::on_Name_currentIndexChanged(int i) +{ + bool validSelection = i >= 0 ; + + d->m_PasteSnippet->setEnabled(validSelection); + d->m_RemoveSnippet->setEnabled(validSelection); + d->m_RenameSnippet->setEnabled(validSelection); + d->m_Content->setEnabled(validSelection); + d->m_SaveSnippets->setEnabled(validSelection); + + if( validSelection ) + { + QString name = d->m_Name->currentText(); + MITK_DEBUG("QmitkPythonSnippets") << "selected snippet " << name.toStdString(); + d->m_Content->setText( d->m_Snippets[name] ); + MITK_DEBUG("QmitkPythonSnippets") << "selected snippet content " << d->m_Snippets[name].toStdString(); + } +} + +void QmitkPythonSnippets::SaveStringMap(const QString &filename, const QmitkPythonSnippets::QStringMap &map) const +{ + MITK_DEBUG("QmitkPythonSnippets") << "saving to xml file " << filename.toStdString(); + + if( filename.isEmpty() ) + { + MITK_WARN("QmitkPythonSnippets") << "empty auto save file path given. quit."; + return; + } + + QFile file(filename); + file.open(QIODevice::WriteOnly); + if( !file.isOpen() ) + { + MITK_WARN("QmitkPythonSnippets") << "could not open file " << filename.toStdString() << " for writing"; + return; + } + QXmlStreamWriter xmlWriter(&file); + + xmlWriter.setAutoFormatting(true); + xmlWriter.writeStartDocument(); + xmlWriter.writeStartElement(SNIPPETS_ROOT_XML_ELEMENT_NAME); + + QStringMap::const_iterator it = d->m_Snippets.begin(); + while( it != d->m_Snippets.end() ) + { + + { + MITK_DEBUG("QmitkPythonSnippets") << "SNIPPETS_XML_ELEMENT_NAME " << SNIPPETS_XML_ELEMENT_NAME.toStdString(); + MITK_DEBUG("QmitkPythonSnippets") << "writing item " << it.key().toStdString(); + } + + xmlWriter.writeStartElement(SNIPPETS_XML_ELEMENT_NAME); + + xmlWriter.writeAttribute( "key", it.key() ); + xmlWriter.writeAttribute( "value", it.value() ); + + xmlWriter.writeEndElement(); + + ++it; + } + + xmlWriter.writeEndDocument(); + if( file.isOpen() ) + file.close(); + + { + MITK_DEBUG("QmitkPythonSnippets") << "SaveStringMap successful "; + } + +} + +bool QmitkPythonSnippets::LoadStringMap( const QString& filename, QmitkPythonSnippets::QStringMap& oldMap ) const +{ + MITK_DEBUG("QmitkPythonSnippets") << "loading from xml file " << filename.toStdString(); + QStringMap map; + + QXmlStreamReader xmlReader; + QFile file; + QByteArray data; + // resource file + if( filename.startsWith(":") ) + { + QResource res( filename ); + data = QByteArray( reinterpret_cast< const char* >( res.data() ), res.size() ); + xmlReader.addData( data ); + } + else + { + file.setFileName( filename ); + if (!file.open(QFile::ReadOnly | QFile::Text)) + { + MITK_ERROR << "Error: Cannot read file " << qPrintable(filename) + << ": " << qPrintable(file.errorString()); + return false; + } + xmlReader.setDevice(&file); + } + + xmlReader.readNext(); + + while(!xmlReader.atEnd()) + { + xmlReader.readNext(); + + if(xmlReader.name() == SNIPPETS_XML_ELEMENT_NAME) + { + QXmlStreamAttributes attributes = xmlReader.attributes(); + QString key; + QString value; + if(attributes.hasAttribute("key")) + { + key = attributes.value("key").toString(); + } + + if(attributes.hasAttribute("value")) + { + value = attributes.value("value").toString(); + } + + if( !key.isEmpty() ) + { + MITK_DEBUG("QmitkPythonSnippets") << "loaded snippet " << key.toStdString(); + MITK_DEBUG("QmitkPythonSnippets") << "value " << value.toStdString(); + map[key] = value; + } + } + } + + if (xmlReader.hasError()) + { + MITK_ERROR << "Error: Failed to parse file " + << qPrintable(filename) << ": " + << qPrintable(xmlReader.errorString()); + return false; + } + else if (file.error() != QFile::NoError) + { + MITK_ERROR << "Error: Cannot read file " << qPrintable(filename) + << ": " << qPrintable(file.errorString()); + return false; + } + + if( file.isOpen() ) + file.close(); + + oldMap = map; + return true; +} + +void QmitkPythonSnippets::Update(const QString &name) +{ + d->m_Name->clear(); + d->m_Content->clear(); + + MITK_DEBUG("QmitkPythonSnippets") << "size of snippets " << d->m_Snippets.size(); + QStringMap::const_iterator it = d->m_Snippets.begin(); + + while( it != d->m_Snippets.end() ) + { + MITK_DEBUG("QmitkPythonSnippets") << "adding item " << it.key().toStdString(); + d->m_Name->addItem( it.key() ); + ++it; + } + + int index = d->m_Name->findText( name ); + if( index >= 0 ) + { + MITK_DEBUG("QmitkPythonSnippets") << "selecting index " << index; + d->m_Name->setCurrentIndex(index); + } + +} + +void QmitkPythonSnippets::on_Content_textChanged() +{ + if( d->m_Content->isEnabled() ) + { + QString name = d->m_Name->currentText(); + QString snippet = d->m_Content->toPlainText(); + d->m_Snippets[name] = snippet; + + this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); + MITK_DEBUG("QmitkPythonSnippets") << "SaveStringMap successful"; + } +} + +void QmitkPythonSnippets::on_SaveSnippets_triggered(bool) +{ + QString fileName = QFileDialog::getSaveFileName(this, "Save snippets", d->m_SaveFileName, "XML files (*.xml)"); + if( !fileName.isEmpty() ) + { + d->m_SaveFileName = fileName; + this->SaveStringMap( d->m_SaveFileName, d->m_Snippets ); + } +} + +void QmitkPythonSnippets::on_LoadSnippets_triggered(bool) +{ + QString fileName = QFileDialog::getOpenFileName(this, "Load snippets", d->m_SaveFileName, "XML files (*.xml)"); + + if( !fileName.isEmpty() ) + { + d->m_SaveFileName = fileName; + QString question = QString("Your current snippets will be overwritten. Proceed?"); + int overwrite = QMessageBox::warning(this, + QString("Confirm overwrite"), + question, + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No ); + + if( overwrite == QMessageBox::Yes ) + { + this->LoadStringMap( d->m_SaveFileName, d->m_Snippets ); + this->Update( d->m_Name->currentText() ); + this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); + } + } + +} diff --git a/Modules/Python/QmitkPythonSnippets.h b/Modules/Python/QmitkPythonSnippets.h new file mode 100644 index 0000000000..6a0b2b97a2 --- /dev/null +++ b/Modules/Python/QmitkPythonSnippets.h @@ -0,0 +1,104 @@ +/*=================================================================== + +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 _QmitkPythonSnippets_H +#define _QmitkPythonSnippets_H + +#include +#include +#include "mitkPythonExports.h" +struct QmitkPythonSnippetsData; + +/// +/// a widget that holds snippets and serializes the snippets to a certain places +class MITK_PYTHON_EXPORT QmitkPythonSnippets: public QWidget +{ + Q_OBJECT + + public: + static const QString DEFAULT_SNIPPET_FILE; + static const QString SNIPPETS_ROOT_XML_ELEMENT_NAME; + static const QString SNIPPETS_XML_ELEMENT_NAME; + /// + /// typedef for string map + typedef QMap QStringMap; + /// + /// build ui here + /// the snippets will be loaded from _AutoSaveFileName if not empty and readable + /// otherwise the default snippets will be loaded + QmitkPythonSnippets( const QString& _AutoSaveFileName="", QWidget* parent=0 ); + /// + /// delete d pointer + virtual ~QmitkPythonSnippets(); +signals: + /// + /// this class whishes to paste sth command + void PasteCommandRequested(const QString& command); + + protected slots: + /// + /// emits PasteCommandRequested signal + void on_PasteSnippet_triggered( bool checked = false ); + /// + /// ask for name as long as it exists, call update() + void on_RenameSnippet_triggered( bool checked = false ); + /// + /// ask for name, create snippet, call update() + void on_AddSnippet_triggered( bool checked = false ); + /// + /// remove the current snippet, call update() + void on_RemoveSnippet_triggered( bool checked = false ); + /// + /// call LoadStringMap with d->m_DefaultSnippetsAutoSaveFileName + void on_RestoreDefaultSnippets_triggered( bool checked = false ); + /// + /// update action state (enable/disable), update text box + void on_Name_currentIndexChanged( int i ); + /// + /// save changed snippet + void on_Content_textChanged(); + /// + /// ask for file, save snippets + void on_SaveSnippets_triggered( bool checked = false ); + /// + /// ask for file, load snippets (do not replace) + void on_LoadSnippets_triggered( bool checked = false ); + + protected: + /// + /// write string map to xml file + void SaveStringMap( const QString& filename, const QStringMap& map ) const; + /// + /// read string map from xml file + bool LoadStringMap( const QString& filename, QStringMap& oldMap ) const; + /// + /// creates a name which does not exist in the list + QString CreateUniqueName(const QString &name) const; + /// + /// update combo box + /// if name is passed, the according element will be selected + void Update(const QString &name = ""); + private: + /// + /// d pointer declaration (holds members) + QmitkPythonSnippetsData* d; +}; + + + + +#endif // _QmitkPythonSnippets_H_INCLUDED + diff --git a/Modules/Python/QmitkPythonSnippets.ui b/Modules/Python/QmitkPythonSnippets.ui new file mode 100644 index 0000000000..f7bc574d07 --- /dev/null +++ b/Modules/Python/QmitkPythonSnippets.ui @@ -0,0 +1,116 @@ + + + QmitkPythonSnippets + + + + 0 + 0 + 613 + 436 + + + + + 0 + 0 + + + + true + + + QmitkTemplate + + + + + + Name: + + + + + + + true + + + + + + + Content: + + + + + + + + + + + :/mitkPython/edit-paste.png:/mitkPython/edit-paste.png + + + Paste snippet! + + + Push button to paste the snippet into the console or the editor. Or double click on the snippet text window. + + + + + + :/mitkPython/edit-delete.png:/mitkPython/edit-delete.png + + + Remove snippet + + + Remove the selected snippet. + + + + + + :/mitkPython/edit-find-replace.png:/mitkPython/edit-find-replace.png + + + Rename snippet + + + Rename the selected snippet. + + + + + + :/mitkPython/document-new.png:/mitkPython/document-new.png + + + Add snippet + + + Add a new snippet to the list. + + + + + + :/mitkPython/edit-clear.png:/mitkPython/edit-clear.png + + + Restore default snippets + + + Clear and restore the default snippets. + + + + + + + + diff --git a/Modules/Python/QmitkPythonTextEditor.cpp b/Modules/Python/QmitkPythonTextEditor.cpp new file mode 100644 index 0000000000..bc4689a39c --- /dev/null +++ b/Modules/Python/QmitkPythonTextEditor.cpp @@ -0,0 +1,184 @@ +/*=================================================================== + +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 "QmitkPythonTextEditor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QmitkPythonScriptEditorHighlighter.h" + +struct QmitkPythonTextEditorData +{ + QString m_FilePath; + + QAction* m_LoadScript; + QAction* m_SaveScript; + QAction* m_RunScript; + QToolBar* m_Toolbar; + + QTextEdit* m_Content; + + QGridLayout* m_Layout; + mitk::IPythonService* m_PythonService; + mitk::ServiceReference m_PythonServiceRef; + + QString m_FileName; +}; + +QmitkPythonTextEditor::QmitkPythonTextEditor(QWidget *parent) + :QWidget(parent), d(new QmitkPythonTextEditorData) +{ + mitk::ModuleContext* context = mitk::GetModuleContext(); + d->m_PythonServiceRef = context->GetServiceReference(); + d->m_PythonService = context->GetService( d->m_PythonServiceRef ); + + d->m_LoadScript = new QAction(this); + d->m_LoadScript->setToolTip("Load script from disk."); + d->m_LoadScript->setObjectName(QString::fromUtf8("LoadScript")); + QIcon icon2; + icon2.addFile(QString::fromUtf8(":/mitkPython/document-open.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_LoadScript->setIcon(icon2); + + d->m_SaveScript = new QAction(this); + d->m_SaveScript->setToolTip("Save script to disk."); + d->m_SaveScript->setObjectName(QString::fromUtf8("SaveScript")); + QIcon icon3; + icon3.addFile(QString::fromUtf8(":/mitkPython/document-save.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_SaveScript->setIcon(icon3); + + d->m_RunScript = new QAction(this); + d->m_RunScript->setToolTip("Run the current script."); + d->m_RunScript->setObjectName(QString::fromUtf8("RunScript")); + QIcon icon4; + icon4.addFile(QString::fromUtf8(":/mitkPython/media-playback-start.png"), QSize(), QIcon::Normal, QIcon::Off); + d->m_RunScript->setIcon(icon4); + + d->m_Toolbar = new QToolBar; + d->m_Toolbar->addAction( d->m_LoadScript ); + d->m_Toolbar->addAction( d->m_SaveScript ); + d->m_Toolbar->addAction( d->m_RunScript ); + + d->m_Content = new QTextEdit(this); + d->m_Content->setObjectName(QString::fromUtf8("Content")); + + QmitkPythonScriptEditorHighlighter* highlighter = + new QmitkPythonScriptEditorHighlighter( d->m_Content->document() ); + + d->m_Layout = new QGridLayout; + d->m_Layout->addWidget( d->m_Toolbar, 0, 0, 1, 1 ); + d->m_Layout->addWidget( d->m_Content, 1, 0, 1, 1 ); + d->m_Layout->setContentsMargins(2,2,2,2); + + this->setLayout(d->m_Layout); + QMetaObject::connectSlotsByName(this); +} + +QmitkPythonTextEditor::~QmitkPythonTextEditor() +{ + mitk::ModuleContext* context = mitk::GetModuleContext(); + context->UngetService( d->m_PythonServiceRef ); + + delete d; +} + +void QmitkPythonTextEditor::dragEnterEvent(QDragEnterEvent *event) +{ + event->accept(); +} + +void QmitkPythonTextEditor::dropEvent(QDropEvent *event) +{ + QList urls = event->mimeData()->urls(); + for(int i = 0; i < urls.size(); i++) + { + this->Paste( urls[i].toString() ); + } +} +/* +bool QmitkPythonTextEditor::canInsertFromMimeData( const QMimeData * ) const +{ + return true; +} +*/ + +void QmitkPythonTextEditor::Paste(const QString &command) +{ + if( this->isVisible() ) + { + d->m_Content->insertPlainText(command + "\n"); + } +} + + +QString QmitkPythonTextEditor::ReadFile(const QString& filename) +{ + QFile file(filename); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + MITK_ERROR << "Could not open file " << filename; + return NULL; + } + + QByteArray total; + QByteArray line; + while (!file.atEnd()) + { + line = file.read(1024); + total.append(line); + } + + return QString(total); +} + +void QmitkPythonTextEditor::on_SaveScript_triggered( bool ) +{ + d->m_FileName = QFileDialog::getSaveFileName(this,tr("Save File"), d->m_FileName,tr("*.py")); + if( d->m_FileName.compare("") != 0) + { + ofstream myfile; + myfile.open(d->m_FileName.toLocal8Bit().data()); + myfile << d->m_Content->toPlainText().toLocal8Bit().data(); + myfile.close(); + } +} + +void QmitkPythonTextEditor::on_LoadScript_triggered( bool ) +{ + d->m_FileName = QFileDialog::getOpenFileName( this, "Load Script", d->m_FileName, tr("*.py")); + if( !d->m_FileName.isEmpty() ) + { + QString contents = this->ReadFile( d->m_FileName ); + d->m_Content->setText(contents); + } +} + +void QmitkPythonTextEditor::on_RunScript_triggered( bool ) +{ + if( !d->m_PythonService ) + { + MITK_ERROR << "Python service not available."; + return; + } + + d->m_PythonService->Execute( d->m_Content->toPlainText().toStdString(), mitk::IPythonService::MULTI_LINE_COMMAND ); +} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonTextEditor.h b/Modules/Python/QmitkPythonTextEditor.h old mode 100755 new mode 100644 similarity index 55% rename from Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonTextEditor.h rename to Modules/Python/QmitkPythonTextEditor.h index a129dea467..0e407ee866 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonTextEditor.h +++ b/Modules/Python/QmitkPythonTextEditor.h @@ -1,50 +1,53 @@ /*=================================================================== 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 QMITKPYTHONTEXTEDITOR_H_ #define QMITKPYTHONTEXTEDITOR_H_ #include #include #include -#include "QmitkPythonMediator.h" +#include "mitkPythonExports.h" +struct QmitkPythonTextEditorData; -class QmitkPythonTextEditor : public QTextEdit, public QmitkPythonPasteClient +/// +/// this is a python text editor with syntax highlightning +class MITK_PYTHON_EXPORT QmitkPythonTextEditor : public QWidget { - // 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: QmitkPythonTextEditor(QWidget *parent = 0); virtual ~QmitkPythonTextEditor(); - - virtual void paste(const QString& command); -signals: +public slots: + void Paste(const QString& command); protected slots: + void on_SaveScript_triggered(bool checked=false); + void on_LoadScript_triggered(bool checked=false); + void on_RunScript_triggered(bool checked=false); protected: - virtual void dragEnterEvent(QDragEnterEvent *event); - virtual void dropEvent(QDropEvent *event); - - virtual bool canInsertFromMimeData( const QMimeData *source ) const; - //virtual void QmitkPythonTextEditor::insertFromMimeData( const QMimeData *source ); + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + //bool canInsertFromMimeData( const QMimeData *source ) const; + QString ReadFile(const QString &filename); private: + QmitkPythonTextEditorData* d; }; #endif diff --git a/Modules/Python/QmitkPythonVariableStackTableModel.cpp b/Modules/Python/QmitkPythonVariableStackTableModel.cpp new file mode 100755 index 0000000000..2ad27d2fd5 --- /dev/null +++ b/Modules/Python/QmitkPythonVariableStackTableModel.cpp @@ -0,0 +1,223 @@ +/*=================================================================== + +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 "QmitkPythonVariableStackTableModel.h" +#include +#include +#include +#include +#include +#include + +const QString QmitkPythonVariableStackTableModel::MITK_IMAGE_VAR_NAME = "mitkImage"; +const QString QmitkPythonVariableStackTableModel::MITK_SURFACE_VAR_NAME = "mitkSurface"; + +QmitkPythonVariableStackTableModel::QmitkPythonVariableStackTableModel(QObject *parent) + :QAbstractTableModel(parent) +{ + mitk::ModuleContext* context = mitk::GetModuleContext(); + m_PythonServiceRef = context->GetServiceReference(); + m_PythonService = context->GetService(m_PythonServiceRef); + m_PythonService->AddPythonCommandObserver( this ); +} + +QmitkPythonVariableStackTableModel::~QmitkPythonVariableStackTableModel() +{ + mitk::ModuleContext* context = mitk::GetModuleContext(); + context->UngetService( m_PythonServiceRef ); + m_PythonService->RemovePythonCommandObserver( this ); +} + +bool QmitkPythonVariableStackTableModel::dropMimeData ( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent ) +{ + // Early exit, returning true, but not actually doing anything (ignoring data). + if (action == Qt::IgnoreAction) + return true; + + // Note, we are returning true if we handled it, and false otherwise + bool returnValue = false; + + if(data->hasFormat("application/x-mitk-datanodes")) + { + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "dropped MITK DataNode"; + returnValue = true; + + QString arg = QString(data->data("application/x-mitk-datanodes").data()); + QStringList listOfDataNodeAddressPointers = arg.split(","); + + QStringList::iterator slIter; + int i = 0; + int j = 0; + for (slIter = listOfDataNodeAddressPointers.begin(); + slIter != listOfDataNodeAddressPointers.end(); + slIter++) + { + long val = (*slIter).toLong(); + mitk::DataNode* node = static_cast((void*)val); + mitk::Image* mitkImage = dynamic_cast(node->GetData()); + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "mitkImage is not null " << (mitkImage != 0? "true": "false"); + + if( mitkImage ) + { + QString varName = MITK_IMAGE_VAR_NAME; + if( i > 0 ) + varName = QString("%1%2").arg(MITK_IMAGE_VAR_NAME).arg(i); + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "varName" << varName.toStdString(); + + bool exportAsCvImage = m_PythonService->IsOpenCvPythonWrappingAvailable(); + + if( mitkImage->GetDimension() == 2 && exportAsCvImage ) + { + int ret = QMessageBox::question(NULL, "Export option", + "2D image detected. Export as OpenCV image to Python instead of an ITK image?", + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + exportAsCvImage = ret == QMessageBox::Yes; + if(exportAsCvImage) + { + m_PythonService->CopyToPythonAsCvImage( mitkImage, MITK_IMAGE_VAR_NAME.toStdString() ); + ++i; + } + } + if( !exportAsCvImage ) + { + if( m_PythonService->IsItkPythonWrappingAvailable() ) + { + m_PythonService->CopyToPythonAsItkImage( mitkImage, MITK_IMAGE_VAR_NAME.toStdString() ); + ++i; + } + else + { + MITK_ERROR << "ITK Python wrapping not available. Skipping export for image " << node->GetName(); + } + } + } + else + { + mitk::Surface* surface = dynamic_cast(node->GetData()); + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "found surface"; + + if( surface ) + { + QString varName = MITK_SURFACE_VAR_NAME; + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "varName" << varName.toStdString(); + + if( j > 0 ) + varName = QString("%1%2").arg(MITK_SURFACE_VAR_NAME).arg(j); + MITK_DEBUG("varName") << "varName" << varName.toStdString(); + + if( m_PythonService->IsVtkPythonWrappingAvailable() ) + { + m_PythonService->CopyToPythonAsVtkPolyData( surface, MITK_SURFACE_VAR_NAME.toStdString() ); + ++j; + } + else + { + MITK_ERROR << "VTK Python wrapping not available. Skipping export for surface " << node->GetName(); + } + } + } + } + } + return returnValue; +} + +QVariant QmitkPythonVariableStackTableModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + QVariant headerData; + + // show only horizontal header + if ( role == Qt::DisplayRole ) + { + if( orientation == Qt::Horizontal ) + { + // first column: "Attribute" + if(section == 0) + headerData = "Attribute"; + else if(section == 1) + headerData = "Type"; + else if(section == 2) + headerData = "Value"; + } + } + + return headerData; +} + +Qt::ItemFlags QmitkPythonVariableStackTableModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + + if(index.isValid()) + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | flags; + else + return Qt::ItemIsDropEnabled | flags; +} + +int QmitkPythonVariableStackTableModel::rowCount(const QModelIndex &) const +{ + return m_VariableStack.size(); +} + +int QmitkPythonVariableStackTableModel::columnCount(const QModelIndex &) const +{ + return 3; +} + +QVariant QmitkPythonVariableStackTableModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && !m_VariableStack.empty()) + { + if(role == Qt::DisplayRole) + { + mitk::PythonVariable item = m_VariableStack.at(index.row()); + if(index.column() == 0) + return QString::fromStdString(item.m_Name); + if(index.column() == 1) + return QString::fromStdString(item.m_Type); + if(index.column() == 2) + return QString::fromStdString(item.m_Value); + } + } + return QVariant(); +} + +QStringList QmitkPythonVariableStackTableModel::mimeTypes() const +{ + return QAbstractTableModel::mimeTypes(); + QStringList types; + types << "application/x-mitk-datanodes"; + types << "application/x-qabstractitemmodeldatalist"; + return types; +} + +Qt::DropActions QmitkPythonVariableStackTableModel::supportedDropActions() const +{ + return Qt::CopyAction | Qt::MoveAction; +} + +void QmitkPythonVariableStackTableModel::CommandExecuted(const std::string& pythonCommand) +{ + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "command was executed " << pythonCommand; + m_VariableStack = m_PythonService->GetVariableStack(); + QAbstractTableModel::reset(); +} + +std::vector QmitkPythonVariableStackTableModel::GetVariableStack() const +{ + return m_VariableStack; +} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStackTreeWidget.h b/Modules/Python/QmitkPythonVariableStackTableModel.h similarity index 51% rename from Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStackTreeWidget.h rename to Modules/Python/QmitkPythonVariableStackTableModel.h index e32114723d..ce45819723 100755 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStackTreeWidget.h +++ b/Modules/Python/QmitkPythonVariableStackTableModel.h @@ -1,68 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKPYTHONVARIABLESTACKTREEWIDGET_H_ -#define QMITKPYTHONVARIABLESTACKTREEWIDGET_H_ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "QmitkPythonMediator.h" - -class QmitkPythonVariableStackTreeWidget : public QAbstractTableModel, public QmitkPythonClient +#ifndef QmitkPythonVariableStackTableModel_h +#define QmitkPythonVariableStackTableModel_h + +#include +#include +#include +#include "mitkIPythonService.h" +#include "mitkPythonExports.h" +#include + +/// +/// implements a table model to show the variables of the Python "__main__" dictionary +/// furthermore implements dragging and dropping of datanodes (conversion from and to python) +/// +class MITK_PYTHON_EXPORT QmitkPythonVariableStackTableModel : public QAbstractTableModel, public mitk::PythonCommandObserver { - // 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: - QmitkPythonVariableStackTreeWidget(QWidget *parent = 0); - virtual ~QmitkPythonVariableStackTreeWidget(); + static const QString MITK_IMAGE_VAR_NAME; + static const QString MITK_SURFACE_VAR_NAME; + + QmitkPythonVariableStackTableModel(QObject *parent = 0); + virtual ~QmitkPythonVariableStackTableModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; Qt::ItemFlags flags( const QModelIndex& index ) const; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QStringList mimeTypes() const; - void clear(); - void setVariableStack(std::vector); - std::vector getVariableStack(); - - QMimeData * mimeData(const QModelIndexList &) const; + QStringList mimeTypes() const; bool dropMimeData ( const QMimeData *, Qt::DropAction, int, int, const QModelIndex & ); Qt::DropActions supportedDropActions() const; Qt::DropActions supportedDragActions() const; - virtual void update(); + void CommandExecuted(const std::string& pythonCommand); -protected: - std::vector m_variableStack; + std::vector GetVariableStack() const; +private: + std::vector m_VariableStack; + mitk::IPythonService* m_PythonService; + mitk::ServiceReference m_PythonServiceRef; }; -#endif +#endif // QmitkPythonVariableStackTableModel_h diff --git a/Modules/Python/QmitkPythonVariableStackTableView.cpp b/Modules/Python/QmitkPythonVariableStackTableView.cpp new file mode 100755 index 0000000000..a062feb62d --- /dev/null +++ b/Modules/Python/QmitkPythonVariableStackTableView.cpp @@ -0,0 +1,107 @@ +/*=================================================================== + +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 "QmitkPythonVariableStackTableView.h" +#include +#include +#include +#include +#include + +QmitkPythonVariableStackTableView::QmitkPythonVariableStackTableView(QWidget *parent) + :QTableView(parent) +{ + m_TableModel = new QmitkPythonVariableStackTableModel(parent); + m_TableModel->CommandExecuted(""); + + this->setSelectionBehavior( QAbstractItemView::SelectRows ); + this->setAlternatingRowColors(true); + this->setDropIndicatorShown(true); + this->setAcceptDrops(true); + this->setModel( m_TableModel ); + + mitk::ModuleContext* context = mitk::GetModuleContext(); + mitk::ServiceReference serviceRef = context->GetServiceReference(); + m_PythonService = context->GetService(serviceRef); + + connect( this, SIGNAL(doubleClicked ( const QModelIndex& )), this, SLOT( OnVariableStackDoubleClicked(const QModelIndex&) ) ); +} + +QmitkPythonVariableStackTableView::~QmitkPythonVariableStackTableView() +{ +} + +void QmitkPythonVariableStackTableView::SetDataStorage(mitk::DataStorage *_DataStorage) +{ + m_DataStorage = _DataStorage; +} + +void QmitkPythonVariableStackTableView::OnVariableStackDoubleClicked(const QModelIndex &index) +{ + if( m_DataStorage.IsNull() || m_PythonService == 0 ) + { + MITK_ERROR << "QmitkPythonVariableStackTableView not configured correctly. Quit"; + return; + } + + int row = index.row(); + std::vector variableStack = m_TableModel->GetVariableStack(); + { + MITK_DEBUG("QmitkPythonVariableStackTableView") << "row " << row; + MITK_DEBUG("QmitkPythonVariableStackTableView") << "variableStack.size(): " << variableStack.size(); + } + + QString varName = QString::fromStdString( variableStack.at(row).m_Name ); + QString type = QString::fromStdString( variableStack.at(row).m_Type ); + QString value = QString::fromStdString( variableStack.at(row).m_Value ); + + { + MITK_DEBUG("QmitkPythonVariableStackTableView") << "varName: " << varName.toStdString(); + MITK_DEBUG("QmitkPythonVariableStackTableView") << "type: " << type.toStdString(); + } + + mitk::Image::Pointer mitkImage; + mitk::Surface::Pointer mitkSurface; + + if( type.startsWith("itkImage") ) + { + mitkImage = m_PythonService->CopyItkImageFromPython(varName.toStdString()); + } + else if( type.startsWith("numpy.ndarray") ) + { + mitkImage = m_PythonService->CopyCvImageFromPython(varName.toStdString()); + } + else if( value.startsWith("(vtkPolyData)") ) + { + mitkSurface = m_PythonService->CopyVtkPolyDataFromPython(varName.toStdString()); + } + + std::string nodeName = varName.toStdString(); + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetName ( nodeName ); + + if( mitkImage.IsNotNull() ) + { + node->SetData( mitkImage ); + } + else if( mitkSurface.IsNotNull() ) + { + node->SetData( mitkSurface ); + } + + m_DataStorage->Add(node); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} diff --git a/Modules/Python/QmitkPythonVariableStackTableView.h b/Modules/Python/QmitkPythonVariableStackTableView.h new file mode 100755 index 0000000000..d486512a44 --- /dev/null +++ b/Modules/Python/QmitkPythonVariableStackTableView.h @@ -0,0 +1,50 @@ +/*=================================================================== + +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 QmitkPythonVariableStackTableView_h +#define QmitkPythonVariableStackTableView_h + +#include +#include +#include "QmitkPythonVariableStackTableModel.h" +#include +#include "mitkPythonExports.h" + +/// +/// implements the table view for the variable stack +/// purpose of this class: 1. Setup the view correctly, 2. Implement the double click to write back results +/// to the datastorage +/// +class MITK_PYTHON_EXPORT QmitkPythonVariableStackTableView : public QTableView +{ + Q_OBJECT + +public: + QmitkPythonVariableStackTableView(QWidget *parent = 0); + virtual ~QmitkPythonVariableStackTableView(); + + void SetDataStorage(mitk::DataStorage* _DataStorage); + +protected slots: + void OnVariableStackDoubleClicked(const QModelIndex &index); + +private: + QmitkPythonVariableStackTableModel* m_TableModel; + mitk::DataStorage::Pointer m_DataStorage; + mitk::IPythonService* m_PythonService; +}; + +#endif // QmitkPythonVariableStackTableView_h diff --git a/Modules/Python/Testing/CMakeLists.txt b/Modules/Python/Testing/CMakeLists.txt new file mode 100644 index 0000000000..2d5e45bb88 --- /dev/null +++ b/Modules/Python/Testing/CMakeLists.txt @@ -0,0 +1,2 @@ +MITK_CREATE_MODULE_TESTS() + diff --git a/Modules/Python/Testing/files.cmake b/Modules/Python/Testing/files.cmake new file mode 100644 index 0000000000..d4301946da --- /dev/null +++ b/Modules/Python/Testing/files.cmake @@ -0,0 +1,3 @@ +set(MODULE_TESTS + mitkPythonTest.cpp +) diff --git a/Modules/Python/Testing/mitkPythonTest.cpp b/Modules/Python/Testing/mitkPythonTest.cpp new file mode 100644 index 0000000000..9be9f6f6b6 --- /dev/null +++ b/Modules/Python/Testing/mitkPythonTest.cpp @@ -0,0 +1,33 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#include +#include +#include +#include +#include +#include + +int mitkPythonTest(int /*argc*/, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("PythonTest") + + itk::SmartPointer _PythonService(new mitk::PythonService()); + + std::string result = _PythonService->Execute( "5+5", mitk::IPythonService::EVAL_COMMAND ); + MITK_TEST_CONDITION( result == "10", "Testing if running python code 5+5 results in 10" ) + + MITK_TEST_END() +} diff --git a/Modules/Python/documentation/mitkPython.dox b/Modules/Python/documentation/mitkPython.dox new file mode 100644 index 0000000000..899290048f --- /dev/null +++ b/Modules/Python/documentation/mitkPython.dox @@ -0,0 +1,17 @@ +/** + +\page mitkPython_Overview The MITK Python Module + +

Brief description

+The MITK Python Module provides a service class for interactively run python code (passed as C++ strings) and evaluate the results. Furthermore the service class offers means to convert an MITK Image to an ITK/OpenCV image in their wrapped python environment. Thus, one can process MITK images with Python Code from the OpenCV and ITK wrapping system. Furthermore one can convert an mitk::Surface to a vtkPolyData in its Python environment.
+Under the hood, the MITK build system takes care that the wrapping build process for ITK/VTK/OpenCV is correctly initiated and all paths are correctly set within MITK code. + +

Build Instructions

+- Install Python 2.x +- Activate MITK_USE_Python in the superbuild process of MITK +- Provide CMake with the correct Python paths (if not found automatically) +- Build MITK: All wrapping will be setup by the MITK superbuild routine + +

Known problems and workarounds

+ + */ diff --git a/Modules/Python/documentation/slides.tex b/Modules/Python/documentation/slides.tex new file mode 100644 index 0000000000..5be2291ea0 --- /dev/null +++ b/Modules/Python/documentation/slides.tex @@ -0,0 +1,44 @@ +\documentclass{beamer} +\usepackage[utf8]{inputenc} +\usepackage{listings} +\usetheme{Warsaw} +\title[The MITK Python Module]{The MITK Python Module\\A short introduction} +\author{Michael Müller} +\institute{mitk.org} +\date{\today} +\begin{document} + +\begin{frame} +\titlepage +\end{frame} + +\begin{frame}{Problem} +Playing around with ITK/VTK/OpenCV functions in C++ is +\center{\textbf{time consuming}} +\\(setup project, write code, compile, adapt parameters, recompile, execute, do it again, do it again, Visual Studio crashes, do it again...) +\end{frame} + +\begin{frame}{Aims} +\begin{itemize} +\item Use Python as an interpreted language to interactively use and test ITK/VTK/OpenCV functions \pause +\item Provide a one click super-build integration \pause +\item Provide a service class to programatically execute and evaluate Python code \pause +\item Create a GUI to interactively work with Python within the MITK workbench +\end{itemize} +\end{frame} + +\begin{frame}{The Python Module} +\textbf{Central class: IPythonService}\\ +Most important functions:\\ + +\end{frame} + +\begin{frame}{The Python View} +write motivation here +\end{frame} + +\begin{frame}{Installation} +write motivation here +\end{frame} + +\end{document} diff --git a/Modules/Python/files.cmake b/Modules/Python/files.cmake new file mode 100644 index 0000000000..6750579650 --- /dev/null +++ b/Modules/Python/files.cmake @@ -0,0 +1,27 @@ +SET(CPP_FILES + mitkPythonActivator.cpp + mitkPythonService.cpp + QmitkCtkPythonShell.cpp + QmitkPythonVariableStackTableModel.cpp + QmitkPythonVariableStackTableView.cpp + QmitkPythonScriptEditorHighlighter.cpp + QmitkPythonTextEditor.cpp + QmitkPythonSnippets.cpp +) + +#SET(UI_FILES +# QmitkPythonSnippets.ui +#) + +SET(MOC_H_FILES + QmitkCtkPythonShell.h + QmitkPythonVariableStackTableModel.h + QmitkPythonVariableStackTableView.h + QmitkPythonScriptEditorHighlighter.h + QmitkPythonTextEditor.h + QmitkPythonSnippets.h +) + +set(QRC_FILES + resources/mitkPython.qrc +) diff --git a/Modules/Python/mitkPythonActivator.cpp b/Modules/Python/mitkPythonActivator.cpp new file mode 100644 index 0000000000..d6d1e65939 --- /dev/null +++ b/Modules/Python/mitkPythonActivator.cpp @@ -0,0 +1,67 @@ +/*=================================================================== + +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 mitkPythonActivator_h +#define mitkPythonActivator_h + +// Microservices +#include +#include "mitkModuleContext.h" +#include "mitkPythonService.h" +#include + +namespace mitk +{ + /// + /// installs the PythonService + /// runs all initial commands (setting env paths etc) + /// + class PythonActivator : public mitk::ModuleActivator + { + public: + + void Load(mitk::ModuleContext* context) + { + MITK_DEBUG << "PythonActivator::Load"; + // Registering PythonService as MicroService + m_PythonService = itk::SmartPointer(new PythonService()); + + ServiceProperties _PythonServiceProps; + _PythonServiceProps["Name"] = std::string("PythonService"); + + m_PythonServiceRegistration = context->RegisterService(m_PythonService, _PythonServiceProps); + } + + void Unload(mitk::ModuleContext* context) + { + MITK_DEBUG("PythonActivator") << "PythonActivator::Unload"; + MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); + m_PythonServiceRegistration.Unregister(); + m_PythonService->Delete(); + MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); + } + + virtual ~PythonActivator() + { + } + + private: + itk::SmartPointer m_PythonService; + ServiceRegistration m_PythonServiceRegistration; + }; +} + +US_EXPORT_MODULE_ACTIVATOR(mitkPython, mitk::PythonActivator) +#endif diff --git a/Modules/Python/mitkPythonService.cpp b/Modules/Python/mitkPythonService.cpp new file mode 100644 index 0000000000..4068f2f094 --- /dev/null +++ b/Modules/Python/mitkPythonService.cpp @@ -0,0 +1,532 @@ +/*=================================================================== + +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 "mitkPythonService.h" +#include +#include +#include +#include +#include +#include "PythonPath.h" + +const QString mitk::PythonService::m_TmpDataFileName("temp_mitk_data_file"); + +mitk::PythonService::PythonService() + : m_ItkWrappingAvailable( true ), m_OpenCVWrappingAvailable( true ), m_VtkWrappingAvailable( true ), m_ErrorOccured( false ) +{ + { + MITK_DEBUG << "will init python if necessary"; + } + bool pythonInitialized = static_cast( Py_IsInitialized() ); //m_PythonManager.isPythonInitialized() ); + { + MITK_DEBUG << "pythonInitialized " << pythonInitialized; + MITK_DEBUG << "m_PythonManager.isPythonInitialized() " << m_PythonManager.isPythonInitialized(); + } + + // due to strange static var behaviour on windows Py_IsInitialized() returns correct value while + // m_PythonManager.isPythonInitialized() does not because it has been constructed and destructed again + if( !m_PythonManager.isPythonInitialized() ) + { + try + { + if( pythonInitialized ) + m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut|PythonQt::PythonAlreadyInitialized); + else + m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut); + + MITK_DEBUG("PythonService") << "initalizing python"; + m_PythonManager.initialize(); + + MITK_DEBUG("PythonService") << "python initalized"; + + QString pythonCommand(PYTHONPATH_COMMAND); + MITK_DEBUG("PythonService") << "registering python paths" << PYTHONPATH_COMMAND; + m_PythonManager.executeString( pythonCommand, ctkAbstractPythonManager::FileInput ); + + /* + //system("export LD_LIBRARY_PATH=/local/muellerm/mitk/bugsquashing/bin-debug/VTK-build/bin:$LD_LIBRARY_PATH"); + //m_PythonManager.executeString( "print sys.path", ctkAbstractPythonManager::SingleInput ); + //MITK_DEBUG("mitk::PythonService") << "result of 'sys.path': " << result.toString().toStdString(); + + //m_PythonManager.executeString( "sys.path.append('/usr/share/pyshared/numpy')", ctkAbstractPythonManager::SingleInput ); + //m_PythonManager.executeString( "import numpy", ctkAbstractPythonManager::SingleInput ); + + MITK_DEBUG("mitk::PythonService") << "Trying to import ITK"; + m_PythonManager.executeString( "import itk", ctkAbstractPythonManager::SingleInput ); + m_ItkWrappingAvailable = !m_PythonManager.pythonErrorOccured(); + MITK_DEBUG("mitk::PythonService") << "m_ItkWrappingAvailable: " << (m_ItkWrappingAvailable? "yes": "no"); + if( !m_ItkWrappingAvailable ) + { + MITK_WARN << "ITK Python wrapping not available. Please check build settings or PYTHONPATH settings."; + } + + { + MITK_DEBUG("mitk::PythonService") << "Trying to import OpenCv"; + PyRun_SimpleString("import cv2\n"); + if (PyErr_Occurred()) + { + PyErr_Print(); + } + else + m_OpenCVWrappingAvailable = true; + + //m_PythonManager.executeString( "import cv2", ctkAbstractPythonManager::SingleInput ); + MITK_DEBUG("mitk::PythonService") << "Investigate if an error occured while importing cv2"; + //m_OpenCVWrappingAvailable = !m_PythonManager.pythonErrorOccured(); + MITK_DEBUG("mitk::PythonService") << "m_OpenCVWrappingAvailable: " << (m_OpenCVWrappingAvailable? "yes": "no"); + if( !m_OpenCVWrappingAvailable ) + { + MITK_WARN << "OpenCV Python wrapping not available. Please check build settings or PYTHONPATH settings."; + } + } + + MITK_DEBUG("mitk::PythonService") << "Trying to import VTK"; + m_PythonManager.executeString( "import vtk", ctkAbstractPythonManager::SingleInput ); + m_VtkWrappingAvailable = !m_PythonManager.pythonErrorOccured(); + MITK_DEBUG("mitk::PythonService") << "m_VtkWrappingAvailable: " << (m_VtkWrappingAvailable? "yes": "no"); + if( !m_VtkWrappingAvailable ) + { + MITK_WARN << "VTK Python wrapping not available. Please check build settings or PYTHONPATH settings."; + } + */ + } + catch (...) + { + MITK_DEBUG("PythonService") << "exception initalizing python"; + } + + } + + //m_PythonManager.executeString( "for path in sys.path:\n print path\n", ctkAbstractPythonManager::SingleInput ); + //m_PythonManager.executeString( "for k, v in os.environ.items():\n print \"%s=%s\" % (k, v)", ctkAbstractPythonManager::SingleInput ); + //m_PythonManager.executeFile("/local/muellerm/Dropbox/13-02-11-python-wrapping/interpreterInfo.py"); + //std::string result = m_PythonManager.executeString( "5+5", ctkAbstractPythonManager::EvalInput ); + //MITK_DEBUG("mitk::PythonService") << "result of '5+5': " << result.toString().toStdString(); +} + +mitk::PythonService::~PythonService() +{ + //QVariant result = m_PythonManager.executeString( "sys.getrefcount(cv2)", ctkAbstractPythonManager::EvalInput ); + //MITK_DEBUG("mitk::PythonService") << "sys.getrefcount(cv2): " << result.toString().toStdString(); + + //m_PythonManager.executeString( "del sys.modules[\"cv2\"]", ctkAbstractPythonManager::SingleInput ); + //m_PythonManager.executeString( "del cv2", ctkAbstractPythonManager::SingleInput ); + MITK_DEBUG("mitk::PythonService") << "destructing PythonService"; +} + +std::string mitk::PythonService::Execute(const std::string &stdpythonCommand, int commandType) +{ + QString pythonCommand = QString::fromStdString(stdpythonCommand); + + { + MITK_DEBUG("mitk::PythonService") << "pythonCommand = " << pythonCommand.toStdString(); + MITK_DEBUG("mitk::PythonService") << "commandType = " << commandType; + } + + QVariant result; + bool commandIssued = true; + + if(commandType == IPythonService::SINGLE_LINE_COMMAND ) + result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::SingleInput ); + else if(commandType == IPythonService::MULTI_LINE_COMMAND ) + result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::FileInput ); + else if(commandType == IPythonService::EVAL_COMMAND ) + result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::EvalInput ); + else + commandIssued = false; + + if(commandIssued) + { + this->NotifyObserver(pythonCommand.toStdString()); + m_ErrorOccured = PythonQt::self()->handleError(); + } + + return result.toString().toStdString(); +} + +void mitk::PythonService::ExecuteScript( const std::string& pythonScript ) +{ + m_PythonManager.executeFile(QString::fromStdString(pythonScript)); +} + +std::vector mitk::PythonService::GetVariableStack() const +{ + std::vector list; + + PyObject* dict = PyImport_GetModuleDict(); + PyObject* object = PyDict_GetItemString(dict, "__main__"); + PyObject* dirMain = PyObject_Dir(object); + PyObject* tempObject = 0; + PyObject* strTempObject = 0; + + if(dirMain) + { + std::string name, attrValue, attrType; + + for(int i = 0; iob_type->tp_name; + + strTempObject = PyObject_Repr(tempObject); + if(strTempObject && ( PyUnicode_Check(strTempObject) || PyString_Check(strTempObject) ) ) + attrValue = PyString_AsString(strTempObject); + else + attrValue = ""; + + mitk::PythonVariable var; + var.m_Name = name; + var.m_Value = attrValue; + var.m_Type = attrType; + list.push_back(var); + } + } + + return list; +} + +bool mitk::PythonService::DoesVariableExist(const std::string& name) const +{ + bool varExists = false; + + std::vector allVars = this->GetVariableStack(); + for(int i = 0; i< allVars.size(); i++) + { + if( allVars.at(i).m_Name == name ) + { + varExists = true; + break; + } + } + + return varExists; +} + +void mitk::PythonService::AddPythonCommandObserver(mitk::PythonCommandObserver *observer) +{ + if(!m_Observer.contains(observer)) + m_Observer.append(observer); +} + +void mitk::PythonService::RemovePythonCommandObserver(mitk::PythonCommandObserver *observer) +{ + m_Observer.removeOne(observer); +} + +void mitk::PythonService::NotifyObserver(const std::string &command) +{ + MITK_DEBUG("mitk::PythonService") << "number of observer " << m_Observer.size(); + for( size_t i=0; i< m_Observer.size(); ++i ) + { + m_Observer.at(i)->CommandExecuted(command); + } +} + +QString mitk::PythonService::GetTempDataFileName(const std::string& ext) const +{ + QString tmpFolder = QDir::tempPath(); + QString fileName = tmpFolder + QDir::separator() + m_TmpDataFileName + QString::fromStdString(ext); + return fileName; +} + +bool mitk::PythonService::CopyToPythonAsItkImage(mitk::Image *image, const std::string &stdvarName) +{ + QString varName = QString::fromStdString( stdvarName ); + // save image + QString fileName = this->GetTempDataFileName( mitk::IOUtil::DEFAULTIMAGEEXTENSION ); + fileName = QDir::fromNativeSeparators( fileName ); + + MITK_DEBUG("PythonService") << "Saving temporary file " << fileName.toStdString(); + if( !mitk::IOUtil::SaveImage(image, fileName.toStdString()) ) + { + MITK_ERROR << "Temporary file could not be created."; + } + else + { + // TODO CORRECT TYPE SETUP, MAKE MITK_DEBUG("PythonService") MITK_DEBUG("PythonService") + int dim = image->GetDimension(); + mitk::PixelType pixelType = image->GetPixelType(); + itk::ImageIOBase::IOPixelType ioPixelType = image->GetPixelType().GetPixelTypeId(); + + // default pixeltype: unsigned short + QString type = "US"; + if( ioPixelType == itk::ImageIOBase::SCALAR ) + { + if( pixelType.GetTypeId() == typeid(double) ) + type = "D"; + else if( pixelType.GetTypeId() == typeid(float) ) + type = "F"; + if( pixelType.GetTypeId() == typeid(long double) ) + type = "LD"; + else if( pixelType.GetTypeId() == typeid(short) ) + type = "SS"; + else if( pixelType.GetTypeId() == typeid(signed char) ) + type = "SC"; + else if( pixelType.GetTypeId() == typeid(signed int) ) + type = "SI"; + else if( pixelType.GetTypeId() == typeid(signed long) ) + type = "SL"; + else if( pixelType.GetTypeId() == typeid(signed short) ) + type = "SS"; + else if( pixelType.GetTypeId() == typeid(unsigned char) ) + type = "UC"; + else if( pixelType.GetTypeId() == typeid(unsigned int) ) + type = "UI"; + else if( pixelType.GetTypeId() == typeid(unsigned long) ) + type = "UL"; + else if( pixelType.GetTypeId() == typeid(unsigned short) ) + type = "US"; + } + + MITK_DEBUG("PythonService") << "Got mitk image with type " << type.toStdString() << " and dim " << dim; + + QString command; + + command.append( QString("imageType = itk.Image[itk.%1, %2]\n") .arg( type ).arg( dim ) ); + + command.append( QString("readerType = itk.ImageFileReader[imageType]\n") ); + command.append( QString("reader = readerType.New()\n") ); + command.append( QString("reader.SetFileName( \"%1\" )\n") .arg(fileName) ); + command.append( QString("reader.Update()\n") ); + command.append( QString("%1 = reader.GetOutput()\n").arg( varName ) ); + + MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + this->Execute( command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); + + QFile file( fileName ); + MITK_DEBUG("PythonService") << "Removing file " << fileName.toStdString(); + file.remove(); + return true; + } + + return false; +} + +mitk::Image::Pointer mitk::PythonService::CopyItkImageFromPython(const std::string &stdvarName) +{ + QString varName = QString::fromStdString( stdvarName ); + mitk::Image::Pointer mitkImage; + QString command; + QString fileName = GetTempDataFileName( mitk::IOUtil::DEFAULTIMAGEEXTENSION ); + fileName = QDir::fromNativeSeparators( fileName ); + + MITK_DEBUG("PythonService") << "Saving temporary file with python itk code " << fileName.toStdString(); + + command.append( QString( "writer = itk.ImageFileWriter[ %1 ].New()\n").arg( varName ) ); + command.append( QString( "writer.SetFileName( \"%1\" )\n").arg(fileName) ); + command.append( QString( "writer.SetInput( %1 )\n").arg(varName) ); + command.append( QString( "writer.Update()\n" ) ); + + MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); + + try + { + MITK_DEBUG("PythonService") << "Loading temporary file " << fileName.toStdString() << " as MITK image"; + mitkImage = mitk::IOUtil::LoadImage( fileName.toStdString() ); + } + catch(std::exception& e) + { + MITK_ERROR << e.what(); + } + + QFile file(fileName); + if( file.exists() ) + { + MITK_DEBUG("PythonService") << "Removing temporary file " << fileName.toStdString(); + file.remove(); + } + + return mitkImage; +} + +bool mitk::PythonService::CopyToPythonAsCvImage( mitk::Image* image, const std::string& stdvarName ) +{ + QString varName = QString::fromStdString( stdvarName ); + + bool convert = false; + if(image->GetDimension() != 2) + { + MITK_ERROR << "Only 2D images allowed for OpenCV images"; + return convert; + } + + // try to save mitk image + QString fileName = this->GetTempDataFileName( ".bmp" ); + fileName = QDir::fromNativeSeparators( fileName ); + MITK_DEBUG("PythonService") << "Saving temporary file " << fileName.toStdString(); + if( !mitk::IOUtil::SaveImage(image, fileName.toStdString()) ) + { + MITK_ERROR << "Temporary file " << fileName.toStdString() << " could not be created."; + return convert; + } + + QString command; + + command.append( QString("%1 = cv2.imread(\"%2\")\n") .arg( varName ).arg( fileName ) ); + MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); + + MITK_DEBUG("PythonService") << "Removing file " << fileName.toStdString(); + QFile file(fileName); + file.remove(); + convert = true; + return convert; +} + +mitk::Image::Pointer mitk::PythonService::CopyCvImageFromPython( const std::string& stdvarName ) +{ + QString varName = QString::fromStdString( stdvarName ); + + mitk::Image::Pointer mitkImage; + QString command; + QString fileName = GetTempDataFileName( ".bmp" ); + fileName = QDir::fromNativeSeparators( fileName ); + + MITK_DEBUG("PythonService") << "run python command to save image with opencv to " << fileName.toStdString(); + + command.append( QString( "cv2.imwrite(\"%1\", %2)\n").arg( fileName ).arg( varName ) ); + + MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); + + try + { + MITK_DEBUG("PythonService") << "Loading temporary file " << fileName.toStdString() << " as MITK image"; + mitkImage = mitk::IOUtil::LoadImage( fileName.toStdString() ); + } + catch(std::exception& e) + { + MITK_ERROR << e.what(); + } + + QFile file(fileName); + if( file.exists() ) + { + MITK_DEBUG("PythonService") << "Removing temporary file " << fileName.toStdString(); + file.remove(); + } + + return mitkImage; +} + +ctkAbstractPythonManager *mitk::PythonService::GetPythonManager() +{ + return &m_PythonManager; +} + +mitk::Surface::Pointer mitk::PythonService::CopyVtkPolyDataFromPython( const std::string& stdvarName ) +{ + QString varName = QString::fromStdString( stdvarName ); + mitk::Surface::Pointer newSurface; + + QString command; + QString fileName = GetTempDataFileName( ".stl" ); + fileName = QDir::fromNativeSeparators( fileName ); + + MITK_DEBUG("PythonService") << "run python command to save polydata with vtk to " << fileName.toStdString(); + command = QString ( + "vtkStlWriter = vtk.vtkSTLWriter()\n" + "vtkStlWriter.SetInput(%1)\n" + "vtkStlWriter.SetFileName(\"%2\")\n" + "vtkStlWriter.Write()\n").arg(varName).arg(fileName); + + MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); + + try + { + MITK_DEBUG("PythonService") << "Loading temporary file " << fileName.toStdString() << " as MITK Surface"; + newSurface = mitk::IOUtil::LoadSurface( fileName.toStdString() ); + } + catch(std::exception& e) + { + MITK_ERROR << e.what(); + } + + QFile file(fileName); + if( file.exists() ) + { + MITK_DEBUG("PythonService") << "Removing temporary file " << fileName.toStdString(); + file.remove(); + } + + return newSurface; +} + +bool mitk::PythonService::CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& stdvarName ) +{ + QString varName = QString::fromStdString( stdvarName ); + bool convert = false; + + // try to save mitk image + QString fileName = this->GetTempDataFileName( ".stl" ); + fileName = QDir::fromNativeSeparators( fileName ); + MITK_DEBUG("PythonService") << "Saving temporary file " << fileName.toStdString(); + if( !mitk::IOUtil::SaveSurface( surface, fileName.toStdString() ) ) + { + MITK_ERROR << "Temporary file " << fileName.toStdString() << " could not be created."; + return convert; + } + + QString command; + + command.append( QString("vtkStlReader = vtk.vtkSTLReader()\n") ); + command.append( QString("vtkStlReader.SetFileName(\"%1\")\n").arg( fileName ) ); + command.append( QString("vtkStlReader.Update()\n") ); + command.append( QString("%1 = vtkStlReader.GetOutput()\n").arg( varName ) ); + MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); + + MITK_DEBUG("PythonService") << "Removing file " << fileName.toStdString(); + QFile file(fileName); + file.remove(); + convert = true; + return convert; +} + +bool mitk::PythonService::IsItkPythonWrappingAvailable() +{ + this->Execute( "import itk\n", IPythonService::SINGLE_LINE_COMMAND ); + + m_ItkWrappingAvailable = !this->PythonErrorOccured(); + + return m_ItkWrappingAvailable; +} + +bool mitk::PythonService::IsOpenCvPythonWrappingAvailable() +{ + this->Execute( "import cv2\n", IPythonService::SINGLE_LINE_COMMAND ); + m_OpenCVWrappingAvailable = !this->PythonErrorOccured(); + + return m_OpenCVWrappingAvailable; +} + +bool mitk::PythonService::IsVtkPythonWrappingAvailable() +{ + this->Execute( "import vtk", IPythonService::SINGLE_LINE_COMMAND ); + m_VtkWrappingAvailable = !this->PythonErrorOccured(); + + return m_VtkWrappingAvailable; +} + +bool mitk::PythonService::PythonErrorOccured() const +{ + return m_ErrorOccured; +} + diff --git a/Modules/Python/mitkPythonService.h b/Modules/Python/mitkPythonService.h new file mode 100644 index 0000000000..9218a19024 --- /dev/null +++ b/Modules/Python/mitkPythonService.h @@ -0,0 +1,105 @@ +/*=================================================================== + +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 mitkPythonService_h +#define mitkPythonService_h + +#include "mitkIPythonService.h" +#include +#include +#include "mitkSurface.h" +#include "mitkPythonExports.h" + +namespace mitk +{ + /// + /// implementation of the IPythonService using ctkabstractpythonmanager + /// \see IPythonService + class MITK_PYTHON_EXPORT PythonService: public itk::LightObject, public mitk::IPythonService + { + public: + /// + /// instantiate python manager here + PythonService(); + /// + /// empty implementation... + ~PythonService(); + /// + /// \see IPythonService::Execute() + std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ); + /// + /// \see IPythonService::ExecuteScript() + void ExecuteScript(const std::string &pathToPythonScript); + /// + /// \see IPythonService::PythonErrorOccured() + bool PythonErrorOccured() const; + /// + /// \see IPythonService::GetVariableStack() + std::vector GetVariableStack() const; + /// + /// \see IPythonService::DoesVariableExist() + bool DoesVariableExist(const std::string& name) const; + /// + /// \see IPythonService::AddPythonCommandObserver() + void AddPythonCommandObserver( PythonCommandObserver* observer ); + /// + /// \see IPythonService::RemovePythonCommandObserver() + void RemovePythonCommandObserver( PythonCommandObserver* observer ); + /// + /// \see IPythonService::NotifyObserver() + void NotifyObserver( const std::string& command ); + /// + /// \see IPythonService::IsItkPythonWrappingAvailable() + bool IsItkPythonWrappingAvailable(); + /// + /// \see IPythonService::CopyToPythonAsItkImage() + bool CopyToPythonAsItkImage( mitk::Image* image, const std::string& varName ); + /// + /// \see IPythonService::CopyItkImageFromPython() + mitk::Image::Pointer CopyItkImageFromPython( const std::string& varName ); + /// + /// \see IPythonService::IsOpenCvPythonWrappingAvailable() + bool IsOpenCvPythonWrappingAvailable(); + /// + /// \see IPythonService::CopyToPythonAsCvImage() + bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ); + /// + /// \see IPythonService::CopyCvImageFromPython() + mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ); + /// + /// \see IPythonService::IsVtkPythonWrappingAvailable() + bool IsVtkPythonWrappingAvailable(); + /// + /// \see IPythonService::CopyToPythonAsVtkPolyData() + bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ); + /// + /// \see IPythonService::CopyVtkPolyDataFromPython() + mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ); + /// + /// \return the ctk abstract python manager instance + ctkAbstractPythonManager* GetPythonManager(); + protected: + QString GetTempDataFileName(const std::string &ext) const; + private: + QList m_Observer; + ctkAbstractPythonManager m_PythonManager; + static const QString m_TmpDataFileName; + bool m_ItkWrappingAvailable; + bool m_OpenCVWrappingAvailable; + bool m_VtkWrappingAvailable; + bool m_ErrorOccured; + }; +} +#endif diff --git a/Modules/Python/resources/PythonSnippets.xml b/Modules/Python/resources/PythonSnippets.xml new file mode 100644 index 0000000000..a301307dd3 --- /dev/null +++ b/Modules/Python/resources/PythonSnippets.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Modules/Python/resources/document-new.png b/Modules/Python/resources/document-new.png new file mode 100644 index 0000000000..e6d64bb90b Binary files /dev/null and b/Modules/Python/resources/document-new.png differ diff --git a/Modules/Python/resources/document-open.png b/Modules/Python/resources/document-open.png new file mode 100644 index 0000000000..f35f258354 Binary files /dev/null and b/Modules/Python/resources/document-open.png differ diff --git a/Modules/Python/resources/document-save.png b/Modules/Python/resources/document-save.png new file mode 100644 index 0000000000..db5c52b769 Binary files /dev/null and b/Modules/Python/resources/document-save.png differ diff --git a/Modules/Python/resources/edit-clear.png b/Modules/Python/resources/edit-clear.png new file mode 100644 index 0000000000..5542948bca Binary files /dev/null and b/Modules/Python/resources/edit-clear.png differ diff --git a/Modules/Python/resources/edit-delete.png b/Modules/Python/resources/edit-delete.png new file mode 100644 index 0000000000..9becb3e2f3 Binary files /dev/null and b/Modules/Python/resources/edit-delete.png differ diff --git a/Modules/Python/resources/edit-find-replace.png b/Modules/Python/resources/edit-find-replace.png new file mode 100644 index 0000000000..0f1b117ff7 Binary files /dev/null and b/Modules/Python/resources/edit-find-replace.png differ diff --git a/Modules/Python/resources/edit-paste.png b/Modules/Python/resources/edit-paste.png new file mode 100644 index 0000000000..dd429ced62 Binary files /dev/null and b/Modules/Python/resources/edit-paste.png differ diff --git a/Modules/Python/resources/media-playback-start.png b/Modules/Python/resources/media-playback-start.png new file mode 100644 index 0000000000..66f32d89b5 Binary files /dev/null and b/Modules/Python/resources/media-playback-start.png differ diff --git a/Modules/Python/resources/mitkPython.qrc b/Modules/Python/resources/mitkPython.qrc new file mode 100644 index 0000000000..55d4c94e13 --- /dev/null +++ b/Modules/Python/resources/mitkPython.qrc @@ -0,0 +1,13 @@ + + + document-new.png + document-open.png + document-save.png + edit-delete.png + edit-paste.png + edit-find-replace.png + edit-clear.png + media-playback-start.png + PythonSnippets.xml + + diff --git a/Modules/Qmitk/QmitkRenderWindow.cpp b/Modules/Qmitk/QmitkRenderWindow.cpp index 91b8244b6a..f9cf89a97d 100644 --- a/Modules/Qmitk/QmitkRenderWindow.cpp +++ b/Modules/Qmitk/QmitkRenderWindow.cpp @@ -1,544 +1,542 @@ /*=================================================================== 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 "QmitkRenderWindow.h" #include #include #include #include #include #include #include #include #include "QmitkEventAdapter.h" // TODO: INTERACTION_LEGACY #include "mitkMousePressEvent.h" #include "mitkMouseMoveEvent.h" #include "mitkMouseReleaseEvent.h" #include "mitkInteractionKeyEvent.h" #include "mitkMouseWheelEvent.h" #include "mitkInternalEvent.h" #include "QmitkRenderWindowMenu.h" QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, QString name, mitk::VtkPropRenderer* /*renderer*/, mitk::RenderingManager* renderingManager) : QVTKWidget(parent), m_ResendQtEvents(true), m_MenuWidget(NULL), m_MenuWidgetActivated(false), m_LayoutIndex(0) { Initialize(renderingManager, name.toStdString().c_str()); // Initialize mitkRenderWindowBase setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); } QmitkRenderWindow::~QmitkRenderWindow() { Destroy(); // Destroy mitkRenderWindowBase } void QmitkRenderWindow::SetResendQtEvents(bool resend) { m_ResendQtEvents = resend; } void QmitkRenderWindow::SetLayoutIndex(unsigned int layoutIndex) { m_LayoutIndex = layoutIndex; if (m_MenuWidget) m_MenuWidget->SetLayoutIndex(layoutIndex); } unsigned int QmitkRenderWindow::GetLayoutIndex() { if (m_MenuWidget) return m_MenuWidget->GetLayoutIndex(); else return 0; } void QmitkRenderWindow::LayoutDesignListChanged(int layoutDesignIndex) { if (m_MenuWidget) m_MenuWidget->UpdateLayoutDesignList(layoutDesignIndex); } void QmitkRenderWindow::mousePressEvent(QMouseEvent *me) { mitk::MousePressEvent::Pointer mPressEvent = mitk::MousePressEvent::New(m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mPressEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mousePressMitkEvent(&myevent); } QVTKWidget::mousePressEvent(me); if (m_ResendQtEvents) me->ignore(); } void QmitkRenderWindow::mouseReleaseEvent(QMouseEvent *me) { mitk::MouseReleaseEvent::Pointer mReleaseEvent = mitk::MouseReleaseEvent::New(m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mReleaseEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mouseReleaseMitkEvent(&myevent); } QVTKWidget::mouseReleaseEvent(me); if (m_ResendQtEvents) me->ignore(); } void QmitkRenderWindow::mouseMoveEvent(QMouseEvent *me) { this->AdjustRenderWindowMenuVisibility(me->pos()); mitk::MouseMoveEvent::Pointer mMoveEvent = mitk::MouseMoveEvent::New(m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me)); if (!this->HandleEvent(mMoveEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); - this->mouseReleaseMitkEvent(&myevent); + this->mouseMoveMitkEvent(&myevent); } - - mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); - this->mouseMoveMitkEvent(&myevent); - QVTKWidget::mouseMoveEvent(me); - } void QmitkRenderWindow::wheelEvent(QWheelEvent *we) { mitk::MouseWheelEvent::Pointer mWheelEvent = mitk::MouseWheelEvent::New(m_Renderer, GetMousePosition(we), GetButtonState(we), GetModifiers(we), GetDelta(we)); if (!this->HandleEvent(mWheelEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::WheelEvent myevent(QmitkEventAdapter::AdaptWheelEvent(m_Renderer, we)); this->wheelMitkEvent(&myevent); } QVTKWidget::wheelEvent(we); if (m_ResendQtEvents) we->ignore(); } void QmitkRenderWindow::keyPressEvent(QKeyEvent *ke) { mitk::ModifierKeys modifiers = GetModifiers(ke); std::string key = GetKeyLetter(ke); mitk::InteractionKeyEvent::Pointer keyEvent = mitk::InteractionKeyEvent::New(m_Renderer, key, modifiers); if (!this->HandleEvent(keyEvent.GetPointer())) { // TODO: INTERACTION_LEGACY QPoint cp = mapFromGlobal(QCursor::pos()); mitk::KeyEvent mke(QmitkEventAdapter::AdaptKeyEvent(m_Renderer, ke, cp)); this->keyPressMitkEvent(&mke); ke->accept(); } QVTKWidget::keyPressEvent(ke); if (m_ResendQtEvents) ke->ignore(); } void QmitkRenderWindow::enterEvent(QEvent *e) { // TODO implement new event QVTKWidget::enterEvent(e); } void QmitkRenderWindow::DeferredHideMenu() { MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu"; if (m_MenuWidget) m_MenuWidget->HideMenu(); } void QmitkRenderWindow::leaveEvent(QEvent *e) { mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(this->m_Renderer, NULL, "LeaveRenderWindow"); if (!this->HandleEvent(internalEvent.GetPointer())) // TODO implement new event MITK_DEBUG << "QmitkRenderWindow::leaveEvent"; if (m_MenuWidget) m_MenuWidget->smoothHide(); QVTKWidget::leaveEvent(e); } void QmitkRenderWindow::paintEvent(QPaintEvent* /*event*/) { //We are using our own interaction and thus have to call the rendering manually. this->GetRenderer()->GetRenderingManager()->RequestUpdate(GetRenderWindow()); } void QmitkRenderWindow::resizeEvent(QResizeEvent* event) { this->resizeMitkEvent(event->size().width(), event->size().height()); QVTKWidget::resizeEvent(event); emit resized(); } void QmitkRenderWindow::moveEvent(QMoveEvent* event) { QVTKWidget::moveEvent(event); // after a move the overlays need to be positioned emit moved(); } void QmitkRenderWindow::showEvent(QShowEvent* event) { QVTKWidget::showEvent(event); // this singleshot is necessary to have the overlays positioned correctly after initial show // simple call of moved() is no use here!! QTimer::singleShot(0, this, SIGNAL( moved() )); } void QmitkRenderWindow::ActivateMenuWidget(bool state, QmitkStdMultiWidget* stdMultiWidget) { m_MenuWidgetActivated = state; if (!m_MenuWidgetActivated && m_MenuWidget) { //disconnect Signal/Slot Connection disconnect(m_MenuWidget, SIGNAL( SignalChangeLayoutDesign(int) ), this, SLOT(OnChangeLayoutDesign(int))); disconnect(m_MenuWidget, SIGNAL( ResetView() ), this, SIGNAL( ResetView())); disconnect(m_MenuWidget, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SIGNAL( ChangeCrosshairRotationMode(int))); delete m_MenuWidget; m_MenuWidget = 0; } else if (m_MenuWidgetActivated && !m_MenuWidget) { //create render window MenuBar for split, close Window or set new setting. m_MenuWidget = new QmitkRenderWindowMenu(this, 0, m_Renderer, stdMultiWidget); m_MenuWidget->SetLayoutIndex(m_LayoutIndex); //create Signal/Slot Connection connect(m_MenuWidget, SIGNAL( SignalChangeLayoutDesign(int) ), this, SLOT(OnChangeLayoutDesign(int))); connect(m_MenuWidget, SIGNAL( ResetView() ), this, SIGNAL( ResetView())); connect(m_MenuWidget, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SIGNAL( ChangeCrosshairRotationMode(int))); } } void QmitkRenderWindow::AdjustRenderWindowMenuVisibility(const QPoint& /*pos*/) { if (m_MenuWidget) { m_MenuWidget->ShowMenu(); m_MenuWidget->MoveWidgetToCorrectPos(1.0f); } } void QmitkRenderWindow::HideRenderWindowMenu() { // DEPRECATED METHOD } void QmitkRenderWindow::OnChangeLayoutDesign(int layoutDesignIndex) { emit SignalLayoutDesignChanged(layoutDesignIndex); } void QmitkRenderWindow::OnWidgetPlaneModeChanged(int mode) { if (m_MenuWidget) m_MenuWidget->NotifyNewWidgetPlanesMode(mode); } void QmitkRenderWindow::FullScreenMode(bool state) { if (m_MenuWidget) m_MenuWidget->ChangeFullScreenMode(state); } void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("application/x-mitk-datanodes")) { event->accept(); } } void QmitkRenderWindow::dropEvent(QDropEvent * event) { if (event->mimeData()->hasFormat("application/x-mitk-datanodes")) { QString arg = QString(event->mimeData()->data("application/x-mitk-datanodes").data()); QStringList listOfDataNodes = arg.split(","); std::vector vectorOfDataNodePointers; for (int i = 0; i < listOfDataNodes.size(); i++) { long val = listOfDataNodes[i].toLong(); mitk::DataNode* node = static_cast((void*) val); vectorOfDataNodePointers.push_back(node); } emit NodesDropped(this, vectorOfDataNodePointers); } } mitk::Point2D QmitkRenderWindow::GetMousePosition(QMouseEvent* me) { mitk::Point2D point; point[0] = me->x(); point[1] = me->y(); return point; } mitk::Point2D QmitkRenderWindow::GetMousePosition(QWheelEvent* we) { mitk::Point2D point; point[0] = we->x(); point[1] = we->y(); return point; } mitk::MouseButtons QmitkRenderWindow::GetEventButton(QMouseEvent* me) { mitk::MouseButtons eventButton; switch (me->button()) { case Qt::LeftButton: eventButton = mitk::LeftMouseButton; break; case Qt::RightButton: eventButton = mitk::RightMouseButton; break; case Qt::MidButton: eventButton = mitk::MiddleMouseButton; break; default: eventButton = mitk::NoButton; break; } return eventButton; } mitk::MouseButtons QmitkRenderWindow::GetButtonState(QMouseEvent* me) { mitk::MouseButtons buttonState = mitk::NoButton; if (me->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::LeftMouseButton; } if (me->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::RightMouseButton; } if (me->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::MiddleMouseButton; } return buttonState; } mitk::ModifierKeys QmitkRenderWindow::GetModifiers(QMouseEvent* me) { mitk::ModifierKeys modifiers = mitk::NoKey; if (me->modifiers() & Qt::ALT) { modifiers = modifiers | mitk::AltKey; } if (me->modifiers() & Qt::CTRL) { modifiers = modifiers | mitk::ControlKey; } if (me->modifiers() & Qt::SHIFT) { modifiers = modifiers | mitk::ShiftKey; } return modifiers; } mitk::MouseButtons QmitkRenderWindow::GetButtonState(QWheelEvent* we) { mitk::MouseButtons buttonState = mitk::NoButton; if (we->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::RightMouseButton; } if (we->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::LeftMouseButton; } if (we->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::MiddleMouseButton; } return buttonState; } mitk::ModifierKeys QmitkRenderWindow::GetModifiers(QWheelEvent* we) { mitk::ModifierKeys modifiers = mitk::NoKey; if (we->modifiers() & Qt::ALT) { modifiers = modifiers | mitk::AltKey; } if (we->modifiers() & Qt::CTRL) { modifiers = modifiers | mitk::ControlKey; } if (we->modifiers() & Qt::SHIFT) { modifiers = modifiers | mitk::ShiftKey; } return modifiers; } mitk::ModifierKeys QmitkRenderWindow::GetModifiers(QKeyEvent* ke) { mitk::ModifierKeys modifiers = mitk::NoKey; if (ke->modifiers() & Qt::ShiftModifier) modifiers = modifiers | mitk::ShiftKey; if (ke->modifiers() & Qt::CTRL) modifiers = modifiers | mitk::ControlKey; if (ke->modifiers() & Qt::ALT) modifiers = modifiers | mitk::AltKey; return modifiers; } std::string QmitkRenderWindow::GetKeyLetter(QKeyEvent *ke) { // Converting Qt Key Event to string element. std::string key = ""; int tkey = ke->key(); if (tkey < 128) { //standard ascii letter key = (char) toupper(tkey); } else { // special keys switch (tkey) { case Qt::Key_Return: key = mitk::KeyReturn; break; case Qt::Key_Enter: key = mitk::KeyEnter; break; case Qt::Key_Escape: key = mitk::KeyEnter; break; case Qt::Key_Delete: key = mitk::KeyDelete; break; case Qt::Key_Up: key = mitk::KeyArrowUp; break; case Qt::Key_Down: key = mitk::KeyArrowDown; break; case Qt::Key_Left: key = mitk::KeyArrowLeft; break; case Qt::Key_Right: key = mitk::KeyArrowRight; break; case Qt::Key_F1: key = mitk::KeyF1; break; case Qt::Key_F2: key = mitk::KeyF2; break; case Qt::Key_F3: key = mitk::KeyF3; break; case Qt::Key_F4: key = mitk::KeyF4; break; case Qt::Key_F5: key = mitk::KeyF5; break; case Qt::Key_F6: key = mitk::KeyF6; break; case Qt::Key_F7: key = mitk::KeyF7; break; case Qt::Key_F8: key = mitk::KeyF8; break; case Qt::Key_F9: key = mitk::KeyF9; break; case Qt::Key_F10: key = mitk::KeyF10; break; case Qt::Key_F11: key = mitk::KeyF11; break; case Qt::Key_F12: key = mitk::KeyF12; break; case Qt::Key_End: - key = mitk::KeyEend; + key = mitk::KeyEnd; break; case Qt::Key_Home: key = mitk::KeyPos1; break; case Qt::Key_Insert: key = mitk::KeyInsert; break; case Qt::Key_PageDown: key = mitk::KeyPageDown; break; case Qt::Key_PageUp: key = mitk::KeyPageUp; break; + case Qt::Key_Space: + key = mitk::KeySpace; + break; } } return key; } int QmitkRenderWindow::GetDelta(QWheelEvent* we) { return we->delta(); } diff --git a/Modules/Qmitk/QmitkServiceListWidget.h b/Modules/Qmitk/QmitkServiceListWidget.h index aefac9a464..9e05ed89d3 100644 --- a/Modules/Qmitk/QmitkServiceListWidget.h +++ b/Modules/Qmitk/QmitkServiceListWidget.h @@ -1,245 +1,247 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _QmitkServiceListWidget_H_INCLUDED #define _QmitkServiceListWidget_H_INCLUDED #include "QmitkExports.h" #include "ui_QmitkServiceListWidgetControls.h" #include //QT headers #include #include //Microservices #include "usServiceReference.h" #include "usModuleContext.h" #include "usServiceEvent.h" #include "usServiceInterface.h" /** * \ingroup QmitkModule * * \brief This widget provides abstraction for the handling of MicroServices. * * Place one in your Plugin and set it to look for a certain interface. * One can also specify a filter and / or a property to use for captioning of * the services. It also offers functionality to signal * ServiceEvents and to return the actual classes, so only a minimum of * interaction with the MicroserviceInterface is required. * To get started, just put it in your Plugin or Widget, call the Initialize * Method and optionally connect it's signals. * As QT limits templating possibilities, events only throw ServiceReferences. * You can manually dereference them using TranslateServiceReference() */ class QMITK_EXPORT QmitkServiceListWidget :public QWidget { //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT private: mitk::ModuleContext* m_Context; /** \brief a filter to further narrow down the list of results*/ std::string m_Filter; /** \brief The name of the ServiceInterface that this class should list */ std::string m_Interface; /** \brief The name of the ServiceProperty that will be displayed in the list to represent the service */ std::string m_NamingProperty; public: static const std::string VIEW_ID; QmitkServiceListWidget(QWidget* p = 0, Qt::WindowFlags f1 = 0); virtual ~QmitkServiceListWidget(); /** \brief This method is part of the widget an needs not to be called separately. */ virtual void CreateQtPartControl(QWidget *parent); /** \brief This method is part of the widget an needs not to be called separately. (Creation of the connections of main and control widget.)*/ virtual void CreateConnections(); /** * \brief Will return true, if a service is currently selected and false otherwise. * * Call this before requesting service references to avoid invalid ServiceReferences. */ bool GetIsServiceSelected(); /** * \brief Returns the currently selected Service as a ServiceReference. * * If no Service is selected, the result will probably be a bad pointer. call GetIsServiceSelected() * beforehand to avoid this */ mitk::ServiceReference GetSelectedServiceReference(); /** * \brief Use this function to return the currently selected service as a class directly. * * Make sure you pass the appropriate type, or else this call will fail. * Usually, you will pass the class itself, not the SmartPointer, but the function returns a pointer. Example: * \verbatim mitk::USDevice::Pointer device = GetSelectedService(); \endverbatim + * @return Returns the current selected device. Returns NULL if no device is selected. */ template T* GetSelectedService() { + if (this->m_Controls->m_ServiceList->currentRow()==-1) return NULL; mitk::ServiceReference ref = GetServiceForListItem( this->m_Controls->m_ServiceList->currentItem() ); return ( m_Context->GetService(ref) ); } /** * \brief Initializes the Widget with essential parameters. * * The string filter is an LDAP parsable String, compare mitk::ModuleContext for examples on filtering. * Pass class T to tell the widget which class it should filter for - only services of this class will be listed. * NamingProperty is a property that will be used to caption the Items in the list. If no filter is supplied, all * matching interfaces are shown. If no namingProperty is supplied, the interfaceName will be used to caption Items in the list. * For example, this Initialization will filter for all USDevices that are set to active. The USDevice's model will be used to display it in the list: * \verbatim std::string filter = "(&(" + mitk::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(IsActive=true))"; m_Controls.m_ActiveVideoDevices->Initialize(mitk::USImageMetadata::PROP_DEV_MODEL ,filter); * \endverbatim */ template void Initialize(const std::string& namingProperty = static_cast< std::string >(""),const std::string& filter = static_cast< std::string >("")) { std::string interfaceName ( us_service_interface_iid() ); m_Interface = interfaceName; InitPrivate(namingProperty, filter); } /** * \brief Translates a serviceReference to a class of the given type. * * Use this to translate the signal's parameters. To adhere to the MicroService contract, * only ServiceReferences stemming from the same widget should be used as parameters for this method. * \verbatim mitk::USDevice::Pointer device = TranslateReference(myDeviceReference); \endverbatim */ template T* TranslateReference(mitk::ServiceReference reference) { return dynamic_cast ( m_Context->GetService(reference) ); } /** *\brief This Function listens to ServiceRegistry changes and updates the list of services accordingly. * * The user of this widget does not need to call this method, it is instead used to recieve events from the module registry. */ void OnServiceEvent(const mitk::ServiceEvent event); signals: /** *\brief Emitted when a new Service matching the filter is being registered. * * Be careful if you use a filter: * If a device does not match the filter when registering, but modifies it's properties later to match the filter, * then the first signal you will see this device in will be ServiceModified. */ void ServiceRegistered(mitk::ServiceReference); /** *\brief Emitted directly before a Service matching the filter is being unregistered. */ void ServiceUnregistering(mitk::ServiceReference); /** *\brief Emitted when a Service matching the filter changes it's properties, or when a service that formerly not matched the filter * changed it's properties and now matches the filter. */ void ServiceModified(mitk::ServiceReference); /** *\brief Emitted when a Service matching the filter changes it's properties, * * and the new properties make it fall trough the filter. This effectively means that * the widget will not track the service anymore. Usually, the Service should still be useable though */ void ServiceModifiedEndMatch(mitk::ServiceReference); /** *\brief Emitted if the user selects a Service from the list. * * If no service is selected, an invalid serviceReference is returned. The user can easily check for this. * if (serviceReference) will evaluate to false, if the reference is invalid and true if valid. */ void ServiceSelectionChanged(mitk::ServiceReference); public slots: protected slots: /** \brief Called, when the selection in the list of Services changes. */ void OnServiceSelectionChanged(); protected: Ui::QmitkServiceListWidgetControls* m_Controls; ///< member holding the UI elements of this widget /** * \brief Internal structure used to link ServiceReferences to their QListWidgetItems */ struct ServiceListLink { mitk::ServiceReference service; QListWidgetItem* item; }; /** * \brief Finishes initialization after Initialize has been called. * * This function assumes that m_Interface is set correctly (Which Initialize does). */ void InitPrivate(const std::string& namingProperty, const std::string& filter); /** * \brief Contains a list of currently active services and their entires in the list. This is wiped with every ServiceRegistryEvent. */ std::vector m_ListContent; /** * \brief Constructs a ListItem from the given service, displays it, and locally stores the service. */ QListWidgetItem* AddServiceToList(mitk::ServiceReference serviceRef); /** * \brief Removes the given service from the list and cleans up. Returns true if successful, false if service was not found. */ bool RemoveServiceFromList(mitk::ServiceReference serviceRef); /** * \brief Returns the serviceReference corresponding to the given ListEntry or an invalid one if none was found (will evaluate to false in bool expressions). */ mitk::ServiceReference GetServiceForListItem(QListWidgetItem* item); /** * \brief Returns a list of ServiceReferences matching the filter criteria by querying the service registry. */ std::list GetAllRegisteredServices(); }; #endif // _QmitkServiceListWidget_H_INCLUDED diff --git a/Modules/Qmitk/QmitkStdMultiWidget.cpp b/Modules/Qmitk/QmitkStdMultiWidget.cpp index 7b4397133a..0b63b24bf0 100644 --- a/Modules/Qmitk/QmitkStdMultiWidget.cpp +++ b/Modules/Qmitk/QmitkStdMultiWidget.cpp @@ -1,2218 +1,2218 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define SMW_INFO MITK_INFO("widget.stdmulti") #include "QmitkStdMultiWidget.h" #include #include #include #include #include #include #include #include #include "mitkProperties.h" #include "mitkGeometry2DDataMapper2D.h" #include "mitkGlobalInteraction.h" #include "mitkDisplayInteractor.h" #include "mitkPointSet.h" #include "mitkPositionEvent.h" #include "mitkStateEvent.h" #include "mitkLine.h" #include "mitkInteractionConst.h" #include "mitkDataStorage.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateProperty.h" #include "mitkStatusBar.h" #include "mitkImage.h" #include "mitkVtkLayerController.h" +#include + QmitkStdMultiWidget::QmitkStdMultiWidget(QWidget* parent, Qt::WindowFlags f, mitk::RenderingManager* renderingManager) : QWidget(parent, f), mitkWidget1(NULL), mitkWidget2(NULL), mitkWidget3(NULL), mitkWidget4(NULL), levelWindowWidget(NULL), QmitkStdMultiWidgetLayout(NULL), m_Layout(LAYOUT_DEFAULT), m_PlaneMode(PLANE_MODE_SLICING), m_RenderingManager(renderingManager), m_GradientBackgroundFlag(true), m_TimeNavigationController(NULL), m_MainSplit(NULL), m_LayoutSplit(NULL), m_SubSplit1(NULL), m_SubSplit2(NULL), mitkWidget1Container(NULL), mitkWidget2Container(NULL), mitkWidget3Container(NULL), mitkWidget4Container(NULL), m_PendingCrosshairPositionEvent(false), m_CrosshairNavigationEnabled(false) { /****************************************************** * Use the global RenderingManager if none was specified * ****************************************************/ if (m_RenderingManager == NULL) { m_RenderingManager = mitk::RenderingManager::GetInstance(); } m_TimeNavigationController = m_RenderingManager->GetTimeNavigationController(); /*******************************/ //Create Widget manually /*******************************/ //create Layouts QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); QmitkStdMultiWidgetLayout->setContentsMargins(0,0,0,0); //Set Layout to widget this->setLayout(QmitkStdMultiWidgetLayout); // QmitkNavigationToolBar* toolBar = new QmitkNavigationToolBar(); // QmitkStdMultiWidgetLayout->addWidget( toolBar ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //creae Widget Container mitkWidget1Container = new QWidget(m_SubSplit1); mitkWidget2Container = new QWidget(m_SubSplit1); mitkWidget3Container = new QWidget(m_SubSplit2); mitkWidget4Container = new QWidget(m_SubSplit2); mitkWidget1Container->setContentsMargins(0,0,0,0); mitkWidget2Container->setContentsMargins(0,0,0,0); mitkWidget3Container->setContentsMargins(0,0,0,0); mitkWidget4Container->setContentsMargins(0,0,0,0); //create Widget Layout QHBoxLayout *mitkWidgetLayout1 = new QHBoxLayout(mitkWidget1Container); QHBoxLayout *mitkWidgetLayout2 = new QHBoxLayout(mitkWidget2Container); QHBoxLayout *mitkWidgetLayout3 = new QHBoxLayout(mitkWidget3Container); QHBoxLayout *mitkWidgetLayout4 = new QHBoxLayout(mitkWidget4Container); mitkWidgetLayout1->setMargin(0); mitkWidgetLayout2->setMargin(0); mitkWidgetLayout3->setMargin(0); mitkWidgetLayout4->setMargin(0); //set Layout to Widget Container mitkWidget1Container->setLayout(mitkWidgetLayout1); mitkWidget2Container->setLayout(mitkWidgetLayout2); mitkWidget3Container->setLayout(mitkWidgetLayout3); mitkWidget4Container->setLayout(mitkWidgetLayout4); //set SizePolicy mitkWidget1Container->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); mitkWidget2Container->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); mitkWidget3Container->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); mitkWidget4Container->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); //insert Widget Container into the splitters m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit2->addWidget( mitkWidget3Container ); m_SubSplit2->addWidget( mitkWidget4Container ); // m_RenderingManager->SetGlobalInteraction( mitk::GlobalInteraction::GetInstance() ); //Create RenderWindows 1 mitkWidget1 = new QmitkRenderWindow(mitkWidget1Container, "stdmulti.widget1", NULL, m_RenderingManager); mitkWidget1->setMaximumSize(2000,2000); mitkWidget1->SetLayoutIndex( AXIAL ); mitkWidgetLayout1->addWidget(mitkWidget1); //Create RenderWindows 2 mitkWidget2 = new QmitkRenderWindow(mitkWidget2Container, "stdmulti.widget2", NULL, m_RenderingManager); mitkWidget2->setMaximumSize(2000,2000); mitkWidget2->setEnabled( TRUE ); mitkWidget2->SetLayoutIndex( SAGITTAL ); mitkWidgetLayout2->addWidget(mitkWidget2); //Create RenderWindows 3 mitkWidget3 = new QmitkRenderWindow(mitkWidget3Container, "stdmulti.widget3", NULL, m_RenderingManager); mitkWidget3->setMaximumSize(2000,2000); mitkWidget3->SetLayoutIndex( CORONAL ); mitkWidgetLayout3->addWidget(mitkWidget3); //Create RenderWindows 4 mitkWidget4 = new QmitkRenderWindow(mitkWidget4Container, "stdmulti.widget4", NULL, m_RenderingManager); mitkWidget4->setMaximumSize(2000,2000); mitkWidget4->SetLayoutIndex( THREE_D ); mitkWidgetLayout4->addWidget(mitkWidget4); //create SignalSlot Connection connect( mitkWidget1, SIGNAL( SignalLayoutDesignChanged(int) ), this, SLOT( OnLayoutDesignChanged(int) ) ); connect( mitkWidget1, SIGNAL( ResetView() ), this, SLOT( ResetCrosshair() ) ); connect( mitkWidget1, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SLOT( SetWidgetPlaneMode(int) ) ); connect( this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget1, SLOT(OnWidgetPlaneModeChanged(int)) ); connect( mitkWidget2, SIGNAL( SignalLayoutDesignChanged(int) ), this, SLOT( OnLayoutDesignChanged(int) ) ); connect( mitkWidget2, SIGNAL( ResetView() ), this, SLOT( ResetCrosshair() ) ); connect( mitkWidget2, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SLOT( SetWidgetPlaneMode(int) ) ); connect( this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget2, SLOT(OnWidgetPlaneModeChanged(int)) ); connect( mitkWidget3, SIGNAL( SignalLayoutDesignChanged(int) ), this, SLOT( OnLayoutDesignChanged(int) ) ); connect( mitkWidget3, SIGNAL( ResetView() ), this, SLOT( ResetCrosshair() ) ); connect( mitkWidget3, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SLOT( SetWidgetPlaneMode(int) ) ); connect( this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget3, SLOT(OnWidgetPlaneModeChanged(int)) ); connect( mitkWidget4, SIGNAL( SignalLayoutDesignChanged(int) ), this, SLOT( OnLayoutDesignChanged(int) ) ); connect( mitkWidget4, SIGNAL( ResetView() ), this, SLOT( ResetCrosshair() ) ); connect( mitkWidget4, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SLOT( SetWidgetPlaneMode(int) ) ); connect( this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget4, SLOT(OnWidgetPlaneModeChanged(int)) ); //Create Level Window Widget levelWindowWidget = new QmitkLevelWindowWidget( m_MainSplit ); //this levelWindowWidget->setObjectName(QString::fromUtf8("levelWindowWidget")); QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth(levelWindowWidget->sizePolicy().hasHeightForWidth()); levelWindowWidget->setSizePolicy(sizePolicy); levelWindowWidget->setMaximumSize(QSize(50, 2000)); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //resize Image. this->resize( QSize(364, 477).expandedTo(minimumSizeHint()) ); //Initialize the widgets. this->InitializeWidget(); //Activate Widget Menu this->ActivateMenuWidget( true ); } void QmitkStdMultiWidget::InitializeWidget() { m_PositionTracker = NULL; // transfer colors in WorldGeometry-Nodes of the associated Renderer QColor qcolor; //float color[3] = {1.0f,1.0f,1.0f}; mitk::DataNode::Pointer planeNode; mitk::IntProperty::Pointer layer; // of widget 1 planeNode = mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetCurrentWorldGeometry2DNode(); planeNode->SetColor(1.0,0.0,0.0); layer = mitk::IntProperty::New(1000); planeNode->SetProperty("layer",layer); // ... of widget 2 planeNode = mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetCurrentWorldGeometry2DNode(); planeNode->SetColor(0.0,1.0,0.0); layer = mitk::IntProperty::New(1000); planeNode->SetProperty("layer",layer); // ... of widget 3 planeNode = mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetCurrentWorldGeometry2DNode(); planeNode->SetColor(0.0,0.0,1.0); layer = mitk::IntProperty::New(1000); planeNode->SetProperty("layer",layer); // ... of widget 4 planeNode = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetCurrentWorldGeometry2DNode(); planeNode->SetColor(1.0,1.0,0.0); layer = mitk::IntProperty::New(1000); planeNode->SetProperty("layer",layer); mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); // Set plane mode (slicing/rotation behavior) to slicing (default) m_PlaneMode = PLANE_MODE_SLICING; // Set default view directions for SNCs mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Axial ); mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Sagittal ); mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Frontal ); mitkWidget4->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Original ); /*************************************************/ //Write Layout Names into the viewers -- hardCoded //Info for later: //int view = this->GetRenderWindow1()->GetSliceNavigationController()->GetDefaultViewDirection(); //QString layoutName; //if( view == mitk::SliceNavigationController::Axial ) // layoutName = "Axial"; //else if( view == mitk::SliceNavigationController::Sagittal ) // layoutName = "Sagittal"; //else if( view == mitk::SliceNavigationController::Frontal ) // layoutName = "Coronal"; //else if( view == mitk::SliceNavigationController::Original ) // layoutName = "Original"; //if( view >= 0 && view < 4 ) // //write LayoutName --> Viewer 3D shoudn't write the layoutName. //Render Window 1 == axial m_CornerAnnotaions[0].cornerText = vtkCornerAnnotation::New(); m_CornerAnnotaions[0].cornerText->SetText(0, "Axial"); m_CornerAnnotaions[0].cornerText->SetMaximumFontSize(12); m_CornerAnnotaions[0].textProp = vtkTextProperty::New(); m_CornerAnnotaions[0].textProp->SetColor( 1.0, 0.0, 0.0 ); m_CornerAnnotaions[0].cornerText->SetTextProperty( m_CornerAnnotaions[0].textProp ); m_CornerAnnotaions[0].ren = vtkRenderer::New(); m_CornerAnnotaions[0].ren->AddActor(m_CornerAnnotaions[0].cornerText); m_CornerAnnotaions[0].ren->InteractiveOff(); mitk::VtkLayerController::GetInstance(this->GetRenderWindow1()->GetRenderWindow())->InsertForegroundRenderer(m_CornerAnnotaions[0].ren,true); //Render Window 2 == sagittal m_CornerAnnotaions[1].cornerText = vtkCornerAnnotation::New(); m_CornerAnnotaions[1].cornerText->SetText(0, "Sagittal"); m_CornerAnnotaions[1].cornerText->SetMaximumFontSize(12); m_CornerAnnotaions[1].textProp = vtkTextProperty::New(); m_CornerAnnotaions[1].textProp->SetColor( 0.0, 1.0, 0.0 ); m_CornerAnnotaions[1].cornerText->SetTextProperty( m_CornerAnnotaions[1].textProp ); m_CornerAnnotaions[1].ren = vtkRenderer::New(); m_CornerAnnotaions[1].ren->AddActor(m_CornerAnnotaions[1].cornerText); m_CornerAnnotaions[1].ren->InteractiveOff(); mitk::VtkLayerController::GetInstance(this->GetRenderWindow2()->GetRenderWindow())->InsertForegroundRenderer(m_CornerAnnotaions[1].ren,true); //Render Window 3 == coronal m_CornerAnnotaions[2].cornerText = vtkCornerAnnotation::New(); m_CornerAnnotaions[2].cornerText->SetText(0, "Coronal"); m_CornerAnnotaions[2].cornerText->SetMaximumFontSize(12); m_CornerAnnotaions[2].textProp = vtkTextProperty::New(); m_CornerAnnotaions[2].textProp->SetColor( 0.295, 0.295, 1.0 ); m_CornerAnnotaions[2].cornerText->SetTextProperty( m_CornerAnnotaions[2].textProp ); m_CornerAnnotaions[2].ren = vtkRenderer::New(); m_CornerAnnotaions[2].ren->AddActor(m_CornerAnnotaions[2].cornerText); m_CornerAnnotaions[2].ren->InteractiveOff(); mitk::VtkLayerController::GetInstance(this->GetRenderWindow3()->GetRenderWindow())->InsertForegroundRenderer(m_CornerAnnotaions[2].ren,true); /*************************************************/ // create a slice rotator // m_SlicesRotator = mitk::SlicesRotator::New(); // @TODO next line causes sure memory leak // rotator will be created nonetheless (will be switched on and off) m_SlicesRotator = mitk::SlicesRotator::New("slices-rotator"); m_SlicesRotator->AddSliceController( mitkWidget1->GetSliceNavigationController() ); m_SlicesRotator->AddSliceController( mitkWidget2->GetSliceNavigationController() ); m_SlicesRotator->AddSliceController( mitkWidget3->GetSliceNavigationController() ); // create a slice swiveller (using the same state-machine as SlicesRotator) m_SlicesSwiveller = mitk::SlicesSwiveller::New("slices-rotator"); m_SlicesSwiveller->AddSliceController( mitkWidget1->GetSliceNavigationController() ); m_SlicesSwiveller->AddSliceController( mitkWidget2->GetSliceNavigationController() ); m_SlicesSwiveller->AddSliceController( mitkWidget3->GetSliceNavigationController() ); //connect to the "time navigation controller": send time via sliceNavigationControllers m_TimeNavigationController->ConnectGeometryTimeEvent( mitkWidget1->GetSliceNavigationController() , false); m_TimeNavigationController->ConnectGeometryTimeEvent( mitkWidget2->GetSliceNavigationController() , false); m_TimeNavigationController->ConnectGeometryTimeEvent( mitkWidget3->GetSliceNavigationController() , false); m_TimeNavigationController->ConnectGeometryTimeEvent( mitkWidget4->GetSliceNavigationController() , false); mitkWidget1->GetSliceNavigationController() ->ConnectGeometrySendEvent(mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); //reverse connection between sliceNavigationControllers and m_TimeNavigationController mitkWidget1->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget2->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget3->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget4->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); m_MouseModeSwitcher = mitk::MouseModeSwitcher::New(); m_LastLeftClickPositionSupplier = mitk::CoordinateSupplier::New("navigation", NULL); mitk::GlobalInteraction::GetInstance()->AddListener( m_LastLeftClickPositionSupplier ); // setup gradient background m_GradientBackground1 = mitk::GradientBackground::New(); m_GradientBackground1->SetRenderWindow( mitkWidget1->GetRenderWindow() ); m_GradientBackground1->Disable(); m_GradientBackground2 = mitk::GradientBackground::New(); m_GradientBackground2->SetRenderWindow( mitkWidget2->GetRenderWindow() ); m_GradientBackground2->Disable(); m_GradientBackground3 = mitk::GradientBackground::New(); m_GradientBackground3->SetRenderWindow( mitkWidget3->GetRenderWindow() ); m_GradientBackground3->Disable(); m_GradientBackground4 = mitk::GradientBackground::New(); m_GradientBackground4->SetRenderWindow( mitkWidget4->GetRenderWindow() ); m_GradientBackground4->SetGradientColors(0.1,0.1,0.1,0.5,0.5,0.5); m_GradientBackground4->Enable(); // setup the department logo rendering m_LogoRendering1 = mitk::ManufacturerLogo::New(); m_LogoRendering1->SetRenderWindow( mitkWidget1->GetRenderWindow() ); m_LogoRendering1->Disable(); m_LogoRendering2 = mitk::ManufacturerLogo::New(); m_LogoRendering2->SetRenderWindow( mitkWidget2->GetRenderWindow() ); m_LogoRendering2->Disable(); m_LogoRendering3 = mitk::ManufacturerLogo::New(); m_LogoRendering3->SetRenderWindow( mitkWidget3->GetRenderWindow() ); m_LogoRendering3->Disable(); m_LogoRendering4 = mitk::ManufacturerLogo::New(); m_LogoRendering4->SetRenderWindow( mitkWidget4->GetRenderWindow() ); m_LogoRendering4->Enable(); m_RectangleRendering1 = mitk::RenderWindowFrame::New(); m_RectangleRendering1->SetRenderWindow( mitkWidget1->GetRenderWindow() ); m_RectangleRendering1->Enable(1.0,0.0,0.0); m_RectangleRendering2 = mitk::RenderWindowFrame::New(); m_RectangleRendering2->SetRenderWindow( mitkWidget2->GetRenderWindow() ); m_RectangleRendering2->Enable(0.0,1.0,0.0); m_RectangleRendering3 = mitk::RenderWindowFrame::New(); m_RectangleRendering3->SetRenderWindow( mitkWidget3->GetRenderWindow() ); m_RectangleRendering3->Enable(0.0,0.0,1.0); m_RectangleRendering4 = mitk::RenderWindowFrame::New(); m_RectangleRendering4->SetRenderWindow( mitkWidget4->GetRenderWindow() ); m_RectangleRendering4->Enable(1.0,1.0,0.0); } QmitkStdMultiWidget::~QmitkStdMultiWidget() { DisablePositionTracking(); DisableNavigationControllerEventListening(); m_TimeNavigationController->Disconnect(mitkWidget1->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(mitkWidget2->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(mitkWidget3->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(mitkWidget4->GetSliceNavigationController()); mitk::VtkLayerController::GetInstance(this->GetRenderWindow1()->GetRenderWindow())->RemoveRenderer( m_CornerAnnotaions[0].ren ); mitk::VtkLayerController::GetInstance(this->GetRenderWindow2()->GetRenderWindow())->RemoveRenderer( m_CornerAnnotaions[1].ren ); mitk::VtkLayerController::GetInstance(this->GetRenderWindow3()->GetRenderWindow())->RemoveRenderer( m_CornerAnnotaions[2].ren ); //Delete CornerAnnotation m_CornerAnnotaions[0].cornerText->Delete(); m_CornerAnnotaions[0].textProp->Delete(); m_CornerAnnotaions[0].ren->Delete(); m_CornerAnnotaions[1].cornerText->Delete(); m_CornerAnnotaions[1].textProp->Delete(); m_CornerAnnotaions[1].ren->Delete(); m_CornerAnnotaions[2].cornerText->Delete(); m_CornerAnnotaions[2].textProp->Delete(); m_CornerAnnotaions[2].ren->Delete(); } void QmitkStdMultiWidget::RemovePlanesFromDataStorage() { if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_Node.IsNotNull()) { if(m_DataStorage.IsNotNull()) { m_DataStorage->Remove(m_PlaneNode1); m_DataStorage->Remove(m_PlaneNode2); m_DataStorage->Remove(m_PlaneNode3); m_DataStorage->Remove(m_Node); } } } void QmitkStdMultiWidget::AddPlanesToDataStorage() { if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_Node.IsNotNull()) { if (m_DataStorage.IsNotNull()) { m_DataStorage->Add(m_Node); m_DataStorage->Add(m_PlaneNode1, m_Node); m_DataStorage->Add(m_PlaneNode2, m_Node); m_DataStorage->Add(m_PlaneNode3, m_Node); static_cast(m_PlaneNode1->GetMapper(mitk::BaseRenderer::Standard2D))->SetDatastorageAndGeometryBaseNode(m_DataStorage, m_Node); static_cast(m_PlaneNode2->GetMapper(mitk::BaseRenderer::Standard2D))->SetDatastorageAndGeometryBaseNode(m_DataStorage, m_Node); static_cast(m_PlaneNode3->GetMapper(mitk::BaseRenderer::Standard2D))->SetDatastorageAndGeometryBaseNode(m_DataStorage, m_Node); } } } void QmitkStdMultiWidget::changeLayoutTo2DImagesUp() { SMW_INFO << "changing layout to 2D images up... " << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //Set Layout to widget this->setLayout(QmitkStdMultiWidgetLayout); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget Container into splitter top m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit1->addWidget( mitkWidget3Container ); //set SplitterSize for splitter top QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); //insert Widget Container into splitter bottom m_SubSplit2->addWidget( mitkWidget4Container ); //set SplitterSize for splitter m_LayoutSplit splitterSize.clear(); splitterSize.push_back(400); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt m_MainSplit->show(); //show Widget if hidden if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); //Change Layout Name m_Layout = LAYOUT_2D_IMAGES_UP; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2D_IMAGES_UP ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2D_IMAGES_UP ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2D_IMAGES_UP ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2D_IMAGES_UP ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutTo2DImagesLeft() { SMW_INFO << "changing layout to 2D images left... " << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( Qt::Vertical, m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget into the splitters m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit1->addWidget( mitkWidget3Container ); //set splitterSize of SubSplit1 QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); m_SubSplit2->addWidget( mitkWidget4Container ); //set splitterSize of Layout Split splitterSize.clear(); splitterSize.push_back(400); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show Widget if hidden if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); //update Layout Name m_Layout = LAYOUT_2D_IMAGES_LEFT; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2D_IMAGES_LEFT ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2D_IMAGES_LEFT ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2D_IMAGES_LEFT ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2D_IMAGES_LEFT ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToDefault() { SMW_INFO << "changing layout to default... " << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget container into the splitters m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit2->addWidget( mitkWidget3Container ); m_SubSplit2->addWidget( mitkWidget4Container ); //set splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); m_SubSplit2->setSizes( splitterSize ); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show Widget if hidden if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_DEFAULT; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_DEFAULT ); mitkWidget2->LayoutDesignListChanged( LAYOUT_DEFAULT ); mitkWidget3->LayoutDesignListChanged( LAYOUT_DEFAULT ); mitkWidget4->LayoutDesignListChanged( LAYOUT_DEFAULT ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToBig3D() { SMW_INFO << "changing layout to big 3D ..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //add widget Splitter to main Splitter m_MainSplit->addWidget( mitkWidget4Container ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); mitkWidget2->hide(); mitkWidget3->hide(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_BIG_3D; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_BIG_3D ); mitkWidget2->LayoutDesignListChanged( LAYOUT_BIG_3D ); mitkWidget3->LayoutDesignListChanged( LAYOUT_BIG_3D ); mitkWidget4->LayoutDesignListChanged( LAYOUT_BIG_3D ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToWidget1() { SMW_INFO << "changing layout to big Widget1 ..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //add widget Splitter to main Splitter m_MainSplit->addWidget( mitkWidget1Container ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets if ( mitkWidget1->isHidden() ) mitkWidget1->show(); mitkWidget2->hide(); mitkWidget3->hide(); mitkWidget4->hide(); m_Layout = LAYOUT_WIDGET1; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_WIDGET1 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_WIDGET1 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_WIDGET1 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_WIDGET1 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToWidget2() { SMW_INFO << "changing layout to big Widget2 ..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //add widget Splitter to main Splitter m_MainSplit->addWidget( mitkWidget2Container ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); mitkWidget3->hide(); mitkWidget4->hide(); m_Layout = LAYOUT_WIDGET2; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_WIDGET2 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_WIDGET2 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_WIDGET2 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_WIDGET2 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToWidget3() { SMW_INFO << "changing layout to big Widget3 ..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //add widget Splitter to main Splitter m_MainSplit->addWidget( mitkWidget3Container ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); mitkWidget2->hide(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); mitkWidget4->hide(); m_Layout = LAYOUT_WIDGET3; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_WIDGET3 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_WIDGET3 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_WIDGET3 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_WIDGET3 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToRowWidget3And4() { SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //add Widgets to splitter m_LayoutSplit->addWidget( mitkWidget3Container ); m_LayoutSplit->addWidget( mitkWidget4Container ); //set Splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); mitkWidget2->hide(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_ROW_WIDGET_3_AND_4; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_ROW_WIDGET_3_AND_4 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_ROW_WIDGET_3_AND_4 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_ROW_WIDGET_3_AND_4 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_ROW_WIDGET_3_AND_4 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToColumnWidget3And4() { SMW_INFO << "changing layout to Widget3 and 4 in one Column..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //add Widgets to splitter m_LayoutSplit->addWidget( mitkWidget3Container ); m_LayoutSplit->addWidget( mitkWidget4Container ); //set SplitterSize QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); mitkWidget2->hide(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_COLUMN_WIDGET_3_AND_4; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_COLUMN_WIDGET_3_AND_4 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_COLUMN_WIDGET_3_AND_4 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_COLUMN_WIDGET_3_AND_4 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_COLUMN_WIDGET_3_AND_4 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToRowWidgetSmall3andBig4() { SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; this->changeLayoutToRowWidget3And4(); m_Layout = LAYOUT_ROW_WIDGET_SMALL3_AND_BIG4; } void QmitkStdMultiWidget::changeLayoutToSmallUpperWidget2Big3and4() { SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( Qt::Vertical, m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget into the splitters m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit2->addWidget( mitkWidget3Container ); m_SubSplit2->addWidget( mitkWidget4Container ); //set Splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit2->setSizes( splitterSize ); splitterSize.clear(); splitterSize.push_back(500); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt m_MainSplit->show(); //show Widget if hidden mitkWidget1->hide(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutTo2x2Dand3DWidget() { SMW_INFO << "changing layout to 2 x 2D and 3D Widget" << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( Qt::Vertical, m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //add Widgets to splitter m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit2->addWidget( mitkWidget4Container ); //set Splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); mitkWidget3->hide(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_2X_2D_AND_3D_WIDGET; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2X_2D_AND_3D_WIDGET ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2X_2D_AND_3D_WIDGET ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2X_2D_AND_3D_WIDGET ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2X_2D_AND_3D_WIDGET ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToLeft2Dand3DRight2D() { SMW_INFO << "changing layout to 2D and 3D left, 2D right Widget" << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( Qt::Vertical, m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //add Widgets to splitter m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget4Container ); m_SubSplit2->addWidget( mitkWidget2Container ); //set Splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); mitkWidget3->hide(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutTo2DUpAnd3DDown() { SMW_INFO << "changing layout to 2D up and 3D down" << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //Set Layout to widget this->setLayout(QmitkStdMultiWidgetLayout); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget Container into splitter top m_SubSplit1->addWidget( mitkWidget1Container ); //set SplitterSize for splitter top QList splitterSize; // splitterSize.push_back(1000); // splitterSize.push_back(1000); // splitterSize.push_back(1000); // m_SubSplit1->setSizes( splitterSize ); //insert Widget Container into splitter bottom m_SubSplit2->addWidget( mitkWidget4Container ); //set SplitterSize for splitter m_LayoutSplit splitterSize.clear(); splitterSize.push_back(700); splitterSize.push_back(700); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt m_MainSplit->show(); //show/hide Widgets if ( mitkWidget1->isHidden() ) mitkWidget1->show(); mitkWidget2->hide(); mitkWidget3->hide(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_2D_UP_AND_3D_DOWN; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2D_UP_AND_3D_DOWN ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2D_UP_AND_3D_DOWN ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2D_UP_AND_3D_DOWN ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2D_UP_AND_3D_DOWN ); //update all Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::SetDataStorage( mitk::DataStorage* ds ) { mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->SetDataStorage(ds); mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->SetDataStorage(ds); mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->SetDataStorage(ds); mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->SetDataStorage(ds); m_DataStorage = ds; } void QmitkStdMultiWidget::Fit() { vtkRenderer * vtkrenderer; mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetDisplayGeometry()->Fit(); int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkObject::SetGlobalWarningDisplay(w); } void QmitkStdMultiWidget::InitPositionTracking() { //PoinSetNode for MouseOrientation m_PositionTrackerNode = mitk::DataNode::New(); m_PositionTrackerNode->SetProperty("name", mitk::StringProperty::New("Mouse Position")); m_PositionTrackerNode->SetData( mitk::PointSet::New() ); m_PositionTrackerNode->SetColor(1.0,0.33,0.0); m_PositionTrackerNode->SetProperty("layer", mitk::IntProperty::New(1001)); m_PositionTrackerNode->SetVisibility(true); m_PositionTrackerNode->SetProperty("inputdevice", mitk::BoolProperty::New(true) ); m_PositionTrackerNode->SetProperty("BaseRendererMapperID", mitk::IntProperty::New(0) );//point position 2D mouse m_PositionTrackerNode->SetProperty("baserenderer", mitk::StringProperty::New("N/A")); } void QmitkStdMultiWidget::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... float white[3] = {1.0f,1.0f,1.0f}; mitk::Geometry2DDataMapper2D::Pointer mapper; // ... of widget 1 m_PlaneNode1 = (mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode1->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode1->SetProperty("name", mitk::StringProperty::New("widget1Plane")); m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::Geometry2DDataMapper2D::New(); m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 2 m_PlaneNode2 =( mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode2->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode2->SetProperty("name", mitk::StringProperty::New("widget2Plane")); m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::Geometry2DDataMapper2D::New(); m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 3 m_PlaneNode3 = (mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode3->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode3->SetProperty("name", mitk::StringProperty::New("widget3Plane")); m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::Geometry2DDataMapper2D::New(); m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_Node = mitk::DataNode::New(); m_Node->SetProperty("name", mitk::StringProperty::New("Widgets")); m_Node->SetProperty("helper object", mitk::BoolProperty::New(true)); } mitk::SliceNavigationController* QmitkStdMultiWidget::GetTimeNavigationController() { return m_TimeNavigationController; } void QmitkStdMultiWidget::EnableStandardLevelWindow() { levelWindowWidget->disconnect(this); levelWindowWidget->SetDataStorage(mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetDataStorage()); levelWindowWidget->show(); } void QmitkStdMultiWidget::DisableStandardLevelWindow() { levelWindowWidget->disconnect(this); levelWindowWidget->hide(); } // CAUTION: Legacy code for enabling Qt-signal-controlled view initialization. // Use RenderingManager::InitializeViews() instead. bool QmitkStdMultiWidget::InitializeStandardViews( const mitk::Geometry3D * geometry ) { return m_RenderingManager->InitializeViews( geometry ); } void QmitkStdMultiWidget::RequestUpdate() { m_RenderingManager->RequestUpdate(mitkWidget1->GetRenderWindow()); m_RenderingManager->RequestUpdate(mitkWidget2->GetRenderWindow()); m_RenderingManager->RequestUpdate(mitkWidget3->GetRenderWindow()); m_RenderingManager->RequestUpdate(mitkWidget4->GetRenderWindow()); } void QmitkStdMultiWidget::ForceImmediateUpdate() { m_RenderingManager->ForceImmediateUpdate(mitkWidget1->GetRenderWindow()); m_RenderingManager->ForceImmediateUpdate(mitkWidget2->GetRenderWindow()); m_RenderingManager->ForceImmediateUpdate(mitkWidget3->GetRenderWindow()); m_RenderingManager->ForceImmediateUpdate(mitkWidget4->GetRenderWindow()); } void QmitkStdMultiWidget::wheelEvent( QWheelEvent * e ) { emit WheelMoved( e ); } void QmitkStdMultiWidget::mousePressEvent(QMouseEvent * e) { if (e->button() == Qt::LeftButton) { mitk::Point3D pointValue = this->GetLastLeftClickPosition(); emit LeftMouseClicked(pointValue); } } void QmitkStdMultiWidget::moveEvent( QMoveEvent* e ) { QWidget::moveEvent( e ); // it is necessary to readjust the position of the overlays as the StdMultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } void QmitkStdMultiWidget::leaveEvent ( QEvent * /*e*/ ) { //set cursor back to initial state m_SlicesRotator->ResetMouseCursor(); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow1() const { return mitkWidget1; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow2() const { return mitkWidget2; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow3() const { return mitkWidget3; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow4() const { return mitkWidget4; } const mitk::Point3D& QmitkStdMultiWidget::GetLastLeftClickPosition() const { return m_LastLeftClickPositionSupplier->GetCurrentPoint(); } const mitk::Point3D QmitkStdMultiWidget::GetCrossPosition() const { const mitk::PlaneGeometry *plane1 = mitkWidget1->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry *plane2 = mitkWidget2->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry *plane3 = mitkWidget3->GetSliceNavigationController()->GetCurrentPlaneGeometry(); mitk::Line3D line; if ( (plane1 != NULL) && (plane2 != NULL) && (plane1->IntersectionLine( plane2, line )) ) { mitk::Point3D point; if ( (plane3 != NULL) && (plane3->IntersectionPoint( line, point )) ) { return point; } } return m_LastLeftClickPositionSupplier->GetCurrentPoint(); } void QmitkStdMultiWidget::EnablePositionTracking() { if (!m_PositionTracker) { m_PositionTracker = mitk::PositionTracker::New("PositionTracker", NULL); } mitk::GlobalInteraction* globalInteraction = mitk::GlobalInteraction::GetInstance(); if (globalInteraction) { if(m_DataStorage.IsNotNull()) m_DataStorage->Add(m_PositionTrackerNode); globalInteraction->AddListener(m_PositionTracker); } } void QmitkStdMultiWidget::DisablePositionTracking() { mitk::GlobalInteraction* globalInteraction = mitk::GlobalInteraction::GetInstance(); if(globalInteraction) { if (m_DataStorage.IsNotNull()) m_DataStorage->Remove(m_PositionTrackerNode); globalInteraction->RemoveListener(m_PositionTracker); } } void QmitkStdMultiWidget::EnsureDisplayContainsPoint( mitk::DisplayGeometry* displayGeometry, const mitk::Point3D& p) { mitk::Point2D pointOnPlane; displayGeometry->Map( p, pointOnPlane ); // point minus origin < width or height ==> outside ? mitk::Vector2D pointOnRenderWindow_MM; pointOnRenderWindow_MM = pointOnPlane.GetVectorFromOrigin() - displayGeometry->GetOriginInMM(); mitk::Vector2D sizeOfDisplay( displayGeometry->GetSizeInMM() ); if ( sizeOfDisplay[0] < pointOnRenderWindow_MM[0] || 0 > pointOnRenderWindow_MM[0] || sizeOfDisplay[1] < pointOnRenderWindow_MM[1] || 0 > pointOnRenderWindow_MM[1] ) { // point is not visible -> move geometry mitk::Vector2D offset( (pointOnRenderWindow_MM - sizeOfDisplay / 2.0) / displayGeometry->GetScaleFactorMMPerDisplayUnit() ); displayGeometry->MoveBy( offset ); } } void QmitkStdMultiWidget::MoveCrossToPosition(const mitk::Point3D& newPosition) { // create a PositionEvent with the given position and // tell the slice navigation controllers to move there mitk::Point2D p2d; mitk::PositionEvent event( mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow()), 0, 0, 0, mitk::Key_unknown, p2d, newPosition ); mitk::StateEvent stateEvent(mitk::EIDLEFTMOUSEBTN, &event); mitk::StateEvent stateEvent2(mitk::EIDLEFTMOUSERELEASE, &event); switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: mitkWidget1->GetSliceNavigationController()->HandleEvent( &stateEvent ); mitkWidget2->GetSliceNavigationController()->HandleEvent( &stateEvent ); mitkWidget3->GetSliceNavigationController()->HandleEvent( &stateEvent ); // just in case SNCs will develop something that depends on the mouse // button being released again mitkWidget1->GetSliceNavigationController()->HandleEvent( &stateEvent2 ); mitkWidget2->GetSliceNavigationController()->HandleEvent( &stateEvent2 ); mitkWidget3->GetSliceNavigationController()->HandleEvent( &stateEvent2 ); break; case PLANE_MODE_ROTATION: m_SlicesRotator->HandleEvent( &stateEvent ); // just in case SNCs will develop something that depends on the mouse // button being released again m_SlicesRotator->HandleEvent( &stateEvent2 ); break; case PLANE_MODE_SWIVEL: m_SlicesSwiveller->HandleEvent( &stateEvent ); // just in case SNCs will develop something that depends on the mouse // button being released again m_SlicesSwiveller->HandleEvent( &stateEvent2 ); break; } // determine if cross is now out of display // if so, move the display window EnsureDisplayContainsPoint( mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow()) ->GetDisplayGeometry(), newPosition ); EnsureDisplayContainsPoint( mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow()) ->GetDisplayGeometry(), newPosition ); EnsureDisplayContainsPoint( mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow()) ->GetDisplayGeometry(), newPosition ); // update displays m_RenderingManager->RequestUpdateAll(); } void QmitkStdMultiWidget::HandleCrosshairPositionEvent() { if(!m_PendingCrosshairPositionEvent) { m_PendingCrosshairPositionEvent=true; QTimer::singleShot(0,this,SLOT( HandleCrosshairPositionEventDelayed() ) ); } } void QmitkStdMultiWidget::HandleCrosshairPositionEventDelayed() { m_PendingCrosshairPositionEvent = false; // find image with highest layer mitk::Point3D crosshairPos = this->GetCrossPosition(); mitk::TNodePredicateDataType::Pointer isImageData = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->m_DataStorage->GetSubset(isImageData).GetPointer(); std::string statusText; mitk::Image::Pointer image; int maxlayer = -32768; mitk::BaseRenderer* baseRenderer = this->mitkWidget1->GetSliceNavigationController()->GetRenderer(); // find image with largest layer, that is the image shown on top in the render window for (unsigned int x = 0; x < nodes->size(); x++) { if ( (nodes->at(x)->GetData()->GetGeometry() != NULL) && nodes->at(x)->GetData()->GetGeometry()->IsInside(crosshairPos) ) { int layer = 0; if(!(nodes->at(x)->GetIntProperty("layer", layer))) continue; if(layer > maxlayer) { if( static_cast(nodes->at(x))->IsVisible( baseRenderer ) ) { image = dynamic_cast(nodes->at(x)->GetData()); maxlayer = layer; } } } } std::stringstream stream; mitk::Index3D p; int timestep = baseRenderer->GetTimeStep(); if(image.IsNotNull() && (image->GetTimeSteps() > timestep )) { image->GetGeometry()->WorldToIndex(crosshairPos, p); stream.precision(2); stream<<"Position: <" << std::fixed < mm"; stream<<"; Index: <"< "; mitk::ScalarType pixelValue = image->GetPixelValueByIndex(p, timestep); - if (fabs(pixelValue)>1000000) + if (fabs(pixelValue)>1000000 || fabs(pixelValue) < 0.01) { - stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, timestep)<<" "; + stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<< std::scientific<< pixelValue <<" "; } else { - stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, timestep)<<" "; + stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<< pixelValue <<" "; } } else { stream << "No image information at this position!"; } statusText = stream.str(); mitk::StatusBar::GetInstance()->DisplayGreyValueText(statusText.c_str()); - - } void QmitkStdMultiWidget::EnableNavigationControllerEventListening() { // Let NavigationControllers listen to GlobalInteraction mitk::GlobalInteraction *gi = mitk::GlobalInteraction::GetInstance(); // Listen for SliceNavigationController mitkWidget1->GetSliceNavigationController()->crosshairPositionEvent.AddListener( mitk::MessageDelegate( this, &QmitkStdMultiWidget::HandleCrosshairPositionEvent ) ); mitkWidget2->GetSliceNavigationController()->crosshairPositionEvent.AddListener( mitk::MessageDelegate( this, &QmitkStdMultiWidget::HandleCrosshairPositionEvent ) ); mitkWidget3->GetSliceNavigationController()->crosshairPositionEvent.AddListener( mitk::MessageDelegate( this, &QmitkStdMultiWidget::HandleCrosshairPositionEvent ) ); switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: gi->AddListener( mitkWidget1->GetSliceNavigationController() ); gi->AddListener( mitkWidget2->GetSliceNavigationController() ); gi->AddListener( mitkWidget3->GetSliceNavigationController() ); gi->AddListener( mitkWidget4->GetSliceNavigationController() ); break; case PLANE_MODE_ROTATION: gi->AddListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: gi->AddListener( m_SlicesSwiveller ); break; } gi->AddListener( m_TimeNavigationController ); m_CrosshairNavigationEnabled = true; } void QmitkStdMultiWidget::DisableNavigationControllerEventListening() { // Do not let NavigationControllers listen to GlobalInteraction mitk::GlobalInteraction *gi = mitk::GlobalInteraction::GetInstance(); switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: gi->RemoveListener( mitkWidget1->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget2->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget3->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget4->GetSliceNavigationController() ); break; case PLANE_MODE_ROTATION: m_SlicesRotator->ResetMouseCursor(); gi->RemoveListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: m_SlicesSwiveller->ResetMouseCursor(); gi->RemoveListener( m_SlicesSwiveller ); break; } gi->RemoveListener( m_TimeNavigationController ); m_CrosshairNavigationEnabled = false; } int QmitkStdMultiWidget::GetLayout() const { return m_Layout; } bool QmitkStdMultiWidget::GetGradientBackgroundFlag() const { return m_GradientBackgroundFlag; } void QmitkStdMultiWidget::EnableGradientBackground() { // gradient background is by default only in widget 4, otherwise // interferences between 2D rendering and VTK rendering may occur. //m_GradientBackground1->Enable(); //m_GradientBackground2->Enable(); //m_GradientBackground3->Enable(); m_GradientBackground4->Enable(); m_GradientBackgroundFlag = true; } void QmitkStdMultiWidget::DisableGradientBackground() { //m_GradientBackground1->Disable(); //m_GradientBackground2->Disable(); //m_GradientBackground3->Disable(); m_GradientBackground4->Disable(); m_GradientBackgroundFlag = false; } void QmitkStdMultiWidget::EnableDepartmentLogo() { m_LogoRendering4->Enable(); } void QmitkStdMultiWidget::DisableDepartmentLogo() { m_LogoRendering4->Disable(); } bool QmitkStdMultiWidget::IsDepartmentLogoEnabled() const { return m_LogoRendering4->IsEnabled(); } bool QmitkStdMultiWidget::IsCrosshairNavigationEnabled() const { return m_CrosshairNavigationEnabled; } mitk::SlicesRotator * QmitkStdMultiWidget::GetSlicesRotator() const { return m_SlicesRotator; } mitk::SlicesSwiveller * QmitkStdMultiWidget::GetSlicesSwiveller() const { return m_SlicesSwiveller; } void QmitkStdMultiWidget::SetWidgetPlaneVisibility(const char* widgetName, bool visible, mitk::BaseRenderer *renderer) { if (m_DataStorage.IsNotNull()) { mitk::DataNode* n = m_DataStorage->GetNamedNode(widgetName); if (n != NULL) n->SetVisibility(visible, renderer); } } void QmitkStdMultiWidget::SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer) { SetWidgetPlaneVisibility("widget1Plane", visible, renderer); SetWidgetPlaneVisibility("widget2Plane", visible, renderer); SetWidgetPlaneVisibility("widget3Plane", visible, renderer); m_RenderingManager->RequestUpdateAll(); } void QmitkStdMultiWidget::SetWidgetPlanesLocked(bool locked) { //do your job and lock or unlock slices. GetRenderWindow1()->GetSliceNavigationController()->SetSliceLocked(locked); GetRenderWindow2()->GetSliceNavigationController()->SetSliceLocked(locked); GetRenderWindow3()->GetSliceNavigationController()->SetSliceLocked(locked); } void QmitkStdMultiWidget::SetWidgetPlanesRotationLocked(bool locked) { //do your job and lock or unlock slices. GetRenderWindow1()->GetSliceNavigationController()->SetSliceRotationLocked(locked); GetRenderWindow2()->GetSliceNavigationController()->SetSliceRotationLocked(locked); GetRenderWindow3()->GetSliceNavigationController()->SetSliceRotationLocked(locked); } void QmitkStdMultiWidget::SetWidgetPlanesRotationLinked( bool link ) { m_SlicesRotator->SetLinkPlanes( link ); m_SlicesSwiveller->SetLinkPlanes( link ); emit WidgetPlanesRotationLinked( link ); } void QmitkStdMultiWidget::SetWidgetPlaneMode( int userMode ) { MITK_DEBUG << "Changing crosshair mode to " << userMode; // first of all reset left mouse button interaction to default if PACS interaction style is active m_MouseModeSwitcher->SelectMouseMode( mitk::MouseModeSwitcher::MousePointer ); emit WidgetNotifyNewCrossHairMode( userMode ); int mode = m_PlaneMode; bool link = false; // Convert user interface mode to actual mode { switch(userMode) { case 0: mode = PLANE_MODE_SLICING; link = false; break; case 1: mode = PLANE_MODE_ROTATION; link = false; break; case 2: mode = PLANE_MODE_ROTATION; link = true; break; case 3: mode = PLANE_MODE_SWIVEL; link = false; break; } } // Slice rotation linked m_SlicesRotator->SetLinkPlanes( link ); m_SlicesSwiveller->SetLinkPlanes( link ); // Do nothing if mode didn't change if ( m_PlaneMode == mode ) { return; } mitk::GlobalInteraction *gi = mitk::GlobalInteraction::GetInstance(); // Remove listeners of previous mode switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: // Notify MainTemplate GUI that this mode has been deselected emit WidgetPlaneModeSlicing( false ); gi->RemoveListener( mitkWidget1->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget2->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget3->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget4->GetSliceNavigationController() ); break; case PLANE_MODE_ROTATION: // Notify MainTemplate GUI that this mode has been deselected emit WidgetPlaneModeRotation( false ); m_SlicesRotator->ResetMouseCursor(); gi->RemoveListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: // Notify MainTemplate GUI that this mode has been deselected emit WidgetPlaneModeSwivel( false ); m_SlicesSwiveller->ResetMouseCursor(); gi->RemoveListener( m_SlicesSwiveller ); break; } // Set new mode and add corresponding listener to GlobalInteraction m_PlaneMode = mode; switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: // Notify MainTemplate GUI that this mode has been selected emit WidgetPlaneModeSlicing( true ); // Add listeners gi->AddListener( mitkWidget1->GetSliceNavigationController() ); gi->AddListener( mitkWidget2->GetSliceNavigationController() ); gi->AddListener( mitkWidget3->GetSliceNavigationController() ); gi->AddListener( mitkWidget4->GetSliceNavigationController() ); m_RenderingManager->InitializeViews(); break; case PLANE_MODE_ROTATION: // Notify MainTemplate GUI that this mode has been selected emit WidgetPlaneModeRotation( true ); // Add listener gi->AddListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: // Notify MainTemplate GUI that this mode has been selected emit WidgetPlaneModeSwivel( true ); // Add listener gi->AddListener( m_SlicesSwiveller ); break; } // Notify MainTemplate GUI that mode has changed emit WidgetPlaneModeChange(m_PlaneMode); } void QmitkStdMultiWidget::SetGradientBackgroundColors( const mitk::Color & upper, const mitk::Color & lower ) { m_GradientBackground1->SetGradientColors(upper[0], upper[1], upper[2], lower[0], lower[1], lower[2]); m_GradientBackground2->SetGradientColors(upper[0], upper[1], upper[2], lower[0], lower[1], lower[2]); m_GradientBackground3->SetGradientColors(upper[0], upper[1], upper[2], lower[0], lower[1], lower[2]); m_GradientBackground4->SetGradientColors(upper[0], upper[1], upper[2], lower[0], lower[1], lower[2]); m_GradientBackgroundFlag = true; } void QmitkStdMultiWidget::SetDepartmentLogoPath( const char * path ) { m_LogoRendering1->SetLogoSource(path); m_LogoRendering2->SetLogoSource(path); m_LogoRendering3->SetLogoSource(path); m_LogoRendering4->SetLogoSource(path); } void QmitkStdMultiWidget::SetWidgetPlaneModeToSlicing( bool activate ) { if ( activate ) { this->SetWidgetPlaneMode( PLANE_MODE_SLICING ); } } void QmitkStdMultiWidget::SetWidgetPlaneModeToRotation( bool activate ) { if ( activate ) { this->SetWidgetPlaneMode( PLANE_MODE_ROTATION ); } } void QmitkStdMultiWidget::SetWidgetPlaneModeToSwivel( bool activate ) { if ( activate ) { this->SetWidgetPlaneMode( PLANE_MODE_SWIVEL ); } } void QmitkStdMultiWidget::OnLayoutDesignChanged( int layoutDesignIndex ) { switch( layoutDesignIndex ) { case LAYOUT_DEFAULT: { this->changeLayoutToDefault(); break; } case LAYOUT_2D_IMAGES_UP: { this->changeLayoutTo2DImagesUp(); break; } case LAYOUT_2D_IMAGES_LEFT: { this->changeLayoutTo2DImagesLeft(); break; } case LAYOUT_BIG_3D: { this->changeLayoutToBig3D(); break; } case LAYOUT_WIDGET1: { this->changeLayoutToWidget1(); break; } case LAYOUT_WIDGET2: { this->changeLayoutToWidget2(); break; } case LAYOUT_WIDGET3: { this->changeLayoutToWidget3(); break; } case LAYOUT_2X_2D_AND_3D_WIDGET: { this->changeLayoutTo2x2Dand3DWidget(); break; } case LAYOUT_ROW_WIDGET_3_AND_4: { this->changeLayoutToRowWidget3And4(); break; } case LAYOUT_COLUMN_WIDGET_3_AND_4: { this->changeLayoutToColumnWidget3And4(); break; } case LAYOUT_ROW_WIDGET_SMALL3_AND_BIG4: { this->changeLayoutToRowWidgetSmall3andBig4(); break; } case LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4: { this->changeLayoutToSmallUpperWidget2Big3and4(); break; } case LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET: { this->changeLayoutToLeft2Dand3DRight2D(); break; } }; } void QmitkStdMultiWidget::UpdateAllWidgets() { mitkWidget1->resize( mitkWidget1Container->frameSize().width()-1, mitkWidget1Container->frameSize().height() ); mitkWidget1->resize( mitkWidget1Container->frameSize().width(), mitkWidget1Container->frameSize().height() ); mitkWidget2->resize( mitkWidget2Container->frameSize().width()-1, mitkWidget2Container->frameSize().height() ); mitkWidget2->resize( mitkWidget2Container->frameSize().width(), mitkWidget2Container->frameSize().height() ); mitkWidget3->resize( mitkWidget3Container->frameSize().width()-1, mitkWidget3Container->frameSize().height() ); mitkWidget3->resize( mitkWidget3Container->frameSize().width(), mitkWidget3Container->frameSize().height() ); mitkWidget4->resize( mitkWidget4Container->frameSize().width()-1, mitkWidget4Container->frameSize().height() ); mitkWidget4->resize( mitkWidget4Container->frameSize().width(), mitkWidget4Container->frameSize().height() ); } void QmitkStdMultiWidget::HideAllWidgetToolbars() { mitkWidget1->HideRenderWindowMenu(); mitkWidget2->HideRenderWindowMenu(); mitkWidget3->HideRenderWindowMenu(); mitkWidget4->HideRenderWindowMenu(); } void QmitkStdMultiWidget::ActivateMenuWidget( bool state ) { mitkWidget1->ActivateMenuWidget( state, this ); mitkWidget2->ActivateMenuWidget( state, this ); mitkWidget3->ActivateMenuWidget( state, this ); mitkWidget4->ActivateMenuWidget( state, this ); } bool QmitkStdMultiWidget::IsMenuWidgetEnabled() const { return mitkWidget1->GetActivateMenuWidgetFlag(); } void QmitkStdMultiWidget::ResetCrosshair() { if (m_DataStorage.IsNotNull()) { mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox" , mitk::BoolProperty::New(false))); mitk::NodePredicateNot::Pointer pred2 = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox" , mitk::BoolProperty::New(true))); mitk::DataStorage::SetOfObjects::ConstPointer rs = m_DataStorage->GetSubset(pred); mitk::DataStorage::SetOfObjects::ConstPointer rs2 = m_DataStorage->GetSubset(pred2); // calculate bounding geometry of these nodes mitk::TimeSlicedGeometry::Pointer bounds = m_DataStorage->ComputeBoundingGeometry3D(rs, "visible"); m_RenderingManager->InitializeViews(bounds); //m_RenderingManager->InitializeViews( m_DataStorage->ComputeVisibleBoundingGeometry3D() ); // reset interactor to normal slicing this->SetWidgetPlaneMode(PLANE_MODE_SLICING); } } void QmitkStdMultiWidget::EnableColoredRectangles() { m_RectangleRendering1->Enable(1.0, 0.0, 0.0); m_RectangleRendering2->Enable(0.0, 1.0, 0.0); m_RectangleRendering3->Enable(0.0, 0.0, 1.0); m_RectangleRendering4->Enable(1.0, 1.0, 0.0); } void QmitkStdMultiWidget::DisableColoredRectangles() { m_RectangleRendering1->Disable(); m_RectangleRendering2->Disable(); m_RectangleRendering3->Disable(); m_RectangleRendering4->Disable(); } bool QmitkStdMultiWidget::IsColoredRectanglesEnabled() const { return m_RectangleRendering1->IsEnabled(); } mitk::MouseModeSwitcher* QmitkStdMultiWidget::GetMouseModeSwitcher() { return m_MouseModeSwitcher; } void QmitkStdMultiWidget::MouseModeSelected( mitk::MouseModeSwitcher::MouseMode mouseMode ) { if ( mouseMode == 0 ) { this->EnableNavigationControllerEventListening(); } else { this->DisableNavigationControllerEventListening(); } } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane1() { return this->m_PlaneNode1; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane2() { return this->m_PlaneNode2; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane3() { return this->m_PlaneNode3; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane(int id) { switch(id) { case 1: return this->m_PlaneNode1; break; case 2: return this->m_PlaneNode2; break; case 3: return this->m_PlaneNode3; break; default: return NULL; } } diff --git a/Modules/QmitkExt/QmitkHistogramJSWidget.cpp b/Modules/QmitkExt/QmitkHistogramJSWidget.cpp new file mode 100644 index 0000000000..c0a2e33188 --- /dev/null +++ b/Modules/QmitkExt/QmitkHistogramJSWidget.cpp @@ -0,0 +1,293 @@ +/*=================================================================== + +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 "QmitkHistogramJSWidget.h" +#include "mitkPixelTypeMultiplex.h" +#include +#include "mitkRenderingManager.h" +#include "mitkBaseRenderer.h" +#include "mitkImageTimeSelector.h" +#include "mitkExtractSliceFilter.h" + +QmitkHistogramJSWidget::QmitkHistogramJSWidget(QWidget *parent) : + QWebView(parent) +{ + // set histogram type to barchart in first instance + m_UseLineGraph = false; + + // set html from source + connect(page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(AddJSObject())); + QUrl myUrl = QUrl("qrc:/qmitk/Histogram.html"); + setUrl(myUrl); + + // set Scrollbars to be always disabled + page()->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); + page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); + + m_ParametricPath = ParametricPathType::New(); +} + +QmitkHistogramJSWidget::~QmitkHistogramJSWidget() +{ + +} + +// adds an Object of Type QmitkHistogramJSWidget to the JavaScript, using QtWebkitBridge +void QmitkHistogramJSWidget::AddJSObject() +{ + page()->mainFrame()->addToJavaScriptWindowObject(QString("histogramData"), this); +} + + +// reloads WebView, everytime its size has been changed, so the size of the Histogram fits to the size of the widget +void QmitkHistogramJSWidget::resizeEvent(QResizeEvent* resizeEvent) +{ + QWebView::resizeEvent(resizeEvent); + this->reload(); +} + +// method to expose data to JavaScript by using properties +void QmitkHistogramJSWidget::ComputeHistogram(HistogramType* histogram) +{ + m_Histogram = histogram; + HistogramConstIteratorType startIt = m_Histogram->End(); + HistogramConstIteratorType endIt = m_Histogram->End(); + HistogramConstIteratorType it; + ClearData(); + unsigned int i = 0; + bool firstValue = false; + // removes frequencies of 0, which are outside the first and last bin + for (it = m_Histogram->Begin() ; it != m_Histogram->End(); ++it) + { + if (it.GetFrequency() > 0.0) + { + endIt = it; + if (!firstValue) + { + firstValue = true; + startIt = it; + } + } + } + ++endIt; + // generating Lists of measurement and frequencies + for (it = startIt ; it != endIt; ++it, ++i) + { + QVariant frequency = it.GetFrequency(); + QVariant measurement = it.GetMeasurementVector()[0]; + m_Frequency.insert(i, frequency); + m_Measurement.insert(i, measurement); + } + m_IntensityProfile = false; + this->SignalDataChanged(); +} + +void QmitkHistogramJSWidget::ClearData() +{ + m_Frequency.clear(); + m_Measurement.clear(); +} + +void QmitkHistogramJSWidget::ClearHistogram() +{ + this->ClearData(); + this->SignalDataChanged(); +} + +QList QmitkHistogramJSWidget::GetFrequency() +{ + return m_Frequency; +} + +QList QmitkHistogramJSWidget::GetMeasurement() +{ + return m_Measurement; +} + +bool QmitkHistogramJSWidget::GetUseLineGraph() +{ + return m_UseLineGraph; +} + +void QmitkHistogramJSWidget::OnBarRadioButtonSelected() +{ + m_UseLineGraph = false; + this->SignalGraphChanged(); +} + +void QmitkHistogramJSWidget::OnLineRadioButtonSelected() +{ + m_UseLineGraph = true; + this->SignalGraphChanged(); +} + +void QmitkHistogramJSWidget::SetImage(mitk::Image* image) +{ + m_Image = image; +} + +void QmitkHistogramJSWidget::SetPlanarFigure(const mitk::PlanarFigure* planarFigure) +{ + m_PlanarFigure = planarFigure; +} + +template +void ReadPixel(mitk::PixelType ptype, mitk::Image::Pointer image, mitk::Index3D indexPoint, double& value) +{ + if (image->GetDimension() == 2) + { + mitk::ImagePixelReadAccessor readAccess(image, image->GetSliceData(0)); + itk::Index<2> idx; + idx[0] = indexPoint[0]; + idx[1] = indexPoint[1]; + value = readAccess.GetPixelByIndex(idx); + } + else if (image->GetDimension() == 3) + { + mitk::ImagePixelReadAccessor readAccess(image, image->GetVolumeData(0)); + itk::Index<3> idx; + idx[0] = indexPoint[0]; + idx[1] = indexPoint[1]; + idx[2] = indexPoint[2]; + value = readAccess.GetPixelByIndex(idx); + } + else + { + //unhandled + } +} + +void QmitkHistogramJSWidget::ComputeIntensityProfile(unsigned int timeStep) +{ + this->ClearData(); + m_ParametricPath->Initialize(); + + if (m_PlanarFigure.IsNull()) + { + mitkThrow() << "PlanarFigure not set!"; + } + + if (m_Image.IsNull()) + { + mitkThrow() << "Image not set!"; + } + + // Get 2D geometry frame of PlanarFigure + mitk::Geometry2D* planarFigureGeometry2D = dynamic_cast(m_PlanarFigure->GetGeometry(0)); + if (planarFigureGeometry2D == NULL) + { + mitkThrow() << "PlanarFigure has no valid geometry!"; + } + + // Get 3D geometry from Image (needed for conversion of point to index) + mitk::Geometry3D* imageGeometry = m_Image->GetGeometry(0); + if (imageGeometry == NULL) + { + mitkThrow() << "Image has no valid geometry!"; + } + + // Get first poly-line of PlanarFigure (other possible poly-lines in PlanarFigure + // are not supported) + const VertexContainerType vertexContainer = m_PlanarFigure->GetPolyLine(0); + + VertexContainerType::const_iterator it; + for (it = vertexContainer.begin(); it != vertexContainer.end(); ++it) + { + // Map PlanarFigure 2D point to 3D point + mitk::Point3D point3D; + planarFigureGeometry2D->Map(it->Point, point3D); + + // Convert world to index coordinates + mitk::Point3D indexPoint3D; + imageGeometry->WorldToIndex(point3D, indexPoint3D); + + ParametricPathType::OutputType index; + index[0] = indexPoint3D[0]; + index[1] = indexPoint3D[1]; + index[2] = indexPoint3D[2]; + + // Add index to parametric path + m_ParametricPath->AddVertex(index); + } + + m_DerivedPath = m_ParametricPath; + + if (m_DerivedPath.IsNull()) + { + mitkThrow() << "No path set!"; + } + + // Fill item model with line profile data + double distance = 0.0; + mitk::Point3D currentWorldPoint; + + double t; + unsigned int i = 0; + for (i = 0, t = m_DerivedPath->StartOfInput(); ;++i) + { + const PathType::OutputType &continousIndex = m_DerivedPath->Evaluate(t); + + mitk::Point3D worldPoint; + imageGeometry->IndexToWorld(continousIndex, worldPoint); + + if (i == 0) + { + currentWorldPoint = worldPoint; + } + + + distance += currentWorldPoint.EuclideanDistanceTo(worldPoint); + mitk::Index3D indexPoint; + imageGeometry->WorldToIndex(worldPoint, indexPoint); + const mitk::PixelType ptype = m_Image->GetPixelType(); + double intensity = 0.0; + if (m_Image->GetDimension() == 4) + { + mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); + timeSelector->SetInput(m_Image); + timeSelector->SetTimeNr(timeStep); + timeSelector->Update(); + mitk::Image::Pointer image = timeSelector->GetOutput(); + mitkPixelTypeMultiplex3( ReadPixel, ptype, image, indexPoint, intensity); + } + else + { + mitkPixelTypeMultiplex3( ReadPixel, ptype, m_Image, indexPoint, intensity); + } + + m_Measurement.insert(i, distance); + m_Frequency.insert(i, intensity); + + // Go to next index; when iteration offset reaches zero, iteration is finished + PathType::OffsetType offset = m_DerivedPath->IncrementInput(t); + if (!(offset[0] || offset[1] || offset[2])) + { + break; + } + + currentWorldPoint = worldPoint; + } + + m_IntensityProfile = true; + m_UseLineGraph = true; + this->SignalDataChanged(); +} + +bool QmitkHistogramJSWidget::GetIntensityProfile() +{ + return m_IntensityProfile; +} diff --git a/Modules/QmitkExt/QmitkHistogramJSWidget.h b/Modules/QmitkExt/QmitkHistogramJSWidget.h new file mode 100644 index 0000000000..7d59f82199 --- /dev/null +++ b/Modules/QmitkExt/QmitkHistogramJSWidget.h @@ -0,0 +1,275 @@ +/*=================================================================== + +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 QMITKHISTOGRAMJSWIDGET_H +#define QMITKHISTOGRAMJSWIDGET_H + +#include +#include +#include +#include "QmitkExtExports.h" +#include +#include "mitkImage.h" +#include "mitkPlanarFigure.h" +#include + +/** +* \brief Widget which shows a histogram using JavaScript. +* +* This class is a QWebView. It shows the histogram for a selected image +* or segmentation. It also can display an intesity profile for +* path elements, which lais over an image. +*/ +class QmitkExt_EXPORT QmitkHistogramJSWidget : public QWebView +{ + Q_OBJECT + + /** + * \brief Measurement property. + * + * This property is used in JavaScript as member of the current object. + * It holds a QList, containing the measurements of the current histogram. + * @see GetMeasurement() + */ + Q_PROPERTY(QList measurement + READ GetMeasurement) + + /** + * \brief Frequency property. + * + * This property is used in JavaScript as member of the current object. + * It holds a QList, containing the frequencies of the current histogram. + * @see GetFrequency() + */ + Q_PROPERTY(QList frequency + READ GetFrequency) + + /** + * \brief Line graph property. + * + * This property is used in JavaScript as member of the current object. + * It holds a boolean, which sais wether to use a line or not. + * @see GetUseLineGraph() + */ + Q_PROPERTY(bool useLineGraph + READ GetUseLineGraph) + + /** + * @brief Intesity profile property. + * + * This property is used in JavaScript as member of the current object. + * It holds a boolean, which sais wether to use an intesity profile or not. + * @see GetIntensityProfile() + */ + Q_PROPERTY(bool intensityProfile + READ GetIntensityProfile) + +public: + typedef mitk::Image::HistogramType HistogramType; + typedef mitk::Image::HistogramType::ConstIterator HistogramConstIteratorType; + typedef itk::PolyLineParametricPath< 3 > ParametricPathType; + typedef itk::ParametricPath< 3 >::Superclass PathType; + typedef mitk::PlanarFigure::PolyLineType VertexContainerType; + + explicit QmitkHistogramJSWidget(QWidget *parent = 0); + + + ~QmitkHistogramJSWidget(); + + /** + * \brief Event which notifies a change of the widget size. + * + * Reimplemented from QWebView::resizeEvent(), + * reloads the webframe + */ + void resizeEvent(QResizeEvent* resizeEvent); + + /** + * \brief Calculates the histogram. + * + * This function removes all frequencies of 0 until the first bin and behind the last bin. + * It writes the measurement and frequency, which are given from the HistogramType, into + * m_Measurement and m_Frequency. + * The SignalDataChanged is called, to update the information, which is displayed in the webframe. + */ + void ComputeHistogram(HistogramType* histogram); + + /** + * \brief Calculates the intesityprofile. + * + * If an image and a pathelement are set, this function + * calculates an intensity profile for a pathelement which lies over an image. + * Sets m_IntensityProfile and m_UseLineGraph to true. + * The SignalDataChanged is called, to update the information, which is displayed in the webframe. + */ + void ComputeIntensityProfile(unsigned int timeStep = 0); + + /** + * \brief Clears the Histogram. + * + * This function clears the data and calls SignalDataChanged to update + * the displayed information in the webframe. + */ + void ClearHistogram(); + + /** + * \brief Getter for measurement. + * + * @return List of measurements. + */ + QList GetMeasurement(); + + /** + * \brief Getter for frequency. + * + * @return List of frequencies. + */ + QList GetFrequency(); + + /** + * \brief Getter for uselineGraph. + * + * @return True if a linegraph should be used. + */ + bool GetUseLineGraph(); + + /** + * \brief Getter for intensity profile. + * + * @return True if current histogram is an intesityprofile + */ + bool GetIntensityProfile(); + + /** + * \brief Setter for reference image. + * + * @param image The corresponding image for an intensity profile. + */ + void SetImage(mitk::Image* image); + + /** + * \brief Setter for planarFigure. + * + * @param planarFigure The pathelement for an intensity profile. + */ + void SetPlanarFigure(const mitk::PlanarFigure* planarFigure); + +private: + + /** + * \brief List of frequencies. + * + * A QList which holds the frequencies of the current histogram + * or holds the intesities of current intensity profile. + */ + QList m_Frequency; + + /** + * \brief List of measurements. + * + * A QList which holds the measurements of the current histogram + * or holds the distances of current intensity profile. + */ + QList m_Measurement; + + /** + * \brief Reference image. + * + * Holds the image to calculate an intesity profile. + */ + mitk::Image::Pointer m_Image; + + /** + * \brief Pathelement. + * + * Holds a not closed planar figure to calculate an intesity profile. + */ + mitk::PlanarFigure::ConstPointer m_PlanarFigure; + + bool m_UseLineGraph; + bool m_IntensityProfile; + + /** + * Holds the current histogram + */ + HistogramType::ConstPointer m_Histogram; + + /** + * Path derived either form user-specified path or from PlanarFigure-generated + * path + */ + PathType::ConstPointer m_DerivedPath; + + /** + * Parametric path as generated from PlanarFigure + */ + ParametricPathType::Pointer m_ParametricPath; + + /** + * \brief Clears data. + * + * Clears the QLists m_Measurement and m_Frequency + */ + void ClearData(); + +private slots: + + /** + * \brief Adds an object to JavaScript. + * + * Adds an object of the widget to JavaScript. + * By using this object JavaScript can react to the signals of the widget + * and can access the QProperties as members of the object. + */ + void AddJSObject(); + +public slots: + + /** + * \brief Slot for radiobutton m_barRadioButton. + * + * Sets m_UseLineGraph to false. + * Calls signal GraphChanged to update the graph in the webframe. + */ + void OnBarRadioButtonSelected(); + + /** + * \brief Slot for radiobutton m_lineRadioButton. + * + * Sets m_UseLineGraph to true. + * Calls signal GraphChanged to update the graph in the webframe. + */ + void OnLineRadioButtonSelected(); + +signals: + + /** + * \brief Signal data has changed. + * + * It has to be called when the data of the histogram or intesity profile has changed. + */ + void SignalDataChanged(); + + /** + * \brief Signal graph has changed. + * + * It has to be called when the graph changed from barchart to linegraph. Vice versa. + */ + void SignalGraphChanged(); +}; + +#endif // QMITKHISTOGRAMJSWIDGET_H diff --git a/Modules/QmitkExt/QmitkSlicesInterpolator.cpp b/Modules/QmitkExt/QmitkSlicesInterpolator.cpp index 275e571f7d..8e89b7ba79 100644 --- a/Modules/QmitkExt/QmitkSlicesInterpolator.cpp +++ b/Modules/QmitkExt/QmitkSlicesInterpolator.cpp @@ -1,1076 +1,1079 @@ /*=================================================================== 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 "QmitkSlicesInterpolator.h" #include "QmitkStdMultiWidget.h" #include "QmitkSelectableGLWidget.h" #include "mitkToolManager.h" #include "mitkDataNodeFactory.h" #include "mitkLevelWindowProperty.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkProgressBar.h" #include "mitkGlobalInteraction.h" #include "mitkOperationEvent.h" #include "mitkUndoController.h" #include "mitkInteractionConst.h" #include "mitkApplyDiffImageOperation.h" #include "mitkDiffImageApplier.h" #include "mitkSegTool2D.h" #include "mitkCoreObjectFactory.h" #include "mitkSurfaceToImageFilter.h" #include #include #include #include #include #include #include #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) const std::map QmitkSlicesInterpolator::createActionToSliceDimension() { std::map actionToSliceDimension; actionToSliceDimension[new QAction("Axial (red window)", 0)] = 2; actionToSliceDimension[new QAction("Sagittal (green window)", 0)] = 0; actionToSliceDimension[new QAction("Coronal (blue window)", 0)] = 1; return actionToSliceDimension; } QmitkSlicesInterpolator::QmitkSlicesInterpolator(QWidget* parent, const char* /*name*/) :QWidget(parent), ACTION_TO_SLICEDIMENSION( createActionToSliceDimension() ), m_Interpolator( mitk::SegmentationInterpolationController::New() ), m_MultiWidget(NULL), m_ToolManager(NULL), m_Initialized(false), m_LastSliceDimension(2), m_LastSliceIndex(0), m_2DInterpolationEnabled(false), m_3DInterpolationEnabled(false) { m_SurfaceInterpolator = mitk::SurfaceInterpolationController::GetInstance(); QHBoxLayout* layout = new QHBoxLayout(this); m_GroupBoxEnableExclusiveInterpolationMode = new QGroupBox("Interpolation", this); QGridLayout* grid = new QGridLayout(m_GroupBoxEnableExclusiveInterpolationMode); m_RBtnEnable3DInterpolation = new QRadioButton("3D",this); connect(m_RBtnEnable3DInterpolation, SIGNAL(toggled(bool)), this, SLOT(On3DInterpolationEnabled(bool))); m_RBtnEnable3DInterpolation->setChecked(true); + m_RBtnEnable3DInterpolation->setToolTip("Interpolate a binary volume from a set of arbitrarily arranged contours."); grid->addWidget(m_RBtnEnable3DInterpolation,0,0); m_BtnAccept3DInterpolation = new QPushButton("Accept", this); m_BtnAccept3DInterpolation->setEnabled(false); connect(m_BtnAccept3DInterpolation, SIGNAL(clicked()), this, SLOT(OnAccept3DInterpolationClicked())); grid->addWidget(m_BtnAccept3DInterpolation, 0,1); m_CbShowMarkers = new QCheckBox("Show Position Nodes", this); m_CbShowMarkers->setChecked(false); connect(m_CbShowMarkers, SIGNAL(toggled(bool)), this, SLOT(OnShowMarkers(bool))); connect(m_CbShowMarkers, SIGNAL(toggled(bool)), this, SIGNAL(SignalShowMarkerNodes(bool))); grid->addWidget(m_CbShowMarkers,0,2); m_RBtnEnable2DInterpolation = new QRadioButton("2D",this); connect(m_RBtnEnable2DInterpolation, SIGNAL(toggled(bool)), this, SLOT(On2DInterpolationEnabled(bool))); + m_RBtnEnable2DInterpolation ->setToolTip("Interpolate contours in left-out slices from a set of slice-by-slice arranged contours."); grid->addWidget(m_RBtnEnable2DInterpolation,1,0); m_BtnAcceptInterpolation = new QPushButton("Accept", this); m_BtnAcceptInterpolation->setEnabled( false ); connect( m_BtnAcceptInterpolation, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked()) ); grid->addWidget(m_BtnAcceptInterpolation,1,1); m_BtnAcceptAllInterpolations = new QPushButton("... for all slices", this); m_BtnAcceptAllInterpolations->setEnabled( false ); connect( m_BtnAcceptAllInterpolations, SIGNAL(clicked()), this, SLOT(OnAcceptAllInterpolationsClicked()) ); grid->addWidget(m_BtnAcceptAllInterpolations,1,2); m_RBtnDisableInterpolation = new QRadioButton("Disable", this); connect(m_RBtnDisableInterpolation, SIGNAL(toggled(bool)), this, SLOT(OnInterpolationDisabled(bool))); + m_RBtnDisableInterpolation->setToolTip("Disable interpolation."); grid->addWidget(m_RBtnDisableInterpolation, 2,0); layout->addWidget(m_GroupBoxEnableExclusiveInterpolationMode); this->setLayout(layout); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnInterpolationInfoChanged ); InterpolationInfoChangedObserverTag = m_Interpolator->AddObserver( itk::ModifiedEvent(), command ); itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged ); SurfaceInterpolationInfoChangedObserverTag = m_SurfaceInterpolator->AddObserver( itk::ModifiedEvent(), command2 ); // feedback node and its visualization properties m_FeedbackNode = mitk::DataNode::New(); mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties( m_FeedbackNode ); m_FeedbackNode->SetProperty( "binary", mitk::BoolProperty::New(true) ); m_FeedbackNode->SetProperty( "outline binary", mitk::BoolProperty::New(true) ); m_FeedbackNode->SetProperty( "color", mitk::ColorProperty::New(255.0, 255.0, 0.0) ); m_FeedbackNode->SetProperty( "texture interpolation", mitk::BoolProperty::New(false) ); m_FeedbackNode->SetProperty( "layer", mitk::IntProperty::New( 20 ) ); m_FeedbackNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( mitk::LevelWindow(0, 1) ) ); m_FeedbackNode->SetProperty( "name", mitk::StringProperty::New("Interpolation feedback") ); m_FeedbackNode->SetProperty( "opacity", mitk::FloatProperty::New(0.8) ); m_FeedbackNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_InterpolatedSurfaceNode = mitk::DataNode::New(); m_InterpolatedSurfaceNode->SetProperty( "color", mitk::ColorProperty::New(255.0,255.0,0.0) ); m_InterpolatedSurfaceNode->SetProperty( "name", mitk::StringProperty::New("Surface Interpolation feedback") ); m_InterpolatedSurfaceNode->SetProperty( "opacity", mitk::FloatProperty::New(0.5) ); m_InterpolatedSurfaceNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); m_InterpolatedSurfaceNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_InterpolatedSurfaceNode->SetVisibility(false); m_3DContourNode = mitk::DataNode::New(); m_3DContourNode->SetProperty( "color", mitk::ColorProperty::New(0.0, 0.0, 0.0) ); m_3DContourNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty( "name", mitk::StringProperty::New("Drawn Contours") ); m_3DContourNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); m_3DContourNode->SetProperty("material.wireframeLineWidth", mitk::FloatProperty::New(2.0f)); m_3DContourNode->SetProperty("3DContourContainer", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); QWidget::setContentsMargins(0, 0, 0, 0); if ( QWidget::layout() != NULL ) { QWidget::layout()->setContentsMargins(0, 0, 0, 0); } //For running 3D Interpolation in background // create a QFuture and a QFutureWatcher connect(&m_Watcher, SIGNAL(started()), this, SLOT(StartUpdateInterpolationTimer())); connect(&m_Watcher, SIGNAL(finished()), this, SLOT(OnSurfaceInterpolationFinished())); connect(&m_Watcher, SIGNAL(finished()), this, SLOT(StopUpdateInterpolationTimer())); m_Timer = new QTimer(this); connect(m_Timer, SIGNAL(timeout()), this, SLOT(ChangeSurfaceColor())); } void QmitkSlicesInterpolator::SetDataStorage( mitk::DataStorage& storage ) { m_DataStorage = &storage; m_SurfaceInterpolator->SetDataStorage(storage); } mitk::DataStorage* QmitkSlicesInterpolator::GetDataStorage() { if ( m_DataStorage.IsNotNull() ) { return m_DataStorage; } else { return NULL; } } void QmitkSlicesInterpolator::Initialize(mitk::ToolManager* toolManager, QmitkStdMultiWidget* multiWidget) { if (m_Initialized) { // remove old observers if (m_ToolManager) { m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified ); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified ); } if (m_MultiWidget) { disconnect( m_MultiWidget, SIGNAL(destroyed(QObject*)), this, SLOT(OnMultiWidgetDeleted(QObject*)) ); mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); slicer->RemoveObserver( TSliceObserverTag ); slicer->RemoveObserver( TTimeObserverTag ); slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); slicer->RemoveObserver( SSliceObserverTag ); slicer->RemoveObserver( STimeObserverTag ); slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); slicer->RemoveObserver( FSliceObserverTag ); slicer->RemoveObserver( FTimeObserverTag ); } //return; } m_MultiWidget = multiWidget; connect( m_MultiWidget, SIGNAL(destroyed(QObject*)), this, SLOT(OnMultiWidgetDeleted(QObject*)) ); m_ToolManager = toolManager; if (m_ToolManager) { // set enabled only if a segmentation is selected mitk::DataNode* node = m_ToolManager->GetWorkingData(0); QWidget::setEnabled( node != NULL ); // react whenever the set of selected segmentation changes m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified ); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified ); // connect to the steppers of the three multi widget widgets. after each change, call the interpolator if (m_MultiWidget) { mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); m_TimeStep.resize(3); m_TimeStep[2] = slicer->GetTime()->GetPos(); { itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnAxialTimeChanged ); TTimeObserverTag = slicer->AddObserver( mitk::SliceNavigationController::GeometryTimeEvent(NULL, 0), command ); } { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnAxialSliceChanged ); TSliceObserverTag = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } // connect to the steppers of the three multi widget widgets. after each change, call the interpolator slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); m_TimeStep[0] = slicer->GetTime()->GetPos(); { itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSagittalTimeChanged ); STimeObserverTag = slicer->AddObserver( mitk::SliceNavigationController::GeometryTimeEvent(NULL, 0), command ); } { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSagittalSliceChanged ); SSliceObserverTag = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } // connect to the steppers of the three multi widget widgets. after each change, call the interpolator slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); m_TimeStep[1] = slicer->GetTime()->GetPos(); { itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnFrontalTimeChanged ); FTimeObserverTag = slicer->AddObserver( mitk::SliceNavigationController::GeometryTimeEvent(NULL, 0), command ); } { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnFrontalSliceChanged ); FSliceObserverTag = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } } } m_Initialized = true; } QmitkSlicesInterpolator::~QmitkSlicesInterpolator() { if (m_MultiWidget) { mitk::SliceNavigationController* slicer; if(m_MultiWidget->mitkWidget1 != NULL) { slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); slicer->RemoveObserver( TSliceObserverTag ); slicer->RemoveObserver( TTimeObserverTag ); } if(m_MultiWidget->mitkWidget2 != NULL) { slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); slicer->RemoveObserver( SSliceObserverTag ); slicer->RemoveObserver( STimeObserverTag ); } if(m_MultiWidget->mitkWidget3 != NULL) { slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); slicer->RemoveObserver( FSliceObserverTag ); slicer->RemoveObserver( FTimeObserverTag ); } } if(m_DataStorage->Exists(m_3DContourNode)) m_DataStorage->Remove(m_3DContourNode); if(m_DataStorage->Exists(m_InterpolatedSurfaceNode)) m_DataStorage->Remove(m_InterpolatedSurfaceNode); // remove observer m_Interpolator->RemoveObserver( InterpolationInfoChangedObserverTag ); m_SurfaceInterpolator->RemoveObserver( SurfaceInterpolationInfoChangedObserverTag ); delete m_Timer; } void QmitkSlicesInterpolator::On2DInterpolationEnabled(bool status) { OnInterpolationActivated(status); m_Interpolator->Activate2DInterpolation(status); } void QmitkSlicesInterpolator::On3DInterpolationEnabled(bool status) { On3DInterpolationActivated(status); } void QmitkSlicesInterpolator::OnInterpolationDisabled(bool status) { if (status) { OnInterpolationActivated(!status); On3DInterpolationActivated(!status); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::OnShowMarkers(bool state) { mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = m_DataStorage->GetSubset(mitk::NodePredicateProperty::New("isContourMarker" , mitk::BoolProperty::New(true))); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { it->Value()->SetProperty("helper object", mitk::BoolProperty::New(!state)); } } void QmitkSlicesInterpolator::OnToolManagerWorkingDataModified() { //Check if the new working data has already a contourlist for 3D interpolation this->SetCurrentContourListID(); if (m_2DInterpolationEnabled) { OnInterpolationActivated( true ); // re-initialize if needed } if (m_3DInterpolationEnabled) { //On3DInterpolationActivated( true); SetCurrentContourListID(); } } void QmitkSlicesInterpolator::OnToolManagerReferenceDataModified() { if (m_2DInterpolationEnabled) { OnInterpolationActivated( true ); // re-initialize if needed } if (m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::OnAxialTimeChanged(itk::Object* sender, const itk::EventObject& e) { const mitk::SliceNavigationController::GeometryTimeEvent& event = dynamic_cast(e); m_TimeStep[2] = event.GetPos(); if (m_LastSliceDimension == 2) { mitk::SliceNavigationController* snc = dynamic_cast( sender ); if (snc) snc->SendSlice(); // will trigger a new interpolation } } void QmitkSlicesInterpolator::OnTransversalTimeChanged(itk::Object* sender, const itk::EventObject& e) { this->OnAxialTimeChanged(sender, e); } void QmitkSlicesInterpolator::OnSagittalTimeChanged(itk::Object* sender, const itk::EventObject& e) { const mitk::SliceNavigationController::GeometryTimeEvent& event = dynamic_cast(e); m_TimeStep[0] = event.GetPos(); if (m_LastSliceDimension == 0) { mitk::SliceNavigationController* snc = dynamic_cast( sender ); if (snc) snc->SendSlice(); // will trigger a new interpolation } } void QmitkSlicesInterpolator::OnFrontalTimeChanged(itk::Object* sender, const itk::EventObject& e) { const mitk::SliceNavigationController::GeometryTimeEvent& event = dynamic_cast(e); m_TimeStep[1] = event.GetPos(); if (m_LastSliceDimension == 1) { mitk::SliceNavigationController* snc = dynamic_cast( sender ); if (snc) snc->SendSlice(); // will trigger a new interpolation } } void QmitkSlicesInterpolator::OnAxialSliceChanged(const itk::EventObject& e) { if ( TranslateAndInterpolateChangedSlice( e, 2 ) ) { if (m_MultiWidget) { mitk::BaseRenderer::GetInstance(m_MultiWidget->mitkWidget1->GetRenderWindow())->RequestUpdate(); } } } void QmitkSlicesInterpolator::OnTransversalSliceChanged(const itk::EventObject& e) { this->OnAxialSliceChanged(e); } void QmitkSlicesInterpolator::OnSagittalSliceChanged(const itk::EventObject& e) { if ( TranslateAndInterpolateChangedSlice( e, 0 ) ) { if (m_MultiWidget) { mitk::BaseRenderer::GetInstance(m_MultiWidget->mitkWidget2->GetRenderWindow())->RequestUpdate(); } } } void QmitkSlicesInterpolator::OnFrontalSliceChanged(const itk::EventObject& e) { if ( TranslateAndInterpolateChangedSlice( e, 1 ) ) { if (m_MultiWidget) { mitk::BaseRenderer::GetInstance(m_MultiWidget->mitkWidget3->GetRenderWindow())->RequestUpdate(); } } } bool QmitkSlicesInterpolator::TranslateAndInterpolateChangedSlice(const itk::EventObject& e, unsigned int windowID) { if (!m_2DInterpolationEnabled) return false; try { const mitk::SliceNavigationController::GeometrySliceEvent& event = dynamic_cast(e); mitk::TimeSlicedGeometry* tsg = event.GetTimeSlicedGeometry(); if (tsg && m_TimeStep.size() > windowID) { mitk::SlicedGeometry3D* slicedGeometry = dynamic_cast(tsg->GetGeometry3D(m_TimeStep[windowID])); if (slicedGeometry) { mitk::PlaneGeometry* plane = dynamic_cast(slicedGeometry->GetGeometry2D( event.GetPos() )); if (plane) Interpolate( plane, m_TimeStep[windowID] ); return true; } } } catch(std::bad_cast) { return false; // so what } return false; } void QmitkSlicesInterpolator::Interpolate( mitk::PlaneGeometry* plane, unsigned int timeStep ) { if (m_ToolManager) { mitk::DataNode* node = m_ToolManager->GetWorkingData(0); if (node) { m_Segmentation = dynamic_cast(node->GetData()); if (m_Segmentation) { int clickedSliceDimension(-1); int clickedSliceIndex(-1); // calculate real slice position, i.e. slice of the image and not slice of the TimeSlicedGeometry mitk::SegTool2D::DetermineAffectedImageSlice( m_Segmentation, plane, clickedSliceDimension, clickedSliceIndex ); mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( clickedSliceDimension, clickedSliceIndex, timeStep ); m_FeedbackNode->SetData( interpolation ); // Workaround for Bug 11318 if ((interpolation.IsNotNull()) && (interpolation->GetGeometry() != NULL)) { if(clickedSliceDimension == 1) { mitk::Point3D orig = interpolation->GetGeometry()->GetOrigin(); orig[0] = orig[0]; orig[1] = orig[1] + 0.5; orig[2] = orig[2]; interpolation->GetGeometry()->SetOrigin(orig); } } // Workaround for Bug 11318 END m_LastSliceDimension = clickedSliceDimension; m_LastSliceIndex = clickedSliceIndex; } } } } void QmitkSlicesInterpolator::OnSurfaceInterpolationFinished() { mitk::Surface::Pointer interpolatedSurface = m_SurfaceInterpolator->GetInterpolationResult(); if(interpolatedSurface.IsNotNull()) { m_BtnAccept3DInterpolation->setEnabled(true); m_InterpolatedSurfaceNode->SetData(interpolatedSurface); m_3DContourNode->SetData(m_SurfaceInterpolator->GetContoursAsSurface()); this->Show3DInterpolationResult(true); if( !m_DataStorage->Exists(m_InterpolatedSurfaceNode) && !m_DataStorage->Exists(m_3DContourNode)) { m_DataStorage->Add(m_3DContourNode); m_DataStorage->Add(m_InterpolatedSurfaceNode); } } else if (interpolatedSurface.IsNull()) { m_BtnAccept3DInterpolation->setEnabled(false); if (m_DataStorage->Exists(m_InterpolatedSurfaceNode)) { this->Show3DInterpolationResult(false); } } if (m_MultiWidget) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::OnAcceptInterpolationClicked() { if (m_Segmentation && m_FeedbackNode->GetData()) { //making interpolation separately undoable mitk::UndoStackItem::IncCurrObjectEventId(); mitk::UndoStackItem::IncCurrGroupEventId(); mitk::UndoStackItem::ExecuteIncrement(); mitk::OverwriteSliceImageFilter::Pointer slicewriter = mitk::OverwriteSliceImageFilter::New(); slicewriter->SetInput( m_Segmentation ); slicewriter->SetCreateUndoInformation( true ); slicewriter->SetSliceImage( dynamic_cast(m_FeedbackNode->GetData()) ); slicewriter->SetSliceDimension( m_LastSliceDimension ); slicewriter->SetSliceIndex( m_LastSliceIndex ); slicewriter->SetTimeStep( m_TimeStep[m_LastSliceDimension] ); slicewriter->Update(); m_FeedbackNode->SetData(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::AcceptAllInterpolations(unsigned int windowID) { // first creates a 3D diff image, then applies this diff to the segmentation if (m_Segmentation) { int sliceDimension(-1); int dummySliceIndex(-1); if (!GetSliceForWindowsID(windowID, sliceDimension, dummySliceIndex)) { return; // cannot determine slice orientation } //making interpolation separately undoable mitk::UndoStackItem::IncCurrObjectEventId(); mitk::UndoStackItem::IncCurrGroupEventId(); mitk::UndoStackItem::ExecuteIncrement(); // create a diff image for the undo operation mitk::Image::Pointer diffImage = mitk::Image::New(); diffImage->Initialize( m_Segmentation ); mitk::PixelType pixelType( mitk::MakeScalarPixelType() ); diffImage->Initialize( pixelType, 3, m_Segmentation->GetDimensions() ); memset( diffImage->GetData(), 0, (pixelType.GetBpe() >> 3) * diffImage->GetDimension(0) * diffImage->GetDimension(1) * diffImage->GetDimension(2) ); // now the diff image is all 0 unsigned int timeStep( m_TimeStep[windowID] ); // a slicewriter to create the diff image mitk::OverwriteSliceImageFilter::Pointer diffslicewriter = mitk::OverwriteSliceImageFilter::New(); diffslicewriter->SetCreateUndoInformation( false ); diffslicewriter->SetInput( diffImage ); diffslicewriter->SetSliceDimension( sliceDimension ); diffslicewriter->SetTimeStep( timeStep ); unsigned int totalChangedSlices(0); unsigned int zslices = m_Segmentation->GetDimension( sliceDimension ); mitk::ProgressBar::GetInstance()->AddStepsToDo(zslices); for (unsigned int sliceIndex = 0; sliceIndex < zslices; ++sliceIndex) { mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( sliceDimension, sliceIndex, timeStep ); if (interpolation.IsNotNull()) // we don't check if interpolation is necessary/sensible - but m_Interpolator does { diffslicewriter->SetSliceImage( interpolation ); diffslicewriter->SetSliceIndex( sliceIndex ); diffslicewriter->Update(); ++totalChangedSlices; } mitk::ProgressBar::GetInstance()->Progress(); } if (totalChangedSlices > 0) { // store undo stack items if ( true ) { // create do/undo operations (we don't execute the doOp here, because it has already been executed during calculation of the diff image mitk::ApplyDiffImageOperation* doOp = new mitk::ApplyDiffImageOperation( mitk::OpTEST, m_Segmentation, diffImage, timeStep ); mitk::ApplyDiffImageOperation* undoOp = new mitk::ApplyDiffImageOperation( mitk::OpTEST, m_Segmentation, diffImage, timeStep ); undoOp->SetFactor( -1.0 ); std::stringstream comment; comment << "Accept all interpolations (" << totalChangedSlices << ")"; mitk::OperationEvent* undoStackItem = new mitk::OperationEvent( mitk::DiffImageApplier::GetInstanceForUndo(), doOp, undoOp, comment.str() ); mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); // acutally apply the changes here mitk::DiffImageApplier::GetInstanceForUndo()->ExecuteOperation( doOp ); } } m_FeedbackNode->SetData(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::FinishInterpolation(int windowID) { //this redirect is for calling from outside if (windowID < 0) OnAcceptAllInterpolationsClicked(); else AcceptAllInterpolations( (unsigned int)windowID ); } void QmitkSlicesInterpolator::OnAcceptAllInterpolationsClicked() { QMenu orientationPopup(this); std::map::const_iterator it; for(it = ACTION_TO_SLICEDIMENSION.begin(); it != ACTION_TO_SLICEDIMENSION.end(); it++) orientationPopup.addAction(it->first); connect( &orientationPopup, SIGNAL(triggered(QAction*)), this, SLOT(OnAcceptAllPopupActivated(QAction*)) ); orientationPopup.exec( QCursor::pos() ); } void QmitkSlicesInterpolator::OnAccept3DInterpolationClicked() { if (m_InterpolatedSurfaceNode.IsNotNull() && m_InterpolatedSurfaceNode->GetData()) { mitk::SurfaceToImageFilter::Pointer s2iFilter = mitk::SurfaceToImageFilter::New(); s2iFilter->MakeOutputBinaryOn(); s2iFilter->SetInput(dynamic_cast(m_InterpolatedSurfaceNode->GetData())); // check if ToolManager holds valid ReferenceData if (m_ToolManager->GetReferenceData(0) == NULL) { return; } s2iFilter->SetImage(dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData())); s2iFilter->Update(); mitk::DataNode* segmentationNode = m_ToolManager->GetWorkingData(0); segmentationNode->SetData(s2iFilter->GetOutput()); m_RBtnDisableInterpolation->setChecked(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::OnAcceptAllPopupActivated(QAction* action) { try { std::map::const_iterator iter = ACTION_TO_SLICEDIMENSION.find( action ); if (iter != ACTION_TO_SLICEDIMENSION.end()) { int windowID = iter->second; AcceptAllInterpolations( windowID ); } } catch(...) { /* Showing message box with possible memory error */ QMessageBox errorInfo; errorInfo.setWindowTitle("Interpolation Process"); errorInfo.setIcon(QMessageBox::Critical); errorInfo.setText("An error occurred during interpolation. Possible cause: Not enough memory!"); errorInfo.exec(); //additional error message on std::cerr std::cerr << "Ill construction in " __FILE__ " l. " << __LINE__ << std::endl; } } void QmitkSlicesInterpolator::OnInterpolationActivated(bool on) { m_2DInterpolationEnabled = on; try { if ( m_DataStorage.IsNotNull() ) { if (on && !m_DataStorage->Exists(m_FeedbackNode)) { m_DataStorage->Add( m_FeedbackNode ); } //else //{ // m_DataStorage->Remove( m_FeedbackNode ); //} } } catch(...) { // don't care (double add/remove) } if (m_ToolManager) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); QWidget::setEnabled( workingNode != NULL ); m_BtnAcceptAllInterpolations->setEnabled( on ); m_BtnAcceptInterpolation->setEnabled( on ); m_FeedbackNode->SetVisibility( on ); if (!on) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } if (workingNode) { mitk::Image* segmentation = dynamic_cast(workingNode->GetData()); if (segmentation) { m_Interpolator->SetSegmentationVolume( segmentation ); if (referenceNode) { mitk::Image* referenceImage = dynamic_cast(referenceNode->GetData()); m_Interpolator->SetReferenceVolume( referenceImage ); // may be NULL } } } } UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::Run3DInterpolation() { m_SurfaceInterpolator->Interpolate(); } void QmitkSlicesInterpolator::StartUpdateInterpolationTimer() { m_Timer->start(500); } void QmitkSlicesInterpolator::StopUpdateInterpolationTimer() { m_Timer->stop(); m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(255.0,255.0,0.0)); mitk::RenderingManager::GetInstance()->RequestUpdate(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); } void QmitkSlicesInterpolator::ChangeSurfaceColor() { float currentColor[3]; m_InterpolatedSurfaceNode->GetColor(currentColor); float yellow[3] = {255.0,255.0,0.0}; if( currentColor[2] == yellow[2]) { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(255.0,255.0,255.0)); } else { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(yellow)); } m_InterpolatedSurfaceNode->Update(); mitk::RenderingManager::GetInstance()->RequestUpdate(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); } void QmitkSlicesInterpolator::On3DInterpolationActivated(bool on) { m_3DInterpolationEnabled = on; try { if ( m_DataStorage.IsNotNull() && m_ToolManager && m_3DInterpolationEnabled) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { bool isInterpolationResult(false); workingNode->GetBoolProperty("3DInterpolationResult",isInterpolationResult); if ((workingNode->IsSelected() && workingNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) && !isInterpolationResult && m_3DInterpolationEnabled) { int ret = QMessageBox::Yes; if (m_SurfaceInterpolator->EstimatePortionOfNeededMemory() > 0.5) { QMessageBox msgBox; msgBox.setText("Due to short handed system memory the 3D interpolation may be very slow!"); msgBox.setInformativeText("Are you sure you want to activate the 3D interpolation?"); msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); ret = msgBox.exec(); } if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); if (ret == QMessageBox::Yes) { m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } else { m_RBtnDisableInterpolation->toggle(); } } else if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnAccept3DInterpolation->setEnabled(m_3DInterpolationEnabled); } } else { QWidget::setEnabled( false ); m_CbShowMarkers->setEnabled(m_3DInterpolationEnabled); } } if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnAccept3DInterpolation->setEnabled(m_3DInterpolationEnabled); } } catch(...) { MITK_ERROR<<"Error with 3D surface interpolation!"; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::EnableInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated OnInterpolationActivated(on); } void QmitkSlicesInterpolator::Enable3DInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated On3DInterpolationActivated(on); } void QmitkSlicesInterpolator::UpdateVisibleSuggestion() { if (m_2DInterpolationEnabled) { // determine which one is the current view, try to do an initial interpolation mitk::BaseRenderer* renderer = mitk::GlobalInteraction::GetInstance()->GetFocus(); if (renderer && renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) { const mitk::TimeSlicedGeometry* timeSlicedGeometry = dynamic_cast( renderer->GetWorldGeometry() ); if (timeSlicedGeometry) { mitk::SliceNavigationController::GeometrySliceEvent event( const_cast(timeSlicedGeometry), renderer->GetSlice() ); if ( renderer->GetCurrentWorldGeometry2DNode() ) { if ( renderer->GetCurrentWorldGeometry2DNode()==this->m_MultiWidget->GetWidgetPlane1() ) { TranslateAndInterpolateChangedSlice( event, 2 ); } else if ( renderer->GetCurrentWorldGeometry2DNode()==this->m_MultiWidget->GetWidgetPlane2() ) { TranslateAndInterpolateChangedSlice( event, 0 ); } else if ( renderer->GetCurrentWorldGeometry2DNode()==this->m_MultiWidget->GetWidgetPlane3() ) { TranslateAndInterpolateChangedSlice( event, 1 ); } } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::OnInterpolationInfoChanged(const itk::EventObject& /*e*/) { // something (e.g. undo) changed the interpolation info, we should refresh our display UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged(const itk::EventObject& /*e*/) { if(m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } bool QmitkSlicesInterpolator::GetSliceForWindowsID(unsigned windowID, int& sliceDimension, int& sliceIndex) { mitk::BaseRenderer* renderer(NULL); // find sliceDimension for windowID: // windowID 2: axial window = renderWindow1 // windowID 1: frontal window = renderWindow3 // windowID 0: sagittal window = renderWindow2 if ( m_MultiWidget ) { switch (windowID) { case 2: default: renderer = m_MultiWidget->mitkWidget1->GetRenderer(); break; case 1: renderer = m_MultiWidget->mitkWidget3->GetRenderer(); break; case 0: renderer = m_MultiWidget->mitkWidget2->GetRenderer(); break; } } if ( m_Segmentation && renderer && renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) { const mitk::TimeSlicedGeometry* timeSlicedGeometry = dynamic_cast( renderer->GetWorldGeometry() ); if (timeSlicedGeometry) { mitk::SlicedGeometry3D* slicedGeometry = dynamic_cast(timeSlicedGeometry->GetGeometry3D(m_TimeStep[windowID])); if (slicedGeometry) { mitk::PlaneGeometry* plane = dynamic_cast(slicedGeometry->GetGeometry2D( renderer->GetSlice() )); Interpolate( plane, m_TimeStep[windowID] ); return mitk::SegTool2D::DetermineAffectedImageSlice( m_Segmentation, plane, sliceDimension, sliceIndex ); } } } return false; } void QmitkSlicesInterpolator::OnMultiWidgetDeleted(QObject*) { if (m_MultiWidget) { m_MultiWidget = NULL; } } void QmitkSlicesInterpolator:: SetCurrentContourListID() { if ( m_DataStorage.IsNotNull() && m_ToolManager ) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { //int listID; bool isInterpolationResult(false); workingNode->GetBoolProperty("3DInterpolationResult",isInterpolationResult); if ((m_MultiWidget != NULL && workingNode->IsSelected() && workingNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) && !isInterpolationResult) { QWidget::setEnabled( true ); mitk::Vector3D spacing = workingNode->GetData()->GetGeometry( m_MultiWidget->GetRenderWindow3()->GetRenderer()->GetTimeStep() )->GetSpacing(); double minSpacing (100); double maxSpacing (0); for (int i =0; i < 3; i++) { if (spacing[i] < minSpacing) { minSpacing = spacing[i]; } else if (spacing[i] > maxSpacing) { maxSpacing = spacing[i]; } } m_SurfaceInterpolator->SetSegmentationImage(dynamic_cast(workingNode->GetData())); m_SurfaceInterpolator->SetMaxSpacing(maxSpacing); m_SurfaceInterpolator->SetMinSpacing(minSpacing); m_SurfaceInterpolator->SetDistanceImageVolume(50000); m_SurfaceInterpolator->SetCurrentSegmentationInterpolationList(dynamic_cast(workingNode->GetData())); } } } } void QmitkSlicesInterpolator::Show3DInterpolationResult(bool status) { if (m_InterpolatedSurfaceNode.IsNotNull()) m_InterpolatedSurfaceNode->SetVisibility(status); if (m_3DContourNode.IsNotNull()) m_3DContourNode->SetVisibility(status, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } diff --git a/Modules/QmitkExt/files.cmake b/Modules/QmitkExt/files.cmake index 0bd4443159..48eefa8b88 100644 --- a/Modules/QmitkExt/files.cmake +++ b/Modules/QmitkExt/files.cmake @@ -1,263 +1,267 @@ set(CPP_FILES QmitkApplicationBase/QmitkCommonFunctionality.cpp QmitkApplicationBase/QmitkIOUtil.cpp #QmitkModels/QmitkDataStorageListModel.cpp #QmitkModels/QmitkPropertiesTableModel.cpp #QmitkModels/QmitkDataStorageTreeModel.cpp #QmitkModels/QmitkDataStorageTableModel.cpp #QmitkModels/QmitkPropertyDelegate.cpp #QmitkModels/QmitkPointListModel.cpp #QmitkAlgorithmFunctionalityComponent.cpp #QmitkBaseAlgorithmComponent.cpp QmitkAboutDialog/QmitkAboutDialog.cpp #QmitkFunctionalityComponents/QmitkSurfaceCreatorComponent.cpp #QmitkFunctionalityComponents/QmitkPixelGreyValueManipulatorComponent.cpp #QmitkFunctionalityComponents/QmitkConnectivityFilterComponent.cpp #QmitkFunctionalityComponents/QmitkImageCropperComponent.cpp #QmitkFunctionalityComponents/QmitkSeedPointSetComponent.cpp #QmitkFunctionalityComponents/QmitkSurfaceTransformerComponent.cpp QmitkPropertyObservers/QmitkBasePropertyView.cpp QmitkPropertyObservers/QmitkBoolPropertyWidget.cpp QmitkPropertyObservers/QmitkColorPropertyEditor.cpp QmitkPropertyObservers/QmitkColorPropertyView.cpp QmitkPropertyObservers/QmitkEnumerationPropertyWidget.cpp QmitkPropertyObservers/QmitkNumberPropertyEditor.cpp QmitkPropertyObservers/QmitkNumberPropertyView.cpp QmitkPropertyObservers/QmitkPropertyViewFactory.cpp QmitkPropertyObservers/QmitkStringPropertyEditor.cpp QmitkPropertyObservers/QmitkStringPropertyOnDemandEdit.cpp QmitkPropertyObservers/QmitkStringPropertyView.cpp QmitkPropertyObservers/QmitkNumberPropertySlider.cpp QmitkPropertyObservers/QmitkUGCombinedRepresentationPropertyWidget.cpp qclickablelabel.cpp #QmitkAbortEventFilter.cpp # QmitkApplicationCursor.cpp QmitkCallbackFromGUIThread.cpp QmitkEditPointDialog.cpp QmitkExtRegisterClasses.cpp QmitkFileChooser.cpp # QmitkRenderingManager.cpp # QmitkRenderingManagerFactory.cpp # QmitkRenderWindow.cpp # QmitkEventAdapter.cpp QmitkFloatingPointSpanSlider.cpp QmitkColorTransferFunctionCanvas.cpp QmitkSlicesInterpolator.cpp QmitkStandardViews.cpp QmitkStepperAdapter.cpp # QmitkLineEditLevelWindowWidget.cpp # mitkSliderLevelWindowWidget.cpp # QmitkLevelWindowWidget.cpp # QmitkPointListWidget.cpp # QmitkPointListView.cpp QmitkPiecewiseFunctionCanvas.cpp QmitkSliderNavigatorWidget.cpp QmitkTransferFunctionCanvas.cpp QmitkCrossWidget.cpp #QmitkLevelWindowRangeChangeDialog.cpp #QmitkLevelWindowPresetDefinitionDialog.cpp # QmitkLevelWindowWidgetContextMenu.cpp QmitkSliceWidget.cpp # QmitkStdMultiWidget.cpp QmitkTransferFunctionWidget.cpp QmitkTransferFunctionGeneratorWidget.cpp QmitkSelectableGLWidget.cpp QmitkToolReferenceDataSelectionBox.cpp QmitkToolWorkingDataSelectionBox.cpp QmitkToolGUIArea.cpp QmitkToolSelectionBox.cpp # QmitkPropertyListPopup.cpp QmitkToolGUI.cpp QmitkNewSegmentationDialog.cpp QmitkPaintbrushToolGUI.cpp QmitkDrawPaintbrushToolGUI.cpp QmitkErasePaintbrushToolGUI.cpp QmitkBinaryThresholdToolGUI.cpp QmitkCalculateGrayValueStatisticsToolGUI.cpp QmitkCopyToClipBoardDialog.cpp # QmitkMaterialEditor.cpp # QmitkMaterialShowcase.cpp # QmitkPropertiesTableEditor.cpp QmitkPrimitiveMovieNavigatorWidget.cpp # QmitkDataStorageComboBox.cpp QmitkHistogram.cpp QmitkHistogramWidget.cpp QmitkPlotWidget.cpp QmitkPlotDialog.cpp QmitkPointListModel.cpp QmitkPointListView.cpp QmitkPointListWidget.cpp QmitkPointListViewWidget.cpp QmitkCorrespondingPointSetsView.cpp QmitkCorrespondingPointSetsModel.cpp QmitkCorrespondingPointSetsWidget.cpp QmitkVideoBackground.cpp QmitkHotkeyLineEdit.cpp QmitkErodeToolGUI.cpp QmitkDilateToolGUI.cpp QmitkMorphologicToolGUI.cpp QmitkOpeningToolGUI.cpp QmitkClosingToolGUI.cpp QmitkBinaryThresholdULToolGUI.cpp QmitkPixelManipulationToolGUI.cpp QmitkRegionGrow3DToolGUI.cpp QmitkToolRoiDataSelectionBox.cpp QmitkBoundingObjectWidget.cpp QmitkAdaptiveRegionGrowingWidget.cpp QmitkModuleTableModel.cpp QmitkModulesDialog.cpp + + QmitkHistogramJSWidget.cpp ) if( NOT ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}.${VTK_BUILD_VERSION} VERSION_LESS 5.4.0 ) set(CPP_FILES ${CPP_FILES} QmitkVtkHistogramWidget.cpp QmitkVtkLineProfileWidget.cpp ) endif() if(NOT APPLE) set(CPP_FILES ${CPP_FILES} QmitkBaseComponent.cpp QmitkBaseFunctionalityComponent.cpp QmitkFunctionalityComponentContainer.cpp QmitkFunctionalityComponents/QmitkThresholdComponent.cpp ) endif() QT4_ADD_RESOURCES(CPP_FILES resources/QmitkResources.qrc) set(MOC_H_FILES QmitkPropertyObservers/QmitkBasePropertyView.h QmitkPropertyObservers/QmitkBoolPropertyWidget.h QmitkPropertyObservers/QmitkColorPropertyEditor.h QmitkPropertyObservers/QmitkColorPropertyView.h QmitkPropertyObservers/QmitkEnumerationPropertyWidget.h QmitkPropertyObservers/QmitkNumberPropertyEditor.h QmitkPropertyObservers/QmitkNumberPropertyView.h QmitkPropertyObservers/QmitkStringPropertyEditor.h QmitkPropertyObservers/QmitkStringPropertyOnDemandEdit.h QmitkPropertyObservers/QmitkStringPropertyView.h QmitkPropertyObservers/QmitkNumberPropertySlider.h QmitkPropertyObservers/QmitkUGCombinedRepresentationPropertyWidget.h # QmitkFunctionalityComponents/QmitkSurfaceCreatorComponent.h #QmitkFunctionalityComponents/QmitkPixelGreyValueManipulatorComponent.h # QmitkFunctionalityComponents/QmitkConnectivityFilterComponent.h # QmitkFunctionalityComponents/QmitkImageCropperComponent.h # QmitkFunctionalityComponents/QmitkSeedPointSetComponent.h # QmitkFunctionalityComponents/QmitkSurfaceTransformerComponent.h qclickablelabel.h QmitkCallbackFromGUIThread.h QmitkEditPointDialog.h #QmitkAlgorithmFunctionalityComponent.h #QmitkBaseAlgorithmComponent.h QmitkStandardViews.h QmitkStepperAdapter.h QmitkSliderNavigatorWidget.h QmitkSliceWidget.h QmitkSlicesInterpolator.h QmitkColorTransferFunctionCanvas.h QmitkPiecewiseFunctionCanvas.h QmitkTransferFunctionCanvas.h QmitkFloatingPointSpanSlider.h QmitkCrossWidget.h QmitkTransferFunctionWidget.h QmitkTransferFunctionGeneratorWidget.h QmitkToolGUIArea.h QmitkToolGUI.h QmitkToolReferenceDataSelectionBox.h QmitkToolWorkingDataSelectionBox.h QmitkToolSelectionBox.h # QmitkPropertyListPopup.h #QmitkSelectableGLWidget.h QmitkNewSegmentationDialog.h QmitkPaintbrushToolGUI.h QmitkDrawPaintbrushToolGUI.h QmitkErasePaintbrushToolGUI.h QmitkBinaryThresholdToolGUI.h QmitkCalculateGrayValueStatisticsToolGUI.h QmitkCopyToClipBoardDialog.h QmitkPrimitiveMovieNavigatorWidget.h QmitkPlotWidget.h QmitkPointListModel.h QmitkPointListView.h QmitkPointListWidget.h QmitkPointListViewWidget.h QmitkCorrespondingPointSetsView.h QmitkCorrespondingPointSetsModel.h QmitkCorrespondingPointSetsWidget.h QmitkHistogramWidget.h QmitkVideoBackground.h QmitkFileChooser.h QmitkHotkeyLineEdit.h QmitkAboutDialog/QmitkAboutDialog.h QmitkErodeToolGUI.h QmitkDilateToolGUI.h QmitkMorphologicToolGUI.h QmitkOpeningToolGUI.h QmitkClosingToolGUI.h QmitkBinaryThresholdULToolGUI.h QmitkPixelManipulationToolGUI.h QmitkRegionGrow3DToolGUI.h QmitkToolRoiDataSelectionBox.h QmitkBoundingObjectWidget.h QmitkPlotWidget.h QmitkAdaptiveRegionGrowingWidget.h + + QmitkHistogramJSWidget.h ) if( NOT ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}.${VTK_BUILD_VERSION} VERSION_LESS 5.4.0 ) set(MOC_H_FILES ${MOC_H_FILES} QmitkVtkHistogramWidget.h QmitkVtkLineProfileWidget.h ) endif() if(NOT APPLE) set(MOC_H_FILES ${MOC_H_FILES} QmitkBaseComponent.h QmitkBaseFunctionalityComponent.h QmitkFunctionalityComponentContainer.h QmitkFunctionalityComponents/QmitkThresholdComponent.h ) endif() set(UI_FILES QmitkSliderNavigator.ui # QmitkLevelWindowRangeChange.ui # QmitkLevelWindowPresetDefinition.ui # QmitkLevelWindowWidget.ui QmitkSliceWidget.ui QmitkTransferFunctionWidget.ui QmitkTransferFunctionGeneratorWidget.ui QmitkSelectableGLWidget.ui QmitkPrimitiveMovieNavigatorWidget.ui QmitkFunctionalityComponentContainerControls.ui QmitkFunctionalityComponents/QmitkThresholdComponentControls.ui QmitkAboutDialog/QmitkAboutDialogGUI.ui QmitkAdaptiveRegionGrowingWidgetControls.ui ) set(QRC_FILES QmitkExt.qrc ) diff --git a/Modules/QmitkExt/resources/Histogram.css b/Modules/QmitkExt/resources/Histogram.css new file mode 100644 index 0000000000..88eb703c20 --- /dev/null +++ b/Modules/QmitkExt/resources/Histogram.css @@ -0,0 +1,35 @@ +body { + font: 10px sans-serif; + background-color: rgb(240,240,240) +} + +.bar { + fill: rgb(0,71,185); + shape-rendering: crispEdges; +} + +.line { + fill: none; + stroke: rgb(0,71,185); + stroke-width: 1; +} + +.axis path, .axis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} + +.infobox { + background-color: rgba(255, 255, 255, 0.75); + padding: 10px; + position: absolute; + width: auto; + display: none; +} + +circle { + stroke: rgb(0,71,185); + stroke-width: 1; + fill-opacity: 0; +} diff --git a/Modules/QmitkExt/resources/Histogram.html b/Modules/QmitkExt/resources/Histogram.html new file mode 100644 index 0000000000..09eaf6a574 --- /dev/null +++ b/Modules/QmitkExt/resources/Histogram.html @@ -0,0 +1,15 @@ + + + + Histogram + + + + +
+

+

+
+ + + diff --git a/Modules/QmitkExt/resources/Histogram.js b/Modules/QmitkExt/resources/Histogram.js new file mode 100644 index 0000000000..2e73055140 --- /dev/null +++ b/Modules/QmitkExt/resources/Histogram.js @@ -0,0 +1,539 @@ +/*=================================================================== + +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. + +===================================================================*/ + +var margin = { + top : 10, + bottom : 50, + left : 45, + right : 20, + }; +var height = histogramData.height - margin.top - margin.bottom; +var width = histogramData.width - margin.left - margin.right; +var tension = 0.8; +var connected = false; +var dur = 1000; +var binSize = 10; +var min; +var max; + +/* + * Connecting signals from qt side with JavaScript methods. + */ +if (!connected) +{ + connected = true; + histogramData.SignalDataChanged.connect(updateHistogram); + histogramData.SignalGraphChanged.connect(updateHistogram); +} + +/* + * Predefinition of scales. + */ +var xScale = d3.scale.linear() + .domain([d3.min(histogramData.measurement)-binSize/2,d3.max(histogramData.measurement)+binSize/2]) + .range([0,width]); + +var yScale = d3.scale.linear() + .domain([d3.min(histogramData.frequency),d3.max(histogramData.frequency)]) + .range([height,margin.top]); + +/* + * Predefinition of axis elements. + */ +var xAxis = d3.svg.axis() + .scale(xScale) + .orient("bottom") + .tickFormat(d3.format("s")); + +var yAxis = d3.svg.axis() + .scale(yScale) + .orient("left") + .tickFormat(d3.format("s")); + +/* + * Predefinition of the zoom. + */ +var zoombie = d3.behavior.zoom().x(xScale).scaleExtent([1, 50]).on("zoom", zoom); + +/* + * Creation of the svg element, which holds the complete histogram. + */ +var svg = d3.select("body") + .append("svg") + .attr("class", "svg") + .attr("width", width + margin.right + margin.left) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate (" + margin.left + "," + margin.top + ")") + .call(zoombie) + .on("mousemove", myMouseMove); + +/* + * Appending a rectangle to the svg, to guarantee the possibility + * of zooming on the whole histogram. + */ +svg.append("rect") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .attr("opacity", 0); + +/* + * Appending a second svg to main svg, which holds only the graph. + */ +var vis = svg.append("svg") + .attr("width", width) + .attr("height", height); + +/* + * Predefinition of the lines. + */ +var line = d3.svg.line() + .interpolate("linear") + .x(function(d,i) { + return xScale(histogramData.measurement[i]-binSize/2); + }) + .y(function(d) { + return yScale(d); + }); + +var linenull = d3.svg.line() + .interpolate("linear") + .x(function(d,i) { + return xScale(histogramData.measurement[i]-binSize/2); + }) + .y(function(d) { + return yScale(0); + }); + +updateHistogram(); + +/* + * Method to update the histogram data + * and to change the displayed graph. + */ +function updateHistogram() +{ + calcBinSize(); + if (!histogramData.useLineGraph) + { + barChart(); + } + else if (histogramData.useLineGraph) + { + linePlot() + } +} + +/* + * Calculation of the bin size. + */ +function calcBinSize() +{ + min = d3.min(histogramData.measurement); + max = d3.max(histogramData.measurement); + binSize = ((max - min) / (histogramData.measurement.length)); +} + +/* + * Method to display histogram as a barchart. + */ +function barChart() +{ + definition(); + + /* + * Change zoom to a fixed y-axis. + */ + zoombie = d3.behavior.zoom().x(xScale).scaleExtent([1, 50]).on("zoom", zoom); + + svg.call(zoombie); + + /* + * Element to animate transition from linegraph to barchart. + */ + vis.selectAll("path.line").remove(); + vis.selectAll("circle").remove(); + + /* + * Definition of the bar elements. + */ + var bar = vis.selectAll("rect.bar").data(histogramData.frequency); + + /* + * Definition how to handle new bar elements. + */ + bar.enter().append("rect") + .attr("class", "bar") + .on("mouseover", myMouseOver) + .on("mouseout", myMouseOut) + .attr("x", function(d,i) { + return xScale(histogramData.measurement[i]-binSize/2); + }) + .attr("y", height) + .attr("height", 0) + .attr("width", barWidth) + + /* + * Definition how to handle changed bar elements. + */ + bar.transition() + .duration(dur) + .attr("x", function(d,i) { + return xScale(histogramData.measurement[i]-binSize/2); + }) + .attr("y", myYPostion) + .attr("height", barHeight) + .attr("width", barWidth); + + /* + * Definition how to handle bar elements which doesn't exist anymore.' + */ + bar.exit() + .transition() + .duration(dur) + .attr("y", height) + .attr("height", 0) + .remove(); + + /* + * Update of axis elements. + * First delete old ones, then generate new. + */ + svg.selectAll("g") + .remove(); + + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + height + ")") + .call(xAxis); + + svg.append("g") + .attr("class", "y axis") + .call(yAxis); +} + +/* + * Method to display histogram as a linegraph. + */ +function linePlot() +{ + definition(); + + /* + * Change zoom to a zoomable y-axis. + */ + zoombie = d3.behavior.zoom().x(xScale).y(yScale).scaleExtent([1, 50]).on("zoom", zoom); + + svg.call(zoombie); + /* + * Elements to animate transitions from barchart to linegraph. + * Different transition when an intesity profile is generated. + */ + if(!histogramData.intensityProfile) + { + vis.selectAll("rect.bar") + .transition() + .duration(dur) + .attr("height", 0) + .remove(); + } + else + { + vis.selectAll("rect.bar") + .transition() + .duration(dur) + .attr("y", height) // <-- + .attr("height", 0) + .remove(); + } + + /* + * Creating circle elements, when an intensity profile is generated to show tooltips. + * Due performance losses tooltips are not supported for line histograms. + */ + if(histogramData.intensityProfile) + { + var circles = vis.selectAll("circle").data(histogramData.frequency); + + /* + * Definition how to handle new circle elements. + */ + circles.enter() + .append("circle") + .on("mouseover", myMouseOverLine) + .on("mouseout", myMouseOutLine) + .attr("cx", function(d,i) { + return xScale(histogramData.measurement[i]-binSize/2); + }) + .attr("cy", function (d) { + return yScale(d) + }) + .attr("r", 5) + .attr("opacity", 0) + .style("stroke", "red") + .style("stroke-width", 1) + .style("fill-opacity", 0); + + /* + * Definition how to handle bar elements which doesn't exist anymore. + */ + circles.exit().remove(); + } + else + { + /* + * Removing of all circle elements if a line histogram is generated. + */ + vis.selectAll("circle").remove(); + } + + /* + * Creating a new path element. + */ + var graph = vis.selectAll("path.line") + .data([histogramData.frequency]); + +/* + * Definition how to handle a new path element, using predefined lines. + */ + graph.enter() + .append("path") + .attr("class", "line") + .transition() + .duration(dur) + .attr("d", line); + +/* + * Definition how to handle change points in an existing path element. + */ + graph.transition() + .duration(dur) + .attr("d", line); + + /* + * Update of axis elements. + * First delete old ones, then generate new. + */ + svg.selectAll("g") + .remove(); + + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + height + ")") + .call(xAxis); + + svg.append("g") + .attr("class", "y axis") + .call(yAxis); +} + +function definition() +{ +/* + * Match scale to current data. + */ + xScale = d3.scale.linear() + .domain([d3.min(histogramData.measurement)-binSize/2,d3.max(histogramData.measurement)+binSize/2]) + .range([0,width]); + + yScale = d3.scale.linear() + .domain([d3.min(histogramData.frequency),d3.max(histogramData.frequency)]) + .range([height,margin.top]); + +/* + * Match axes to current scale + */ + xAxis = d3.svg.axis() + .scale(xScale) + .orient("bottom") + .tickFormat(d3.format("s")); + + yAxis = d3.svg.axis() + .scale(yScale) + .orient("left") + .tickFormat(d3.format("s")); +} + +/* + * Method to calculate barwidth in px. + */ +function barWidth(d, i) +{ + var bw; + if (i != (histogramData.measurement.length-1)) + { + bw =(xScale(histogramData.measurement[i + 1]) - xScale(histogramData.measurement[i])) * (histogramData.frequency.length / (histogramData.frequency.length + 1)) - 1; + } + else + { + bw =(xScale(histogramData.measurement[i]) - xScale(histogramData.measurement[i - 1])) * (histogramData.frequency.length / (histogramData.frequency.length + 1)) - 1; + } + /* + * Ensure barwidth is not smaller than 1px. + */ + bw = bw > 1 ? bw : 1; + return bw; +} + +/* + * Method to calculate barheight in px. + * Ensure barheight is not smaller than 1px. + */ +function barHeight(d) +{ + var bh; + bh = height - yScale(d); + bh = bh >=2 ? bh : 2; + return bh; +} + +/* + * Method to calculate dynamical y positions. + */ +function myYPostion(d) +{ + var myy = yScale(d); + myy = (height-myy) > 2 ? myy : (height-2); + if (d == 0) + { + return height; + } + return myy; +} + +/* + * Method to fit parameters of bars/line when zoomed. + * Update axes elements. + * Resets the view if scale is 1. + */ +function zoom() +{ + if (zoombie.scale() == 1) + { + zoombie.translate([0,0]); + xScale.domain([d3.min(histogramData.measurement)-binSize/2,d3.max(histogramData.measurement)+binSize/2]); + yScale.domain([d3.min(histogramData.frequency),d3.max(histogramData.frequency)]); + } + if (!histogramData.useLineGraph) + { + svg.select(".x.axis").call(xAxis); + vis.selectAll(".bar") + .attr("width", barWidth) + .attr("x", function(d, i) { + return xScale(histogramData.measurement[i]-binSize/2); + }); + } + else + { + svg.select(".x.axis").call(xAxis); + svg.select(".y.axis").call(yAxis); + vis.selectAll("path.line") + .attr("transform", "translate(" + zoombie.translate() + ")scale(" + zoombie.scale() + ")") + .style("stroke-width", 1 / zoombie.scale()); + vis.selectAll("circle") + .attr("cx", function(d, i) { + return xScale(histogramData.measurement[i]-binSize/2); + }) + .attr("cy", function(d) { + return yScale(d); + }); + } +} + +/* + * Method to show infobox, while mouse is over a bin. + */ +function myMouseOver() +{ + var myBar = d3.select(this); + var reScale = d3.scale.linear() + .domain(xScale.range()) + .range(xScale.domain()); + var y = myBar.data(); + var x = reScale(myBar.attr("x")); + myBar.style("fill", "red"); + d3.select(".infobox").style("display", "block"); + if ((min >= 0) && (max <= 2)) //tooltip for float images + { + d3.select(".measurement").text("Greayvalue: " + (Math.round(x*1000)/1000)); + } + else + { + d3.select(".measurement").text("Greyvalue: " + (Math.round(x*10)/10) + " ... " + (Math.round((x+binSize)*10)/10)); + } + d3.select(".frequency").text("Frequency: " + y); +} + +/* + * Hide infobox, when mouse not over a bin. + */ +function myMouseOut() +{ + var myBar = d3.select(this); + myBar.style("fill", d3.rgb(0,71,185)); + d3.select(".infobox").style("display", "none"); +} + +/* + * Show tooltip, while mouse is over a circle in an intesity profile. + */ +function myMouseOverLine() +{ + var myCircle = d3.select(this) + var reScale = d3.scale.linear() + .domain(xScale.range()) + .range(xScale.domain()); + var y = myCircle.data(); + var x = reScale(myCircle.attr("cx")); + + x = x >= 0 ? x : 0; + + myCircle.attr("opacity", 1); + d3.select(".infobox").style("display", "block"); + d3.select(".measurement").text("Distance: " + (Math.round(x*100)/100) + " mm"); + d3.select(".frequency").text("Intesity: " + y); +} + +/* + * Hide infobox, when mouse not over a circle. + */ +function myMouseOutLine() +{ + var myCircle = d3.select(this); + myCircle.attr("opacity", 0); + d3.select(".infobox").style("display", "none"); +} + +/* + * Update mousecoordinates when mouse is moved. + * Tooltip is shown on the right side of the mouse until it reaches the right boundary, + * the it switches to the left side. + */ +function myMouseMove() +{ + var infobox = d3.select(".infobox"); + var coords = d3.mouse(this); + if ((coords[0]+120)<(width-margin.right)) + { + infobox.style("left", coords[0] + 75 + "px"); + infobox.style("top", coords[1] + "px"); + } + else + { + infobox.style("left", coords[0] - 90 + "px"); + infobox.style("top",coords[1] + "px"); + } +} diff --git a/Modules/QmitkExt/resources/QmitkResources.qrc b/Modules/QmitkExt/resources/QmitkResources.qrc index fbeade59c1..fe2dfcebfa 100644 --- a/Modules/QmitkExt/resources/QmitkResources.qrc +++ b/Modules/QmitkExt/resources/QmitkResources.qrc @@ -1,18 +1,22 @@ Logo_mbiATdkfz_small.png cross.png QmitkStandardViewsDialogBar.xpm play.xpm stop.xpm logo_mint-medical.png Logo_mbiATdkfz_gross.png btnSetPoints.png btnAddPointSet.png btnMoveUp.png btnMoveDown.png btnRemovePoint.png btnSwapSets.png ModuleView.png + Histogram.html + Histogram.js + Histogram.css + d3.v2.js diff --git a/Modules/QmitkExt/resources/d3.v2.js b/Modules/QmitkExt/resources/d3.v2.js new file mode 100644 index 0000000000..fc0503c984 --- /dev/null +++ b/Modules/QmitkExt/resources/d3.v2.js @@ -0,0 +1,7033 @@ +(function() { + function d3_class(ctor, properties) { + try { + for (var key in properties) { + Object.defineProperty(ctor.prototype, key, { + value: properties[key], + enumerable: false + }); + } + } catch (e) { + ctor.prototype = properties; + } + } + function d3_arrayCopy(pseudoarray) { + var i = -1, n = pseudoarray.length, array = []; + while (++i < n) array.push(pseudoarray[i]); + return array; + } + function d3_arraySlice(pseudoarray) { + return Array.prototype.slice.call(pseudoarray); + } + function d3_Map() {} + function d3_identity(d) { + return d; + } + function d3_this() { + return this; + } + function d3_true() { + return true; + } + function d3_functor(v) { + return typeof v === "function" ? v : function() { + return v; + }; + } + function d3_rebind(target, source, method) { + return function() { + var value = method.apply(source, arguments); + return arguments.length ? target : value; + }; + } + function d3_number(x) { + return x != null && !isNaN(x); + } + function d3_zipLength(d) { + return d.length; + } + function d3_splitter(d) { + return d == null; + } + function d3_collapse(s) { + return s.trim().replace(/\s+/g, " "); + } + function d3_range_integerScale(x) { + var k = 1; + while (x * k % 1) k *= 10; + return k; + } + function d3_dispatch() {} + function d3_dispatch_event(dispatch) { + function event() { + var z = listeners, i = -1, n = z.length, l; + while (++i < n) if (l = z[i].on) l.apply(this, arguments); + return dispatch; + } + var listeners = [], listenerByName = new d3_Map; + event.on = function(name, listener) { + var l = listenerByName.get(name), i; + if (arguments.length < 2) return l && l.on; + if (l) { + l.on = null; + listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); + listenerByName.remove(name); + } + if (listener) listeners.push(listenerByName.set(name, { + on: listener + })); + return dispatch; + }; + return event; + } + function d3_format_precision(x, p) { + return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1); + } + function d3_format_typeDefault(x) { + return x + ""; + } + function d3_format_group(value) { + var i = value.lastIndexOf("."), f = i >= 0 ? value.substring(i) : (i = value.length, ""), t = []; + while (i > 0) t.push(value.substring(i -= 3, i + 3)); + return t.reverse().join(",") + f; + } + function d3_formatPrefix(d, i) { + var k = Math.pow(10, Math.abs(8 - i) * 3); + return { + scale: i > 8 ? function(d) { + return d / k; + } : function(d) { + return d * k; + }, + symbol: d + }; + } + function d3_ease_clamp(f) { + return function(t) { + return t <= 0 ? 0 : t >= 1 ? 1 : f(t); + }; + } + function d3_ease_reverse(f) { + return function(t) { + return 1 - f(1 - t); + }; + } + function d3_ease_reflect(f) { + return function(t) { + return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); + }; + } + function d3_ease_identity(t) { + return t; + } + function d3_ease_poly(e) { + return function(t) { + return Math.pow(t, e); + }; + } + function d3_ease_sin(t) { + return 1 - Math.cos(t * Math.PI / 2); + } + function d3_ease_exp(t) { + return Math.pow(2, 10 * (t - 1)); + } + function d3_ease_circle(t) { + return 1 - Math.sqrt(1 - t * t); + } + function d3_ease_elastic(a, p) { + var s; + if (arguments.length < 2) p = .45; + if (arguments.length < 1) { + a = 1; + s = p / 4; + } else s = p / (2 * Math.PI) * Math.asin(1 / a); + return function(t) { + return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * Math.PI / p); + }; + } + function d3_ease_back(s) { + if (!s) s = 1.70158; + return function(t) { + return t * t * ((s + 1) * t - s); + }; + } + function d3_ease_bounce(t) { + return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; + } + function d3_eventCancel() { + d3.event.stopPropagation(); + d3.event.preventDefault(); + } + function d3_eventSource() { + var e = d3.event, s; + while (s = e.sourceEvent) e = s; + return e; + } + function d3_eventDispatch(target) { + var dispatch = new d3_dispatch, i = 0, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + dispatch.of = function(thiz, argumentz) { + return function(e1) { + try { + var e0 = e1.sourceEvent = d3.event; + e1.target = target; + d3.event = e1; + dispatch[e1.type].apply(thiz, argumentz); + } finally { + d3.event = e0; + } + }; + }; + return dispatch; + } + function d3_transform(m) { + var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; + if (r0[0] * r1[1] < r1[0] * r0[1]) { + r0[0] *= -1; + r0[1] *= -1; + kx *= -1; + kz *= -1; + } + this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_transformDegrees; + this.translate = [ m.e, m.f ]; + this.scale = [ kx, ky ]; + this.skew = ky ? Math.atan2(kz, ky) * d3_transformDegrees : 0; + } + function d3_transformDot(a, b) { + return a[0] * b[0] + a[1] * b[1]; + } + function d3_transformNormalize(a) { + var k = Math.sqrt(d3_transformDot(a, a)); + if (k) { + a[0] /= k; + a[1] /= k; + } + return k; + } + function d3_transformCombine(a, b, k) { + a[0] += k * b[0]; + a[1] += k * b[1]; + return a; + } + function d3_interpolateByName(name) { + return name == "transform" ? d3.interpolateTransform : d3.interpolate; + } + function d3_uninterpolateNumber(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return (x - a) * b; + }; + } + function d3_uninterpolateClamp(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return Math.max(0, Math.min(1, (x - a) * b)); + }; + } + function d3_rgb(r, g, b) { + return new d3_Rgb(r, g, b); + } + function d3_Rgb(r, g, b) { + this.r = r; + this.g = g; + this.b = b; + } + function d3_rgb_hex(v) { + return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); + } + function d3_rgb_parse(format, rgb, hsl) { + var r = 0, g = 0, b = 0, m1, m2, name; + m1 = /([a-z]+)\((.*)\)/i.exec(format); + if (m1) { + m2 = m1[2].split(","); + switch (m1[1]) { + case "hsl": + { + return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); + } + case "rgb": + { + return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); + } + } + } + if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); + if (format != null && format.charAt(0) === "#") { + if (format.length === 4) { + r = format.charAt(1); + r += r; + g = format.charAt(2); + g += g; + b = format.charAt(3); + b += b; + } else if (format.length === 7) { + r = format.substring(1, 3); + g = format.substring(3, 5); + b = format.substring(5, 7); + } + r = parseInt(r, 16); + g = parseInt(g, 16); + b = parseInt(b, 16); + } + return rgb(r, g, b); + } + function d3_rgb_hsl(r, g, b) { + var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; + if (d) { + s = l < .5 ? d / (max + min) : d / (2 - max - min); + if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; + h *= 60; + } else { + s = h = 0; + } + return d3_hsl(h, s, l); + } + function d3_rgb_lab(r, g, b) { + r = d3_rgb_xyz(r); + g = d3_rgb_xyz(g); + b = d3_rgb_xyz(b); + var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); + return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); + } + function d3_rgb_xyz(r) { + return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); + } + function d3_rgb_parseNumber(c) { + var f = parseFloat(c); + return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; + } + function d3_hsl(h, s, l) { + return new d3_Hsl(h, s, l); + } + function d3_Hsl(h, s, l) { + this.h = h; + this.s = s; + this.l = l; + } + function d3_hsl_rgb(h, s, l) { + function v(h) { + if (h > 360) h -= 360; else if (h < 0) h += 360; + if (h < 60) return m1 + (m2 - m1) * h / 60; + if (h < 180) return m2; + if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; + return m1; + } + function vv(h) { + return Math.round(v(h) * 255); + } + var m1, m2; + h = h % 360; + if (h < 0) h += 360; + s = s < 0 ? 0 : s > 1 ? 1 : s; + l = l < 0 ? 0 : l > 1 ? 1 : l; + m2 = l <= .5 ? l * (1 + s) : l + s - l * s; + m1 = 2 * l - m2; + return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); + } + function d3_hcl(h, c, l) { + return new d3_Hcl(h, c, l); + } + function d3_Hcl(h, c, l) { + this.h = h; + this.c = c; + this.l = l; + } + function d3_hcl_lab(h, c, l) { + return d3_lab(l, Math.cos(h *= Math.PI / 180) * c, Math.sin(h) * c); + } + function d3_lab(l, a, b) { + return new d3_Lab(l, a, b); + } + function d3_Lab(l, a, b) { + this.l = l; + this.a = a; + this.b = b; + } + function d3_lab_rgb(l, a, b) { + var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; + x = d3_lab_xyz(x) * d3_lab_X; + y = d3_lab_xyz(y) * d3_lab_Y; + z = d3_lab_xyz(z) * d3_lab_Z; + return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); + } + function d3_lab_hcl(l, a, b) { + return d3_hcl(Math.atan2(b, a) / Math.PI * 180, Math.sqrt(a * a + b * b), l); + } + function d3_lab_xyz(x) { + return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; + } + function d3_xyz_lab(x) { + return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; + } + function d3_xyz_rgb(r) { + return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); + } + function d3_selection(groups) { + d3_arraySubclass(groups, d3_selectionPrototype); + return groups; + } + function d3_selection_selector(selector) { + return function() { + return d3_select(selector, this); + }; + } + function d3_selection_selectorAll(selector) { + return function() { + return d3_selectAll(selector, this); + }; + } + function d3_selection_attr(name, value) { + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrConstant() { + this.setAttribute(name, value); + } + function attrConstantNS() { + this.setAttributeNS(name.space, name.local, value); + } + function attrFunction() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); + } + function attrFunctionNS() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); + } + name = d3.ns.qualify(name); + return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; + } + function d3_selection_classedRe(name) { + return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); + } + function d3_selection_classed(name, value) { + function classedConstant() { + var i = -1; + while (++i < n) name[i](this, value); + } + function classedFunction() { + var i = -1, x = value.apply(this, arguments); + while (++i < n) name[i](this, x); + } + name = name.trim().split(/\s+/).map(d3_selection_classedName); + var n = name.length; + return typeof value === "function" ? classedFunction : classedConstant; + } + function d3_selection_classedName(name) { + var re = d3_selection_classedRe(name); + return function(node, value) { + if (c = node.classList) return value ? c.add(name) : c.remove(name); + var c = node.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c; + if (value) { + re.lastIndex = 0; + if (!re.test(cv)) { + cv = d3_collapse(cv + " " + name); + if (cb) c.baseVal = cv; else node.className = cv; + } + } else if (cv) { + cv = d3_collapse(cv.replace(re, " ")); + if (cb) c.baseVal = cv; else node.className = cv; + } + }; + } + function d3_selection_style(name, value, priority) { + function styleNull() { + this.style.removeProperty(name); + } + function styleConstant() { + this.style.setProperty(name, value, priority); + } + function styleFunction() { + var x = value.apply(this, arguments); + if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); + } + return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; + } + function d3_selection_property(name, value) { + function propertyNull() { + delete this[name]; + } + function propertyConstant() { + this[name] = value; + } + function propertyFunction() { + var x = value.apply(this, arguments); + if (x == null) delete this[name]; else this[name] = x; + } + return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; + } + function d3_selection_dataNode(data) { + return { + __data__: data + }; + } + function d3_selection_filter(selector) { + return function() { + return d3_selectMatches(this, selector); + }; + } + function d3_selection_sortComparator(comparator) { + if (!arguments.length) comparator = d3.ascending; + return function(a, b) { + return comparator(a && a.__data__, b && b.__data__); + }; + } + function d3_selection_on(type, listener, capture) { + function onRemove() { + var wrapper = this[name]; + if (wrapper) { + this.removeEventListener(type, wrapper, wrapper.$); + delete this[name]; + } + } + function onAdd() { + function wrapper(e) { + var o = d3.event; + d3.event = e; + args[0] = node.__data__; + try { + listener.apply(node, args); + } finally { + d3.event = o; + } + } + var node = this, args = arguments; + onRemove.call(this); + this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture); + wrapper._ = listener; + } + var name = "__on" + type, i = type.indexOf("."); + if (i > 0) type = type.substring(0, i); + return listener ? onAdd : onRemove; + } + function d3_selection_each(groups, callback) { + for (var j = 0, m = groups.length; j < m; j++) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { + if (node = group[i]) callback(node, i, j); + } + } + return groups; + } + function d3_selection_enter(selection) { + d3_arraySubclass(selection, d3_selection_enterPrototype); + return selection; + } + function d3_transition(groups, id, time) { + d3_arraySubclass(groups, d3_transitionPrototype); + var tweens = new d3_Map, event = d3.dispatch("start", "end"), ease = d3_transitionEase; + groups.id = id; + groups.time = time; + groups.tween = function(name, tween) { + if (arguments.length < 2) return tweens.get(name); + if (tween == null) tweens.remove(name); else tweens.set(name, tween); + return groups; + }; + groups.ease = function(value) { + if (!arguments.length) return ease; + ease = typeof value === "function" ? value : d3.ease.apply(d3, arguments); + return groups; + }; + groups.each = function(type, listener) { + if (arguments.length < 2) return d3_transition_each.call(groups, type); + event.on(type, listener); + return groups; + }; + d3.timer(function(elapsed) { + return d3_selection_each(groups, function(node, i, j) { + function start(elapsed) { + if (lock.active > id) return stop(); + lock.active = id; + tweens.forEach(function(key, value) { + if (value = value.call(node, d, i)) { + tweened.push(value); + } + }); + event.start.call(node, d, i); + if (!tick(elapsed)) d3.timer(tick, 0, time); + return 1; + } + function tick(elapsed) { + if (lock.active !== id) return stop(); + var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; + while (n > 0) { + tweened[--n].call(node, e); + } + if (t >= 1) { + stop(); + d3_transitionId = id; + event.end.call(node, d, i); + d3_transitionId = 0; + return 1; + } + } + function stop() { + if (!--lock.count) delete node.__transition__; + return 1; + } + var tweened = [], delay = node.delay, duration = node.duration, lock = (node = node.node).__transition__ || (node.__transition__ = { + active: 0, + count: 0 + }), d = node.__data__; + ++lock.count; + delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time); + }); + }, 0, time); + return groups; + } + function d3_transition_each(callback) { + var id = d3_transitionId, ease = d3_transitionEase, delay = d3_transitionDelay, duration = d3_transitionDuration; + d3_transitionId = this.id; + d3_transitionEase = this.ease(); + d3_selection_each(this, function(node, i, j) { + d3_transitionDelay = node.delay; + d3_transitionDuration = node.duration; + callback.call(node = node.node, node.__data__, i, j); + }); + d3_transitionId = id; + d3_transitionEase = ease; + d3_transitionDelay = delay; + d3_transitionDuration = duration; + return this; + } + function d3_tweenNull(d, i, a) { + return a != "" && d3_tweenRemove; + } + function d3_tweenByName(b, name) { + return d3.tween(b, d3_interpolateByName(name)); + } + function d3_timer_step() { + var elapsed, now = Date.now(), t1 = d3_timer_queue; + while (t1) { + elapsed = now - t1.then; + if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed); + t1 = t1.next; + } + var delay = d3_timer_flush() - now; + if (delay > 24) { + if (isFinite(delay)) { + clearTimeout(d3_timer_timeout); + d3_timer_timeout = setTimeout(d3_timer_step, delay); + } + d3_timer_interval = 0; + } else { + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + } + function d3_timer_flush() { + var t0 = null, t1 = d3_timer_queue, then = Infinity; + while (t1) { + if (t1.flush) { + t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next; + } else { + then = Math.min(then, t1.then + t1.delay); + t1 = (t0 = t1).next; + } + } + return then; + } + function d3_mousePoint(container, e) { + var svg = container.ownerSVGElement || container; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + if (d3_mouse_bug44083 < 0 && (window.scrollX || window.scrollY)) { + svg = d3.select(document.body).append("svg").style("position", "absolute").style("top", 0).style("left", 0); + var ctm = svg[0][0].getScreenCTM(); + d3_mouse_bug44083 = !(ctm.f || ctm.e); + svg.remove(); + } + if (d3_mouse_bug44083) { + point.x = e.pageX; + point.y = e.pageY; + } else { + point.x = e.clientX; + point.y = e.clientY; + } + point = point.matrixTransform(container.getScreenCTM().inverse()); + return [ point.x, point.y ]; + } + var rect = container.getBoundingClientRect(); + return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; + } + function d3_noop() {} + function d3_scaleExtent(domain) { + var start = domain[0], stop = domain[domain.length - 1]; + return start < stop ? [ start, stop ] : [ stop, start ]; + } + function d3_scaleRange(scale) { + return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); + } + function d3_scale_nice(domain, nice) { + var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; + if (x1 < x0) { + dx = i0, i0 = i1, i1 = dx; + dx = x0, x0 = x1, x1 = dx; + } + if (nice = nice(x1 - x0)) { + domain[i0] = nice.floor(x0); + domain[i1] = nice.ceil(x1); + } + return domain; + } + function d3_scale_niceDefault() { + return Math; + } + function d3_scale_linear(domain, range, interpolate, clamp) { + function rescale() { + var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; + output = linear(domain, range, uninterpolate, interpolate); + input = linear(range, domain, uninterpolate, d3.interpolate); + return scale; + } + function scale(x) { + return output(x); + } + var output, input; + scale.invert = function(y) { + return input(y); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.map(Number); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.rangeRound = function(x) { + return scale.range(x).interpolate(d3.interpolateRound); + }; + scale.clamp = function(x) { + if (!arguments.length) return clamp; + clamp = x; + return rescale(); + }; + scale.interpolate = function(x) { + if (!arguments.length) return interpolate; + interpolate = x; + return rescale(); + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m) { + return d3_scale_linearTickFormat(domain, m); + }; + scale.nice = function() { + d3_scale_nice(domain, d3_scale_linearNice); + return rescale(); + }; + scale.copy = function() { + return d3_scale_linear(domain, range, interpolate, clamp); + }; + return rescale(); + } + function d3_scale_linearRebind(scale, linear) { + return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); + } + function d3_scale_linearNice(dx) { + dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1); + return dx && { + floor: function(x) { + return Math.floor(x / dx) * dx; + }, + ceil: function(x) { + return Math.ceil(x / dx) * dx; + } + }; + } + function d3_scale_linearTickRange(domain, m) { + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; + if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; + extent[0] = Math.ceil(extent[0] / step) * step; + extent[1] = Math.floor(extent[1] / step) * step + step * .5; + extent[2] = step; + return extent; + } + function d3_scale_linearTicks(domain, m) { + return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); + } + function d3_scale_linearTickFormat(domain, m) { + return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f"); + } + function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { + var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); + return function(x) { + return i(u(x)); + }; + } + function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { + var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; + if (domain[k] < domain[0]) { + domain = domain.slice().reverse(); + range = range.slice().reverse(); + } + while (++j <= k) { + u.push(uninterpolate(domain[j - 1], domain[j])); + i.push(interpolate(range[j - 1], range[j])); + } + return function(x) { + var j = d3.bisect(domain, x, 1, k) - 1; + return i[j](u[j](x)); + }; + } + function d3_scale_log(linear, log) { + function scale(x) { + return linear(log(x)); + } + var pow = log.pow; + scale.invert = function(x) { + return pow(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return linear.domain().map(pow); + log = x[0] < 0 ? d3_scale_logn : d3_scale_logp; + pow = log.pow; + linear.domain(x.map(log)); + return scale; + }; + scale.nice = function() { + linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault)); + return scale; + }; + scale.ticks = function() { + var extent = d3_scaleExtent(linear.domain()), ticks = []; + if (extent.every(isFinite)) { + var i = Math.floor(extent[0]), j = Math.ceil(extent[1]), u = pow(extent[0]), v = pow(extent[1]); + if (log === d3_scale_logn) { + ticks.push(pow(i)); + for (; i++ < j; ) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k); + } else { + for (; i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k); + ticks.push(pow(i)); + } + for (i = 0; ticks[i] < u; i++) {} + for (j = ticks.length; ticks[j - 1] > v; j--) {} + ticks = ticks.slice(i, j); + } + return ticks; + }; + scale.tickFormat = function(n, format) { + if (arguments.length < 2) format = d3_scale_logFormat; + if (arguments.length < 1) return format; + var k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12, Math.floor) : (e = 1e-12, Math.ceil), e; + return function(d) { + return d / pow(f(log(d) + e)) <= k ? format(d) : ""; + }; + }; + scale.copy = function() { + return d3_scale_log(linear.copy(), log); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_scale_logp(x) { + return Math.log(x < 0 ? 0 : x) / Math.LN10; + } + function d3_scale_logn(x) { + return -Math.log(x > 0 ? 0 : -x) / Math.LN10; + } + function d3_scale_pow(linear, exponent) { + function scale(x) { + return linear(powp(x)); + } + var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); + scale.invert = function(x) { + return powb(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return linear.domain().map(powb); + linear.domain(x.map(powp)); + return scale; + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(scale.domain(), m); + }; + scale.tickFormat = function(m) { + return d3_scale_linearTickFormat(scale.domain(), m); + }; + scale.nice = function() { + return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice)); + }; + scale.exponent = function(x) { + if (!arguments.length) return exponent; + var domain = scale.domain(); + powp = d3_scale_powPow(exponent = x); + powb = d3_scale_powPow(1 / exponent); + return scale.domain(domain); + }; + scale.copy = function() { + return d3_scale_pow(linear.copy(), exponent); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_scale_powPow(e) { + return function(x) { + return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); + }; + } + function d3_scale_ordinal(domain, ranger) { + function scale(x) { + return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; + } + function steps(start, step) { + return d3.range(domain.length).map(function(i) { + return start + step * i; + }); + } + var index, range, rangeBand; + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = []; + index = new d3_Map; + var i = -1, n = x.length, xi; + while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); + return scale[ranger.t].apply(scale, ranger.a); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + rangeBand = 0; + ranger = { + t: "range", + a: arguments + }; + return scale; + }; + scale.rangePoints = function(x, padding) { + if (arguments.length < 2) padding = 0; + var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); + range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); + rangeBand = 0; + ranger = { + t: "rangePoints", + a: arguments + }; + return scale; + }; + scale.rangeBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); + range = steps(start + step * outerPadding, step); + if (reverse) range.reverse(); + rangeBand = step * (1 - padding); + ranger = { + t: "rangeBands", + a: arguments + }; + return scale; + }; + scale.rangeRoundBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; + range = steps(start + Math.round(error / 2), step); + if (reverse) range.reverse(); + rangeBand = Math.round(step * (1 - padding)); + ranger = { + t: "rangeRoundBands", + a: arguments + }; + return scale; + }; + scale.rangeBand = function() { + return rangeBand; + }; + scale.rangeExtent = function() { + return d3_scaleExtent(ranger.a[0]); + }; + scale.copy = function() { + return d3_scale_ordinal(domain, ranger); + }; + return scale.domain(domain); + } + function d3_scale_quantile(domain, range) { + function rescale() { + var k = 0, n = domain.length, q = range.length; + thresholds = []; + while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); + return scale; + } + function scale(x) { + if (isNaN(x = +x)) return NaN; + return range[d3.bisect(thresholds, x)]; + } + var thresholds; + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.filter(function(d) { + return !isNaN(d); + }).sort(d3.ascending); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.quantiles = function() { + return thresholds; + }; + scale.copy = function() { + return d3_scale_quantile(domain, range); + }; + return rescale(); + } + function d3_scale_quantize(x0, x1, range) { + function scale(x) { + return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; + } + function rescale() { + kx = range.length / (x1 - x0); + i = range.length - 1; + return scale; + } + var kx, i; + scale.domain = function(x) { + if (!arguments.length) return [ x0, x1 ]; + x0 = +x[0]; + x1 = +x[x.length - 1]; + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.copy = function() { + return d3_scale_quantize(x0, x1, range); + }; + return rescale(); + } + function d3_scale_threshold(domain, range) { + function scale(x) { + return range[d3.bisect(domain, x)]; + } + scale.domain = function(_) { + if (!arguments.length) return domain; + domain = _; + return scale; + }; + scale.range = function(_) { + if (!arguments.length) return range; + range = _; + return scale; + }; + scale.copy = function() { + return d3_scale_threshold(domain, range); + }; + return scale; + } + function d3_scale_identity(domain) { + function identity(x) { + return +x; + } + identity.invert = identity; + identity.domain = identity.range = function(x) { + if (!arguments.length) return domain; + domain = x.map(identity); + return identity; + }; + identity.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + identity.tickFormat = function(m) { + return d3_scale_linearTickFormat(domain, m); + }; + identity.copy = function() { + return d3_scale_identity(domain); + }; + return identity; + } + function d3_svg_arcInnerRadius(d) { + return d.innerRadius; + } + function d3_svg_arcOuterRadius(d) { + return d.outerRadius; + } + function d3_svg_arcStartAngle(d) { + return d.startAngle; + } + function d3_svg_arcEndAngle(d) { + return d.endAngle; + } + function d3_svg_line(projection) { + function line(data) { + function segment() { + segments.push("M", interpolate(projection(points), tension)); + } + var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); + } else if (points.length) { + segment(); + points = []; + } + } + if (points.length) segment(); + return segments.length ? segments.join("") : null; + } + var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; + line.x = function(_) { + if (!arguments.length) return x; + x = _; + return line; + }; + line.y = function(_) { + if (!arguments.length) return y; + y = _; + return line; + }; + line.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return line; + }; + line.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + return line; + }; + line.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return line; + }; + return line; + } + function d3_svg_lineX(d) { + return d[0]; + } + function d3_svg_lineY(d) { + return d[1]; + } + function d3_svg_lineLinear(points) { + return points.join("L"); + } + function d3_svg_lineLinearClosed(points) { + return d3_svg_lineLinear(points) + "Z"; + } + function d3_svg_lineStepBefore(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); + return path.join(""); + } + function d3_svg_lineStepAfter(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); + return path.join(""); + } + function d3_svg_lineCardinalOpen(points, tension) { + return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineCardinalClosed(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); + } + function d3_svg_lineCardinal(points, tension, closed) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineHermite(points, tangents) { + if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { + return d3_svg_lineLinear(points); + } + var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; + if (quad) { + path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; + p0 = points[1]; + pi = 2; + } + if (tangents.length > 1) { + t = tangents[1]; + p = points[pi]; + pi++; + path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + for (var i = 2; i < tangents.length; i++, pi++) { + p = points[pi]; + t = tangents[i]; + path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + } + } + if (quad) { + var lp = points[pi]; + path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; + } + return path; + } + function d3_svg_lineCardinalTangents(points, tension) { + var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; + while (++i < n) { + p0 = p1; + p1 = p2; + p2 = points[i]; + tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); + } + return tangents; + } + function d3_svg_lineBasis(points) { + if (points.length < 3) return d3_svg_lineLinear(points); + var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0 ]; + d3_svg_lineBasisBezier(path, px, py); + while (++i < n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + i = -1; + while (++i < 2) { + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBasisOpen(points) { + if (points.length < 4) return d3_svg_lineLinear(points); + var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; + while (++i < 3) { + pi = points[i]; + px.push(pi[0]); + py.push(pi[1]); + } + path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); + --i; + while (++i < n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBasisClosed(points) { + var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; + while (++i < 4) { + pi = points[i % n]; + px.push(pi[0]); + py.push(pi[1]); + } + path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + --i; + while (++i < m) { + pi = points[i % n]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBundle(points, tension) { + var n = points.length - 1; + if (n) { + var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; + while (++i <= n) { + p = points[i]; + t = i / n; + p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); + p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); + } + } + return d3_svg_lineBasis(points); + } + function d3_svg_lineDot4(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + function d3_svg_lineBasisBezier(path, x, y) { + path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); + } + function d3_svg_lineSlope(p0, p1) { + return (p1[1] - p0[1]) / (p1[0] - p0[0]); + } + function d3_svg_lineFiniteDifferences(points) { + var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); + while (++i < j) { + m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; + } + m[i] = d; + return m; + } + function d3_svg_lineMonotoneTangents(points) { + var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; + while (++i < j) { + d = d3_svg_lineSlope(points[i], points[i + 1]); + if (Math.abs(d) < 1e-6) { + m[i] = m[i + 1] = 0; + } else { + a = m[i] / d; + b = m[i + 1] / d; + s = a * a + b * b; + if (s > 9) { + s = d * 3 / Math.sqrt(s); + m[i] = s * a; + m[i + 1] = s * b; + } + } + } + i = -1; + while (++i <= j) { + s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); + tangents.push([ s || 0, m[i] * s || 0 ]); + } + return tangents; + } + function d3_svg_lineMonotone(points) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); + } + function d3_svg_lineRadial(points) { + var point, i = -1, n = points.length, r, a; + while (++i < n) { + point = points[i]; + r = point[0]; + a = point[1] + d3_svg_arcOffset; + point[0] = r * Math.cos(a); + point[1] = r * Math.sin(a); + } + return points; + } + function d3_svg_area(projection) { + function area(data) { + function segment() { + segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); + } + var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { + return x; + } : d3_functor(x1), fy1 = y0 === y1 ? function() { + return y; + } : d3_functor(y1), x, y; + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); + points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); + } else if (points0.length) { + segment(); + points0 = []; + points1 = []; + } + } + if (points0.length) segment(); + return segments.length ? segments.join("") : null; + } + var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; + area.x = function(_) { + if (!arguments.length) return x1; + x0 = x1 = _; + return area; + }; + area.x0 = function(_) { + if (!arguments.length) return x0; + x0 = _; + return area; + }; + area.x1 = function(_) { + if (!arguments.length) return x1; + x1 = _; + return area; + }; + area.y = function(_) { + if (!arguments.length) return y1; + y0 = y1 = _; + return area; + }; + area.y0 = function(_) { + if (!arguments.length) return y0; + y0 = _; + return area; + }; + area.y1 = function(_) { + if (!arguments.length) return y1; + y1 = _; + return area; + }; + area.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return area; + }; + area.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + interpolateReverse = interpolate.reverse || interpolate; + L = interpolate.closed ? "M" : "L"; + return area; + }; + area.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return area; + }; + return area; + } + function d3_svg_chordSource(d) { + return d.source; + } + function d3_svg_chordTarget(d) { + return d.target; + } + function d3_svg_chordRadius(d) { + return d.radius; + } + function d3_svg_chordStartAngle(d) { + return d.startAngle; + } + function d3_svg_chordEndAngle(d) { + return d.endAngle; + } + function d3_svg_diagonalProjection(d) { + return [ d.x, d.y ]; + } + function d3_svg_diagonalRadialProjection(projection) { + return function() { + var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; + return [ r * Math.cos(a), r * Math.sin(a) ]; + }; + } + function d3_svg_symbolSize() { + return 64; + } + function d3_svg_symbolType() { + return "circle"; + } + function d3_svg_symbolCircle(size) { + var r = Math.sqrt(size / Math.PI); + return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; + } + function d3_svg_axisX(selection, x) { + selection.attr("transform", function(d) { + return "translate(" + x(d) + ",0)"; + }); + } + function d3_svg_axisY(selection, y) { + selection.attr("transform", function(d) { + return "translate(0," + y(d) + ")"; + }); + } + function d3_svg_axisSubdivide(scale, ticks, m) { + subticks = []; + if (m && ticks.length > 1) { + var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; + while (++i < n) { + for (j = m; --j > 0; ) { + if ((v = +ticks[i] - j * d) >= extent[0]) { + subticks.push(v); + } + } + } + for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { + subticks.push(v); + } + } + return subticks; + } + function d3_behavior_zoomDelta() { + if (!d3_behavior_zoomDiv) { + d3_behavior_zoomDiv = d3.select("body").append("div").style("visibility", "hidden").style("top", 0).style("height", 0).style("width", 0).style("overflow-y", "scroll").append("div").style("height", "2000px").node().parentNode; + } + var e = d3.event, delta; + try { + d3_behavior_zoomDiv.scrollTop = 1e3; + d3_behavior_zoomDiv.dispatchEvent(e); + delta = 1e3 - d3_behavior_zoomDiv.scrollTop; + } catch (error) { + delta = e.wheelDelta || -e.detail * 5; + } + return delta; + } + function d3_layout_bundlePath(link) { + var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; + while (start !== lca) { + start = start.parent; + points.push(start); + } + var k = points.length; + while (end !== lca) { + points.splice(k, 0, end); + end = end.parent; + } + return points; + } + function d3_layout_bundleAncestors(node) { + var ancestors = [], parent = node.parent; + while (parent != null) { + ancestors.push(node); + node = parent; + parent = parent.parent; + } + ancestors.push(node); + return ancestors; + } + function d3_layout_bundleLeastCommonAncestor(a, b) { + if (a === b) return a; + var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; + while (aNode === bNode) { + sharedNode = aNode; + aNode = aNodes.pop(); + bNode = bNodes.pop(); + } + return sharedNode; + } + function d3_layout_forceDragstart(d) { + d.fixed |= 2; + } + function d3_layout_forceDragend(d) { + d.fixed &= 1; + } + function d3_layout_forceMouseover(d) { + d.fixed |= 4; + } + function d3_layout_forceMouseout(d) { + d.fixed &= 3; + } + function d3_layout_forceAccumulate(quad, alpha, charges) { + var cx = 0, cy = 0; + quad.charge = 0; + if (!quad.leaf) { + var nodes = quad.nodes, n = nodes.length, i = -1, c; + while (++i < n) { + c = nodes[i]; + if (c == null) continue; + d3_layout_forceAccumulate(c, alpha, charges); + quad.charge += c.charge; + cx += c.charge * c.cx; + cy += c.charge * c.cy; + } + } + if (quad.point) { + if (!quad.leaf) { + quad.point.x += Math.random() - .5; + quad.point.y += Math.random() - .5; + } + var k = alpha * charges[quad.point.index]; + quad.charge += quad.pointCharge = k; + cx += k * quad.point.x; + cy += k * quad.point.y; + } + quad.cx = cx / quad.charge; + quad.cy = cy / quad.charge; + } + function d3_layout_forceLinkDistance(link) { + return 20; + } + function d3_layout_forceLinkStrength(link) { + return 1; + } + function d3_layout_stackX(d) { + return d.x; + } + function d3_layout_stackY(d) { + return d.y; + } + function d3_layout_stackOut(d, y0, y) { + d.y0 = y0; + d.y = y; + } + function d3_layout_stackOrderDefault(data) { + return d3.range(data.length); + } + function d3_layout_stackOffsetZero(data) { + var j = -1, m = data[0].length, y0 = []; + while (++j < m) y0[j] = 0; + return y0; + } + function d3_layout_stackMaxIndex(array) { + var i = 1, j = 0, v = array[0][1], k, n = array.length; + for (; i < n; ++i) { + if ((k = array[i][1]) > v) { + j = i; + v = k; + } + } + return j; + } + function d3_layout_stackReduceSum(d) { + return d.reduce(d3_layout_stackSum, 0); + } + function d3_layout_stackSum(p, d) { + return p + d[1]; + } + function d3_layout_histogramBinSturges(range, values) { + return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); + } + function d3_layout_histogramBinFixed(range, n) { + var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; + while (++x <= n) f[x] = m * x + b; + return f; + } + function d3_layout_histogramRange(values) { + return [ d3.min(values), d3.max(values) ]; + } + function d3_layout_hierarchyRebind(object, hierarchy) { + d3.rebind(object, hierarchy, "sort", "children", "value"); + object.links = d3_layout_hierarchyLinks; + object.nodes = function(d) { + d3_layout_hierarchyInline = true; + return (object.nodes = object)(d); + }; + return object; + } + function d3_layout_hierarchyChildren(d) { + return d.children; + } + function d3_layout_hierarchyValue(d) { + return d.value; + } + function d3_layout_hierarchySort(a, b) { + return b.value - a.value; + } + function d3_layout_hierarchyLinks(nodes) { + return d3.merge(nodes.map(function(parent) { + return (parent.children || []).map(function(child) { + return { + source: parent, + target: child + }; + }); + })); + } + function d3_layout_packSort(a, b) { + return a.value - b.value; + } + function d3_layout_packInsert(a, b) { + var c = a._pack_next; + a._pack_next = b; + b._pack_prev = a; + b._pack_next = c; + c._pack_prev = b; + } + function d3_layout_packSplice(a, b) { + a._pack_next = b; + b._pack_prev = a; + } + function d3_layout_packIntersects(a, b) { + var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; + return dr * dr - dx * dx - dy * dy > .001; + } + function d3_layout_packSiblings(node) { + function bound(node) { + xMin = Math.min(node.x - node.r, xMin); + xMax = Math.max(node.x + node.r, xMax); + yMin = Math.min(node.y - node.r, yMin); + yMax = Math.max(node.y + node.r, yMax); + } + if (!(nodes = node.children) || !(n = nodes.length)) return; + var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; + nodes.forEach(d3_layout_packLink); + a = nodes[0]; + a.x = -a.r; + a.y = 0; + bound(a); + if (n > 1) { + b = nodes[1]; + b.x = b.r; + b.y = 0; + bound(b); + if (n > 2) { + c = nodes[2]; + d3_layout_packPlace(a, b, c); + bound(c); + d3_layout_packInsert(a, c); + a._pack_prev = c; + d3_layout_packInsert(c, b); + b = a._pack_next; + for (i = 3; i < n; i++) { + d3_layout_packPlace(a, b, c = nodes[i]); + var isect = 0, s1 = 1, s2 = 1; + for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { + if (d3_layout_packIntersects(j, c)) { + isect = 1; + break; + } + } + if (isect == 1) { + for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { + if (d3_layout_packIntersects(k, c)) { + break; + } + } + } + if (isect) { + if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); + i--; + } else { + d3_layout_packInsert(a, c); + b = c; + bound(c); + } + } + } + } + var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; + for (i = 0; i < n; i++) { + c = nodes[i]; + c.x -= cx; + c.y -= cy; + cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); + } + node.r = cr; + nodes.forEach(d3_layout_packUnlink); + } + function d3_layout_packLink(node) { + node._pack_next = node._pack_prev = node; + } + function d3_layout_packUnlink(node) { + delete node._pack_next; + delete node._pack_prev; + } + function d3_layout_packTransform(node, x, y, k) { + var children = node.children; + node.x = x += k * node.x; + node.y = y += k * node.y; + node.r *= k; + if (children) { + var i = -1, n = children.length; + while (++i < n) d3_layout_packTransform(children[i], x, y, k); + } + } + function d3_layout_packPlace(a, b, c) { + var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; + if (db && (dx || dy)) { + var da = b.r + c.r, dc = dx * dx + dy * dy; + da *= da; + db *= db; + var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); + c.x = a.x + x * dx + y * dy; + c.y = a.y + x * dy - y * dx; + } else { + c.x = a.x + db; + c.y = a.y; + } + } + function d3_layout_clusterY(children) { + return 1 + d3.max(children, function(child) { + return child.y; + }); + } + function d3_layout_clusterX(children) { + return children.reduce(function(x, child) { + return x + child.x; + }, 0) / children.length; + } + function d3_layout_clusterLeft(node) { + var children = node.children; + return children && children.length ? d3_layout_clusterLeft(children[0]) : node; + } + function d3_layout_clusterRight(node) { + var children = node.children, n; + return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; + } + function d3_layout_treeSeparation(a, b) { + return a.parent == b.parent ? 1 : 2; + } + function d3_layout_treeLeft(node) { + var children = node.children; + return children && children.length ? children[0] : node._tree.thread; + } + function d3_layout_treeRight(node) { + var children = node.children, n; + return children && (n = children.length) ? children[n - 1] : node._tree.thread; + } + function d3_layout_treeSearch(node, compare) { + var children = node.children; + if (children && (n = children.length)) { + var child, n, i = -1; + while (++i < n) { + if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { + node = child; + } + } + } + return node; + } + function d3_layout_treeRightmost(a, b) { + return a.x - b.x; + } + function d3_layout_treeLeftmost(a, b) { + return b.x - a.x; + } + function d3_layout_treeDeepest(a, b) { + return a.depth - b.depth; + } + function d3_layout_treeVisitAfter(node, callback) { + function visit(node, previousSibling) { + var children = node.children; + if (children && (n = children.length)) { + var child, previousChild = null, i = -1, n; + while (++i < n) { + child = children[i]; + visit(child, previousChild); + previousChild = child; + } + } + callback(node, previousSibling); + } + visit(node, null); + } + function d3_layout_treeShift(node) { + var shift = 0, change = 0, children = node.children, i = children.length, child; + while (--i >= 0) { + child = children[i]._tree; + child.prelim += shift; + child.mod += shift; + shift += child.shift + (change += child.change); + } + } + function d3_layout_treeMove(ancestor, node, shift) { + ancestor = ancestor._tree; + node = node._tree; + var change = shift / (node.number - ancestor.number); + ancestor.change += change; + node.change -= change; + node.shift += shift; + node.prelim += shift; + node.mod += shift; + } + function d3_layout_treeAncestor(vim, node, ancestor) { + return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; + } + function d3_layout_treemapPadNull(node) { + return { + x: node.x, + y: node.y, + dx: node.dx, + dy: node.dy + }; + } + function d3_layout_treemapPad(node, padding) { + var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; + if (dx < 0) { + x += dx / 2; + dx = 0; + } + if (dy < 0) { + y += dy / 2; + dy = 0; + } + return { + x: x, + y: y, + dx: dx, + dy: dy + }; + } + function d3_dsv(delimiter, mimeType) { + function dsv(url, callback) { + d3.text(url, mimeType, function(text) { + callback(text && dsv.parse(text)); + }); + } + function formatRow(row) { + return row.map(formatValue).join(delimiter); + } + function formatValue(text) { + return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; + } + var reParse = new RegExp("\r\n|[" + delimiter + "\r\n]", "g"), reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); + dsv.parse = function(text) { + var header; + return dsv.parseRows(text, function(row, i) { + if (i) { + var o = {}, j = -1, m = header.length; + while (++j < m) o[header[j]] = row[j]; + return o; + } else { + header = row; + return null; + } + }); + }; + dsv.parseRows = function(text, f) { + function token() { + if (reParse.lastIndex >= text.length) return EOF; + if (eol) { + eol = false; + return EOL; + } + var j = reParse.lastIndex; + if (text.charCodeAt(j) === 34) { + var i = j; + while (i++ < text.length) { + if (text.charCodeAt(i) === 34) { + if (text.charCodeAt(i + 1) !== 34) break; + i++; + } + } + reParse.lastIndex = i + 2; + var c = text.charCodeAt(i + 1); + if (c === 13) { + eol = true; + if (text.charCodeAt(i + 2) === 10) reParse.lastIndex++; + } else if (c === 10) { + eol = true; + } + return text.substring(j + 1, i).replace(/""/g, '"'); + } + var m = reParse.exec(text); + if (m) { + eol = m[0].charCodeAt(0) !== delimiterCode; + return text.substring(j, m.index); + } + reParse.lastIndex = text.length; + return text.substring(j); + } + var EOL = {}, EOF = {}, rows = [], n = 0, t, eol; + reParse.lastIndex = 0; + while ((t = token()) !== EOF) { + var a = []; + while (t !== EOL && t !== EOF) { + a.push(t); + t = token(); + } + if (f && !(a = f(a, n++))) continue; + rows.push(a); + } + return rows; + }; + dsv.format = function(rows) { + return rows.map(formatRow).join("\n"); + }; + return dsv; + } + function d3_geo_type(types, defaultValue) { + return function(object) { + return object && types.hasOwnProperty(object.type) ? types[object.type](object) : defaultValue; + }; + } + function d3_path_circle(radius) { + return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + +2 * radius + "z"; + } + function d3_geo_bounds(o, f) { + if (d3_geo_boundsTypes.hasOwnProperty(o.type)) d3_geo_boundsTypes[o.type](o, f); + } + function d3_geo_boundsFeature(o, f) { + d3_geo_bounds(o.geometry, f); + } + function d3_geo_boundsFeatureCollection(o, f) { + for (var a = o.features, i = 0, n = a.length; i < n; i++) { + d3_geo_bounds(a[i].geometry, f); + } + } + function d3_geo_boundsGeometryCollection(o, f) { + for (var a = o.geometries, i = 0, n = a.length; i < n; i++) { + d3_geo_bounds(a[i], f); + } + } + function d3_geo_boundsLineString(o, f) { + for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) { + f.apply(null, a[i]); + } + } + function d3_geo_boundsMultiLineString(o, f) { + for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) { + for (var b = a[i], j = 0, m = b.length; j < m; j++) { + f.apply(null, b[j]); + } + } + } + function d3_geo_boundsMultiPolygon(o, f) { + for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) { + for (var b = a[i][0], j = 0, m = b.length; j < m; j++) { + f.apply(null, b[j]); + } + } + } + function d3_geo_boundsPoint(o, f) { + f.apply(null, o.coordinates); + } + function d3_geo_boundsPolygon(o, f) { + for (var a = o.coordinates[0], i = 0, n = a.length; i < n; i++) { + f.apply(null, a[i]); + } + } + function d3_geo_greatArcSource(d) { + return d.source; + } + function d3_geo_greatArcTarget(d) { + return d.target; + } + function d3_geo_greatArcInterpolator() { + function interpolate(t) { + var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; + return [ Math.atan2(y, x) / d3_geo_radians, Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_geo_radians ]; + } + var x0, y0, cy0, sy0, kx0, ky0, x1, y1, cy1, sy1, kx1, ky1, d, k; + interpolate.distance = function() { + if (d == null) k = 1 / Math.sin(d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0))))); + return d; + }; + interpolate.source = function(_) { + var cx0 = Math.cos(x0 = _[0] * d3_geo_radians), sx0 = Math.sin(x0); + cy0 = Math.cos(y0 = _[1] * d3_geo_radians); + sy0 = Math.sin(y0); + kx0 = cy0 * cx0; + ky0 = cy0 * sx0; + d = null; + return interpolate; + }; + interpolate.target = function(_) { + var cx1 = Math.cos(x1 = _[0] * d3_geo_radians), sx1 = Math.sin(x1); + cy1 = Math.cos(y1 = _[1] * d3_geo_radians); + sy1 = Math.sin(y1); + kx1 = cy1 * cx1; + ky1 = cy1 * sx1; + d = null; + return interpolate; + }; + return interpolate; + } + function d3_geo_greatArcInterpolate(a, b) { + var i = d3_geo_greatArcInterpolator().source(a).target(b); + i.distance(); + return i; + } + function d3_geom_contourStart(grid) { + var x = 0, y = 0; + while (true) { + if (grid(x, y)) { + return [ x, y ]; + } + if (x === 0) { + x = y + 1; + y = 0; + } else { + x = x - 1; + y = y + 1; + } + } + } + function d3_geom_hullCCW(i1, i2, i3, v) { + var t, a, b, c, d, e, f; + t = v[i1]; + a = t[0]; + b = t[1]; + t = v[i2]; + c = t[0]; + d = t[1]; + t = v[i3]; + e = t[0]; + f = t[1]; + return (f - b) * (c - a) - (d - b) * (e - a) > 0; + } + function d3_geom_polygonInside(p, a, b) { + return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); + } + function d3_geom_polygonIntersect(c, d, a, b) { + var x1 = c[0], x2 = d[0], x3 = a[0], x4 = b[0], y1 = c[1], y2 = d[1], y3 = a[1], y4 = b[1], x13 = x1 - x3, x21 = x2 - x1, x43 = x4 - x3, y13 = y1 - y3, y21 = y2 - y1, y43 = y4 - y3, ua = (x43 * y13 - y43 * x13) / (y43 * x21 - x43 * y21); + return [ x1 + ua * x21, y1 + ua * y21 ]; + } + function d3_voronoi_tessellate(vertices, callback) { + var Sites = { + list: vertices.map(function(v, i) { + return { + index: i, + x: v[0], + y: v[1] + }; + }).sort(function(a, b) { + return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; + }), + bottomSite: null + }; + var EdgeList = { + list: [], + leftEnd: null, + rightEnd: null, + init: function() { + EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.leftEnd.r = EdgeList.rightEnd; + EdgeList.rightEnd.l = EdgeList.leftEnd; + EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); + }, + createHalfEdge: function(edge, side) { + return { + edge: edge, + side: side, + vertex: null, + l: null, + r: null + }; + }, + insert: function(lb, he) { + he.l = lb; + he.r = lb.r; + lb.r.l = he; + lb.r = he; + }, + leftBound: function(p) { + var he = EdgeList.leftEnd; + do { + he = he.r; + } while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); + he = he.l; + return he; + }, + del: function(he) { + he.l.r = he.r; + he.r.l = he.l; + he.edge = null; + }, + right: function(he) { + return he.r; + }, + left: function(he) { + return he.l; + }, + leftRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; + }, + rightRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[d3_voronoi_opposite[he.side]]; + } + }; + var Geom = { + bisect: function(s1, s2) { + var newEdge = { + region: { + l: s1, + r: s2 + }, + ep: { + l: null, + r: null + } + }; + var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; + newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; + if (adx > ady) { + newEdge.a = 1; + newEdge.b = dy / dx; + newEdge.c /= dx; + } else { + newEdge.b = 1; + newEdge.a = dx / dy; + newEdge.c /= dy; + } + return newEdge; + }, + intersect: function(el1, el2) { + var e1 = el1.edge, e2 = el2.edge; + if (!e1 || !e2 || e1.region.r == e2.region.r) { + return null; + } + var d = e1.a * e2.b - e1.b * e2.a; + if (Math.abs(d) < 1e-10) { + return null; + } + var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; + if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { + el = el1; + e = e1; + } else { + el = el2; + e = e2; + } + var rightOfSite = xint >= e.region.r.x; + if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { + return null; + } + return { + x: xint, + y: yint + }; + }, + rightOf: function(he, p) { + var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; + if (rightOfSite && he.side === "l") { + return 1; + } + if (!rightOfSite && he.side === "r") { + return 0; + } + if (e.a === 1) { + var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; + if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { + above = fast = dyp >= e.b * dxp; + } else { + above = p.x + p.y * e.b > e.c; + if (e.b < 0) { + above = !above; + } + if (!above) { + fast = 1; + } + } + if (!fast) { + var dxs = topsite.x - e.region.l.x; + above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); + if (e.b < 0) { + above = !above; + } + } + } else { + var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; + above = t1 * t1 > t2 * t2 + t3 * t3; + } + return he.side === "l" ? above : !above; + }, + endPoint: function(edge, side, site) { + edge.ep[side] = site; + if (!edge.ep[d3_voronoi_opposite[side]]) return; + callback(edge); + }, + distance: function(s, t) { + var dx = s.x - t.x, dy = s.y - t.y; + return Math.sqrt(dx * dx + dy * dy); + } + }; + var EventQueue = { + list: [], + insert: function(he, site, offset) { + he.vertex = site; + he.ystar = site.y + offset; + for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { + var next = list[i]; + if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { + continue; + } else { + break; + } + } + list.splice(i, 0, he); + }, + del: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} + ls.splice(i, 1); + }, + empty: function() { + return EventQueue.list.length === 0; + }, + nextEvent: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { + if (ls[i] == he) return ls[i + 1]; + } + return null; + }, + min: function() { + var elem = EventQueue.list[0]; + return { + x: elem.vertex.x, + y: elem.ystar + }; + }, + extractMin: function() { + return EventQueue.list.shift(); + } + }; + EdgeList.init(); + Sites.bottomSite = Sites.list.shift(); + var newSite = Sites.list.shift(), newIntStar; + var lbnd, rbnd, llbnd, rrbnd, bisector; + var bot, top, temp, p, v; + var e, pm; + while (true) { + if (!EventQueue.empty()) { + newIntStar = EventQueue.min(); + } + if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { + lbnd = EdgeList.leftBound(newSite); + rbnd = EdgeList.right(lbnd); + bot = EdgeList.rightRegion(lbnd); + e = Geom.bisect(bot, newSite); + bisector = EdgeList.createHalfEdge(e, "l"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(lbnd, bisector); + if (p) { + EventQueue.del(lbnd); + EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); + } + lbnd = bisector; + bisector = EdgeList.createHalfEdge(e, "r"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(bisector, rbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, newSite)); + } + newSite = Sites.list.shift(); + } else if (!EventQueue.empty()) { + lbnd = EventQueue.extractMin(); + llbnd = EdgeList.left(lbnd); + rbnd = EdgeList.right(lbnd); + rrbnd = EdgeList.right(rbnd); + bot = EdgeList.leftRegion(lbnd); + top = EdgeList.rightRegion(rbnd); + v = lbnd.vertex; + Geom.endPoint(lbnd.edge, lbnd.side, v); + Geom.endPoint(rbnd.edge, rbnd.side, v); + EdgeList.del(lbnd); + EventQueue.del(rbnd); + EdgeList.del(rbnd); + pm = "l"; + if (bot.y > top.y) { + temp = bot; + bot = top; + top = temp; + pm = "r"; + } + e = Geom.bisect(bot, top); + bisector = EdgeList.createHalfEdge(e, pm); + EdgeList.insert(llbnd, bisector); + Geom.endPoint(e, d3_voronoi_opposite[pm], v); + p = Geom.intersect(llbnd, bisector); + if (p) { + EventQueue.del(llbnd); + EventQueue.insert(llbnd, p, Geom.distance(p, bot)); + } + p = Geom.intersect(bisector, rrbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, bot)); + } + } else { + break; + } + } + for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { + callback(lbnd.edge); + } + } + function d3_geom_quadtreeNode() { + return { + leaf: true, + nodes: [], + point: null + }; + } + function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { + if (!f(node, x1, y1, x2, y2)) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; + if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); + if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); + if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); + if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); + } + } + function d3_geom_quadtreePoint(p) { + return { + x: p[0], + y: p[1] + }; + } + function d3_time_utc() { + this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); + } + function d3_time_formatAbbreviate(name) { + return name.substring(0, 3); + } + function d3_time_parse(date, template, string, j) { + var c, p, i = 0, n = template.length, m = string.length; + while (i < n) { + if (j >= m) return -1; + c = template.charCodeAt(i++); + if (c == 37) { + p = d3_time_parsers[template.charAt(i++)]; + if (!p || (j = p(date, string, j)) < 0) return -1; + } else if (c != string.charCodeAt(j++)) { + return -1; + } + } + return j; + } + function d3_time_formatRe(names) { + return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); + } + function d3_time_formatLookup(names) { + var map = new d3_Map, i = -1, n = names.length; + while (++i < n) map.set(names[i].toLowerCase(), i); + return map; + } + function d3_time_parseWeekdayAbbrev(date, string, i) { + d3_time_dayAbbrevRe.lastIndex = 0; + var n = d3_time_dayAbbrevRe.exec(string.substring(i)); + return n ? i += n[0].length : -1; + } + function d3_time_parseWeekday(date, string, i) { + d3_time_dayRe.lastIndex = 0; + var n = d3_time_dayRe.exec(string.substring(i)); + return n ? i += n[0].length : -1; + } + function d3_time_parseMonthAbbrev(date, string, i) { + d3_time_monthAbbrevRe.lastIndex = 0; + var n = d3_time_monthAbbrevRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i += n[0].length) : -1; + } + function d3_time_parseMonth(date, string, i) { + d3_time_monthRe.lastIndex = 0; + var n = d3_time_monthRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i += n[0].length) : -1; + } + function d3_time_parseLocaleFull(date, string, i) { + return d3_time_parse(date, d3_time_formats.c.toString(), string, i); + } + function d3_time_parseLocaleDate(date, string, i) { + return d3_time_parse(date, d3_time_formats.x.toString(), string, i); + } + function d3_time_parseLocaleTime(date, string, i) { + return d3_time_parse(date, d3_time_formats.X.toString(), string, i); + } + function d3_time_parseFullYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 4)); + return n ? (date.y = +n[0], i += n[0].length) : -1; + } + function d3_time_parseYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -1; + } + function d3_time_expandYear(d) { + return d + (d > 68 ? 1900 : 2e3); + } + function d3_time_parseMonthNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.m = n[0] - 1, i += n[0].length) : -1; + } + function d3_time_parseDay(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.d = +n[0], i += n[0].length) : -1; + } + function d3_time_parseHour24(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.H = +n[0], i += n[0].length) : -1; + } + function d3_time_parseMinutes(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.M = +n[0], i += n[0].length) : -1; + } + function d3_time_parseSeconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.S = +n[0], i += n[0].length) : -1; + } + function d3_time_parseMilliseconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.L = +n[0], i += n[0].length) : -1; + } + function d3_time_parseAmPm(date, string, i) { + var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); + return n == null ? -1 : (date.p = n, i); + } + function d3_time_zone(d) { + var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; + return zs + d3_time_zfill2(zh) + d3_time_zfill2(zm); + } + function d3_time_formatIsoNative(date) { + return date.toISOString(); + } + function d3_time_interval(local, step, number) { + function round(date) { + var d0 = local(date), d1 = offset(d0, 1); + return date - d0 < d1 - date ? d0 : d1; + } + function ceil(date) { + step(date = local(new d3_time(date - 1)), 1); + return date; + } + function offset(date, k) { + step(date = new d3_time(+date), k); + return date; + } + function range(t0, t1, dt) { + var time = ceil(t0), times = []; + if (dt > 1) { + while (time < t1) { + if (!(number(time) % dt)) times.push(new Date(+time)); + step(time, 1); + } + } else { + while (time < t1) times.push(new Date(+time)), step(time, 1); + } + return times; + } + function range_utc(t0, t1, dt) { + try { + d3_time = d3_time_utc; + var utc = new d3_time_utc; + utc._ = t0; + return range(utc, t1, dt); + } finally { + d3_time = Date; + } + } + local.floor = local; + local.round = round; + local.ceil = ceil; + local.offset = offset; + local.range = range; + var utc = local.utc = d3_time_interval_utc(local); + utc.floor = utc; + utc.round = d3_time_interval_utc(round); + utc.ceil = d3_time_interval_utc(ceil); + utc.offset = d3_time_interval_utc(offset); + utc.range = range_utc; + return local; + } + function d3_time_interval_utc(method) { + return function(date, k) { + try { + d3_time = d3_time_utc; + var utc = new d3_time_utc; + utc._ = date; + return method(utc, k)._; + } finally { + d3_time = Date; + } + }; + } + function d3_time_scale(linear, methods, format) { + function scale(x) { + return linear(x); + } + scale.invert = function(x) { + return d3_time_scaleDate(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return linear.domain().map(d3_time_scaleDate); + linear.domain(x); + return scale; + }; + scale.nice = function(m) { + return scale.domain(d3_scale_nice(scale.domain(), function() { + return m; + })); + }; + scale.ticks = function(m, k) { + var extent = d3_time_scaleExtent(scale.domain()); + if (typeof m !== "function") { + var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); + if (i == d3_time_scaleSteps.length) return methods.year(extent, m); + if (!i) return linear.ticks(m).map(d3_time_scaleDate); + if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i; + m = methods[i]; + k = m[1]; + m = m[0].range; + } + return m(extent[0], new Date(+extent[1] + 1), k); + }; + scale.tickFormat = function() { + return format; + }; + scale.copy = function() { + return d3_time_scale(linear.copy(), methods, format); + }; + return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); + } + function d3_time_scaleExtent(domain) { + var start = domain[0], stop = domain[domain.length - 1]; + return start < stop ? [ start, stop ] : [ stop, start ]; + } + function d3_time_scaleDate(t) { + return new Date(t); + } + function d3_time_scaleFormat(formats) { + return function(date) { + var i = formats.length - 1, f = formats[i]; + while (!f[1](date)) f = formats[--i]; + return f[0](date); + }; + } + function d3_time_scaleSetYear(y) { + var d = new Date(y, 0, 1); + d.setFullYear(y); + return d; + } + function d3_time_scaleGetYear(d) { + var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); + return y + (d - d0) / (d1 - d0); + } + function d3_time_scaleUTCSetYear(y) { + var d = new Date(Date.UTC(y, 0, 1)); + d.setUTCFullYear(y); + return d; + } + function d3_time_scaleUTCGetYear(d) { + var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); + return y + (d - d0) / (d1 - d0); + } + if (!Date.now) Date.now = function() { + return +(new Date); + }; + try { + document.createElement("div").style.setProperty("opacity", 0, ""); + } catch (error) { + var d3_style_prototype = CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; + d3_style_prototype.setProperty = function(name, value, priority) { + d3_style_setProperty.call(this, name, value + "", priority); + }; + } + d3 = { + version: "2.10.1" + }; + var d3_array = d3_arraySlice; + try { + d3_array(document.documentElement.childNodes)[0].nodeType; + } catch (e) { + d3_array = d3_arrayCopy; + } + var d3_arraySubclass = [].__proto__ ? function(array, prototype) { + array.__proto__ = prototype; + } : function(array, prototype) { + for (var property in prototype) array[property] = prototype[property]; + }; + d3.map = function(object) { + var map = new d3_Map; + for (var key in object) map.set(key, object[key]); + return map; + }; + d3_class(d3_Map, { + has: function(key) { + return d3_map_prefix + key in this; + }, + get: function(key) { + return this[d3_map_prefix + key]; + }, + set: function(key, value) { + return this[d3_map_prefix + key] = value; + }, + remove: function(key) { + key = d3_map_prefix + key; + return key in this && delete this[key]; + }, + keys: function() { + var keys = []; + this.forEach(function(key) { + keys.push(key); + }); + return keys; + }, + values: function() { + var values = []; + this.forEach(function(key, value) { + values.push(value); + }); + return values; + }, + entries: function() { + var entries = []; + this.forEach(function(key, value) { + entries.push({ + key: key, + value: value + }); + }); + return entries; + }, + forEach: function(f) { + for (var key in this) { + if (key.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, key.substring(1), this[key]); + } + } + } + }); + var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); + d3.functor = d3_functor; + d3.rebind = function(target, source) { + var i = 1, n = arguments.length, method; + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); + return target; + }; + d3.ascending = function(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; + }; + d3.descending = function(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; + }; + d3.mean = function(array, f) { + var n = array.length, a, m = 0, i = -1, j = 0; + if (arguments.length === 1) { + while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; + } else { + while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; + } + return j ? m : undefined; + }; + d3.median = function(array, f) { + if (arguments.length > 1) array = array.map(f); + array = array.filter(d3_number); + return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; + }; + d3.min = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && a > b) a = b; + } else { + while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; + } + return a; + }; + d3.max = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && b > a) a = b; + } else { + while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; + } + return a; + }; + d3.extent = function(array, f) { + var i = -1, n = array.length, a, b, c; + if (arguments.length === 1) { + while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined; + while (++i < n) if ((b = array[i]) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } else { + while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } + return [ a, c ]; + }; + d3.random = { + normal: function(µ, σ) { + var n = arguments.length; + if (n < 2) σ = 1; + if (n < 1) µ = 0; + return function() { + var x, y, r; + do { + x = Math.random() * 2 - 1; + y = Math.random() * 2 - 1; + r = x * x + y * y; + } while (!r || r > 1); + return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); + }; + }, + logNormal: function(µ, σ) { + var n = arguments.length; + if (n < 2) σ = 1; + if (n < 1) µ = 0; + var random = d3.random.normal(); + return function() { + return Math.exp(µ + σ * random()); + }; + }, + irwinHall: function(m) { + return function() { + for (var s = 0, j = 0; j < m; j++) s += Math.random(); + return s / m; + }; + } + }; + d3.sum = function(array, f) { + var s = 0, n = array.length, a, i = -1; + if (arguments.length === 1) { + while (++i < n) if (!isNaN(a = +array[i])) s += a; + } else { + while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; + } + return s; + }; + d3.quantile = function(values, p) { + var H = (values.length - 1) * p + 1, h = Math.floor(H), v = values[h - 1], e = H - h; + return e ? v + e * (values[h] - v) : v; + }; + d3.transpose = function(matrix) { + return d3.zip.apply(d3, matrix); + }; + d3.zip = function() { + if (!(n = arguments.length)) return []; + for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { + for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { + zip[j] = arguments[j][i]; + } + } + return zips; + }; + d3.bisector = function(f) { + return { + left: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; + } + return lo; + }, + right: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; + } + return lo; + } + }; + }; + var d3_bisector = d3.bisector(function(d) { + return d; + }); + d3.bisectLeft = d3_bisector.left; + d3.bisect = d3.bisectRight = d3_bisector.right; + d3.first = function(array, f) { + var i = 0, n = array.length, a = array[0], b; + if (arguments.length === 1) f = d3.ascending; + while (++i < n) { + if (f.call(array, a, b = array[i]) > 0) { + a = b; + } + } + return a; + }; + d3.last = function(array, f) { + var i = 0, n = array.length, a = array[0], b; + if (arguments.length === 1) f = d3.ascending; + while (++i < n) { + if (f.call(array, a, b = array[i]) <= 0) { + a = b; + } + } + return a; + }; + d3.nest = function() { + function map(array, depth) { + if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; + var i = -1, n = array.length, key = keys[depth++], keyValue, object, valuesByKey = new d3_Map, values, o = {}; + while (++i < n) { + if (values = valuesByKey.get(keyValue = key(object = array[i]))) { + values.push(object); + } else { + valuesByKey.set(keyValue, [ object ]); + } + } + valuesByKey.forEach(function(keyValue, values) { + o[keyValue] = map(values, depth); + }); + return o; + } + function entries(map, depth) { + if (depth >= keys.length) return map; + var a = [], sortKey = sortKeys[depth++], key; + for (key in map) { + a.push({ + key: key, + values: entries(map[key], depth) + }); + } + if (sortKey) a.sort(function(a, b) { + return sortKey(a.key, b.key); + }); + return a; + } + var nest = {}, keys = [], sortKeys = [], sortValues, rollup; + nest.map = function(array) { + return map(array, 0); + }; + nest.entries = function(array) { + return entries(map(array, 0), 0); + }; + nest.key = function(d) { + keys.push(d); + return nest; + }; + nest.sortKeys = function(order) { + sortKeys[keys.length - 1] = order; + return nest; + }; + nest.sortValues = function(order) { + sortValues = order; + return nest; + }; + nest.rollup = function(f) { + rollup = f; + return nest; + }; + return nest; + }; + d3.keys = function(map) { + var keys = []; + for (var key in map) keys.push(key); + return keys; + }; + d3.values = function(map) { + var values = []; + for (var key in map) values.push(map[key]); + return values; + }; + d3.entries = function(map) { + var entries = []; + for (var key in map) entries.push({ + key: key, + value: map[key] + }); + return entries; + }; + d3.permute = function(array, indexes) { + var permutes = [], i = -1, n = indexes.length; + while (++i < n) permutes[i] = array[indexes[i]]; + return permutes; + }; + d3.merge = function(arrays) { + return Array.prototype.concat.apply([], arrays); + }; + d3.split = function(array, f) { + var arrays = [], values = [], value, i = -1, n = array.length; + if (arguments.length < 2) f = d3_splitter; + while (++i < n) { + if (f.call(values, value = array[i], i)) { + values = []; + } else { + if (!values.length) arrays.push(values); + values.push(value); + } + } + return arrays; + }; + d3.range = function(start, stop, step) { + if (arguments.length < 3) { + step = 1; + if (arguments.length < 2) { + stop = start; + start = 0; + } + } + if ((stop - start) / step === Infinity) throw new Error("infinite range"); + var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; + start *= k, stop *= k, step *= k; + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); + return range; + }; + d3.requote = function(s) { + return s.replace(d3_requote_re, "\\$&"); + }; + var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; + d3.round = function(x, n) { + return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); + }; + d3.xhr = function(url, mime, callback) { + var req = new XMLHttpRequest; + if (arguments.length < 3) callback = mime, mime = null; else if (mime && req.overrideMimeType) req.overrideMimeType(mime); + req.open("GET", url, true); + if (mime) req.setRequestHeader("Accept", mime); + req.onreadystatechange = function() { + if (req.readyState === 4) { + var s = req.status; + callback(!s && req.response || s >= 200 && s < 300 || s === 304 ? req : null); + } + }; + req.send(null); + }; + d3.text = function(url, mime, callback) { + function ready(req) { + callback(req && req.responseText); + } + if (arguments.length < 3) { + callback = mime; + mime = null; + } + d3.xhr(url, mime, ready); + }; + d3.json = function(url, callback) { + d3.text(url, "application/json", function(text) { + callback(text ? JSON.parse(text) : null); + }); + }; + d3.html = function(url, callback) { + d3.text(url, "text/html", function(text) { + if (text != null) { + var range = document.createRange(); + range.selectNode(document.body); + text = range.createContextualFragment(text); + } + callback(text); + }); + }; + d3.xml = function(url, mime, callback) { + function ready(req) { + callback(req && req.responseXML); + } + if (arguments.length < 3) { + callback = mime; + mime = null; + } + d3.xhr(url, mime, ready); + }; + var d3_nsPrefix = { + svg: "http://www.w3.org/2000/svg", + xhtml: "http://www.w3.org/1999/xhtml", + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" + }; + d3.ns = { + prefix: d3_nsPrefix, + qualify: function(name) { + var i = name.indexOf(":"), prefix = name; + if (i >= 0) { + prefix = name.substring(0, i); + name = name.substring(i + 1); + } + return d3_nsPrefix.hasOwnProperty(prefix) ? { + space: d3_nsPrefix[prefix], + local: name + } : name; + } + }; + d3.dispatch = function() { + var dispatch = new d3_dispatch, i = -1, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + return dispatch; + }; + d3_dispatch.prototype.on = function(type, listener) { + var i = type.indexOf("."), name = ""; + if (i > 0) { + name = type.substring(i + 1); + type = type.substring(0, i); + } + return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); + }; + d3.format = function(specifier) { + var match = d3_format_re.exec(specifier), fill = match[1] || " ", sign = match[3] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; + if (precision) precision = +precision.substring(1); + if (zfill) { + fill = "0"; + if (comma) width -= Math.floor((width - 1) / 4); + } + switch (type) { + case "n": + comma = true; + type = "g"; + break; + case "%": + scale = 100; + suffix = "%"; + type = "f"; + break; + case "p": + scale = 100; + suffix = "%"; + type = "r"; + break; + case "d": + integer = true; + precision = 0; + break; + case "s": + scale = -1; + type = "r"; + break; + } + if (type == "r" && !precision) type = "g"; + type = d3_format_types.get(type) || d3_format_typeDefault; + return function(value) { + if (integer && value % 1) return ""; + var negative = value < 0 && (value = -value) ? "-" : sign; + if (scale < 0) { + var prefix = d3.formatPrefix(value, precision); + value = prefix.scale(value); + suffix = prefix.symbol; + } else { + value *= scale; + } + value = type(value, precision); + if (zfill) { + var length = value.length + negative.length; + if (length < width) value = (new Array(width - length + 1)).join(fill) + value; + if (comma) value = d3_format_group(value); + value = negative + value; + } else { + if (comma) value = d3_format_group(value); + value = negative + value; + var length = value.length; + if (length < width) value = (new Array(width - length + 1)).join(fill) + value; + } + return value + suffix; + }; + }; + var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/; + var d3_format_types = d3.map({ + g: function(x, p) { + return x.toPrecision(p); + }, + e: function(x, p) { + return x.toExponential(p); + }, + f: function(x, p) { + return x.toFixed(p); + }, + r: function(x, p) { + return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p))); + } + }); + var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "μ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); + d3.formatPrefix = function(value, precision) { + var i = 0; + if (value) { + if (value < 0) value *= -1; + if (precision) value = d3.round(value, d3_format_precision(value, precision)); + i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); + i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); + } + return d3_formatPrefixes[8 + i / 3]; + }; + var d3_ease_quad = d3_ease_poly(2), d3_ease_cubic = d3_ease_poly(3), d3_ease_default = function() { + return d3_ease_identity; + }; + var d3_ease = d3.map({ + linear: d3_ease_default, + poly: d3_ease_poly, + quad: function() { + return d3_ease_quad; + }, + cubic: function() { + return d3_ease_cubic; + }, + sin: function() { + return d3_ease_sin; + }, + exp: function() { + return d3_ease_exp; + }, + circle: function() { + return d3_ease_circle; + }, + elastic: d3_ease_elastic, + back: d3_ease_back, + bounce: function() { + return d3_ease_bounce; + } + }); + var d3_ease_mode = d3.map({ + "in": d3_ease_identity, + out: d3_ease_reverse, + "in-out": d3_ease_reflect, + "out-in": function(f) { + return d3_ease_reflect(d3_ease_reverse(f)); + } + }); + d3.ease = function(name) { + var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; + t = d3_ease.get(t) || d3_ease_default; + m = d3_ease_mode.get(m) || d3_ease_identity; + return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); + }; + d3.event = null; + d3.transform = function(string) { + var g = document.createElementNS(d3.ns.prefix.svg, "g"); + return (d3.transform = function(string) { + g.setAttribute("transform", string); + var t = g.transform.baseVal.consolidate(); + return new d3_transform(t ? t.matrix : d3_transformIdentity); + })(string); + }; + d3_transform.prototype.toString = function() { + return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; + }; + var d3_transformDegrees = 180 / Math.PI, d3_transformIdentity = { + a: 1, + b: 0, + c: 0, + d: 1, + e: 0, + f: 0 + }; + d3.interpolate = function(a, b) { + var i = d3.interpolators.length, f; + while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; + return f; + }; + d3.interpolateNumber = function(a, b) { + b -= a; + return function(t) { + return a + b * t; + }; + }; + d3.interpolateRound = function(a, b) { + b -= a; + return function(t) { + return Math.round(a + b * t); + }; + }; + d3.interpolateString = function(a, b) { + var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; + d3_interpolate_number.lastIndex = 0; + for (i = 0; m = d3_interpolate_number.exec(b); ++i) { + if (m.index) s.push(b.substring(s0, s1 = m.index)); + q.push({ + i: s.length, + x: m[0] + }); + s.push(null); + s0 = d3_interpolate_number.lastIndex; + } + if (s0 < b.length) s.push(b.substring(s0)); + for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { + o = q[i]; + if (o.x == m[0]) { + if (o.i) { + if (s[o.i + 1] == null) { + s[o.i - 1] += o.x; + s.splice(o.i, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } else { + s[o.i - 1] += o.x + s[o.i + 1]; + s.splice(o.i, 2); + for (j = i + 1; j < n; ++j) q[j].i -= 2; + } + } else { + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } + } + q.splice(i, 1); + n--; + i--; + } else { + o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); + } + } + while (i < n) { + o = q.pop(); + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + } + n--; + } + if (s.length === 1) { + return s[0] == null ? q[0].x : function() { + return b; + }; + } + return function(t) { + for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + }; + d3.interpolateTransform = function(a, b) { + var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; + if (ta[0] != tb[0] || ta[1] != tb[1]) { + s.push("translate(", null, ",", null, ")"); + q.push({ + i: 1, + x: d3.interpolateNumber(ta[0], tb[0]) + }, { + i: 3, + x: d3.interpolateNumber(ta[1], tb[1]) + }); + } else if (tb[0] || tb[1]) { + s.push("translate(" + tb + ")"); + } else { + s.push(""); + } + if (ra != rb) { + if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; + q.push({ + i: s.push(s.pop() + "rotate(", null, ")") - 2, + x: d3.interpolateNumber(ra, rb) + }); + } else if (rb) { + s.push(s.pop() + "rotate(" + rb + ")"); + } + if (wa != wb) { + q.push({ + i: s.push(s.pop() + "skewX(", null, ")") - 2, + x: d3.interpolateNumber(wa, wb) + }); + } else if (wb) { + s.push(s.pop() + "skewX(" + wb + ")"); + } + if (ka[0] != kb[0] || ka[1] != kb[1]) { + n = s.push(s.pop() + "scale(", null, ",", null, ")"); + q.push({ + i: n - 4, + x: d3.interpolateNumber(ka[0], kb[0]) + }, { + i: n - 2, + x: d3.interpolateNumber(ka[1], kb[1]) + }); + } else if (kb[0] != 1 || kb[1] != 1) { + s.push(s.pop() + "scale(" + kb + ")"); + } + n = q.length; + return function(t) { + var i = -1, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + }; + d3.interpolateRgb = function(a, b) { + a = d3.rgb(a); + b = d3.rgb(b); + var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; + return function(t) { + return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); + }; + }; + d3.interpolateHsl = function(a, b) { + a = d3.hsl(a); + b = d3.hsl(b); + var h0 = a.h, s0 = a.s, l0 = a.l, h1 = b.h - h0, s1 = b.s - s0, l1 = b.l - l0; + if (h1 > 180) h1 -= 360; else if (h1 < -180) h1 += 360; + return function(t) { + return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t) + ""; + }; + }; + d3.interpolateLab = function(a, b) { + a = d3.lab(a); + b = d3.lab(b); + var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; + return function(t) { + return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; + }; + }; + d3.interpolateHcl = function(a, b) { + a = d3.hcl(a); + b = d3.hcl(b); + var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; + if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; + }; + }; + d3.interpolateArray = function(a, b) { + var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; + for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i])); + for (; i < na; ++i) c[i] = a[i]; + for (; i < nb; ++i) c[i] = b[i]; + return function(t) { + for (i = 0; i < n0; ++i) c[i] = x[i](t); + return c; + }; + }; + d3.interpolateObject = function(a, b) { + var i = {}, c = {}, k; + for (k in a) { + if (k in b) { + i[k] = d3_interpolateByName(k)(a[k], b[k]); + } else { + c[k] = a[k]; + } + } + for (k in b) { + if (!(k in a)) { + c[k] = b[k]; + } + } + return function(t) { + for (k in i) c[k] = i[k](t); + return c; + }; + }; + var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; + d3.interpolators = [ d3.interpolateObject, function(a, b) { + return b instanceof Array && d3.interpolateArray(a, b); + }, function(a, b) { + return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + ""); + }, function(a, b) { + return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(a, b); + }, function(a, b) { + return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b); + } ]; + d3.rgb = function(r, g, b) { + return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); + }; + d3_Rgb.prototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + var r = this.r, g = this.g, b = this.b, i = 30; + if (!r && !g && !b) return d3_rgb(i, i, i); + if (r && r < i) r = i; + if (g && g < i) g = i; + if (b && b < i) b = i; + return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)), Math.min(255, Math.floor(b / k))); + }; + d3_Rgb.prototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(k * this.b)); + }; + d3_Rgb.prototype.hsl = function() { + return d3_rgb_hsl(this.r, this.g, this.b); + }; + d3_Rgb.prototype.toString = function() { + return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); + }; + var d3_rgb_names = d3.map({ + aliceblue: "#f0f8ff", + antiquewhite: "#faebd7", + aqua: "#00ffff", + aquamarine: "#7fffd4", + azure: "#f0ffff", + beige: "#f5f5dc", + bisque: "#ffe4c4", + black: "#000000", + blanchedalmond: "#ffebcd", + blue: "#0000ff", + blueviolet: "#8a2be2", + brown: "#a52a2a", + burlywood: "#deb887", + cadetblue: "#5f9ea0", + chartreuse: "#7fff00", + chocolate: "#d2691e", + coral: "#ff7f50", + cornflowerblue: "#6495ed", + cornsilk: "#fff8dc", + crimson: "#dc143c", + cyan: "#00ffff", + darkblue: "#00008b", + darkcyan: "#008b8b", + darkgoldenrod: "#b8860b", + darkgray: "#a9a9a9", + darkgreen: "#006400", + darkgrey: "#a9a9a9", + darkkhaki: "#bdb76b", + darkmagenta: "#8b008b", + darkolivegreen: "#556b2f", + darkorange: "#ff8c00", + darkorchid: "#9932cc", + darkred: "#8b0000", + darksalmon: "#e9967a", + darkseagreen: "#8fbc8f", + darkslateblue: "#483d8b", + darkslategray: "#2f4f4f", + darkslategrey: "#2f4f4f", + darkturquoise: "#00ced1", + darkviolet: "#9400d3", + deeppink: "#ff1493", + deepskyblue: "#00bfff", + dimgray: "#696969", + dimgrey: "#696969", + dodgerblue: "#1e90ff", + firebrick: "#b22222", + floralwhite: "#fffaf0", + forestgreen: "#228b22", + fuchsia: "#ff00ff", + gainsboro: "#dcdcdc", + ghostwhite: "#f8f8ff", + gold: "#ffd700", + goldenrod: "#daa520", + gray: "#808080", + green: "#008000", + greenyellow: "#adff2f", + grey: "#808080", + honeydew: "#f0fff0", + hotpink: "#ff69b4", + indianred: "#cd5c5c", + indigo: "#4b0082", + ivory: "#fffff0", + khaki: "#f0e68c", + lavender: "#e6e6fa", + lavenderblush: "#fff0f5", + lawngreen: "#7cfc00", + lemonchiffon: "#fffacd", + lightblue: "#add8e6", + lightcoral: "#f08080", + lightcyan: "#e0ffff", + lightgoldenrodyellow: "#fafad2", + lightgray: "#d3d3d3", + lightgreen: "#90ee90", + lightgrey: "#d3d3d3", + lightpink: "#ffb6c1", + lightsalmon: "#ffa07a", + lightseagreen: "#20b2aa", + lightskyblue: "#87cefa", + lightslategray: "#778899", + lightslategrey: "#778899", + lightsteelblue: "#b0c4de", + lightyellow: "#ffffe0", + lime: "#00ff00", + limegreen: "#32cd32", + linen: "#faf0e6", + magenta: "#ff00ff", + maroon: "#800000", + mediumaquamarine: "#66cdaa", + mediumblue: "#0000cd", + mediumorchid: "#ba55d3", + mediumpurple: "#9370db", + mediumseagreen: "#3cb371", + mediumslateblue: "#7b68ee", + mediumspringgreen: "#00fa9a", + mediumturquoise: "#48d1cc", + mediumvioletred: "#c71585", + midnightblue: "#191970", + mintcream: "#f5fffa", + mistyrose: "#ffe4e1", + moccasin: "#ffe4b5", + navajowhite: "#ffdead", + navy: "#000080", + oldlace: "#fdf5e6", + olive: "#808000", + olivedrab: "#6b8e23", + orange: "#ffa500", + orangered: "#ff4500", + orchid: "#da70d6", + palegoldenrod: "#eee8aa", + palegreen: "#98fb98", + paleturquoise: "#afeeee", + palevioletred: "#db7093", + papayawhip: "#ffefd5", + peachpuff: "#ffdab9", + peru: "#cd853f", + pink: "#ffc0cb", + plum: "#dda0dd", + powderblue: "#b0e0e6", + purple: "#800080", + red: "#ff0000", + rosybrown: "#bc8f8f", + royalblue: "#4169e1", + saddlebrown: "#8b4513", + salmon: "#fa8072", + sandybrown: "#f4a460", + seagreen: "#2e8b57", + seashell: "#fff5ee", + sienna: "#a0522d", + silver: "#c0c0c0", + skyblue: "#87ceeb", + slateblue: "#6a5acd", + slategray: "#708090", + slategrey: "#708090", + snow: "#fffafa", + springgreen: "#00ff7f", + steelblue: "#4682b4", + tan: "#d2b48c", + teal: "#008080", + thistle: "#d8bfd8", + tomato: "#ff6347", + turquoise: "#40e0d0", + violet: "#ee82ee", + wheat: "#f5deb3", + white: "#ffffff", + whitesmoke: "#f5f5f5", + yellow: "#ffff00", + yellowgreen: "#9acd32" + }); + d3_rgb_names.forEach(function(key, value) { + d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb)); + }); + d3.hsl = function(h, s, l) { + return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); + }; + d3_Hsl.prototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, this.l / k); + }; + d3_Hsl.prototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, k * this.l); + }; + d3_Hsl.prototype.rgb = function() { + return d3_hsl_rgb(this.h, this.s, this.l); + }; + d3_Hsl.prototype.toString = function() { + return this.rgb().toString(); + }; + d3.hcl = function(h, c, l) { + return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); + }; + d3_Hcl.prototype.brighter = function(k) { + return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); + }; + d3_Hcl.prototype.darker = function(k) { + return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); + }; + d3_Hcl.prototype.rgb = function() { + return d3_hcl_lab(this.h, this.c, this.l).rgb(); + }; + d3_Hcl.prototype.toString = function() { + return this.rgb() + ""; + }; + d3.lab = function(l, a, b) { + return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); + }; + var d3_lab_K = 18; + var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; + d3_Lab.prototype.brighter = function(k) { + return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_Lab.prototype.darker = function(k) { + return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_Lab.prototype.rgb = function() { + return d3_lab_rgb(this.l, this.a, this.b); + }; + d3_Lab.prototype.toString = function() { + return this.rgb() + ""; + }; + var d3_select = function(s, n) { + return n.querySelector(s); + }, d3_selectAll = function(s, n) { + return n.querySelectorAll(s); + }, d3_selectRoot = document.documentElement, d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, d3_selectMatches = function(n, s) { + return d3_selectMatcher.call(n, s); + }; + if (typeof Sizzle === "function") { + d3_select = function(s, n) { + return Sizzle(s, n)[0] || null; + }; + d3_selectAll = function(s, n) { + return Sizzle.uniqueSort(Sizzle(s, n)); + }; + d3_selectMatches = Sizzle.matchesSelector; + } + var d3_selectionPrototype = []; + d3.selection = function() { + return d3_selectionRoot; + }; + d3.selection.prototype = d3_selectionPrototype; + d3_selectionPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, group, node; + if (typeof selector !== "function") selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(subnode = selector.call(node, node.__data__, i)); + if (subnode && "__data__" in node) subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + d3_selectionPrototype.selectAll = function(selector) { + var subgroups = [], subgroup, node; + if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i))); + subgroup.parentNode = node; + } + } + } + return d3_selection(subgroups); + }; + d3_selectionPrototype.attr = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(); + name = d3.ns.qualify(name); + return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); + } + for (value in name) this.each(d3_selection_attr(value, name[value])); + return this; + } + return this.each(d3_selection_attr(name, value)); + }; + d3_selectionPrototype.classed = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; + if (value = node.classList) { + while (++i < n) if (!value.contains(name[i])) return false; + } else { + value = node.className; + if (value.baseVal != null) value = value.baseVal; + while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; + } + return true; + } + for (value in name) this.each(d3_selection_classed(value, name[value])); + return this; + } + return this.each(d3_selection_classed(name, value)); + }; + d3_selectionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); + return this; + } + if (n < 2) return window.getComputedStyle(this.node(), null).getPropertyValue(name); + priority = ""; + } + return this.each(d3_selection_style(name, value, priority)); + }; + d3_selectionPrototype.property = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") return this.node()[name]; + for (value in name) this.each(d3_selection_property(value, name[value])); + return this; + } + return this.each(d3_selection_property(name, value)); + }; + d3_selectionPrototype.text = function(value) { + return arguments.length < 1 ? this.node().textContent : this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + } : value == null ? function() { + this.textContent = ""; + } : function() { + this.textContent = value; + }); + }; + d3_selectionPrototype.html = function(value) { + return arguments.length < 1 ? this.node().innerHTML : this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + } : value == null ? function() { + this.innerHTML = ""; + } : function() { + this.innerHTML = value; + }); + }; + d3_selectionPrototype.append = function(name) { + function append() { + return this.appendChild(document.createElementNS(this.namespaceURI, name)); + } + function appendNS() { + return this.appendChild(document.createElementNS(name.space, name.local)); + } + name = d3.ns.qualify(name); + return this.select(name.local ? appendNS : append); + }; + d3_selectionPrototype.insert = function(name, before) { + function insert() { + return this.insertBefore(document.createElementNS(this.namespaceURI, name), d3_select(before, this)); + } + function insertNS() { + return this.insertBefore(document.createElementNS(name.space, name.local), d3_select(before, this)); + } + name = d3.ns.qualify(name); + return this.select(name.local ? insertNS : insert); + }; + d3_selectionPrototype.remove = function() { + return this.each(function() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); + }); + }; + d3_selectionPrototype.data = function(value, key) { + function bind(group, groupData) { + var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), n1 = Math.max(n, m), updateNodes = [], enterNodes = [], exitNodes = [], node, nodeData; + if (key) { + var nodeByKeyValue = new d3_Map, keyValues = [], keyValue, j = groupData.length; + for (i = -1; ++i < n; ) { + keyValue = key.call(node = group[i], node.__data__, i); + if (nodeByKeyValue.has(keyValue)) { + exitNodes[j++] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + keyValues.push(keyValue); + } + for (i = -1; ++i < m; ) { + keyValue = key.call(groupData, nodeData = groupData[i], i); + if (nodeByKeyValue.has(keyValue)) { + updateNodes[i] = node = nodeByKeyValue.get(keyValue); + node.__data__ = nodeData; + enterNodes[i] = exitNodes[i] = null; + } else { + enterNodes[i] = d3_selection_dataNode(nodeData); + updateNodes[i] = exitNodes[i] = null; + } + nodeByKeyValue.remove(keyValue); + } + for (i = -1; ++i < n; ) { + if (nodeByKeyValue.has(keyValues[i])) { + exitNodes[i] = group[i]; + } + } + } else { + for (i = -1; ++i < n0; ) { + node = group[i]; + nodeData = groupData[i]; + if (node) { + node.__data__ = nodeData; + updateNodes[i] = node; + enterNodes[i] = exitNodes[i] = null; + } else { + enterNodes[i] = d3_selection_dataNode(nodeData); + updateNodes[i] = exitNodes[i] = null; + } + } + for (; i < m; ++i) { + enterNodes[i] = d3_selection_dataNode(groupData[i]); + updateNodes[i] = exitNodes[i] = null; + } + for (; i < n1; ++i) { + exitNodes[i] = group[i]; + enterNodes[i] = updateNodes[i] = null; + } + } + enterNodes.update = updateNodes; + enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; + enter.push(enterNodes); + update.push(updateNodes); + exit.push(exitNodes); + } + var i = -1, n = this.length, group, node; + if (!arguments.length) { + value = new Array(n = (group = this[0]).length); + while (++i < n) { + if (node = group[i]) { + value[i] = node.__data__; + } + } + return value; + } + var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); + if (typeof value === "function") { + while (++i < n) { + bind(group = this[i], value.call(group, group.parentNode.__data__, i)); + } + } else { + while (++i < n) { + bind(group = this[i], value); + } + } + update.enter = function() { + return enter; + }; + update.exit = function() { + return exit; + }; + return update; + }; + d3_selectionPrototype.datum = d3_selectionPrototype.map = function(value) { + return arguments.length < 1 ? this.property("__data__") : this.property("__data__", value); + }; + d3_selectionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_selection(subgroups); + }; + d3_selectionPrototype.order = function() { + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { + if (node = group[i]) { + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + return this; + }; + d3_selectionPrototype.sort = function(comparator) { + comparator = d3_selection_sortComparator.apply(this, arguments); + for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); + return this.order(); + }; + d3_selectionPrototype.on = function(type, listener, capture) { + var n = arguments.length; + if (n < 3) { + if (typeof type !== "string") { + if (n < 2) listener = false; + for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); + return this; + } + if (n < 2) return (n = this.node()["__on" + type]) && n._; + capture = false; + } + return this.each(d3_selection_on(type, listener, capture)); + }; + d3_selectionPrototype.each = function(callback) { + return d3_selection_each(this, function(node, i, j) { + callback.call(node, node.__data__, i, j); + }); + }; + d3_selectionPrototype.call = function(callback) { + callback.apply(this, (arguments[0] = this, arguments)); + return this; + }; + d3_selectionPrototype.empty = function() { + return !this.node(); + }; + d3_selectionPrototype.node = function(callback) { + for (var j = 0, m = this.length; j < m; j++) { + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + var node = group[i]; + if (node) return node; + } + } + return null; + }; + d3_selectionPrototype.transition = function() { + var subgroups = [], subgroup, node; + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + subgroup.push((node = group[i]) ? { + node: node, + delay: d3_transitionDelay, + duration: d3_transitionDuration + } : null); + } + } + return d3_transition(subgroups, d3_transitionId || ++d3_transitionNextId, Date.now()); + }; + var d3_selectionRoot = d3_selection([ [ document ] ]); + d3_selectionRoot[0].parentNode = d3_selectRoot; + d3.select = function(selector) { + return typeof selector === "string" ? d3_selectionRoot.select(selector) : d3_selection([ [ selector ] ]); + }; + d3.selectAll = function(selector) { + return typeof selector === "string" ? d3_selectionRoot.selectAll(selector) : d3_selection([ d3_array(selector) ]); + }; + var d3_selection_enterPrototype = []; + d3.selection.enter = d3_selection_enter; + d3.selection.enter.prototype = d3_selection_enterPrototype; + d3_selection_enterPrototype.append = d3_selectionPrototype.append; + d3_selection_enterPrototype.insert = d3_selectionPrototype.insert; + d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; + d3_selection_enterPrototype.node = d3_selectionPrototype.node; + d3_selection_enterPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, upgroup, group, node; + for (var j = -1, m = this.length; ++j < m; ) { + upgroup = (group = this[j]).update; + subgroups.push(subgroup = []); + subgroup.parentNode = group.parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i)); + subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + var d3_transitionPrototype = [], d3_transitionNextId = 0, d3_transitionId = 0, d3_transitionDefaultDelay = 0, d3_transitionDefaultDuration = 250, d3_transitionDefaultEase = d3.ease("cubic-in-out"), d3_transitionDelay = d3_transitionDefaultDelay, d3_transitionDuration = d3_transitionDefaultDuration, d3_transitionEase = d3_transitionDefaultEase; + d3_transitionPrototype.call = d3_selectionPrototype.call; + d3.transition = function(selection) { + return arguments.length ? d3_transitionId ? selection.transition() : selection : d3_selectionRoot.transition(); + }; + d3.transition.prototype = d3_transitionPrototype; + d3_transitionPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, node; + if (typeof selector !== "function") selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if ((node = group[i]) && (subnode = selector.call(node.node, node.node.__data__, i))) { + if ("__data__" in node.node) subnode.__data__ = node.node.__data__; + subgroup.push({ + node: subnode, + delay: node.delay, + duration: node.duration + }); + } else { + subgroup.push(null); + } + } + } + return d3_transition(subgroups, this.id, this.time).ease(this.ease()); + }; + d3_transitionPrototype.selectAll = function(selector) { + var subgroups = [], subgroup, subnodes, node; + if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subnodes = selector.call(node.node, node.node.__data__, i); + subgroups.push(subgroup = []); + for (var k = -1, o = subnodes.length; ++k < o; ) { + subgroup.push({ + node: subnodes[k], + delay: node.delay, + duration: node.duration + }); + } + } + } + } + return d3_transition(subgroups, this.id, this.time).ease(this.ease()); + }; + d3_transitionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node.node, node.node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_transition(subgroups, this.id, this.time).ease(this.ease()); + }; + d3_transitionPrototype.attr = function(name, value) { + if (arguments.length < 2) { + for (value in name) this.attrTween(value, d3_tweenByName(name[value], value)); + return this; + } + return this.attrTween(name, d3_tweenByName(value, name)); + }; + d3_transitionPrototype.attrTween = function(nameNS, tween) { + function attrTween(d, i) { + var f = tween.call(this, d, i, this.getAttribute(name)); + return f === d3_tweenRemove ? (this.removeAttribute(name), null) : f && function(t) { + this.setAttribute(name, f(t)); + }; + } + function attrTweenNS(d, i) { + var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); + return f === d3_tweenRemove ? (this.removeAttributeNS(name.space, name.local), null) : f && function(t) { + this.setAttributeNS(name.space, name.local, f(t)); + }; + } + var name = d3.ns.qualify(nameNS); + return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.styleTween(priority, d3_tweenByName(name[priority], priority), value); + return this; + } + priority = ""; + } + return this.styleTween(name, d3_tweenByName(value, name), priority); + }; + d3_transitionPrototype.styleTween = function(name, tween, priority) { + if (arguments.length < 3) priority = ""; + return this.tween("style." + name, function(d, i) { + var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name)); + return f === d3_tweenRemove ? (this.style.removeProperty(name), null) : f && function(t) { + this.style.setProperty(name, f(t), priority); + }; + }); + }; + d3_transitionPrototype.text = function(value) { + return this.tween("text", function(d, i) { + this.textContent = typeof value === "function" ? value.call(this, d, i) : value; + }); + }; + d3_transitionPrototype.remove = function() { + return this.each("end.transition", function() { + var p; + if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); + }); + }; + d3_transitionPrototype.delay = function(value) { + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.delay = value.call(node = node.node, node.__data__, i, j) | 0; + } : (value = value | 0, function(node) { + node.delay = value; + })); + }; + d3_transitionPrototype.duration = function(value) { + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.duration = Math.max(1, value.call(node = node.node, node.__data__, i, j) | 0); + } : (value = Math.max(1, value | 0), function(node) { + node.duration = value; + })); + }; + d3_transitionPrototype.transition = function() { + return this.select(d3_this); + }; + d3.tween = function(b, interpolate) { + function tweenFunction(d, i, a) { + var v = b.call(this, d, i); + return v == null ? a != "" && d3_tweenRemove : a != v && interpolate(a, v); + } + function tweenString(d, i, a) { + return a != b && interpolate(a, b); + } + return typeof b === "function" ? tweenFunction : b == null ? d3_tweenNull : (b += "", tweenString); + }; + var d3_tweenRemove = {}; + var d3_timer_queue = null, d3_timer_interval, d3_timer_timeout; + d3.timer = function(callback, delay, then) { + var found = false, t0, t1 = d3_timer_queue; + if (arguments.length < 3) { + if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return; + then = Date.now(); + } + while (t1) { + if (t1.callback === callback) { + t1.then = then; + t1.delay = delay; + found = true; + break; + } + t0 = t1; + t1 = t1.next; + } + if (!found) d3_timer_queue = { + callback: callback, + then: then, + delay: delay, + next: d3_timer_queue + }; + if (!d3_timer_interval) { + d3_timer_timeout = clearTimeout(d3_timer_timeout); + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + }; + d3.timer.flush = function() { + var elapsed, now = Date.now(), t1 = d3_timer_queue; + while (t1) { + elapsed = now - t1.then; + if (!t1.delay) t1.flush = t1.callback(elapsed); + t1 = t1.next; + } + d3_timer_flush(); + }; + var d3_timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { + setTimeout(callback, 17); + }; + d3.mouse = function(container) { + return d3_mousePoint(container, d3_eventSource()); + }; + var d3_mouse_bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0; + d3.touches = function(container, touches) { + if (arguments.length < 2) touches = d3_eventSource().touches; + return touches ? d3_array(touches).map(function(touch) { + var point = d3_mousePoint(container, touch); + point.identifier = touch.identifier; + return point; + }) : []; + }; + d3.scale = {}; + d3.scale.linear = function() { + return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3.interpolate, false); + }; + d3.scale.log = function() { + return d3_scale_log(d3.scale.linear(), d3_scale_logp); + }; + var d3_scale_logFormat = d3.format(".0e"); + d3_scale_logp.pow = function(x) { + return Math.pow(10, x); + }; + d3_scale_logn.pow = function(x) { + return -Math.pow(10, -x); + }; + d3.scale.pow = function() { + return d3_scale_pow(d3.scale.linear(), 1); + }; + d3.scale.sqrt = function() { + return d3.scale.pow().exponent(.5); + }; + d3.scale.ordinal = function() { + return d3_scale_ordinal([], { + t: "range", + a: [ [] ] + }); + }; + d3.scale.category10 = function() { + return d3.scale.ordinal().range(d3_category10); + }; + d3.scale.category20 = function() { + return d3.scale.ordinal().range(d3_category20); + }; + d3.scale.category20b = function() { + return d3.scale.ordinal().range(d3_category20b); + }; + d3.scale.category20c = function() { + return d3.scale.ordinal().range(d3_category20c); + }; + var d3_category10 = [ "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf" ]; + var d3_category20 = [ "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" ]; + var d3_category20b = [ "#393b79", "#5254a3", "#6b6ecf", "#9c9ede", "#637939", "#8ca252", "#b5cf6b", "#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#e7969c", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6" ]; + var d3_category20c = [ "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", "#636363", "#969696", "#bdbdbd", "#d9d9d9" ]; + d3.scale.quantile = function() { + return d3_scale_quantile([], []); + }; + d3.scale.quantize = function() { + return d3_scale_quantize(0, 1, [ 0, 1 ]); + }; + d3.scale.threshold = function() { + return d3_scale_threshold([ .5 ], [ 0, 1 ]); + }; + d3.scale.identity = function() { + return d3_scale_identity([ 0, 1 ]); + }; + d3.svg = {}; + d3.svg.arc = function() { + function arc() { + var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, a0 = a1, a1 = da), a1 - a0), df = da < Math.PI ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); + return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; + } + var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + arc.innerRadius = function(v) { + if (!arguments.length) return innerRadius; + innerRadius = d3_functor(v); + return arc; + }; + arc.outerRadius = function(v) { + if (!arguments.length) return outerRadius; + outerRadius = d3_functor(v); + return arc; + }; + arc.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return arc; + }; + arc.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return arc; + }; + arc.centroid = function() { + var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; + return [ Math.cos(a) * r, Math.sin(a) * r ]; + }; + return arc; + }; + var d3_svg_arcOffset = -Math.PI / 2, d3_svg_arcMax = 2 * Math.PI - 1e-6; + d3.svg.line = function() { + return d3_svg_line(d3_identity); + }; + var d3_svg_lineInterpolators = d3.map({ + linear: d3_svg_lineLinear, + "linear-closed": d3_svg_lineLinearClosed, + "step-before": d3_svg_lineStepBefore, + "step-after": d3_svg_lineStepAfter, + basis: d3_svg_lineBasis, + "basis-open": d3_svg_lineBasisOpen, + "basis-closed": d3_svg_lineBasisClosed, + bundle: d3_svg_lineBundle, + cardinal: d3_svg_lineCardinal, + "cardinal-open": d3_svg_lineCardinalOpen, + "cardinal-closed": d3_svg_lineCardinalClosed, + monotone: d3_svg_lineMonotone + }); + d3_svg_lineInterpolators.forEach(function(key, value) { + value.key = key; + value.closed = /-closed$/.test(key); + }); + var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; + d3.svg.line.radial = function() { + var line = d3_svg_line(d3_svg_lineRadial); + line.radius = line.x, delete line.x; + line.angle = line.y, delete line.y; + return line; + }; + d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; + d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; + d3.svg.area = function() { + return d3_svg_area(d3_identity); + }; + d3.svg.area.radial = function() { + var area = d3_svg_area(d3_svg_lineRadial); + area.radius = area.x, delete area.x; + area.innerRadius = area.x0, delete area.x0; + area.outerRadius = area.x1, delete area.x1; + area.angle = area.y, delete area.y; + area.startAngle = area.y0, delete area.y0; + area.endAngle = area.y1, delete area.y1; + return area; + }; + d3.svg.chord = function() { + function chord(d, i) { + var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); + return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; + } + function subgroup(self, f, d, i) { + var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; + return { + r: r, + a0: a0, + a1: a1, + p0: [ r * Math.cos(a0), r * Math.sin(a0) ], + p1: [ r * Math.cos(a1), r * Math.sin(a1) ] + }; + } + function equals(a, b) { + return a.a0 == b.a0 && a.a1 == b.a1; + } + function arc(r, p, a) { + return "A" + r + "," + r + " 0 " + +(a > Math.PI) + ",1 " + p; + } + function curve(r0, p0, r1, p1) { + return "Q 0,0 " + p1; + } + var source = d3_svg_chordSource, target = d3_svg_chordTarget, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + chord.radius = function(v) { + if (!arguments.length) return radius; + radius = d3_functor(v); + return chord; + }; + chord.source = function(v) { + if (!arguments.length) return source; + source = d3_functor(v); + return chord; + }; + chord.target = function(v) { + if (!arguments.length) return target; + target = d3_functor(v); + return chord; + }; + chord.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return chord; + }; + chord.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return chord; + }; + return chord; + }; + d3.svg.diagonal = function() { + function diagonal(d, i) { + var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { + x: p0.x, + y: m + }, { + x: p3.x, + y: m + }, p3 ]; + p = p.map(projection); + return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; + } + var source = d3_svg_chordSource, target = d3_svg_chordTarget, projection = d3_svg_diagonalProjection; + diagonal.source = function(x) { + if (!arguments.length) return source; + source = d3_functor(x); + return diagonal; + }; + diagonal.target = function(x) { + if (!arguments.length) return target; + target = d3_functor(x); + return diagonal; + }; + diagonal.projection = function(x) { + if (!arguments.length) return projection; + projection = x; + return diagonal; + }; + return diagonal; + }; + d3.svg.diagonal.radial = function() { + var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; + diagonal.projection = function(x) { + return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; + }; + return diagonal; + }; + d3.svg.mouse = d3.mouse; + d3.svg.touches = d3.touches; + d3.svg.symbol = function() { + function symbol(d, i) { + return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); + } + var type = d3_svg_symbolType, size = d3_svg_symbolSize; + symbol.type = function(x) { + if (!arguments.length) return type; + type = d3_functor(x); + return symbol; + }; + symbol.size = function(x) { + if (!arguments.length) return size; + size = d3_functor(x); + return symbol; + }; + return symbol; + }; + var d3_svg_symbols = d3.map({ + circle: d3_svg_symbolCircle, + cross: function(size) { + var r = Math.sqrt(size / 5) / 2; + return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; + }, + diamond: function(size) { + var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; + return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; + }, + square: function(size) { + var r = Math.sqrt(size) / 2; + return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; + }, + "triangle-down": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; + }, + "triangle-up": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; + } + }); + d3.svg.symbolTypes = d3_svg_symbols.keys(); + var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * Math.PI / 180); + d3.svg.axis = function() { + function axis(g) { + g.each(function() { + var g = d3.select(this); + var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; + var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", "g").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); + var tick = g.selectAll("g").data(ticks, String), tickEnter = tick.enter().insert("g", "path").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; + var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathEnter = path.enter().append("path").attr("class", "domain"), pathUpdate = d3.transition(path); + var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; + this.__chart__ = scale1; + tickEnter.append("line").attr("class", "tick"); + tickEnter.append("text"); + var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); + switch (orient) { + case "bottom": + { + tickTransform = d3_svg_axisX; + subtickEnter.attr("y2", tickMinorSize); + subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); + lineEnter.attr("y2", tickMajorSize); + textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); + lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); + textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); + text.attr("dy", ".71em").attr("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); + break; + } + case "top": + { + tickTransform = d3_svg_axisX; + subtickEnter.attr("y2", -tickMinorSize); + subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); + lineEnter.attr("y2", -tickMajorSize); + textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); + lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); + textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); + text.attr("dy", "0em").attr("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); + break; + } + case "left": + { + tickTransform = d3_svg_axisY; + subtickEnter.attr("x2", -tickMinorSize); + subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); + lineEnter.attr("x2", -tickMajorSize); + textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); + lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); + textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); + text.attr("dy", ".32em").attr("text-anchor", "end"); + pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); + break; + } + case "right": + { + tickTransform = d3_svg_axisY; + subtickEnter.attr("x2", tickMinorSize); + subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); + lineEnter.attr("x2", tickMajorSize); + textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); + lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); + textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); + text.attr("dy", ".32em").attr("text-anchor", "start"); + pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); + break; + } + } + if (scale.ticks) { + tickEnter.call(tickTransform, scale0); + tickUpdate.call(tickTransform, scale1); + tickExit.call(tickTransform, scale1); + subtickEnter.call(tickTransform, scale0); + subtickUpdate.call(tickTransform, scale1); + subtickExit.call(tickTransform, scale1); + } else { + var dx = scale1.rangeBand() / 2, x = function(d) { + return scale1(d) + dx; + }; + tickEnter.call(tickTransform, x); + tickUpdate.call(tickTransform, x); + } + }); + } + var scale = d3.scale.linear(), orient = "bottom", tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; + axis.scale = function(x) { + if (!arguments.length) return scale; + scale = x; + return axis; + }; + axis.orient = function(x) { + if (!arguments.length) return orient; + orient = x; + return axis; + }; + axis.ticks = function() { + if (!arguments.length) return tickArguments_; + tickArguments_ = arguments; + return axis; + }; + axis.tickValues = function(x) { + if (!arguments.length) return tickValues; + tickValues = x; + return axis; + }; + axis.tickFormat = function(x) { + if (!arguments.length) return tickFormat_; + tickFormat_ = x; + return axis; + }; + axis.tickSize = function(x, y, z) { + if (!arguments.length) return tickMajorSize; + var n = arguments.length - 1; + tickMajorSize = +x; + tickMinorSize = n > 1 ? +y : tickMajorSize; + tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; + return axis; + }; + axis.tickPadding = function(x) { + if (!arguments.length) return tickPadding; + tickPadding = +x; + return axis; + }; + axis.tickSubdivide = function(x) { + if (!arguments.length) return tickSubdivide; + tickSubdivide = +x; + return axis; + }; + return axis; + }; + d3.svg.brush = function() { + function brush(g) { + g.each(function() { + var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; + g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); + bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); + fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); + tz.enter().append("g").attr("class", function(d) { + return "resize " + d; + }).style("cursor", function(d) { + return d3_svg_brushCursor[d]; + }).append("rect").attr("x", function(d) { + return /[ew]$/.test(d) ? -3 : null; + }).attr("y", function(d) { + return /^[ns]/.test(d) ? -3 : null; + }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); + tz.style("display", brush.empty() ? "none" : null); + tz.exit().remove(); + if (x) { + e = d3_scaleRange(x); + bg.attr("x", e[0]).attr("width", e[1] - e[0]); + redrawX(g); + } + if (y) { + e = d3_scaleRange(y); + bg.attr("y", e[0]).attr("height", e[1] - e[0]); + redrawY(g); + } + redraw(g); + }); + } + function redraw(g) { + g.selectAll(".resize").attr("transform", function(d) { + return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; + }); + } + function redrawX(g) { + g.select(".extent").attr("x", extent[0][0]); + g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); + } + function redrawY(g) { + g.select(".extent").attr("y", extent[0][1]); + g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); + } + function brushstart() { + function mouse() { + var touches = d3.event.changedTouches; + return touches ? d3.touches(target, touches)[0] : d3.mouse(target); + } + function keydown() { + if (d3.event.keyCode == 32) { + if (!dragging) { + center = null; + origin[0] -= extent[1][0]; + origin[1] -= extent[1][1]; + dragging = 2; + } + d3_eventCancel(); + } + } + function keyup() { + if (d3.event.keyCode == 32 && dragging == 2) { + origin[0] += extent[1][0]; + origin[1] += extent[1][1]; + dragging = 0; + d3_eventCancel(); + } + } + function brushmove() { + var point = mouse(), moved = false; + if (offset) { + point[0] += offset[0]; + point[1] += offset[1]; + } + if (!dragging) { + if (d3.event.altKey) { + if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; + origin[0] = extent[+(point[0] < center[0])][0]; + origin[1] = extent[+(point[1] < center[1])][1]; + } else center = null; + } + if (resizingX && move1(point, x, 0)) { + redrawX(g); + moved = true; + } + if (resizingY && move1(point, y, 1)) { + redrawY(g); + moved = true; + } + if (moved) { + redraw(g); + event_({ + type: "brush", + mode: dragging ? "move" : "resize" + }); + } + } + function move1(point, scale, i) { + var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; + if (dragging) { + r0 -= position; + r1 -= size + position; + } + min = Math.max(r0, Math.min(r1, point[i])); + if (dragging) { + max = (min += position) + size; + } else { + if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); + if (position < min) { + max = min; + min = position; + } else { + max = position; + } + } + if (extent[0][i] !== min || extent[1][i] !== max) { + extentDomain = null; + extent[0][i] = min; + extent[1][i] = max; + return true; + } + } + function brushend() { + brushmove(); + g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); + d3.select("body").style("cursor", null); + w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); + event_({ + type: "brushend" + }); + d3_eventCancel(); + } + var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), center, origin = mouse(), offset; + var w = d3.select(window).on("mousemove.brush", brushmove).on("mouseup.brush", brushend).on("touchmove.brush", brushmove).on("touchend.brush", brushend).on("keydown.brush", keydown).on("keyup.brush", keyup); + if (dragging) { + origin[0] = extent[0][0] - origin[0]; + origin[1] = extent[0][1] - origin[1]; + } else if (resizing) { + var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); + offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; + origin[0] = extent[ex][0]; + origin[1] = extent[ey][1]; + } else if (d3.event.altKey) center = origin.slice(); + g.style("pointer-events", "none").selectAll(".resize").style("display", null); + d3.select("body").style("cursor", eventTarget.style("cursor")); + event_({ + type: "brushstart" + }); + brushmove(); + d3_eventCancel(); + } + var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], extentDomain; + brush.x = function(z) { + if (!arguments.length) return x; + x = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.y = function(z) { + if (!arguments.length) return y; + y = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.extent = function(z) { + var x0, x1, y0, y1, t; + if (!arguments.length) { + z = extentDomain || extent; + if (x) { + x0 = z[0][0], x1 = z[1][0]; + if (!extentDomain) { + x0 = extent[0][0], x1 = extent[1][0]; + if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + } + } + if (y) { + y0 = z[0][1], y1 = z[1][1]; + if (!extentDomain) { + y0 = extent[0][1], y1 = extent[1][1]; + if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + } + } + return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; + } + extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; + if (x) { + x0 = z[0], x1 = z[1]; + if (y) x0 = x0[0], x1 = x1[0]; + extentDomain[0][0] = x0, extentDomain[1][0] = x1; + if (x.invert) x0 = x(x0), x1 = x(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; + } + if (y) { + y0 = z[0], y1 = z[1]; + if (x) y0 = y0[1], y1 = y1[1]; + extentDomain[0][1] = y0, extentDomain[1][1] = y1; + if (y.invert) y0 = y(y0), y1 = y(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; + } + return brush; + }; + brush.clear = function() { + extentDomain = null; + extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; + return brush; + }; + brush.empty = function() { + return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; + }; + return d3.rebind(brush, event, "on"); + }; + var d3_svg_brushCursor = { + n: "ns-resize", + e: "ew-resize", + s: "ns-resize", + w: "ew-resize", + nw: "nwse-resize", + ne: "nesw-resize", + se: "nwse-resize", + sw: "nesw-resize" + }; + var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; + d3.behavior = {}; + d3.behavior.drag = function() { + function drag() { + this.on("mousedown.drag", mousedown).on("touchstart.drag", mousedown); + } + function mousedown() { + function point() { + var p = target.parentNode; + return touchId ? d3.touches(p).filter(function(p) { + return p.identifier === touchId; + })[0] : d3.mouse(p); + } + function dragmove() { + if (!target.parentNode) return dragend(); + var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; + moved |= dx | dy; + origin_ = p; + d3_eventCancel(); + event_({ + type: "drag", + x: p[0] + offset[0], + y: p[1] + offset[1], + dx: dx, + dy: dy + }); + } + function dragend() { + event_({ + type: "dragend" + }); + if (moved) { + d3_eventCancel(); + if (d3.event.target === eventTarget) w.on("click.drag", click, true); + } + w.on(touchId ? "touchmove.drag-" + touchId : "mousemove.drag", null).on(touchId ? "touchend.drag-" + touchId : "mouseup.drag", null); + } + function click() { + d3_eventCancel(); + w.on("click.drag", null); + } + var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, touchId = d3.event.touches && d3.event.changedTouches[0].identifier, offset, origin_ = point(), moved = 0; + var w = d3.select(window).on(touchId ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove).on(touchId ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true); + if (origin) { + offset = origin.apply(target, arguments); + offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; + } else { + offset = [ 0, 0 ]; + } + if (!touchId) d3_eventCancel(); + event_({ + type: "dragstart" + }); + } + var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null; + drag.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return drag; + }; + return d3.rebind(drag, event, "on"); + }; + d3.behavior.zoom = function() { + function zoom() { + this.on("mousedown.zoom", mousedown).on("mousewheel.zoom", mousewheel).on("mousemove.zoom", mousemove).on("DOMMouseScroll.zoom", mousewheel).on("dblclick.zoom", dblclick).on("touchstart.zoom", touchstart).on("touchmove.zoom", touchmove).on("touchend.zoom", touchstart); + } + function location(p) { + return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; + } + function point(l) { + return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; + } + function scaleTo(s) { + scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); + } + function translateTo(p, l) { + l = point(l); + translate[0] += p[0] - l[0]; + translate[1] += p[1] - l[1]; + } + function dispatch(event) { + if (x1) x1.domain(x0.range().map(function(x) { + return (x - translate[0]) / scale; + }).map(x0.invert)); + if (y1) y1.domain(y0.range().map(function(y) { + return (y - translate[1]) / scale; + }).map(y0.invert)); + d3.event.preventDefault(); + event({ + type: "zoom", + scale: scale, + translate: translate + }); + } + function mousedown() { + function mousemove() { + moved = 1; + translateTo(d3.mouse(target), l); + dispatch(event_); + } + function mouseup() { + if (moved) d3_eventCancel(); + w.on("mousemove.zoom", null).on("mouseup.zoom", null); + if (moved && d3.event.target === eventTarget) w.on("click.zoom", click, true); + } + function click() { + d3_eventCancel(); + w.on("click.zoom", null); + } + var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, moved = 0, w = d3.select(window).on("mousemove.zoom", mousemove).on("mouseup.zoom", mouseup), l = location(d3.mouse(target)); + window.focus(); + d3_eventCancel(); + } + function mousewheel() { + if (!translate0) translate0 = location(d3.mouse(this)); + scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); + translateTo(d3.mouse(this), translate0); + dispatch(event.of(this, arguments)); + } + function mousemove() { + translate0 = null; + } + function dblclick() { + var p = d3.mouse(this), l = location(p); + scaleTo(d3.event.shiftKey ? scale / 2 : scale * 2); + translateTo(p, l); + dispatch(event.of(this, arguments)); + } + function touchstart() { + var touches = d3.touches(this), now = Date.now(); + scale0 = scale; + translate0 = {}; + touches.forEach(function(t) { + translate0[t.identifier] = location(t); + }); + d3_eventCancel(); + if (touches.length === 1) { + if (now - touchtime < 500) { + var p = touches[0], l = location(touches[0]); + scaleTo(scale * 2); + translateTo(p, l); + dispatch(event.of(this, arguments)); + } + touchtime = now; + } + } + function touchmove() { + var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier]; + if (p1 = touches[1]) { + var p1, l1 = translate0[p1.identifier]; + p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; + l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; + scaleTo(d3.event.scale * scale0); + } + translateTo(p0, l0); + touchtime = null; + dispatch(event.of(this, arguments)); + } + var translate = [ 0, 0 ], translate0, scale = 1, scale0, scaleExtent = d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1, touchtime; + zoom.translate = function(x) { + if (!arguments.length) return translate; + translate = x.map(Number); + return zoom; + }; + zoom.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + return zoom; + }; + zoom.scaleExtent = function(x) { + if (!arguments.length) return scaleExtent; + scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); + return zoom; + }; + zoom.x = function(z) { + if (!arguments.length) return x1; + x1 = z; + x0 = z.copy(); + return zoom; + }; + zoom.y = function(z) { + if (!arguments.length) return y1; + y1 = z; + y0 = z.copy(); + return zoom; + }; + return d3.rebind(zoom, event, "on"); + }; + var d3_behavior_zoomDiv, d3_behavior_zoomInfinity = [ 0, Infinity ]; + d3.layout = {}; + d3.layout.bundle = function() { + return function(links) { + var paths = [], i = -1, n = links.length; + while (++i < n) paths.push(d3_layout_bundlePath(links[i])); + return paths; + }; + }; + d3.layout.chord = function() { + function relayout() { + var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; + chords = []; + groups = []; + k = 0, i = -1; + while (++i < n) { + x = 0, j = -1; + while (++j < n) { + x += matrix[i][j]; + } + groupSums.push(x); + subgroupIndex.push(d3.range(n)); + k += x; + } + if (sortGroups) { + groupIndex.sort(function(a, b) { + return sortGroups(groupSums[a], groupSums[b]); + }); + } + if (sortSubgroups) { + subgroupIndex.forEach(function(d, i) { + d.sort(function(a, b) { + return sortSubgroups(matrix[i][a], matrix[i][b]); + }); + }); + } + k = (2 * Math.PI - padding * n) / k; + x = 0, i = -1; + while (++i < n) { + x0 = x, j = -1; + while (++j < n) { + var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; + subgroups[di + "-" + dj] = { + index: di, + subindex: dj, + startAngle: a0, + endAngle: a1, + value: v + }; + } + groups[di] = { + index: di, + startAngle: x0, + endAngle: x, + value: (x - x0) / k + }; + x += padding; + } + i = -1; + while (++i < n) { + j = i - 1; + while (++j < n) { + var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; + if (source.value || target.value) { + chords.push(source.value < target.value ? { + source: target, + target: source + } : { + source: source, + target: target + }); + } + } + } + if (sortChords) resort(); + } + function resort() { + chords.sort(function(a, b) { + return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); + }); + } + var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; + chord.matrix = function(x) { + if (!arguments.length) return matrix; + n = (matrix = x) && matrix.length; + chords = groups = null; + return chord; + }; + chord.padding = function(x) { + if (!arguments.length) return padding; + padding = x; + chords = groups = null; + return chord; + }; + chord.sortGroups = function(x) { + if (!arguments.length) return sortGroups; + sortGroups = x; + chords = groups = null; + return chord; + }; + chord.sortSubgroups = function(x) { + if (!arguments.length) return sortSubgroups; + sortSubgroups = x; + chords = null; + return chord; + }; + chord.sortChords = function(x) { + if (!arguments.length) return sortChords; + sortChords = x; + if (chords) resort(); + return chord; + }; + chord.chords = function() { + if (!chords) relayout(); + return chords; + }; + chord.groups = function() { + if (!groups) relayout(); + return groups; + }; + return chord; + }; + d3.layout.force = function() { + function repulse(node) { + return function(quad, x1, y1, x2, y2) { + if (quad.point !== node) { + var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); + if ((x2 - x1) * dn < theta) { + var k = quad.charge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + return true; + } + if (quad.point && isFinite(dn)) { + var k = quad.pointCharge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + } + } + return !quad.charge; + }; + } + function dragmove(d) { + d.px = d3.event.x; + d.py = d3.event.y; + force.resume(); + } + var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, interval, nodes = [], links = [], distances, strengths, charges; + force.tick = function() { + if ((alpha *= .99) < .005) { + event.end({ + type: "end", + alpha: alpha = 0 + }); + return true; + } + var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; + for (i = 0; i < m; ++i) { + o = links[i]; + s = o.source; + t = o.target; + x = t.x - s.x; + y = t.y - s.y; + if (l = x * x + y * y) { + l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; + x *= l; + y *= l; + t.x -= x * (k = s.weight / (t.weight + s.weight)); + t.y -= y * k; + s.x += x * (k = 1 - k); + s.y += y * k; + } + } + if (k = alpha * gravity) { + x = size[0] / 2; + y = size[1] / 2; + i = -1; + if (k) while (++i < n) { + o = nodes[i]; + o.x += (x - o.x) * k; + o.y += (y - o.y) * k; + } + } + if (charge) { + d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); + i = -1; + while (++i < n) { + if (!(o = nodes[i]).fixed) { + q.visit(repulse(o)); + } + } + } + i = -1; + while (++i < n) { + o = nodes[i]; + if (o.fixed) { + o.x = o.px; + o.y = o.py; + } else { + o.x -= (o.px - (o.px = o.x)) * friction; + o.y -= (o.py - (o.py = o.y)) * friction; + } + } + event.tick({ + type: "tick", + alpha: alpha + }); + }; + force.nodes = function(x) { + if (!arguments.length) return nodes; + nodes = x; + return force; + }; + force.links = function(x) { + if (!arguments.length) return links; + links = x; + return force; + }; + force.size = function(x) { + if (!arguments.length) return size; + size = x; + return force; + }; + force.linkDistance = function(x) { + if (!arguments.length) return linkDistance; + linkDistance = d3_functor(x); + return force; + }; + force.distance = force.linkDistance; + force.linkStrength = function(x) { + if (!arguments.length) return linkStrength; + linkStrength = d3_functor(x); + return force; + }; + force.friction = function(x) { + if (!arguments.length) return friction; + friction = x; + return force; + }; + force.charge = function(x) { + if (!arguments.length) return charge; + charge = typeof x === "function" ? x : +x; + return force; + }; + force.gravity = function(x) { + if (!arguments.length) return gravity; + gravity = x; + return force; + }; + force.theta = function(x) { + if (!arguments.length) return theta; + theta = x; + return force; + }; + force.alpha = function(x) { + if (!arguments.length) return alpha; + if (alpha) { + if (x > 0) alpha = x; else alpha = 0; + } else if (x > 0) { + event.start({ + type: "start", + alpha: alpha = x + }); + d3.timer(force.tick); + } + return force; + }; + force.start = function() { + function position(dimension, size) { + var neighbors = neighbor(i), j = -1, m = neighbors.length, x; + while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; + return Math.random() * size; + } + function neighbor() { + if (!neighbors) { + neighbors = []; + for (j = 0; j < n; ++j) { + neighbors[j] = []; + } + for (j = 0; j < m; ++j) { + var o = links[j]; + neighbors[o.source.index].push(o.target); + neighbors[o.target.index].push(o.source); + } + } + return neighbors[i]; + } + var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; + for (i = 0; i < n; ++i) { + (o = nodes[i]).index = i; + o.weight = 0; + } + distances = []; + strengths = []; + for (i = 0; i < m; ++i) { + o = links[i]; + if (typeof o.source == "number") o.source = nodes[o.source]; + if (typeof o.target == "number") o.target = nodes[o.target]; + distances[i] = linkDistance.call(this, o, i); + strengths[i] = linkStrength.call(this, o, i); + ++o.source.weight; + ++o.target.weight; + } + for (i = 0; i < n; ++i) { + o = nodes[i]; + if (isNaN(o.x)) o.x = position("x", w); + if (isNaN(o.y)) o.y = position("y", h); + if (isNaN(o.px)) o.px = o.x; + if (isNaN(o.py)) o.py = o.y; + } + charges = []; + if (typeof charge === "function") { + for (i = 0; i < n; ++i) { + charges[i] = +charge.call(this, nodes[i], i); + } + } else { + for (i = 0; i < n; ++i) { + charges[i] = charge; + } + } + return force.resume(); + }; + force.resume = function() { + return force.alpha(.1); + }; + force.stop = function() { + return force.alpha(0); + }; + force.drag = function() { + if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart", d3_layout_forceDragstart).on("drag", dragmove).on("dragend", d3_layout_forceDragend); + this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); + }; + return d3.rebind(force, event, "on"); + }; + d3.layout.partition = function() { + function position(node, x, dx, dy) { + var children = node.children; + node.x = x; + node.y = node.depth * dy; + node.dx = dx; + node.dy = dy; + if (children && (n = children.length)) { + var i = -1, n, c, d; + dx = node.value ? dx / node.value : 0; + while (++i < n) { + position(c = children[i], x, d = c.value * dx, dy); + x += d; + } + } + } + function depth(node) { + var children = node.children, d = 0; + if (children && (n = children.length)) { + var i = -1, n; + while (++i < n) d = Math.max(d, depth(children[i])); + } + return 1 + d; + } + function partition(d, i) { + var nodes = hierarchy.call(this, d, i); + position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); + return nodes; + } + var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; + partition.size = function(x) { + if (!arguments.length) return size; + size = x; + return partition; + }; + return d3_layout_hierarchyRebind(partition, hierarchy); + }; + d3.layout.pie = function() { + function pie(data, i) { + var values = data.map(function(d, i) { + return +value.call(pie, d, i); + }); + var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); + var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - startAngle) / d3.sum(values); + var index = d3.range(data.length); + if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { + return values[j] - values[i]; + } : function(i, j) { + return sort(data[i], data[j]); + }); + var arcs = []; + index.forEach(function(i) { + var d; + arcs[i] = { + data: data[i], + value: d = values[i], + startAngle: a, + endAngle: a += d * k + }; + }); + return arcs; + } + var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * Math.PI; + pie.value = function(x) { + if (!arguments.length) return value; + value = x; + return pie; + }; + pie.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return pie; + }; + pie.startAngle = function(x) { + if (!arguments.length) return startAngle; + startAngle = x; + return pie; + }; + pie.endAngle = function(x) { + if (!arguments.length) return endAngle; + endAngle = x; + return pie; + }; + return pie; + }; + var d3_layout_pieSortByValue = {}; + d3.layout.stack = function() { + function stack(data, index) { + var series = data.map(function(d, i) { + return values.call(stack, d, i); + }); + var points = series.map(function(d, i) { + return d.map(function(v, i) { + return [ x.call(stack, v, i), y.call(stack, v, i) ]; + }); + }); + var orders = order.call(stack, points, index); + series = d3.permute(series, orders); + points = d3.permute(points, orders); + var offsets = offset.call(stack, points, index); + var n = series.length, m = series[0].length, i, j, o; + for (j = 0; j < m; ++j) { + out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); + for (i = 1; i < n; ++i) { + out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); + } + } + return data; + } + var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; + stack.values = function(x) { + if (!arguments.length) return values; + values = x; + return stack; + }; + stack.order = function(x) { + if (!arguments.length) return order; + order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; + return stack; + }; + stack.offset = function(x) { + if (!arguments.length) return offset; + offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; + return stack; + }; + stack.x = function(z) { + if (!arguments.length) return x; + x = z; + return stack; + }; + stack.y = function(z) { + if (!arguments.length) return y; + y = z; + return stack; + }; + stack.out = function(z) { + if (!arguments.length) return out; + out = z; + return stack; + }; + return stack; + }; + var d3_layout_stackOrders = d3.map({ + "inside-out": function(data) { + var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { + return max[a] - max[b]; + }), top = 0, bottom = 0, tops = [], bottoms = []; + for (i = 0; i < n; ++i) { + j = index[i]; + if (top < bottom) { + top += sums[j]; + tops.push(j); + } else { + bottom += sums[j]; + bottoms.push(j); + } + } + return bottoms.reverse().concat(tops); + }, + reverse: function(data) { + return d3.range(data.length).reverse(); + }, + "default": d3_layout_stackOrderDefault + }); + var d3_layout_stackOffsets = d3.map({ + silhouette: function(data) { + var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o > max) max = o; + sums.push(o); + } + for (j = 0; j < m; ++j) { + y0[j] = (max - sums[j]) / 2; + } + return y0; + }, + wiggle: function(data) { + var n = data.length, x = data[0], m = x.length, max = 0, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; + y0[0] = o = o0 = 0; + for (j = 1; j < m; ++j) { + for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; + for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { + for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { + s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; + } + s2 += s3 * data[i][j][1]; + } + y0[j] = o -= s1 ? s2 / s1 * dx : 0; + if (o < o0) o0 = o; + } + for (j = 0; j < m; ++j) y0[j] -= o0; + return y0; + }, + expand: function(data) { + var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; + } + for (j = 0; j < m; ++j) y0[j] = 0; + return y0; + }, + zero: d3_layout_stackOffsetZero + }); + d3.layout.histogram = function() { + function histogram(data, i) { + var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; + while (++i < m) { + bin = bins[i] = []; + bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); + bin.y = 0; + } + if (m > 0) { + i = -1; + while (++i < n) { + x = values[i]; + if (x >= range[0] && x <= range[1]) { + bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; + bin.y += k; + bin.push(data[i]); + } + } + } + return bins; + } + var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; + histogram.value = function(x) { + if (!arguments.length) return valuer; + valuer = x; + return histogram; + }; + histogram.range = function(x) { + if (!arguments.length) return ranger; + ranger = d3_functor(x); + return histogram; + }; + histogram.bins = function(x) { + if (!arguments.length) return binner; + binner = typeof x === "number" ? function(range) { + return d3_layout_histogramBinFixed(range, x); + } : d3_functor(x); + return histogram; + }; + histogram.frequency = function(x) { + if (!arguments.length) return frequency; + frequency = !!x; + return histogram; + }; + return histogram; + }; + d3.layout.hierarchy = function() { + function recurse(data, depth, nodes) { + var childs = children.call(hierarchy, data, depth), node = d3_layout_hierarchyInline ? data : { + data: data + }; + node.depth = depth; + nodes.push(node); + if (childs && (n = childs.length)) { + var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; + while (++i < n) { + d = recurse(childs[i], j, nodes); + d.parent = node; + c.push(d); + v += d.value; + } + if (sort) c.sort(sort); + if (value) node.value = v; + } else if (value) { + node.value = +value.call(hierarchy, data, depth) || 0; + } + return node; + } + function revalue(node, depth) { + var children = node.children, v = 0; + if (children && (n = children.length)) { + var i = -1, n, j = depth + 1; + while (++i < n) v += revalue(children[i], j); + } else if (value) { + v = +value.call(hierarchy, d3_layout_hierarchyInline ? node : node.data, depth) || 0; + } + if (value) node.value = v; + return v; + } + function hierarchy(d) { + var nodes = []; + recurse(d, 0, nodes); + return nodes; + } + var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; + hierarchy.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return hierarchy; + }; + hierarchy.children = function(x) { + if (!arguments.length) return children; + children = x; + return hierarchy; + }; + hierarchy.value = function(x) { + if (!arguments.length) return value; + value = x; + return hierarchy; + }; + hierarchy.revalue = function(root) { + revalue(root, 0); + return root; + }; + return hierarchy; + }; + var d3_layout_hierarchyInline = false; + d3.layout.pack = function() { + function pack(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0]; + root.x = 0; + root.y = 0; + d3_layout_treeVisitAfter(root, function(d) { + d.r = Math.sqrt(d.value); + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + var w = size[0], h = size[1], k = Math.max(2 * root.r / w, 2 * root.r / h); + if (padding > 0) { + var dr = padding * k / 2; + d3_layout_treeVisitAfter(root, function(d) { + d.r += dr; + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + d3_layout_treeVisitAfter(root, function(d) { + d.r -= dr; + }); + k = Math.max(2 * root.r / w, 2 * root.r / h); + } + d3_layout_packTransform(root, w / 2, h / 2, 1 / k); + return nodes; + } + var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ]; + pack.size = function(x) { + if (!arguments.length) return size; + size = x; + return pack; + }; + pack.padding = function(_) { + if (!arguments.length) return padding; + padding = +_; + return pack; + }; + return d3_layout_hierarchyRebind(pack, hierarchy); + }; + d3.layout.cluster = function() { + function cluster(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0, kx, ky; + d3_layout_treeVisitAfter(root, function(node) { + var children = node.children; + if (children && children.length) { + node.x = d3_layout_clusterX(children); + node.y = d3_layout_clusterY(children); + } else { + node.x = previousNode ? x += separation(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; + d3_layout_treeVisitAfter(root, function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; + }); + return nodes; + } + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ]; + cluster.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return cluster; + }; + cluster.size = function(x) { + if (!arguments.length) return size; + size = x; + return cluster; + }; + return d3_layout_hierarchyRebind(cluster, hierarchy); + }; + d3.layout.tree = function() { + function tree(d, i) { + function firstWalk(node, previousSibling) { + var children = node.children, layout = node._tree; + if (children && (n = children.length)) { + var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; + while (++i < n) { + child = children[i]; + firstWalk(child, previousChild); + ancestor = apportion(child, previousChild, ancestor); + previousChild = child; + } + d3_layout_treeShift(node); + var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + layout.mod = layout.prelim - midpoint; + } else { + layout.prelim = midpoint; + } + } else { + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + } + } + } + function secondWalk(node, x) { + node.x = node._tree.prelim + x; + var children = node.children; + if (children && (n = children.length)) { + var i = -1, n; + x += node._tree.mod; + while (++i < n) { + secondWalk(children[i], x); + } + } + } + function apportion(node, previousSibling, ancestor) { + if (previousSibling) { + var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; + while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { + vom = d3_layout_treeLeft(vom); + vop = d3_layout_treeRight(vop); + vop._tree.ancestor = node; + shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); + if (shift > 0) { + d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); + sip += shift; + sop += shift; + } + sim += vim._tree.mod; + sip += vip._tree.mod; + som += vom._tree.mod; + sop += vop._tree.mod; + } + if (vim && !d3_layout_treeRight(vop)) { + vop._tree.thread = vim; + vop._tree.mod += sim - sop; + } + if (vip && !d3_layout_treeLeft(vom)) { + vom._tree.thread = vip; + vom._tree.mod += sip - som; + ancestor = node; + } + } + return ancestor; + } + var nodes = hierarchy.call(this, d, i), root = nodes[0]; + d3_layout_treeVisitAfter(root, function(node, previousSibling) { + node._tree = { + ancestor: node, + prelim: 0, + mod: 0, + change: 0, + shift: 0, + number: previousSibling ? previousSibling._tree.number + 1 : 0 + }; + }); + firstWalk(root); + secondWalk(root, -root._tree.prelim); + var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; + d3_layout_treeVisitAfter(root, function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = node.depth / y1 * size[1]; + delete node._tree; + }); + return nodes; + } + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ]; + tree.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return tree; + }; + tree.size = function(x) { + if (!arguments.length) return size; + size = x; + return tree; + }; + return d3_layout_hierarchyRebind(tree, hierarchy); + }; + d3.layout.treemap = function() { + function scale(children, k) { + var i = -1, n = children.length, child, area; + while (++i < n) { + area = (child = children[i]).value * (k < 0 ? 0 : k); + child.area = isNaN(area) || area <= 0 ? 0 : area; + } + } + function squarify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = Math.min(rect.dx, rect.dy), n; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while ((n = remaining.length) > 0) { + row.push(child = remaining[n - 1]); + row.area += child.area; + if ((score = worst(row, u)) <= best) { + remaining.pop(); + best = score; + } else { + row.area -= row.pop().area; + position(row, u, rect, false); + u = Math.min(rect.dx, rect.dy); + row.length = row.area = 0; + best = Infinity; + } + } + if (row.length) { + position(row, u, rect, true); + row.length = row.area = 0; + } + children.forEach(squarify); + } + } + function stickify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), remaining = children.slice(), child, row = []; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while (child = remaining.pop()) { + row.push(child); + row.area += child.area; + if (child.z != null) { + position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); + row.length = row.area = 0; + } + } + children.forEach(stickify); + } + } + function worst(row, u) { + var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; + while (++i < n) { + if (!(r = row[i].area)) continue; + if (r < rmin) rmin = r; + if (r > rmax) rmax = r; + } + s *= s; + u *= u; + return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; + } + function position(row, u, rect, flush) { + var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; + if (u == rect.dx) { + if (flush || v > rect.dy) v = rect.dy; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dy = v; + x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); + } + o.z = true; + o.dx += rect.x + rect.dx - x; + rect.y += v; + rect.dy -= v; + } else { + if (flush || v > rect.dx) v = rect.dx; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dx = v; + y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); + } + o.z = false; + o.dy += rect.y + rect.dy - y; + rect.x += v; + rect.dx -= v; + } + } + function treemap(d) { + var nodes = stickies || hierarchy(d), root = nodes[0]; + root.x = 0; + root.y = 0; + root.dx = size[0]; + root.dy = size[1]; + if (stickies) hierarchy.revalue(root); + scale([ root ], root.dx * root.dy / root.value); + (stickies ? stickify : squarify)(root); + if (sticky) stickies = nodes; + return nodes; + } + var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, ratio = .5 * (1 + Math.sqrt(5)); + treemap.size = function(x) { + if (!arguments.length) return size; + size = x; + return treemap; + }; + treemap.padding = function(x) { + function padFunction(node) { + var p = x.call(treemap, node, node.depth); + return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); + } + function padConstant(node) { + return d3_layout_treemapPad(node, x); + } + if (!arguments.length) return padding; + var type; + pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], padConstant) : padConstant; + return treemap; + }; + treemap.round = function(x) { + if (!arguments.length) return round != Number; + round = x ? Math.round : Number; + return treemap; + }; + treemap.sticky = function(x) { + if (!arguments.length) return sticky; + sticky = x; + stickies = null; + return treemap; + }; + treemap.ratio = function(x) { + if (!arguments.length) return ratio; + ratio = x; + return treemap; + }; + return d3_layout_hierarchyRebind(treemap, hierarchy); + }; + d3.csv = d3_dsv(",", "text/csv"); + d3.tsv = d3_dsv("\t", "text/tab-separated-values"); + d3.geo = {}; + var d3_geo_radians = Math.PI / 180; + d3.geo.azimuthal = function() { + function azimuthal(coordinates) { + var x1 = coordinates[0] * d3_geo_radians - x0, y1 = coordinates[1] * d3_geo_radians, cx1 = Math.cos(x1), sx1 = Math.sin(x1), cy1 = Math.cos(y1), sy1 = Math.sin(y1), cc = mode !== "orthographic" ? sy0 * sy1 + cy0 * cy1 * cx1 : null, c, k = mode === "stereographic" ? 1 / (1 + cc) : mode === "gnomonic" ? 1 / cc : mode === "equidistant" ? (c = Math.acos(cc), c ? c / Math.sin(c) : 0) : mode === "equalarea" ? Math.sqrt(2 / (1 + cc)) : 1, x = k * cy1 * sx1, y = k * (sy0 * cy1 * cx1 - cy0 * sy1); + return [ scale * x + translate[0], scale * y + translate[1] ]; + } + var mode = "orthographic", origin, scale = 200, translate = [ 480, 250 ], x0, y0, cy0, sy0; + azimuthal.invert = function(coordinates) { + var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale, p = Math.sqrt(x * x + y * y), c = mode === "stereographic" ? 2 * Math.atan(p) : mode === "gnomonic" ? Math.atan(p) : mode === "equidistant" ? p : mode === "equalarea" ? 2 * Math.asin(.5 * p) : Math.asin(p), sc = Math.sin(c), cc = Math.cos(c); + return [ (x0 + Math.atan2(x * sc, p * cy0 * cc + y * sy0 * sc)) / d3_geo_radians, Math.asin(cc * sy0 - (p ? y * sc * cy0 / p : 0)) / d3_geo_radians ]; + }; + azimuthal.mode = function(x) { + if (!arguments.length) return mode; + mode = x + ""; + return azimuthal; + }; + azimuthal.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + x0 = origin[0] * d3_geo_radians; + y0 = origin[1] * d3_geo_radians; + cy0 = Math.cos(y0); + sy0 = Math.sin(y0); + return azimuthal; + }; + azimuthal.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + return azimuthal; + }; + azimuthal.translate = function(x) { + if (!arguments.length) return translate; + translate = [ +x[0], +x[1] ]; + return azimuthal; + }; + return azimuthal.origin([ 0, 0 ]); + }; + d3.geo.albers = function() { + function albers(coordinates) { + var t = n * (d3_geo_radians * coordinates[0] - lng0), p = Math.sqrt(C - 2 * n * Math.sin(d3_geo_radians * coordinates[1])) / n; + return [ scale * p * Math.sin(t) + translate[0], scale * (p * Math.cos(t) - p0) + translate[1] ]; + } + function reload() { + var phi1 = d3_geo_radians * parallels[0], phi2 = d3_geo_radians * parallels[1], lat0 = d3_geo_radians * origin[1], s = Math.sin(phi1), c = Math.cos(phi1); + lng0 = d3_geo_radians * origin[0]; + n = .5 * (s + Math.sin(phi2)); + C = c * c + 2 * n * s; + p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n; + return albers; + } + var origin = [ -98, 38 ], parallels = [ 29.5, 45.5 ], scale = 1e3, translate = [ 480, 250 ], lng0, n, C, p0; + albers.invert = function(coordinates) { + var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale, p0y = p0 + y, t = Math.atan2(x, p0y), p = Math.sqrt(x * x + p0y * p0y); + return [ (lng0 + t / n) / d3_geo_radians, Math.asin((C - p * p * n * n) / (2 * n)) / d3_geo_radians ]; + }; + albers.origin = function(x) { + if (!arguments.length) return origin; + origin = [ +x[0], +x[1] ]; + return reload(); + }; + albers.parallels = function(x) { + if (!arguments.length) return parallels; + parallels = [ +x[0], +x[1] ]; + return reload(); + }; + albers.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + return albers; + }; + albers.translate = function(x) { + if (!arguments.length) return translate; + translate = [ +x[0], +x[1] ]; + return albers; + }; + return reload(); + }; + d3.geo.albersUsa = function() { + function albersUsa(coordinates) { + var lon = coordinates[0], lat = coordinates[1]; + return (lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48)(coordinates); + } + var lower48 = d3.geo.albers(); + var alaska = d3.geo.albers().origin([ -160, 60 ]).parallels([ 55, 65 ]); + var hawaii = d3.geo.albers().origin([ -160, 20 ]).parallels([ 8, 18 ]); + var puertoRico = d3.geo.albers().origin([ -60, 10 ]).parallels([ 8, 18 ]); + albersUsa.scale = function(x) { + if (!arguments.length) return lower48.scale(); + lower48.scale(x); + alaska.scale(x * .6); + hawaii.scale(x); + puertoRico.scale(x * 1.5); + return albersUsa.translate(lower48.translate()); + }; + albersUsa.translate = function(x) { + if (!arguments.length) return lower48.translate(); + var dz = lower48.scale() / 1e3, dx = x[0], dy = x[1]; + lower48.translate(x); + alaska.translate([ dx - 400 * dz, dy + 170 * dz ]); + hawaii.translate([ dx - 190 * dz, dy + 200 * dz ]); + puertoRico.translate([ dx + 580 * dz, dy + 430 * dz ]); + return albersUsa; + }; + return albersUsa.scale(lower48.scale()); + }; + d3.geo.bonne = function() { + function bonne(coordinates) { + var x = coordinates[0] * d3_geo_radians - x0, y = coordinates[1] * d3_geo_radians - y0; + if (y1) { + var p = c1 + y1 - y, E = x * Math.cos(y) / p; + x = p * Math.sin(E); + y = p * Math.cos(E) - c1; + } else { + x *= Math.cos(y); + y *= -1; + } + return [ scale * x + translate[0], scale * y + translate[1] ]; + } + var scale = 200, translate = [ 480, 250 ], x0, y0, y1, c1; + bonne.invert = function(coordinates) { + var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale; + if (y1) { + var c = c1 + y, p = Math.sqrt(x * x + c * c); + y = c1 + y1 - p; + x = x0 + p * Math.atan2(x, c) / Math.cos(y); + } else { + y *= -1; + x /= Math.cos(y); + } + return [ x / d3_geo_radians, y / d3_geo_radians ]; + }; + bonne.parallel = function(x) { + if (!arguments.length) return y1 / d3_geo_radians; + c1 = 1 / Math.tan(y1 = x * d3_geo_radians); + return bonne; + }; + bonne.origin = function(x) { + if (!arguments.length) return [ x0 / d3_geo_radians, y0 / d3_geo_radians ]; + x0 = x[0] * d3_geo_radians; + y0 = x[1] * d3_geo_radians; + return bonne; + }; + bonne.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + return bonne; + }; + bonne.translate = function(x) { + if (!arguments.length) return translate; + translate = [ +x[0], +x[1] ]; + return bonne; + }; + return bonne.origin([ 0, 0 ]).parallel(45); + }; + d3.geo.equirectangular = function() { + function equirectangular(coordinates) { + var x = coordinates[0] / 360, y = -coordinates[1] / 360; + return [ scale * x + translate[0], scale * y + translate[1] ]; + } + var scale = 500, translate = [ 480, 250 ]; + equirectangular.invert = function(coordinates) { + var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale; + return [ 360 * x, -360 * y ]; + }; + equirectangular.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + return equirectangular; + }; + equirectangular.translate = function(x) { + if (!arguments.length) return translate; + translate = [ +x[0], +x[1] ]; + return equirectangular; + }; + return equirectangular; + }; + d3.geo.mercator = function() { + function mercator(coordinates) { + var x = coordinates[0] / 360, y = -(Math.log(Math.tan(Math.PI / 4 + coordinates[1] * d3_geo_radians / 2)) / d3_geo_radians) / 360; + return [ scale * x + translate[0], scale * Math.max(-.5, Math.min(.5, y)) + translate[1] ]; + } + var scale = 500, translate = [ 480, 250 ]; + mercator.invert = function(coordinates) { + var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale; + return [ 360 * x, 2 * Math.atan(Math.exp(-360 * y * d3_geo_radians)) / d3_geo_radians - 90 ]; + }; + mercator.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + return mercator; + }; + mercator.translate = function(x) { + if (!arguments.length) return translate; + translate = [ +x[0], +x[1] ]; + return mercator; + }; + return mercator; + }; + d3.geo.path = function() { + function path(d, i) { + if (typeof pointRadius === "function") pointCircle = d3_path_circle(pointRadius.apply(this, arguments)); + pathType(d); + var result = buffer.length ? buffer.join("") : null; + buffer = []; + return result; + } + function project(coordinates) { + return projection(coordinates).join(","); + } + function polygonArea(coordinates) { + var sum = area(coordinates[0]), i = 0, n = coordinates.length; + while (++i < n) sum -= area(coordinates[i]); + return sum; + } + function polygonCentroid(coordinates) { + var polygon = d3.geom.polygon(coordinates[0].map(projection)), area = polygon.area(), centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1), x = centroid[0], y = centroid[1], z = area, i = 0, n = coordinates.length; + while (++i < n) { + polygon = d3.geom.polygon(coordinates[i].map(projection)); + area = polygon.area(); + centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1); + x -= centroid[0]; + y -= centroid[1]; + z -= area; + } + return [ x, y, 6 * z ]; + } + function area(coordinates) { + return Math.abs(d3.geom.polygon(coordinates.map(projection)).area()); + } + var pointRadius = 4.5, pointCircle = d3_path_circle(pointRadius), projection = d3.geo.albersUsa(), buffer = []; + var pathType = d3_geo_type({ + FeatureCollection: function(o) { + var features = o.features, i = -1, n = features.length; + while (++i < n) buffer.push(pathType(features[i].geometry)); + }, + Feature: function(o) { + pathType(o.geometry); + }, + Point: function(o) { + buffer.push("M", project(o.coordinates), pointCircle); + }, + MultiPoint: function(o) { + var coordinates = o.coordinates, i = -1, n = coordinates.length; + while (++i < n) buffer.push("M", project(coordinates[i]), pointCircle); + }, + LineString: function(o) { + var coordinates = o.coordinates, i = -1, n = coordinates.length; + buffer.push("M"); + while (++i < n) buffer.push(project(coordinates[i]), "L"); + buffer.pop(); + }, + MultiLineString: function(o) { + var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m; + while (++i < n) { + subcoordinates = coordinates[i]; + j = -1; + m = subcoordinates.length; + buffer.push("M"); + while (++j < m) buffer.push(project(subcoordinates[j]), "L"); + buffer.pop(); + } + }, + Polygon: function(o) { + var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m; + while (++i < n) { + subcoordinates = coordinates[i]; + j = -1; + if ((m = subcoordinates.length - 1) > 0) { + buffer.push("M"); + while (++j < m) buffer.push(project(subcoordinates[j]), "L"); + buffer[buffer.length - 1] = "Z"; + } + } + }, + MultiPolygon: function(o) { + var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m, subsubcoordinates, k, p; + while (++i < n) { + subcoordinates = coordinates[i]; + j = -1; + m = subcoordinates.length; + while (++j < m) { + subsubcoordinates = subcoordinates[j]; + k = -1; + if ((p = subsubcoordinates.length - 1) > 0) { + buffer.push("M"); + while (++k < p) buffer.push(project(subsubcoordinates[k]), "L"); + buffer[buffer.length - 1] = "Z"; + } + } + } + }, + GeometryCollection: function(o) { + var geometries = o.geometries, i = -1, n = geometries.length; + while (++i < n) buffer.push(pathType(geometries[i])); + } + }); + var areaType = path.area = d3_geo_type({ + FeatureCollection: function(o) { + var area = 0, features = o.features, i = -1, n = features.length; + while (++i < n) area += areaType(features[i]); + return area; + }, + Feature: function(o) { + return areaType(o.geometry); + }, + Polygon: function(o) { + return polygonArea(o.coordinates); + }, + MultiPolygon: function(o) { + var sum = 0, coordinates = o.coordinates, i = -1, n = coordinates.length; + while (++i < n) sum += polygonArea(coordinates[i]); + return sum; + }, + GeometryCollection: function(o) { + var sum = 0, geometries = o.geometries, i = -1, n = geometries.length; + while (++i < n) sum += areaType(geometries[i]); + return sum; + } + }, 0); + var centroidType = path.centroid = d3_geo_type({ + Feature: function(o) { + return centroidType(o.geometry); + }, + Polygon: function(o) { + var centroid = polygonCentroid(o.coordinates); + return [ centroid[0] / centroid[2], centroid[1] / centroid[2] ]; + }, + MultiPolygon: function(o) { + var area = 0, coordinates = o.coordinates, centroid, x = 0, y = 0, z = 0, i = -1, n = coordinates.length; + while (++i < n) { + centroid = polygonCentroid(coordinates[i]); + x += centroid[0]; + y += centroid[1]; + z += centroid[2]; + } + return [ x / z, y / z ]; + } + }); + path.projection = function(x) { + projection = x; + return path; + }; + path.pointRadius = function(x) { + if (typeof x === "function") pointRadius = x; else { + pointRadius = +x; + pointCircle = d3_path_circle(pointRadius); + } + return path; + }; + return path; + }; + d3.geo.bounds = function(feature) { + var left = Infinity, bottom = Infinity, right = -Infinity, top = -Infinity; + d3_geo_bounds(feature, function(x, y) { + if (x < left) left = x; + if (x > right) right = x; + if (y < bottom) bottom = y; + if (y > top) top = y; + }); + return [ [ left, bottom ], [ right, top ] ]; + }; + var d3_geo_boundsTypes = { + Feature: d3_geo_boundsFeature, + FeatureCollection: d3_geo_boundsFeatureCollection, + GeometryCollection: d3_geo_boundsGeometryCollection, + LineString: d3_geo_boundsLineString, + MultiLineString: d3_geo_boundsMultiLineString, + MultiPoint: d3_geo_boundsLineString, + MultiPolygon: d3_geo_boundsMultiPolygon, + Point: d3_geo_boundsPoint, + Polygon: d3_geo_boundsPolygon + }; + d3.geo.circle = function() { + function circle() {} + function visible(point) { + return arc.distance(point) < radians; + } + function clip(coordinates) { + var i = -1, n = coordinates.length, clipped = [], p0, p1, p2, d0, d1; + while (++i < n) { + d1 = arc.distance(p2 = coordinates[i]); + if (d1 < radians) { + if (p1) clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1))); + clipped.push(p2); + p0 = p1 = null; + } else { + p1 = p2; + if (!p0 && clipped.length) { + clipped.push(d3_geo_greatArcInterpolate(clipped[clipped.length - 1], p1)((radians - d0) / (d1 - d0))); + p0 = p1; + } + } + d0 = d1; + } + p0 = coordinates[0]; + p1 = clipped[0]; + if (p1 && p2[0] === p0[0] && p2[1] === p0[1] && !(p2[0] === p1[0] && p2[1] === p1[1])) { + clipped.push(p1); + } + return resample(clipped); + } + function resample(coordinates) { + var i = 0, n = coordinates.length, j, m, resampled = n ? [ coordinates[0] ] : coordinates, resamples, origin = arc.source(); + while (++i < n) { + resamples = arc.source(coordinates[i - 1])(coordinates[i]).coordinates; + for (j = 0, m = resamples.length; ++j < m; ) resampled.push(resamples[j]); + } + arc.source(origin); + return resampled; + } + var origin = [ 0, 0 ], degrees = 90 - .01, radians = degrees * d3_geo_radians, arc = d3.geo.greatArc().source(origin).target(d3_identity); + circle.clip = function(d) { + if (typeof origin === "function") arc.source(origin.apply(this, arguments)); + return clipType(d) || null; + }; + var clipType = d3_geo_type({ + FeatureCollection: function(o) { + var features = o.features.map(clipType).filter(d3_identity); + return features && (o = Object.create(o), o.features = features, o); + }, + Feature: function(o) { + var geometry = clipType(o.geometry); + return geometry && (o = Object.create(o), o.geometry = geometry, o); + }, + Point: function(o) { + return visible(o.coordinates) && o; + }, + MultiPoint: function(o) { + var coordinates = o.coordinates.filter(visible); + return coordinates.length && { + type: o.type, + coordinates: coordinates + }; + }, + LineString: function(o) { + var coordinates = clip(o.coordinates); + return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); + }, + MultiLineString: function(o) { + var coordinates = o.coordinates.map(clip).filter(function(d) { + return d.length; + }); + return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); + }, + Polygon: function(o) { + var coordinates = o.coordinates.map(clip); + return coordinates[0].length && (o = Object.create(o), o.coordinates = coordinates, o); + }, + MultiPolygon: function(o) { + var coordinates = o.coordinates.map(function(d) { + return d.map(clip); + }).filter(function(d) { + return d[0].length; + }); + return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); + }, + GeometryCollection: function(o) { + var geometries = o.geometries.map(clipType).filter(d3_identity); + return geometries.length && (o = Object.create(o), o.geometries = geometries, o); + } + }); + circle.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + if (typeof origin !== "function") arc.source(origin); + return circle; + }; + circle.angle = function(x) { + if (!arguments.length) return degrees; + radians = (degrees = +x) * d3_geo_radians; + return circle; + }; + return d3.rebind(circle, arc, "precision"); + }; + d3.geo.greatArc = function() { + function greatArc() { + var d = greatArc.distance.apply(this, arguments), t = 0, dt = precision / d, coordinates = [ p0 ]; + while ((t += dt) < 1) coordinates.push(interpolate(t)); + coordinates.push(p1); + return { + type: "LineString", + coordinates: coordinates + }; + } + var source = d3_geo_greatArcSource, p0, target = d3_geo_greatArcTarget, p1, precision = 6 * d3_geo_radians, interpolate = d3_geo_greatArcInterpolator(); + greatArc.distance = function() { + if (typeof source === "function") interpolate.source(p0 = source.apply(this, arguments)); + if (typeof target === "function") interpolate.target(p1 = target.apply(this, arguments)); + return interpolate.distance(); + }; + greatArc.source = function(_) { + if (!arguments.length) return source; + source = _; + if (typeof source !== "function") interpolate.source(p0 = source); + return greatArc; + }; + greatArc.target = function(_) { + if (!arguments.length) return target; + target = _; + if (typeof target !== "function") interpolate.target(p1 = target); + return greatArc; + }; + greatArc.precision = function(_) { + if (!arguments.length) return precision / d3_geo_radians; + precision = _ * d3_geo_radians; + return greatArc; + }; + return greatArc; + }; + d3.geo.greatCircle = d3.geo.circle; + d3.geom = {}; + d3.geom.contour = function(grid, start) { + var s = start || d3_geom_contourStart(grid), c = [], x = s[0], y = s[1], dx = 0, dy = 0, pdx = NaN, pdy = NaN, i = 0; + do { + i = 0; + if (grid(x - 1, y - 1)) i += 1; + if (grid(x, y - 1)) i += 2; + if (grid(x - 1, y)) i += 4; + if (grid(x, y)) i += 8; + if (i === 6) { + dx = pdy === -1 ? -1 : 1; + dy = 0; + } else if (i === 9) { + dx = 0; + dy = pdx === 1 ? -1 : 1; + } else { + dx = d3_geom_contourDx[i]; + dy = d3_geom_contourDy[i]; + } + if (dx != pdx && dy != pdy) { + c.push([ x, y ]); + pdx = dx; + pdy = dy; + } + x += dx; + y += dy; + } while (s[0] != x || s[1] != y); + return c; + }; + var d3_geom_contourDx = [ 1, 0, 1, 1, -1, 0, -1, 1, 0, 0, 0, 0, -1, 0, -1, NaN ], d3_geom_contourDy = [ 0, -1, 0, 0, 0, -1, 0, 0, 1, -1, 1, 1, 0, -1, 0, NaN ]; + d3.geom.hull = function(vertices) { + if (vertices.length < 3) return []; + var len = vertices.length, plen = len - 1, points = [], stack = [], i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; + for (i = 1; i < len; ++i) { + if (vertices[i][1] < vertices[h][1]) { + h = i; + } else if (vertices[i][1] == vertices[h][1]) { + h = vertices[i][0] < vertices[h][0] ? i : h; + } + } + for (i = 0; i < len; ++i) { + if (i === h) continue; + y1 = vertices[i][1] - vertices[h][1]; + x1 = vertices[i][0] - vertices[h][0]; + points.push({ + angle: Math.atan2(y1, x1), + index: i + }); + } + points.sort(function(a, b) { + return a.angle - b.angle; + }); + a = points[0].angle; + v = points[0].index; + u = 0; + for (i = 1; i < plen; ++i) { + j = points[i].index; + if (a == points[i].angle) { + x1 = vertices[v][0] - vertices[h][0]; + y1 = vertices[v][1] - vertices[h][1]; + x2 = vertices[j][0] - vertices[h][0]; + y2 = vertices[j][1] - vertices[h][1]; + if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { + points[i].index = -1; + } else { + points[u].index = -1; + a = points[i].angle; + u = i; + v = j; + } + } else { + a = points[i].angle; + u = i; + v = j; + } + } + stack.push(h); + for (i = 0, j = 0; i < 2; ++j) { + if (points[j].index !== -1) { + stack.push(points[j].index); + i++; + } + } + sp = stack.length; + for (; j < plen; ++j) { + if (points[j].index === -1) continue; + while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { + --sp; + } + stack[sp++] = points[j].index; + } + var poly = []; + for (i = 0; i < sp; ++i) { + poly.push(vertices[stack[i]]); + } + return poly; + }; + d3.geom.polygon = function(coordinates) { + coordinates.area = function() { + var i = 0, n = coordinates.length, a = coordinates[n - 1][0] * coordinates[0][1], b = coordinates[n - 1][1] * coordinates[0][0]; + while (++i < n) { + a += coordinates[i - 1][0] * coordinates[i][1]; + b += coordinates[i - 1][1] * coordinates[i][0]; + } + return (b - a) * .5; + }; + coordinates.centroid = function(k) { + var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c; + if (!arguments.length) k = -1 / (6 * coordinates.area()); + while (++i < n) { + a = b; + b = coordinates[i]; + c = a[0] * b[1] - b[0] * a[1]; + x += (a[0] + b[0]) * c; + y += (a[1] + b[1]) * c; + } + return [ x * k, y * k ]; + }; + coordinates.clip = function(subject) { + var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d; + while (++i < n) { + input = subject.slice(); + subject.length = 0; + b = coordinates[i]; + c = input[(m = input.length) - 1]; + j = -1; + while (++j < m) { + d = input[j]; + if (d3_geom_polygonInside(d, a, b)) { + if (!d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + subject.push(d); + } else if (d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + c = d; + } + a = b; + } + return subject; + }; + return coordinates; + }; + d3.geom.voronoi = function(vertices) { + var polygons = vertices.map(function() { + return []; + }); + d3_voronoi_tessellate(vertices, function(e) { + var s1, s2, x1, x2, y1, y2; + if (e.a === 1 && e.b >= 0) { + s1 = e.ep.r; + s2 = e.ep.l; + } else { + s1 = e.ep.l; + s2 = e.ep.r; + } + if (e.a === 1) { + y1 = s1 ? s1.y : -1e6; + x1 = e.c - e.b * y1; + y2 = s2 ? s2.y : 1e6; + x2 = e.c - e.b * y2; + } else { + x1 = s1 ? s1.x : -1e6; + y1 = e.c - e.a * x1; + x2 = s2 ? s2.x : 1e6; + y2 = e.c - e.a * x2; + } + var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; + polygons[e.region.l.index].push(v1, v2); + polygons[e.region.r.index].push(v1, v2); + }); + return polygons.map(function(polygon, i) { + var cx = vertices[i][0], cy = vertices[i][1]; + polygon.forEach(function(v) { + v.angle = Math.atan2(v[0] - cx, v[1] - cy); + }); + return polygon.sort(function(a, b) { + return a.angle - b.angle; + }).filter(function(d, i) { + return !i || d.angle - polygon[i - 1].angle > 1e-10; + }); + }); + }; + var d3_voronoi_opposite = { + l: "r", + r: "l" + }; + d3.geom.delaunay = function(vertices) { + var edges = vertices.map(function() { + return []; + }), triangles = []; + d3_voronoi_tessellate(vertices, function(e) { + edges[e.region.l.index].push(vertices[e.region.r.index]); + }); + edges.forEach(function(edge, i) { + var v = vertices[i], cx = v[0], cy = v[1]; + edge.forEach(function(v) { + v.angle = Math.atan2(v[0] - cx, v[1] - cy); + }); + edge.sort(function(a, b) { + return a.angle - b.angle; + }); + for (var j = 0, m = edge.length - 1; j < m; j++) { + triangles.push([ v, edge[j], edge[j + 1] ]); + } + }); + return triangles; + }; + d3.geom.quadtree = function(points, x1, y1, x2, y2) { + function insert(n, p, x1, y1, x2, y2) { + if (isNaN(p.x) || isNaN(p.y)) return; + if (n.leaf) { + var v = n.point; + if (v) { + if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < .01) { + insertChild(n, p, x1, y1, x2, y2); + } else { + n.point = null; + insertChild(n, v, x1, y1, x2, y2); + insertChild(n, p, x1, y1, x2, y2); + } + } else { + n.point = p; + } + } else { + insertChild(n, p, x1, y1, x2, y2); + } + } + function insertChild(n, p, x1, y1, x2, y2) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = p.x >= sx, bottom = p.y >= sy, i = (bottom << 1) + right; + n.leaf = false; + n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); + if (right) x1 = sx; else x2 = sx; + if (bottom) y1 = sy; else y2 = sy; + insert(n, p, x1, y1, x2, y2); + } + var p, i = -1, n = points.length; + if (n && isNaN(points[0].x)) points = points.map(d3_geom_quadtreePoint); + if (arguments.length < 5) { + if (arguments.length === 3) { + y2 = x2 = y1; + y1 = x1; + } else { + x1 = y1 = Infinity; + x2 = y2 = -Infinity; + while (++i < n) { + p = points[i]; + if (p.x < x1) x1 = p.x; + if (p.y < y1) y1 = p.y; + if (p.x > x2) x2 = p.x; + if (p.y > y2) y2 = p.y; + } + var dx = x2 - x1, dy = y2 - y1; + if (dx > dy) y2 = y1 + dx; else x2 = x1 + dy; + } + } + var root = d3_geom_quadtreeNode(); + root.add = function(p) { + insert(root, p, x1, y1, x2, y2); + }; + root.visit = function(f) { + d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2); + }; + points.forEach(root.add); + return root; + }; + d3.time = {}; + var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; + d3_time_utc.prototype = { + getDate: function() { + return this._.getUTCDate(); + }, + getDay: function() { + return this._.getUTCDay(); + }, + getFullYear: function() { + return this._.getUTCFullYear(); + }, + getHours: function() { + return this._.getUTCHours(); + }, + getMilliseconds: function() { + return this._.getUTCMilliseconds(); + }, + getMinutes: function() { + return this._.getUTCMinutes(); + }, + getMonth: function() { + return this._.getUTCMonth(); + }, + getSeconds: function() { + return this._.getUTCSeconds(); + }, + getTime: function() { + return this._.getTime(); + }, + getTimezoneOffset: function() { + return 0; + }, + valueOf: function() { + return this._.valueOf(); + }, + setDate: function() { + d3_time_prototype.setUTCDate.apply(this._, arguments); + }, + setDay: function() { + d3_time_prototype.setUTCDay.apply(this._, arguments); + }, + setFullYear: function() { + d3_time_prototype.setUTCFullYear.apply(this._, arguments); + }, + setHours: function() { + d3_time_prototype.setUTCHours.apply(this._, arguments); + }, + setMilliseconds: function() { + d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); + }, + setMinutes: function() { + d3_time_prototype.setUTCMinutes.apply(this._, arguments); + }, + setMonth: function() { + d3_time_prototype.setUTCMonth.apply(this._, arguments); + }, + setSeconds: function() { + d3_time_prototype.setUTCSeconds.apply(this._, arguments); + }, + setTime: function() { + d3_time_prototype.setTime.apply(this._, arguments); + } + }; + var d3_time_prototype = Date.prototype; + var d3_time_formatDateTime = "%a %b %e %H:%M:%S %Y", d3_time_formatDate = "%m/%d/%y", d3_time_formatTime = "%H:%M:%S"; + var d3_time_days = d3_time_daySymbols, d3_time_dayAbbreviations = d3_time_days.map(d3_time_formatAbbreviate), d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = d3_time_months.map(d3_time_formatAbbreviate); + d3.time.format = function(template) { + function format(date) { + var string = [], i = -1, j = 0, c, f; + while (++i < n) { + if (template.charCodeAt(i) == 37) { + string.push(template.substring(j, i), (f = d3_time_formats[c = template.charAt(++i)]) ? f(date) : c); + j = i + 1; + } + } + string.push(template.substring(j, i)); + return string.join(""); + } + var n = template.length; + format.parse = function(string) { + var d = { + y: 1900, + m: 0, + d: 1, + H: 0, + M: 0, + S: 0, + L: 0 + }, i = d3_time_parse(d, template, string, 0); + if (i != string.length) return null; + if ("p" in d) d.H = d.H % 12 + d.p * 12; + var date = new d3_time; + date.setFullYear(d.y, d.m, d.d); + date.setHours(d.H, d.M, d.S, d.L); + return date; + }; + format.toString = function() { + return template; + }; + return format; + }; + var d3_time_zfill2 = d3.format("02d"), d3_time_zfill3 = d3.format("03d"), d3_time_zfill4 = d3.format("04d"), d3_time_sfill2 = d3.format("2d"); + var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations); + var d3_time_formats = { + a: function(d) { + return d3_time_dayAbbreviations[d.getDay()]; + }, + A: function(d) { + return d3_time_days[d.getDay()]; + }, + b: function(d) { + return d3_time_monthAbbreviations[d.getMonth()]; + }, + B: function(d) { + return d3_time_months[d.getMonth()]; + }, + c: d3.time.format(d3_time_formatDateTime), + d: function(d) { + return d3_time_zfill2(d.getDate()); + }, + e: function(d) { + return d3_time_sfill2(d.getDate()); + }, + H: function(d) { + return d3_time_zfill2(d.getHours()); + }, + I: function(d) { + return d3_time_zfill2(d.getHours() % 12 || 12); + }, + j: function(d) { + return d3_time_zfill3(1 + d3.time.dayOfYear(d)); + }, + L: function(d) { + return d3_time_zfill3(d.getMilliseconds()); + }, + m: function(d) { + return d3_time_zfill2(d.getMonth() + 1); + }, + M: function(d) { + return d3_time_zfill2(d.getMinutes()); + }, + p: function(d) { + return d.getHours() >= 12 ? "PM" : "AM"; + }, + S: function(d) { + return d3_time_zfill2(d.getSeconds()); + }, + U: function(d) { + return d3_time_zfill2(d3.time.sundayOfYear(d)); + }, + w: function(d) { + return d.getDay(); + }, + W: function(d) { + return d3_time_zfill2(d3.time.mondayOfYear(d)); + }, + x: d3.time.format(d3_time_formatDate), + X: d3.time.format(d3_time_formatTime), + y: function(d) { + return d3_time_zfill2(d.getFullYear() % 100); + }, + Y: function(d) { + return d3_time_zfill4(d.getFullYear() % 1e4); + }, + Z: d3_time_zone, + "%": function(d) { + return "%"; + } + }; + var d3_time_parsers = { + a: d3_time_parseWeekdayAbbrev, + A: d3_time_parseWeekday, + b: d3_time_parseMonthAbbrev, + B: d3_time_parseMonth, + c: d3_time_parseLocaleFull, + d: d3_time_parseDay, + e: d3_time_parseDay, + H: d3_time_parseHour24, + I: d3_time_parseHour24, + L: d3_time_parseMilliseconds, + m: d3_time_parseMonthNumber, + M: d3_time_parseMinutes, + p: d3_time_parseAmPm, + S: d3_time_parseSeconds, + x: d3_time_parseLocaleDate, + X: d3_time_parseLocaleTime, + y: d3_time_parseYear, + Y: d3_time_parseFullYear + }; + var d3_time_numberRe = /^\s*\d+/; + var d3_time_amPmLookup = d3.map({ + am: 0, + pm: 1 + }); + d3.time.format.utc = function(template) { + function format(date) { + try { + d3_time = d3_time_utc; + var utc = new d3_time; + utc._ = date; + return local(utc); + } finally { + d3_time = Date; + } + } + var local = d3.time.format(template); + format.parse = function(string) { + try { + d3_time = d3_time_utc; + var date = local.parse(string); + return date && date._; + } finally { + d3_time = Date; + } + }; + format.toString = local.toString; + return format; + }; + var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); + d3.time.format.iso = Date.prototype.toISOString ? d3_time_formatIsoNative : d3_time_formatIso; + d3_time_formatIsoNative.parse = function(string) { + var date = new Date(string); + return isNaN(date) ? null : date; + }; + d3_time_formatIsoNative.toString = d3_time_formatIso.toString; + d3.time.second = d3_time_interval(function(date) { + return new d3_time(Math.floor(date / 1e3) * 1e3); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 1e3); + }, function(date) { + return date.getSeconds(); + }); + d3.time.seconds = d3.time.second.range; + d3.time.seconds.utc = d3.time.second.utc.range; + d3.time.minute = d3_time_interval(function(date) { + return new d3_time(Math.floor(date / 6e4) * 6e4); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 6e4); + }, function(date) { + return date.getMinutes(); + }); + d3.time.minutes = d3.time.minute.range; + d3.time.minutes.utc = d3.time.minute.utc.range; + d3.time.hour = d3_time_interval(function(date) { + var timezone = date.getTimezoneOffset() / 60; + return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 36e5); + }, function(date) { + return date.getHours(); + }); + d3.time.hours = d3.time.hour.range; + d3.time.hours.utc = d3.time.hour.utc.range; + d3.time.day = d3_time_interval(function(date) { + var day = new d3_time(1970, 0); + day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); + return day; + }, function(date, offset) { + date.setDate(date.getDate() + offset); + }, function(date) { + return date.getDate() - 1; + }); + d3.time.days = d3.time.day.range; + d3.time.days.utc = d3.time.day.utc.range; + d3.time.dayOfYear = function(date) { + var year = d3.time.year(date); + return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); + }; + d3_time_daySymbols.forEach(function(day, i) { + day = day.toLowerCase(); + i = 7 - i; + var interval = d3.time[day] = d3_time_interval(function(date) { + (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); + return date; + }, function(date, offset) { + date.setDate(date.getDate() + Math.floor(offset) * 7); + }, function(date) { + var day = d3.time.year(date).getDay(); + return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); + }); + d3.time[day + "s"] = interval.range; + d3.time[day + "s"].utc = interval.utc.range; + d3.time[day + "OfYear"] = function(date) { + var day = d3.time.year(date).getDay(); + return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); + }; + }); + d3.time.week = d3.time.sunday; + d3.time.weeks = d3.time.sunday.range; + d3.time.weeks.utc = d3.time.sunday.utc.range; + d3.time.weekOfYear = d3.time.sundayOfYear; + d3.time.month = d3_time_interval(function(date) { + date = d3.time.day(date); + date.setDate(1); + return date; + }, function(date, offset) { + date.setMonth(date.getMonth() + offset); + }, function(date) { + return date.getMonth(); + }); + d3.time.months = d3.time.month.range; + d3.time.months.utc = d3.time.month.utc.range; + d3.time.year = d3_time_interval(function(date) { + date = d3.time.day(date); + date.setMonth(0, 1); + return date; + }, function(date, offset) { + date.setFullYear(date.getFullYear() + offset); + }, function(date) { + return date.getFullYear(); + }); + d3.time.years = d3.time.year.range; + d3.time.years.utc = d3.time.year.utc.range; + var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; + var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ]; + var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), function(d) { + return true; + } ], [ d3.time.format("%B"), function(d) { + return d.getMonth(); + } ], [ d3.time.format("%b %d"), function(d) { + return d.getDate() != 1; + } ], [ d3.time.format("%a %d"), function(d) { + return d.getDay() && d.getDate() != 1; + } ], [ d3.time.format("%I %p"), function(d) { + return d.getHours(); + } ], [ d3.time.format("%I:%M"), function(d) { + return d.getMinutes(); + } ], [ d3.time.format(":%S"), function(d) { + return d.getSeconds(); + } ], [ d3.time.format(".%L"), function(d) { + return d.getMilliseconds(); + } ] ]; + var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); + d3_time_scaleLocalMethods.year = function(extent, m) { + return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); + }; + d3.time.scale = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); + }; + var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { + return [ m[0].utc, m[1] ]; + }); + var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), function(d) { + return true; + } ], [ d3.time.format.utc("%B"), function(d) { + return d.getUTCMonth(); + } ], [ d3.time.format.utc("%b %d"), function(d) { + return d.getUTCDate() != 1; + } ], [ d3.time.format.utc("%a %d"), function(d) { + return d.getUTCDay() && d.getUTCDate() != 1; + } ], [ d3.time.format.utc("%I %p"), function(d) { + return d.getUTCHours(); + } ], [ d3.time.format.utc("%I:%M"), function(d) { + return d.getUTCMinutes(); + } ], [ d3.time.format.utc(":%S"), function(d) { + return d.getUTCSeconds(); + } ], [ d3.time.format.utc(".%L"), function(d) { + return d.getUTCMilliseconds(); + } ] ]; + var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); + d3_time_scaleUTCMethods.year = function(extent, m) { + return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); + }; + d3.time.scale.utc = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); + }; +})(); \ No newline at end of file diff --git a/Config/mitkRigidRegistrationPresets.xml b/Modules/RigidRegistration/Resources/mitkRigidRegistrationPresets.xml similarity index 97% rename from Config/mitkRigidRegistrationPresets.xml rename to Modules/RigidRegistration/Resources/mitkRigidRegistrationPresets.xml index ebd99c545d..d134dc0cef 100644 --- a/Config/mitkRigidRegistrationPresets.xml +++ b/Modules/RigidRegistration/Resources/mitkRigidRegistrationPresets.xml @@ -1,45 +1,45 @@ - + - + - + diff --git a/Config/mitkRigidRegistrationTestPresets.xml b/Modules/RigidRegistration/Resources/mitkRigidRegistrationTestPresets.xml similarity index 99% rename from Config/mitkRigidRegistrationTestPresets.xml rename to Modules/RigidRegistration/Resources/mitkRigidRegistrationTestPresets.xml index 1f0f6c293e..a4423af0e4 100644 --- a/Config/mitkRigidRegistrationTestPresets.xml +++ b/Modules/RigidRegistration/Resources/mitkRigidRegistrationTestPresets.xml @@ -1,280 +1,280 @@ - + - + - + - - + + diff --git a/Modules/RigidRegistration/files.cmake b/Modules/RigidRegistration/files.cmake index 1346bd73de..14735e7ec5 100644 --- a/Modules/RigidRegistration/files.cmake +++ b/Modules/RigidRegistration/files.cmake @@ -1,13 +1,18 @@ set(CPP_FILES mitkImageRegistrationMethod.cpp mitkMetricParameters.cpp mitkOptimizerFactory.cpp mitkOptimizerParameters.cpp mitkRigidRegistrationObserver.cpp mitkRigidRegistrationPreset.cpp mitkTransformParameters.cpp mitkPyramidalRegistrationMethod.cpp ) +set(RESOURCE_FILES + mitkRigidRegistrationPresets.xml + mitkRigidRegistrationTestPresets.xml +) + MITK_MULTIPLEX_PICTYPE( mitkImageRegistrationMethod-TYPE.cpp ) -MITK_MULTIPLEX_PICTYPE( mitkPyramidalRegistrationMethod-TYPE.cpp ) \ No newline at end of file +MITK_MULTIPLEX_PICTYPE( mitkPyramidalRegistrationMethod-TYPE.cpp ) diff --git a/Modules/RigidRegistration/mitkRigidRegistrationPreset.cpp b/Modules/RigidRegistration/mitkRigidRegistrationPreset.cpp index 3f0ef3efa0..d816c92de2 100644 --- a/Modules/RigidRegistration/mitkRigidRegistrationPreset.cpp +++ b/Modules/RigidRegistration/mitkRigidRegistrationPreset.cpp @@ -1,1162 +1,1158 @@ /*=================================================================== 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 "mitkRigidRegistrationPreset.h" -#include "mitkStandardFileLocations.h" #include "mitkMetricParameters.h" #include "mitkOptimizerParameters.h" #include "mitkTransformParameters.h" +#include "mitkGetModuleContext.h" +#include "mitkModuleContext.h" +#include "mitkModule.h" +#include "mitkModuleResource.h" +#include "mitkModuleResourceStream.h" + namespace mitk { RigidRegistrationPreset::RigidRegistrationPreset() { m_Name = ""; m_XmlFileName = "mitkRigidRegistrationPresets.xml"; } RigidRegistrationPreset::~RigidRegistrationPreset() { } bool RigidRegistrationPreset::LoadPreset() { - std::string location1 = MITK_ROOT; - std::string location2 = "/QFunctionalities/QmitkRigidRegistration"; - std::string location = location1 + location2; - mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(location.c_str(), true); - mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch("/bin", true); - std::string xmlFileName = mitk::StandardFileLocations::GetInstance()->FindFile("mitkRigidRegistrationPresets.xml", "Config"); - - if (!xmlFileName.empty()) - { - m_XmlFileName = xmlFileName; - return LoadPreset(m_XmlFileName); - } - else - return false; + return LoadPreset("mitkRigidRegistrationPresets.xml"); } bool RigidRegistrationPreset::LoadPreset(std::string fileName) { if ( fileName.empty() ) return false; - vtkXMLParser::SetFileName( fileName.c_str() ); - m_XmlFileName = fileName; + ModuleResource presetResource = GetModuleContext()->GetModule()->GetResource(fileName); + if (!presetResource) return false; + + ModuleResourceStream presetStream(presetResource); + + vtkXMLParser::SetStream(&presetStream); if ( !vtkXMLParser::Parse() ) { #ifdef INTERDEBUG MITK_INFO<<"RigidRegistrationPreset::LoadPreset xml file cannot parse!"< transformValues; transformValues.SetSize(25); transformValues.fill(0); std::string transform = ReadXMLStringAttribut( "TRANSFORM", atts ); double trans = atof(transform.c_str()); transformValues[0] = trans; transformValues = this->loadTransformValues(transformValues, trans, atts); m_TransformValues[m_Name] = transformValues; } else if (elementNameString == "metric") { itk::Array metricValues; metricValues.SetSize(25); metricValues.fill(0); std::string metric = ReadXMLStringAttribut( "METRIC", atts ); double met = atof(metric.c_str()); metricValues[0] = met; metricValues = this->loadMetricValues(metricValues, met, atts); m_MetricValues[m_Name] = metricValues; } else if (elementNameString == "optimizer") { itk::Array optimizerValues; optimizerValues.SetSize(25); optimizerValues.fill(0); std::string optimizer = ReadXMLStringAttribut( "OPTIMIZER", atts ); double opt = atof(optimizer.c_str()); optimizerValues[0] = opt; optimizerValues = this->loadOptimizerValues(optimizerValues, opt, atts); m_OptimizerValues[m_Name] = optimizerValues; } else if (elementNameString == "interpolator") { itk::Array interpolatorValues; interpolatorValues.SetSize(25); interpolatorValues.fill(0); std::string interpolator = ReadXMLStringAttribut( "INTERPOLATOR", atts ); double inter = atof(interpolator.c_str()); interpolatorValues[0] = inter; interpolatorValues = this->loadInterpolatorValues(interpolatorValues/*, inter, atts*/); m_InterpolatorValues[m_Name] = interpolatorValues; } } std::string RigidRegistrationPreset::ReadXMLStringAttribut( std::string name, const char** atts ) { if(atts) { const char** attsIter = atts; while(*attsIter) { if ( name == *attsIter ) { attsIter++; return *attsIter; } attsIter++; attsIter++; } } return std::string(); } itk::Array RigidRegistrationPreset::getTransformValues(std::string name) { return m_TransformValues[name]; } itk::Array RigidRegistrationPreset::getMetricValues(std::string name) { return m_MetricValues[name]; } itk::Array RigidRegistrationPreset::getOptimizerValues(std::string name) { return m_OptimizerValues[name]; } itk::Array RigidRegistrationPreset::getInterpolatorValues(std::string name) { return m_InterpolatorValues[name]; } std::map >& RigidRegistrationPreset::getTransformValuesPresets() { return m_TransformValues; } std::map >& RigidRegistrationPreset::getMetricValuesPresets() { return m_MetricValues; } std::map >& RigidRegistrationPreset::getOptimizerValuesPresets() { return m_OptimizerValues; } std::map >& RigidRegistrationPreset::getInterpolatorValuesPresets() { return m_InterpolatorValues; } bool RigidRegistrationPreset::save() { //XMLWriter writer(m_XmlFileName.c_str()); //return saveXML(writer); return false; } //bool RigidRegistrationPreset::saveXML(mitk::XMLWriter& xmlWriter) //{ // xmlWriter.BeginNode("mitkRigidRegistrationPresets"); // for( std::map >::iterator iter = m_TransformValues.begin(); iter != m_TransformValues.end(); iter++ ) { // std::string item = ((*iter).first.c_str()); // xmlWriter.BeginNode("preset"); // xmlWriter.WriteProperty("NAME", item); // xmlWriter.BeginNode("transform"); // this->saveTransformValues(xmlWriter, item); // xmlWriter.EndNode(); // xmlWriter.BeginNode("metric"); // this->saveMetricValues(xmlWriter, item); // xmlWriter.EndNode(); // xmlWriter.BeginNode("optimizer"); // this->saveOptimizerValues(xmlWriter, item); // xmlWriter.EndNode(); // xmlWriter.BeginNode("interpolator"); // this->saveInterpolatorValues(xmlWriter, item); // xmlWriter.EndNode(); // xmlWriter.EndNode(); // } // xmlWriter.EndNode(); // return true; //} bool RigidRegistrationPreset::newPresets(std::map > newTransformValues, std::map > newMetricValues, std::map > newOptimizerValues, std::map > newInterpolatorValues, std::string fileName) { if ( !fileName.empty() ) { m_XmlFileName = fileName; } m_TransformValues = newTransformValues; m_MetricValues = newMetricValues; m_OptimizerValues = newOptimizerValues; m_InterpolatorValues = newInterpolatorValues; return save(); } //void RigidRegistrationPreset::saveTransformValues(mitk::XMLWriter& xmlWriter, std::string item) //{ // itk::Array transformValues = m_TransformValues[item]; // double transform = transformValues[0]; // xmlWriter.WriteProperty("TRANSFORM", transformValues[0]); // if (transform == mitk::TransformParameters::TRANSLATIONTRANSFORM || transform == mitk::TransformParameters::SCALETRANSFORM || // transform == mitk::TransformParameters::SCALELOGARITHMICTRANSFORM || transform == mitk::TransformParameters::VERSORTRANSFORM || // transform == mitk::TransformParameters::RIGID2DTRANSFORM || transform == mitk::TransformParameters::EULER2DTRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // } // else if (transform == mitk::TransformParameters::AFFINETRANSFORM || transform == mitk::TransformParameters::FIXEDCENTEROFROTATIONAFFINETRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // xmlWriter.WriteProperty("SCALE4", transformValues[5]); // xmlWriter.WriteProperty("SCALE5", transformValues[6]); // xmlWriter.WriteProperty("SCALE6", transformValues[7]); // xmlWriter.WriteProperty("SCALE7", transformValues[8]); // xmlWriter.WriteProperty("SCALE8", transformValues[9]); // xmlWriter.WriteProperty("SCALE9", transformValues[10]); // xmlWriter.WriteProperty("SCALE10", transformValues[11]); // xmlWriter.WriteProperty("SCALE11", transformValues[12]); // xmlWriter.WriteProperty("SCALE12", transformValues[13]); // /* xmlWriter.WriteProperty("SCALE13", transformValues[14]); // xmlWriter.WriteProperty("SCALE14", transformValues[15]); // xmlWriter.WriteProperty("SCALE15", transformValues[16]); // xmlWriter.WriteProperty("SCALE16", transformValues[17]);*/ // xmlWriter.WriteProperty("USEINITIALIZER", transformValues[14]); // xmlWriter.WriteProperty("USEMOMENTS", transformValues[15]); // } // else if (transform == mitk::TransformParameters::RIGID3DTRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // xmlWriter.WriteProperty("SCALE4", transformValues[5]); // xmlWriter.WriteProperty("SCALE5", transformValues[6]); // xmlWriter.WriteProperty("SCALE6", transformValues[7]); // xmlWriter.WriteProperty("SCALE7", transformValues[8]); // xmlWriter.WriteProperty("SCALE8", transformValues[9]); // xmlWriter.WriteProperty("SCALE9", transformValues[10]); // xmlWriter.WriteProperty("SCALE10", transformValues[11]); // xmlWriter.WriteProperty("SCALE11", transformValues[12]); // xmlWriter.WriteProperty("SCALE12", transformValues[13]); // xmlWriter.WriteProperty("USEINITIALIZER", transformValues[14]); // xmlWriter.WriteProperty("USEMOMENTS", transformValues[15]); // } // else if (transform == mitk::TransformParameters::EULER3DTRANSFORM || transform == mitk::TransformParameters::CENTEREDEULER3DTRANSFORM // || transform == mitk::TransformParameters::VERSORRIGID3DTRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // xmlWriter.WriteProperty("SCALE4", transformValues[5]); // xmlWriter.WriteProperty("SCALE5", transformValues[6]); // xmlWriter.WriteProperty("SCALE6", transformValues[7]); // xmlWriter.WriteProperty("USEINITIALIZER", transformValues[8]); // xmlWriter.WriteProperty("USEMOMENTS", transformValues[9]); // } // else if (transform == mitk::TransformParameters::QUATERNIONRIGIDTRANSFORM || transform == mitk::TransformParameters::SIMILARITY3DTRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // xmlWriter.WriteProperty("SCALE4", transformValues[5]); // xmlWriter.WriteProperty("SCALE5", transformValues[6]); // xmlWriter.WriteProperty("SCALE6", transformValues[7]); // xmlWriter.WriteProperty("SCALE7", transformValues[8]); // xmlWriter.WriteProperty("USEINITIALIZER", transformValues[9]); // xmlWriter.WriteProperty("USEMOMENTS", transformValues[10]); // } // else if (transform == mitk::TransformParameters::SCALESKEWVERSOR3DTRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // xmlWriter.WriteProperty("SCALE4", transformValues[5]); // xmlWriter.WriteProperty("SCALE5", transformValues[6]); // xmlWriter.WriteProperty("SCALE6", transformValues[7]); // xmlWriter.WriteProperty("SCALE7", transformValues[8]); // xmlWriter.WriteProperty("SCALE8", transformValues[9]); // xmlWriter.WriteProperty("SCALE9", transformValues[10]); // xmlWriter.WriteProperty("SCALE10", transformValues[11]); // xmlWriter.WriteProperty("SCALE11", transformValues[12]); // xmlWriter.WriteProperty("SCALE12", transformValues[13]); // xmlWriter.WriteProperty("SCALE13", transformValues[14]); // xmlWriter.WriteProperty("SCALE14", transformValues[15]); // xmlWriter.WriteProperty("SCALE15", transformValues[16]); // xmlWriter.WriteProperty("USEINITIALIZER", transformValues[17]); // xmlWriter.WriteProperty("USEMOMENTS", transformValues[18]); // } // else if (transform == mitk::TransformParameters::CENTEREDRIGID2DTRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // xmlWriter.WriteProperty("SCALE4", transformValues[5]); // xmlWriter.WriteProperty("SCALE5", transformValues[6]); // xmlWriter.WriteProperty("ANGLE", transformValues[7]); // xmlWriter.WriteProperty("USEINITIALIZER", transformValues[8]); // xmlWriter.WriteProperty("USEMOMENTS", transformValues[9]); // } // else if (transform == mitk::TransformParameters::SIMILARITY2DTRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // xmlWriter.WriteProperty("SCALE4", transformValues[5]); // xmlWriter.WriteProperty("SCALE", transformValues[6]); // xmlWriter.WriteProperty("ANGLE", transformValues[7]); // xmlWriter.WriteProperty("USEINITIALIZER", transformValues[8]); // xmlWriter.WriteProperty("USEMOMENTS", transformValues[9]); // } // else if (transform == mitk::TransformParameters::CENTEREDSIMILARITY2DTRANSFORM) // { // xmlWriter.WriteProperty("USESCALES", transformValues[1]); // xmlWriter.WriteProperty("SCALE1", transformValues[2]); // xmlWriter.WriteProperty("SCALE2", transformValues[3]); // xmlWriter.WriteProperty("SCALE3", transformValues[4]); // xmlWriter.WriteProperty("SCALE4", transformValues[5]); // xmlWriter.WriteProperty("SCALE5", transformValues[6]); // xmlWriter.WriteProperty("SCALE6", transformValues[7]); // xmlWriter.WriteProperty("SCALE", transformValues[8]); // xmlWriter.WriteProperty("ANGLE", transformValues[9]); // xmlWriter.WriteProperty("USEINITIALIZER", transformValues[10]); // xmlWriter.WriteProperty("USEMOMENTS", transformValues[11]); // } //} //void RigidRegistrationPreset::saveMetricValues(mitk::XMLWriter& xmlWriter, std::string item) //{ // itk::Array metricValues = m_MetricValues[item]; // double metric = metricValues[0]; // xmlWriter.WriteProperty("METRIC", metricValues[0]); // xmlWriter.WriteProperty("COMPUTEGRADIENT", metricValues[1]); // if (metric == mitk::MetricParameters::MEANSQUARESIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::NORMALIZEDCORRELATIONIMAGETOIMAGEMETRIC // || metric == mitk::MetricParameters::GRADIENTDIFFERENCEIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::MATCHCARDINALITYIMAGETOIMAGEMETRIC // || metric == mitk::MetricParameters::KAPPASTATISTICIMAGETOIMAGEMETRIC) // { // } // else if (metric == mitk::MetricParameters::KULLBACKLEIBLERCOMPAREHISTOGRAMIMAGETOIMAGEMETRIC // || metric == mitk::MetricParameters::CORRELATIONCOEFFICIENTHISTOGRAMIMAGETOIMAGEMETRIC // || metric == mitk::MetricParameters::MEANSQUARESHISTOGRAMIMAGETOIMAGEMETRIC // || metric == mitk::MetricParameters::MUTUALINFORMATIONHISTOGRAMIMAGETOIMAGEMETRIC // || metric == mitk::MetricParameters::NORMALIZEDMUTUALINFORMATIONHISTOGRAMIMAGETOIMAGEMETRIC) // { // xmlWriter.WriteProperty("HISTOGRAMBINS", metricValues[2]); // } // else if (metric == mitk::MetricParameters::MATTESMUTUALINFORMATIONIMAGETOIMAGEMETRIC) // { // xmlWriter.WriteProperty("USESAMPLING", metricValues[2]); // xmlWriter.WriteProperty("SPATIALSAMPLES", metricValues[3]); // xmlWriter.WriteProperty("HISTOGRAMBINS", metricValues[4]); // } // else if (metric == mitk::MetricParameters::MEANRECIPROCALSQUAREDIFFERENCEIMAGETOIMAGEMETRIC) // { // xmlWriter.WriteProperty("LAMBDA", metricValues[2]); // } // else if (metric == mitk::MetricParameters::MUTUALINFORMATIONIMAGETOIMAGEMETRIC) // { // xmlWriter.WriteProperty("SPATIALSAMPLES", metricValues[2]); // xmlWriter.WriteProperty("FIXEDSTANDARDDEVIATION", metricValues[3]); // xmlWriter.WriteProperty("MOVINGSTANDARDDEVIATION", metricValues[4]); // xmlWriter.WriteProperty("USENORMALIZERANDSMOOTHER", metricValues[5]); // xmlWriter.WriteProperty("FIXEDSMOOTHERVARIANCE", metricValues[6]); // xmlWriter.WriteProperty("MOVINGSMOOTHERVARIANCE", metricValues[7]); // } //} //void RigidRegistrationPreset::saveOptimizerValues(mitk::XMLWriter& xmlWriter, std::string item) //{ // itk::Array optimizerValues = m_OptimizerValues[item]; // double optimizer = optimizerValues[0]; // xmlWriter.WriteProperty("OPTIMIZER", optimizerValues[0]); // xmlWriter.WriteProperty("MAXIMIZE", optimizerValues[1]); // if (optimizer == mitk::OptimizerParameters::EXHAUSTIVEOPTIMIZER) // { // xmlWriter.WriteProperty("STEPLENGTH", optimizerValues[2]); // xmlWriter.WriteProperty("NUMBEROFSTEPS", optimizerValues[3]); // } // else if (optimizer == mitk::OptimizerParameters::GRADIENTDESCENTOPTIMIZER // || optimizer == mitk::OptimizerParameters::QUATERNIONRIGIDTRANSFORMGRADIENTDESCENTOPTIMIZER) // { // xmlWriter.WriteProperty("LEARNINGRATE", optimizerValues[2]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[3]); // } // else if (optimizer == mitk::OptimizerParameters::LBFGSBOPTIMIZER) // { // } // else if (optimizer == mitk::OptimizerParameters::ONEPLUSONEEVOLUTIONARYOPTIMIZER) // { // xmlWriter.WriteProperty("SHRINKFACTOR", optimizerValues[2]); // xmlWriter.WriteProperty("GROWTHFACTOR", optimizerValues[3]); // xmlWriter.WriteProperty("EPSILON", optimizerValues[4]); // xmlWriter.WriteProperty("INITIALRADIUS", optimizerValues[5]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[6]); // } // else if (optimizer == mitk::OptimizerParameters::POWELLOPTIMIZER) // { // xmlWriter.WriteProperty("STEPLENGTH", optimizerValues[2]); // xmlWriter.WriteProperty("STEPTOLERANCE", optimizerValues[3]); // xmlWriter.WriteProperty("VALUETOLERANCE", optimizerValues[4]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[5]); // } // else if (optimizer == mitk::OptimizerParameters::FRPROPTIMIZER) // { // xmlWriter.WriteProperty("USEFLETCHREEVES", optimizerValues[2]); // xmlWriter.WriteProperty("STEPLENGTH", optimizerValues[3]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[4]); // } // else if (optimizer == mitk::OptimizerParameters::REGULARSTEPGRADIENTDESCENTOPTIMIZER) // { // xmlWriter.WriteProperty("GRADIENTMAGNITUDETOLERANCE", optimizerValues[2]); // xmlWriter.WriteProperty("MINSTEPLENGTH", optimizerValues[3]); // xmlWriter.WriteProperty("MAXSTEPLENGTH", optimizerValues[4]); // xmlWriter.WriteProperty("RELAXATIONFACTOR", optimizerValues[5]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[6]); // } // else if (optimizer == mitk::OptimizerParameters::VERSORTRANSFORMOPTIMIZER || optimizer == mitk::OptimizerParameters::VERSORRIGID3DTRANSFORMOPTIMIZER) // { // xmlWriter.WriteProperty("GRADIENTMAGNITUDETOLERANCE", optimizerValues[2]); // xmlWriter.WriteProperty("MINSTEPLENGTH", optimizerValues[3]); // xmlWriter.WriteProperty("MAXSTEPLENGTH", optimizerValues[4]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[5]); // } // else if (optimizer == mitk::OptimizerParameters::AMOEBAOPTIMIZER) // { // xmlWriter.WriteProperty("SIMPLEXDELTA1", optimizerValues[2]); // xmlWriter.WriteProperty("SIMPLEXDELTA2", optimizerValues[3]); // xmlWriter.WriteProperty("SIMPLEXDELTA3", optimizerValues[4]); // xmlWriter.WriteProperty("SIMPLEXDELTA4", optimizerValues[5]); // xmlWriter.WriteProperty("SIMPLEXDELTA5", optimizerValues[6]); // xmlWriter.WriteProperty("SIMPLEXDELTA6", optimizerValues[7]); // xmlWriter.WriteProperty("SIMPLEXDELTA7", optimizerValues[8]); // xmlWriter.WriteProperty("SIMPLEXDELTA8", optimizerValues[9]); // xmlWriter.WriteProperty("SIMPLEXDELTA9", optimizerValues[10]); // xmlWriter.WriteProperty("SIMPLEXDELTA10", optimizerValues[11]); // xmlWriter.WriteProperty("SIMPLEXDELTA11", optimizerValues[12]); // xmlWriter.WriteProperty("SIMPLEXDELTA12", optimizerValues[13]); // xmlWriter.WriteProperty("SIMPLEXDELTA13", optimizerValues[14]); // xmlWriter.WriteProperty("SIMPLEXDELTA14", optimizerValues[15]); // xmlWriter.WriteProperty("SIMPLEXDELTA15", optimizerValues[16]); // xmlWriter.WriteProperty("SIMPLEXDELTA16", optimizerValues[17]); // xmlWriter.WriteProperty("PARAMETERSCONVERGENCETOLERANCE", optimizerValues[18]); // xmlWriter.WriteProperty("FUNCTIONCONVERGENCETOLERANCE", optimizerValues[19]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[20]); // } // else if (optimizer == mitk::OptimizerParameters::CONJUGATEGRADIENTOPTIMIZER) // { // } // else if (optimizer == mitk::OptimizerParameters::LBFGSOPTIMIZER) // { // xmlWriter.WriteProperty("GRADIENTCONVERGENCETOLERANCE", optimizerValues[2]); // xmlWriter.WriteProperty("LINESEARCHACCURACY", optimizerValues[3]); // xmlWriter.WriteProperty("DEFAULTSTEPLENGTH", optimizerValues[4]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[5]); // xmlWriter.WriteProperty("USETRACE", optimizerValues[6]); // } // else if (optimizer == mitk::OptimizerParameters::SPSAOPTIMIZER) // { // xmlWriter.WriteProperty("a", optimizerValues[2]); // xmlWriter.WriteProperty("A", optimizerValues[3]); // xmlWriter.WriteProperty("ALPHA", optimizerValues[4]); // xmlWriter.WriteProperty("c", optimizerValues[5]); // xmlWriter.WriteProperty("GAMMA", optimizerValues[6]); // xmlWriter.WriteProperty("TOLERANCE", optimizerValues[7]); // xmlWriter.WriteProperty("STATEOFCONVERGENCEDECAYRATE", optimizerValues[8]); // xmlWriter.WriteProperty("MINNUMBERITERATIONS", optimizerValues[9]); // xmlWriter.WriteProperty("NUMBERPERTURBATIONS", optimizerValues[10]); // xmlWriter.WriteProperty("NUMBERITERATIONS", optimizerValues[11]); // } //} //void RigidRegistrationPreset::saveInterpolatorValues(mitk::XMLWriter& xmlWriter, std::string item) //{ // itk::Array interpolatorValues = m_InterpolatorValues[item]; // xmlWriter.WriteProperty("INTERPOLATOR", interpolatorValues[0]); //} itk::Array RigidRegistrationPreset::loadTransformValues(itk::Array transformValues, double transform, const char **atts) { if (transform == mitk::TransformParameters::TRANSLATIONTRANSFORM || transform == mitk::TransformParameters::SCALETRANSFORM || transform == mitk::TransformParameters::SCALELOGARITHMICTRANSFORM || transform == mitk::TransformParameters::VERSORTRANSFORM || transform == mitk::TransformParameters::RIGID2DTRANSFORM || transform == mitk::TransformParameters::EULER2DTRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; } else if (transform == mitk::TransformParameters::AFFINETRANSFORM || transform == mitk::TransformParameters::FIXEDCENTEROFROTATIONAFFINETRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; std::string scale4 = ReadXMLStringAttribut( "SCALE4", atts ); double sca4 = atof(scale4.c_str()); transformValues[5] = sca4; std::string scale5 = ReadXMLStringAttribut( "SCALE5", atts ); double sca5 = atof(scale5.c_str()); transformValues[6] = sca5; std::string scale6 = ReadXMLStringAttribut( "SCALE6", atts ); double sca6 = atof(scale6.c_str()); transformValues[7] = sca6; std::string scale7 = ReadXMLStringAttribut( "SCALE7", atts ); double sca7 = atof(scale7.c_str()); transformValues[8] = sca7; std::string scale8 = ReadXMLStringAttribut( "SCALE8", atts ); double sca8 = atof(scale8.c_str()); transformValues[9] = sca8; std::string scale9 = ReadXMLStringAttribut( "SCALE9", atts ); double sca9 = atof(scale9.c_str()); transformValues[10] = sca9; std::string scale10 = ReadXMLStringAttribut( "SCALE10", atts ); double sca10 = atof(scale10.c_str()); transformValues[11] = sca10; std::string scale11 = ReadXMLStringAttribut( "SCALE11", atts ); double sca11 = atof(scale11.c_str()); transformValues[12] = sca11; std::string scale12 = ReadXMLStringAttribut( "SCALE12", atts ); double sca12 = atof(scale12.c_str()); transformValues[13] = sca12; /* std::string scale13 = ReadXMLStringAttribut( "SCALE13", atts ); double sca13 = atof(scale13.c_str()); transformValues[14] = sca13; std::string scale14 = ReadXMLStringAttribut( "SCALE14", atts ); double sca14 = atof(scale14.c_str()); transformValues[15] = sca14; std::string scale15 = ReadXMLStringAttribut( "SCALE15", atts ); double sca15 = atof(scale15.c_str()); transformValues[16] = sca15; std::string scale16 = ReadXMLStringAttribut( "SCALE16", atts ); double sca16 = atof(scale16.c_str()); transformValues[17] = sca16; */ std::string useInitializer = ReadXMLStringAttribut( "USEINITIALIZER", atts ); double useIni = atof(useInitializer.c_str()); transformValues[14] = useIni; std::string useMoments = ReadXMLStringAttribut( "USEMOMENTS", atts ); double useMo = atof(useMoments.c_str()); transformValues[15] = useMo; } else if (transform == mitk::TransformParameters::RIGID3DTRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; std::string scale4 = ReadXMLStringAttribut( "SCALE4", atts ); double sca4 = atof(scale4.c_str()); transformValues[5] = sca4; std::string scale5 = ReadXMLStringAttribut( "SCALE5", atts ); double sca5 = atof(scale5.c_str()); transformValues[6] = sca5; std::string scale6 = ReadXMLStringAttribut( "SCALE6", atts ); double sca6 = atof(scale6.c_str()); transformValues[7] = sca6; std::string scale7 = ReadXMLStringAttribut( "SCALE7", atts ); double sca7 = atof(scale7.c_str()); transformValues[8] = sca7; std::string scale8 = ReadXMLStringAttribut( "SCALE8", atts ); double sca8 = atof(scale8.c_str()); transformValues[9] = sca8; std::string scale9 = ReadXMLStringAttribut( "SCALE9", atts ); double sca9 = atof(scale9.c_str()); transformValues[10] = sca9; std::string scale10 = ReadXMLStringAttribut( "SCALE10", atts ); double sca10 = atof(scale10.c_str()); transformValues[11] = sca10; std::string scale11 = ReadXMLStringAttribut( "SCALE11", atts ); double sca11 = atof(scale11.c_str()); transformValues[12] = sca11; std::string scale12 = ReadXMLStringAttribut( "SCALE12", atts ); double sca12 = atof(scale12.c_str()); transformValues[13] = sca12; std::string useInitializer = ReadXMLStringAttribut( "USEINITIALIZER", atts ); double useIni = atof(useInitializer.c_str()); transformValues[14] = useIni; std::string useMoments = ReadXMLStringAttribut( "USEMOMENTS", atts ); double useMo = atof(useMoments.c_str()); transformValues[15] = useMo; } else if (transform == mitk::TransformParameters::EULER3DTRANSFORM || transform == mitk::TransformParameters::CENTEREDEULER3DTRANSFORM || transform == mitk::TransformParameters::VERSORRIGID3DTRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; std::string scale4 = ReadXMLStringAttribut( "SCALE4", atts ); double sca4 = atof(scale4.c_str()); transformValues[5] = sca4; std::string scale5 = ReadXMLStringAttribut( "SCALE5", atts ); double sca5 = atof(scale5.c_str()); transformValues[6] = sca5; std::string scale6 = ReadXMLStringAttribut( "SCALE6", atts ); double sca6 = atof(scale6.c_str()); transformValues[7] = sca6; std::string useInitializer = ReadXMLStringAttribut( "USEINITIALIZER", atts ); double useIni = atof(useInitializer.c_str()); transformValues[8] = useIni; std::string useMoments = ReadXMLStringAttribut( "USEMOMENTS", atts ); double useMo = atof(useMoments.c_str()); transformValues[9] = useMo; } else if (transform == mitk::TransformParameters::QUATERNIONRIGIDTRANSFORM || transform == mitk::TransformParameters::SIMILARITY3DTRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; std::string scale4 = ReadXMLStringAttribut( "SCALE4", atts ); double sca4 = atof(scale4.c_str()); transformValues[5] = sca4; std::string scale5 = ReadXMLStringAttribut( "SCALE5", atts ); double sca5 = atof(scale5.c_str()); transformValues[6] = sca5; std::string scale6 = ReadXMLStringAttribut( "SCALE6", atts ); double sca6 = atof(scale6.c_str()); transformValues[7] = sca6; std::string scale7 = ReadXMLStringAttribut( "SCALE7", atts ); double sca7 = atof(scale7.c_str()); transformValues[8] = sca7; std::string useInitializer = ReadXMLStringAttribut( "USEINITIALIZER", atts ); double useIni = atof(useInitializer.c_str()); transformValues[9] = useIni; std::string useMoments = ReadXMLStringAttribut( "USEMOMENTS", atts ); double useMo = atof(useMoments.c_str()); transformValues[10] = useMo; } else if (transform == mitk::TransformParameters::SCALESKEWVERSOR3DTRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; std::string scale4 = ReadXMLStringAttribut( "SCALE4", atts ); double sca4 = atof(scale4.c_str()); transformValues[5] = sca4; std::string scale5 = ReadXMLStringAttribut( "SCALE5", atts ); double sca5 = atof(scale5.c_str()); transformValues[6] = sca5; std::string scale6 = ReadXMLStringAttribut( "SCALE6", atts ); double sca6 = atof(scale6.c_str()); transformValues[7] = sca6; std::string scale7 = ReadXMLStringAttribut( "SCALE7", atts ); double sca7 = atof(scale7.c_str()); transformValues[8] = sca7; std::string scale8 = ReadXMLStringAttribut( "SCALE8", atts ); double sca8 = atof(scale8.c_str()); transformValues[9] = sca8; std::string scale9 = ReadXMLStringAttribut( "SCALE9", atts ); double sca9 = atof(scale9.c_str()); transformValues[10] = sca9; std::string scale10 = ReadXMLStringAttribut( "SCALE10", atts ); double sca10 = atof(scale10.c_str()); transformValues[11] = sca10; std::string scale11 = ReadXMLStringAttribut( "SCALE11", atts ); double sca11 = atof(scale11.c_str()); transformValues[12] = sca11; std::string scale12 = ReadXMLStringAttribut( "SCALE12", atts ); double sca12 = atof(scale12.c_str()); transformValues[13] = sca12; std::string scale13 = ReadXMLStringAttribut( "SCALE13", atts ); double sca13 = atof(scale13.c_str()); transformValues[14] = sca13; std::string scale14 = ReadXMLStringAttribut( "SCALE14", atts ); double sca14 = atof(scale14.c_str()); transformValues[15] = sca14; std::string scale15 = ReadXMLStringAttribut( "SCALE15", atts ); double sca15 = atof(scale15.c_str()); transformValues[16] = sca15; std::string useInitializer = ReadXMLStringAttribut( "USEINITIALIZER", atts ); double useIni = atof(useInitializer.c_str()); transformValues[17] = useIni; std::string useMoments = ReadXMLStringAttribut( "USEMOMENTS", atts ); double useMo = atof(useMoments.c_str()); transformValues[18] = useMo; } else if (transform == mitk::TransformParameters::CENTEREDRIGID2DTRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; std::string scale4 = ReadXMLStringAttribut( "SCALE4", atts ); double sca4 = atof(scale4.c_str()); transformValues[5] = sca4; std::string scale5 = ReadXMLStringAttribut( "SCALE5", atts ); double sca5 = atof(scale5.c_str()); transformValues[6] = sca5; std::string angle = ReadXMLStringAttribut( "ANGLE", atts ); double ang = atof(angle.c_str()); transformValues[7] = ang; std::string useInitializer = ReadXMLStringAttribut( "USEINITIALIZER", atts ); double useIni = atof(useInitializer.c_str()); transformValues[8] = useIni; std::string useMoments = ReadXMLStringAttribut( "USEMOMENTS", atts ); double useMo = atof(useMoments.c_str()); transformValues[9] = useMo; } else if (transform == mitk::TransformParameters::SIMILARITY2DTRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; std::string scale4 = ReadXMLStringAttribut( "SCALE4", atts ); double sca4 = atof(scale4.c_str()); transformValues[5] = sca4; std::string scale = ReadXMLStringAttribut( "SCALE", atts ); double sca = atof(scale.c_str()); transformValues[6] = sca; std::string angle = ReadXMLStringAttribut( "ANGLE", atts ); double ang = atof(angle.c_str()); transformValues[7] = ang; std::string useInitializer = ReadXMLStringAttribut( "USEINITIALIZER", atts ); double useIni = atof(useInitializer.c_str()); transformValues[8] = useIni; std::string useMoments = ReadXMLStringAttribut( "USEMOMENTS", atts ); double useMo = atof(useMoments.c_str()); transformValues[9] = useMo; } else if (transform == mitk::TransformParameters::CENTEREDSIMILARITY2DTRANSFORM) { std::string useScales = ReadXMLStringAttribut( "USESCALES", atts ); double useSca = atof(useScales.c_str()); transformValues[1] = useSca; std::string scale1 = ReadXMLStringAttribut( "SCALE1", atts ); double sca1 = atof(scale1.c_str()); transformValues[2] = sca1; std::string scale2 = ReadXMLStringAttribut( "SCALE2", atts ); double sca2 = atof(scale2.c_str()); transformValues[3] = sca2; std::string scale3 = ReadXMLStringAttribut( "SCALE3", atts ); double sca3 = atof(scale3.c_str()); transformValues[4] = sca3; std::string scale4 = ReadXMLStringAttribut( "SCALE4", atts ); double sca4 = atof(scale4.c_str()); transformValues[5] = sca4; std::string scale5 = ReadXMLStringAttribut( "SCALE5", atts ); double sca5 = atof(scale5.c_str()); transformValues[6] = sca5; std::string scale6 = ReadXMLStringAttribut( "SCALE6", atts ); double sca6 = atof(scale6.c_str()); transformValues[7] = sca6; std::string scale = ReadXMLStringAttribut( "SCALE", atts ); double sca = atof(scale.c_str()); transformValues[8] = sca; std::string angle = ReadXMLStringAttribut( "ANGLE", atts ); double ang = atof(angle.c_str()); transformValues[9] = ang; std::string useInitializer = ReadXMLStringAttribut( "USEINITIALIZER", atts ); double useIni = atof(useInitializer.c_str()); transformValues[10] = useIni; std::string useMoments = ReadXMLStringAttribut( "USEMOMENTS", atts ); double useMo = atof(useMoments.c_str()); transformValues[11] = useMo; } return transformValues; } itk::Array RigidRegistrationPreset::loadMetricValues(itk::Array metricValues, double metric, const char **atts) { std::string computeGradient = ReadXMLStringAttribut( "COMPUTEGRADIENT", atts ); double compGra = atof(computeGradient.c_str()); metricValues[1] = compGra; if (metric == mitk::MetricParameters::MEANSQUARESIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::NORMALIZEDCORRELATIONIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::GRADIENTDIFFERENCEIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::MATCHCARDINALITYIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::KAPPASTATISTICIMAGETOIMAGEMETRIC) { } else if (metric == mitk::MetricParameters::KULLBACKLEIBLERCOMPAREHISTOGRAMIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::CORRELATIONCOEFFICIENTHISTOGRAMIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::MEANSQUARESHISTOGRAMIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::MUTUALINFORMATIONHISTOGRAMIMAGETOIMAGEMETRIC || metric == mitk::MetricParameters::NORMALIZEDMUTUALINFORMATIONHISTOGRAMIMAGETOIMAGEMETRIC) { std::string histogramBins = ReadXMLStringAttribut( "HISTOGRAMBINS", atts ); double histBins = atof(histogramBins.c_str()); metricValues[2] = histBins; } else if (metric == mitk::MetricParameters::MATTESMUTUALINFORMATIONIMAGETOIMAGEMETRIC) { std::string useSampling = ReadXMLStringAttribut( "USESAMPLING", atts ); double useSamp = atof(useSampling.c_str()); metricValues[2] = useSamp; std::string spatialSamples = ReadXMLStringAttribut( "SPATIALSAMPLES", atts ); double spatSamp = atof(spatialSamples.c_str()); metricValues[3] = spatSamp; std::string histogramBins = ReadXMLStringAttribut( "HISTOGRAMBINS", atts ); double histBins = atof(histogramBins.c_str()); metricValues[4] = histBins; } else if (metric == mitk::MetricParameters::MEANRECIPROCALSQUAREDIFFERENCEIMAGETOIMAGEMETRIC) { std::string lambda = ReadXMLStringAttribut( "LAMBDA", atts ); double lamb = atof(lambda.c_str()); metricValues[2] = lamb; } else if (metric == mitk::MetricParameters::MUTUALINFORMATIONIMAGETOIMAGEMETRIC) { std::string spatialSamples = ReadXMLStringAttribut( "SPATIALSAMPLES", atts ); double spatSamp = atof(spatialSamples.c_str()); metricValues[2] = spatSamp; std::string fixedStandardDeviation = ReadXMLStringAttribut( "FIXEDSTANDARDDEVIATION", atts ); double fiStaDev = atof(fixedStandardDeviation.c_str()); metricValues[3] = fiStaDev; std::string movingStandardDeviation = ReadXMLStringAttribut( "MOVINGSTANDARDDEVIATION", atts ); double moStaDev = atof(movingStandardDeviation.c_str()); metricValues[4] = moStaDev; std::string useNormalizer = ReadXMLStringAttribut( "USENORMALIZERANDSMOOTHER", atts ); double useNormal = atof(useNormalizer.c_str()); metricValues[5] = useNormal; std::string fixedSmootherVariance = ReadXMLStringAttribut( "FIXEDSMOOTHERVARIANCE", atts ); double fiSmoVa = atof(fixedSmootherVariance.c_str()); metricValues[6] = fiSmoVa; std::string movingSmootherVariance = ReadXMLStringAttribut( "MOVINGSMOOTHERVARIANCE", atts ); double moSmoVa = atof(movingSmootherVariance.c_str()); metricValues[7] = moSmoVa; } return metricValues; } itk::Array RigidRegistrationPreset::loadOptimizerValues(itk::Array optimizerValues, double optimizer, const char **atts) { std::string maximize = ReadXMLStringAttribut( "MAXIMIZE", atts ); double max = atof(maximize.c_str()); optimizerValues[1] = max; if (optimizer == mitk::OptimizerParameters::EXHAUSTIVEOPTIMIZER) { std::string stepLength = ReadXMLStringAttribut( "STEPLENGTH", atts ); double stepLe = atof(stepLength.c_str()); optimizerValues[2] = stepLe; std::string numberOfSteps = ReadXMLStringAttribut( "NUMBEROFSTEPS", atts ); double numSteps = atof(numberOfSteps.c_str()); optimizerValues[3] = numSteps; } else if (optimizer == mitk::OptimizerParameters::GRADIENTDESCENTOPTIMIZER || optimizer == mitk::OptimizerParameters::QUATERNIONRIGIDTRANSFORMGRADIENTDESCENTOPTIMIZER) { std::string learningRate = ReadXMLStringAttribut( "LEARNINGRATE", atts ); double learn = atof(learningRate.c_str()); optimizerValues[2] = learn; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[3] = numIt; } else if (optimizer == mitk::OptimizerParameters::LBFGSBOPTIMIZER) { } else if (optimizer == mitk::OptimizerParameters::ONEPLUSONEEVOLUTIONARYOPTIMIZER) { std::string shrinkFactor = ReadXMLStringAttribut( "SHRINKFACTOR", atts ); double shrink = atof(shrinkFactor.c_str()); optimizerValues[2] = shrink; std::string growthFactor = ReadXMLStringAttribut( "GROWTHFACTOR", atts ); double growth = atof(growthFactor.c_str()); optimizerValues[3] = growth; std::string epsilon = ReadXMLStringAttribut( "EPSILON", atts ); double eps = atof(epsilon.c_str()); optimizerValues[4] = eps; std::string initialRadius = ReadXMLStringAttribut( "INITIALRADIUS", atts ); double initRad = atof(initialRadius.c_str()); optimizerValues[5] = initRad; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[6] = numIt; } else if (optimizer == mitk::OptimizerParameters::POWELLOPTIMIZER) { std::string stepLength = ReadXMLStringAttribut( "STEPLENGTH", atts ); double stepLe = atof(stepLength.c_str()); optimizerValues[2] = stepLe; std::string stepTolerance = ReadXMLStringAttribut( "STEPTOLERANCE", atts ); double stepTo = atof(stepTolerance.c_str()); optimizerValues[3] = stepTo; std::string valueTolerance = ReadXMLStringAttribut( "VALUETOLERANCE", atts ); double valTo = atof(valueTolerance.c_str()); optimizerValues[4] = valTo; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[5] = numIt; } else if (optimizer == mitk::OptimizerParameters::FRPROPTIMIZER) { std::string useFletchReeves = ReadXMLStringAttribut( "USEFLETCHREEVES", atts ); double useFleRe = atof(useFletchReeves.c_str()); optimizerValues[2] = useFleRe; std::string stepLength = ReadXMLStringAttribut( "STEPLENGTH", atts ); double stepLe = atof(stepLength.c_str()); optimizerValues[3] = stepLe; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[4] = numIt; } else if (optimizer == mitk::OptimizerParameters::REGULARSTEPGRADIENTDESCENTOPTIMIZER) { std::string gradientMagnitudeTolerance = ReadXMLStringAttribut( "GRADIENTMAGNITUDETOLERANCE", atts ); double graMagTo = atof(gradientMagnitudeTolerance.c_str()); optimizerValues[2] = graMagTo; std::string minStepLength = ReadXMLStringAttribut( "MINSTEPLENGTH", atts ); double minStep = atof(minStepLength.c_str()); optimizerValues[3] = minStep; std::string maxStepLength = ReadXMLStringAttribut( "MAXSTEPLENGTH", atts ); double maxStep = atof(maxStepLength.c_str()); optimizerValues[4] = maxStep; std::string relaxationFactor = ReadXMLStringAttribut( "RELAXATIONFACTOR", atts ); double relFac = atof(relaxationFactor.c_str()); optimizerValues[5] = relFac; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[6] = numIt; } else if (optimizer == mitk::OptimizerParameters::VERSORTRANSFORMOPTIMIZER || optimizer == mitk::OptimizerParameters::VERSORRIGID3DTRANSFORMOPTIMIZER) { std::string gradientMagnitudeTolerance = ReadXMLStringAttribut( "GRADIENTMAGNITUDETOLERANCE", atts ); double graMagTo = atof(gradientMagnitudeTolerance.c_str()); optimizerValues[2] = graMagTo; std::string minStepLength = ReadXMLStringAttribut( "MINSTEPLENGTH", atts ); double minStep = atof(minStepLength.c_str()); optimizerValues[3] = minStep; std::string maxStepLength = ReadXMLStringAttribut( "MAXSTEPLENGTH", atts ); double maxStep = atof(maxStepLength.c_str()); optimizerValues[4] = maxStep; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[5] = numIt; } else if (optimizer == mitk::OptimizerParameters::AMOEBAOPTIMIZER) { std::string simplexDelta1 = ReadXMLStringAttribut( "SIMPLEXDELTA1", atts ); double simpDel1 = atof(simplexDelta1.c_str()); optimizerValues[2] = simpDel1; std::string simplexDelta2 = ReadXMLStringAttribut( "SIMPLEXDELTA2", atts ); double simpDel2 = atof(simplexDelta2.c_str()); optimizerValues[3] = simpDel2; std::string simplexDelta3 = ReadXMLStringAttribut( "SIMPLEXDELTA3", atts ); double simpDel3 = atof(simplexDelta3.c_str()); optimizerValues[4] = simpDel3; std::string simplexDelta4 = ReadXMLStringAttribut( "SIMPLEXDELTA4", atts ); double simpDel4 = atof(simplexDelta4.c_str()); optimizerValues[5] = simpDel4; std::string simplexDelta5 = ReadXMLStringAttribut( "SIMPLEXDELTA5", atts ); double simpDel5 = atof(simplexDelta5.c_str()); optimizerValues[6] = simpDel5; std::string simplexDelta6 = ReadXMLStringAttribut( "SIMPLEXDELTA6", atts ); double simpDel6 = atof(simplexDelta6.c_str()); optimizerValues[7] = simpDel6; std::string simplexDelta7 = ReadXMLStringAttribut( "SIMPLEXDELTA7", atts ); double simpDel7 = atof(simplexDelta7.c_str()); optimizerValues[8] = simpDel7; std::string simplexDelta8 = ReadXMLStringAttribut( "SIMPLEXDELTA8", atts ); double simpDel8 = atof(simplexDelta8.c_str()); optimizerValues[9] = simpDel8; std::string simplexDelta9 = ReadXMLStringAttribut( "SIMPLEXDELTA9", atts ); double simpDel9 = atof(simplexDelta9.c_str()); optimizerValues[10] = simpDel9; std::string simplexDelta10 = ReadXMLStringAttribut( "SIMPLEXDELTA10", atts ); double simpDel10 = atof(simplexDelta10.c_str()); optimizerValues[11] = simpDel10; std::string simplexDelta11 = ReadXMLStringAttribut( "SIMPLEXDELTA11", atts ); double simpDel11 = atof(simplexDelta11.c_str()); optimizerValues[12] = simpDel11; std::string simplexDelta12 = ReadXMLStringAttribut( "SIMPLEXDELTA12", atts ); double simpDel12 = atof(simplexDelta12.c_str()); optimizerValues[13] = simpDel12; std::string simplexDelta13 = ReadXMLStringAttribut( "SIMPLEXDELTA13", atts ); double simpDel13 = atof(simplexDelta13.c_str()); optimizerValues[14] = simpDel13; std::string simplexDelta14 = ReadXMLStringAttribut( "SIMPLEXDELTA14", atts ); double simpDel14 = atof(simplexDelta14.c_str()); optimizerValues[15] = simpDel14; std::string simplexDelta15 = ReadXMLStringAttribut( "SIMPLEXDELTA15", atts ); double simpDel15 = atof(simplexDelta15.c_str()); optimizerValues[16] = simpDel15; std::string simplexDelta16 = ReadXMLStringAttribut( "SIMPLEXDELTA16", atts ); double simpDel16 = atof(simplexDelta16.c_str()); optimizerValues[17] = simpDel16; std::string parametersConvergenceTolerance = ReadXMLStringAttribut( "PARAMETERSCONVERGENCETOLERANCE", atts ); double paramConv = atof(parametersConvergenceTolerance.c_str()); optimizerValues[18] = paramConv; std::string functionConvergenceTolerance = ReadXMLStringAttribut( "FUNCTIONCONVERGENCETOLERANCE", atts ); double funcConv = atof(functionConvergenceTolerance.c_str()); optimizerValues[19] = funcConv; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[20] = numIt; } else if (optimizer == mitk::OptimizerParameters::CONJUGATEGRADIENTOPTIMIZER) { } else if (optimizer == mitk::OptimizerParameters::LBFGSOPTIMIZER) { std::string GradientConvergenceTolerance = ReadXMLStringAttribut( "GRADIENTCONVERGENCETOLERANCE", atts ); double graConTo = atof(GradientConvergenceTolerance.c_str()); optimizerValues[2] = graConTo; std::string lineSearchAccuracy = ReadXMLStringAttribut( "LINESEARCHACCURACY", atts ); double lineSearch = atof(lineSearchAccuracy.c_str()); optimizerValues[3] = lineSearch; std::string defaultStepLength = ReadXMLStringAttribut( "DEFAULTSTEPLENGTH", atts ); double defStep = atof(defaultStepLength.c_str()); optimizerValues[4] = defStep; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[5] = numIt; std::string useTrace = ReadXMLStringAttribut( "USETRACE", atts ); double useTr = atof(useTrace.c_str()); optimizerValues[6] = useTr; } else if (optimizer == mitk::OptimizerParameters::SPSAOPTIMIZER) { std::string a = ReadXMLStringAttribut( "a", atts ); double a1 = atof(a.c_str()); optimizerValues[2] = a1; std::string a2 = ReadXMLStringAttribut( "A", atts ); double a3 = atof(a2.c_str()); optimizerValues[3] = a3; std::string alpha = ReadXMLStringAttribut( "ALPHA", atts ); double alp = atof(alpha.c_str()); optimizerValues[4] = alp; std::string c = ReadXMLStringAttribut( "c", atts ); double c1 = atof(c.c_str()); optimizerValues[5] = c1; std::string gamma = ReadXMLStringAttribut( "GAMMA", atts ); double gam = atof(gamma.c_str()); optimizerValues[6] = gam; std::string tolerance = ReadXMLStringAttribut( "TOLERANCE", atts ); double tol = atof(tolerance.c_str()); optimizerValues[7] = tol; std::string stateOfConvergenceDecayRate = ReadXMLStringAttribut( "STATEOFCONVERGENCEDECAYRATE", atts ); double stateOfConvergence = atof(stateOfConvergenceDecayRate.c_str()); optimizerValues[8] = stateOfConvergence; std::string minNumberIterations = ReadXMLStringAttribut( "MINNUMBERITERATIONS", atts ); double minNumIt = atof(minNumberIterations.c_str()); optimizerValues[9] = minNumIt; std::string numberPerturbations = ReadXMLStringAttribut( "NUMBERPERTURBATIONS", atts ); double numPer = atof(numberPerturbations.c_str()); optimizerValues[10] = numPer; std::string numberIterations = ReadXMLStringAttribut( "NUMBERITERATIONS", atts ); double numIt = atof(numberIterations.c_str()); optimizerValues[11] = numIt; } return optimizerValues; } itk::Array RigidRegistrationPreset::loadInterpolatorValues(itk::Array interpolatorValues/*, double interpolator, const char **atts*/) { return interpolatorValues; } } diff --git a/Modules/SceneSerialization/mitkPropertyListDeserializer.cpp b/Modules/SceneSerialization/mitkPropertyListDeserializer.cpp index 12387c2f90..1166e226a4 100644 --- a/Modules/SceneSerialization/mitkPropertyListDeserializer.cpp +++ b/Modules/SceneSerialization/mitkPropertyListDeserializer.cpp @@ -1,93 +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. ===================================================================*/ #include "mitkPropertyListDeserializer.h" #include mitk::PropertyListDeserializer::PropertyListDeserializer() { } mitk::PropertyListDeserializer::~PropertyListDeserializer() { } bool mitk::PropertyListDeserializer::Deserialize() { bool error(false); TiXmlDocument document( m_Filename ); if (!document.LoadFile()) { MITK_ERROR << "Could not open/read/parse " << m_Filename << "\nTinyXML reports: " << document.ErrorDesc() << std::endl; return false; } // find version node --> note version in some variable int fileVersion = 1; TiXmlElement* versionObject = document.FirstChildElement("Version"); if (versionObject) { if ( versionObject->QueryIntAttribute( "FileVersion", &fileVersion ) != TIXML_SUCCESS ) { MITK_ERROR << "Property file " << m_Filename << " does not contain version information! Trying version 1 format." << std::endl; } } std::stringstream propertyListDeserializerClassName; propertyListDeserializerClassName << "PropertyListDeserializerV" << fileVersion; std::list readers = itk::ObjectFactoryBase::CreateAllInstance(propertyListDeserializerClassName.str().c_str()); if (readers.size() < 1) { MITK_ERROR << "No property list reader found for file version " << fileVersion; } if (readers.size() > 1) { MITK_WARN << "Multiple property list readers found for file version " << fileVersion << ". Using arbitrary first one."; } for ( std::list::iterator iter = readers.begin(); iter != readers.end(); ++iter ) { if (PropertyListDeserializer* reader = dynamic_cast( iter->GetPointer() ) ) { reader->SetFilename( m_Filename ); bool success = reader->Deserialize(); error |= !success; m_PropertyList = reader->GetOutput(); if ( error ) { - MITK_ERROR << "There were errors while loding property list file " << m_Filename << ". Your data may be corrupted"; + MITK_ERROR << "There were errors while loading property list file " << m_Filename << ". Your data may be corrupted"; } break; } } return !error; } mitk::PropertyList::Pointer mitk::PropertyListDeserializer::GetOutput() { return m_PropertyList; } diff --git a/Modules/SceneSerialization/mitkPropertyListDeserializerV1.cpp b/Modules/SceneSerialization/mitkPropertyListDeserializerV1.cpp index 0644f26aca..a983424353 100644 --- a/Modules/SceneSerialization/mitkPropertyListDeserializerV1.cpp +++ b/Modules/SceneSerialization/mitkPropertyListDeserializerV1.cpp @@ -1,90 +1,90 @@ /*=================================================================== 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 "mitkSerializerMacros.h" #include "mitkPropertyListDeserializerV1.h" #include "mitkBasePropertySerializer.h" #include MITK_REGISTER_SERIALIZER(PropertyListDeserializerV1) mitk::PropertyListDeserializerV1::PropertyListDeserializerV1() { } mitk::PropertyListDeserializerV1::~PropertyListDeserializerV1() { } bool mitk::PropertyListDeserializerV1::Deserialize() { bool error(false); m_PropertyList = PropertyList::New(); TiXmlDocument document( m_Filename ); if (!document.LoadFile()) { MITK_ERROR << "Could not open/read/parse " << m_Filename << "\nTinyXML reports: " << document.ErrorDesc() << std::endl; return false; } for( TiXmlElement* propertyElement = document.FirstChildElement("property"); propertyElement != NULL; propertyElement = propertyElement->NextSiblingElement("property") ) { const char* keya = propertyElement->Attribute("key"); std::string key( keya ? keya : ""); const char* typea = propertyElement->Attribute("type"); std::string type( typea ? typea : ""); // hand propertyElement to specific reader std::stringstream propertyDeserializerClassName; propertyDeserializerClassName << type << "Serializer"; std::list readers = itk::ObjectFactoryBase::CreateAllInstance(propertyDeserializerClassName.str().c_str()); if (readers.size() < 1) { MITK_ERROR << "No property reader found for " << type; error = true; } if (readers.size() > 1) { MITK_WARN << "Multiple property readers found for " << type << ". Using arbitrary first one."; } for ( std::list::iterator iter = readers.begin(); iter != readers.end(); ++iter ) { if (BasePropertySerializer* reader = dynamic_cast( iter->GetPointer() ) ) { BaseProperty::Pointer property = reader->Deserialize( propertyElement->FirstChildElement() ); if (property.IsNotNull()) { m_PropertyList->ReplaceProperty(key, property); } else { - MITK_ERROR << "There were errors while loding property '" << key << "' of type " << type << ". Your data may be corrupted"; + MITK_ERROR << "There were errors while loading property '" << key << "' of type " << type << ". Your data may be corrupted"; error = true; } break; } } } return !error; } diff --git a/Modules/SceneSerialization/mitkSceneIO.cpp b/Modules/SceneSerialization/mitkSceneIO.cpp index 7be4213556..cb68cc0ecd 100644 --- a/Modules/SceneSerialization/mitkSceneIO.cpp +++ b/Modules/SceneSerialization/mitkSceneIO.cpp @@ -1,533 +1,533 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include "mitkSceneIO.h" #include "mitkBaseDataSerializer.h" #include "mitkPropertyListSerializer.h" #include "mitkSceneReader.h" #include "mitkProgressBar.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" #include #include #include #include #include #include "itksys/SystemTools.hxx" mitk::SceneIO::SceneIO() :m_WorkingDirectory(""), m_UnzipErrors(0) { } mitk::SceneIO::~SceneIO() { } std::string mitk::SceneIO::CreateEmptyTempDirectory() { mitk::UIDGenerator uidGen("UID_",6); //std::string returnValue = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + Poco::Path::separator() + "SceneIOTemp" + uidGen.GetUID(); std::string returnValue = Poco::Path::temp() + "SceneIOTemp" + uidGen.GetUID(); std::string uniquename = returnValue + Poco::Path::separator(); Poco::File tempdir( uniquename ); try { bool existsNot = tempdir.createDirectory(); if (!existsNot) { MITK_ERROR << "Warning: Directory already exitsts: " << uniquename << " (choosing another)"; returnValue = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + Poco::Path::separator() + "SceneIOTempDirectory" + uidGen.GetUID(); uniquename = returnValue + Poco::Path::separator(); Poco::File tempdir2( uniquename ); if (!tempdir2.createDirectory()) { MITK_ERROR << "Warning: Second directory also already exitsts: " << uniquename; } } } catch( std::exception& e ) { MITK_ERROR << "Could not create temporary directory " << uniquename << ":" << e.what(); return ""; } return returnValue; } mitk::DataStorage::Pointer mitk::SceneIO::LoadScene( const std::string& filename, DataStorage* pStorage, bool clearStorageFirst ) { // prepare data storage DataStorage::Pointer storage = pStorage; if ( storage.IsNull() ) { storage = StandaloneDataStorage::New().GetPointer(); } if ( clearStorageFirst ) { try { storage->Remove( storage->GetAll() ); } catch(...) { MITK_ERROR << "DataStorage cannot be cleared properly."; } } // test input filename if ( filename.empty() ) { MITK_ERROR << "No filename given. Not possible to load scene."; return NULL; } // test if filename can be read std::ifstream file( filename.c_str(), std::ios::binary ); if (!file.good()) { MITK_ERROR << "Cannot open '" << filename << "' for reading"; return NULL; } // get new temporary directory m_WorkingDirectory = CreateEmptyTempDirectory(); if (m_WorkingDirectory.empty()) { MITK_ERROR << "Could not create temporary directory. Cannot open scene files."; return NULL; } // unzip all filenames contents to temp dir m_UnzipErrors = 0; Poco::Zip::Decompress unzipper( file, Poco::Path( m_WorkingDirectory ) ); unzipper.EError += Poco::Delegate >(this, &SceneIO::OnUnzipError); unzipper.EOk += Poco::Delegate >(this, &SceneIO::OnUnzipOk); unzipper.decompressAllFiles(); unzipper.EError -= Poco::Delegate >(this, &SceneIO::OnUnzipError); unzipper.EOk -= Poco::Delegate >(this, &SceneIO::OnUnzipOk); if ( m_UnzipErrors ) { MITK_ERROR << "There were " << m_UnzipErrors << " errors unzipping '" << filename << "'. Will attempt to read whatever could be unzipped."; } // test if index.xml exists // parse index.xml with TinyXML TiXmlDocument document( m_WorkingDirectory + Poco::Path::separator() + "index.xml" ); if (!document.LoadFile()) { MITK_ERROR << "Could not open/read/parse " << m_WorkingDirectory << "/index.xml\nTinyXML reports: " << document.ErrorDesc() << std::endl; return NULL; } SceneReader::Pointer reader = SceneReader::New(); if ( !reader->LoadScene( document, m_WorkingDirectory, storage ) ) { - MITK_ERROR << "There were errors while loding scene file " << filename << ". Your data may be corrupted"; + MITK_ERROR << "There were errors while loading scene file " << filename << ". Your data may be corrupted"; } // delete temp directory try { Poco::File deleteDir( m_WorkingDirectory ); deleteDir.remove(true); // recursive } catch(...) { MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory; } // return new data storage, even if empty or uncomplete (return as much as possible but notify calling method) return storage; } bool mitk::SceneIO::SaveScene( DataStorage::SetOfObjects::ConstPointer sceneNodes, const DataStorage* storage, const std::string& filename) { if (!sceneNodes) { MITK_ERROR << "No set of nodes given. Not possible to save scene."; return false; } if (!storage) { MITK_ERROR << "No data storage given. Not possible to save scene."; // \TODO: Technically, it would be possible to save the nodes without their relation return false; } if ( filename.empty() ) { MITK_ERROR << "No filename given. Not possible to save scene."; return false; } try { m_FailedNodes = DataStorage::SetOfObjects::New(); m_FailedProperties = PropertyList::New(); // start XML DOM TiXmlDocument document; TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "UTF-8", "" ); // TODO what to write here? encoding? standalone would mean that we provide a DTD somewhere... document.LinkEndChild( decl ); TiXmlElement* version = new TiXmlElement("Version"); version->SetAttribute("Writer", __FILE__ ); version->SetAttribute("Revision", "$Revision: 17055 $" ); version->SetAttribute("FileVersion", 1 ); document.LinkEndChild(version); //DataStorage::SetOfObjects::ConstPointer sceneNodes = storage->GetSubset( predicate ); if ( sceneNodes.IsNull() ) { MITK_WARN << "Saving empty scene to " << filename; } else { if ( sceneNodes->size() == 0 ) { MITK_WARN << "Saving empty scene to " << filename; } MITK_INFO << "Storing scene with " << sceneNodes->size() << " objects to " << filename; m_WorkingDirectory = CreateEmptyTempDirectory(); if (m_WorkingDirectory.empty()) { MITK_ERROR << "Could not create temporary directory. Cannot create scene files."; return false; } ProgressBar::GetInstance()->AddStepsToDo( sceneNodes->size() ); // find out about dependencies typedef std::map< DataNode*, std::string > UIDMapType; typedef std::map< DataNode*, std::list > SourcesMapType; UIDMapType nodeUIDs; // for dependencies: ID of each node SourcesMapType sourceUIDs; // for dependencies: IDs of a node's parent nodes UIDGenerator nodeUIDGen("OBJECT_"); for (DataStorage::SetOfObjects::const_iterator iter = sceneNodes->begin(); iter != sceneNodes->end(); ++iter) { DataNode* node = iter->GetPointer(); if (!node) continue; // unlikely event that we get a NULL pointer as an object for saving. just ignore // generate UIDs for all source objects DataStorage::SetOfObjects::ConstPointer sourceObjects = storage->GetSources( node ); for ( mitk::DataStorage::SetOfObjects::const_iterator sourceIter = sourceObjects->begin(); sourceIter != sourceObjects->end(); ++sourceIter ) { if ( std::find( sceneNodes->begin(), sceneNodes->end(), *sourceIter ) == sceneNodes->end() ) continue; // source is not saved, so don't generate a UID for this source // create a uid for the parent object if ( nodeUIDs[ *sourceIter ].empty() ) { nodeUIDs[ *sourceIter ] = nodeUIDGen.GetUID(); } // store this dependency for writing sourceUIDs[ node ].push_back( nodeUIDs[*sourceIter] ); } if ( nodeUIDs[ node ].empty() ) { nodeUIDs[ node ] = nodeUIDGen.GetUID(); } } // write out objects, dependencies and properties for (DataStorage::SetOfObjects::const_iterator iter = sceneNodes->begin(); iter != sceneNodes->end(); ++iter) { DataNode* node = iter->GetPointer(); if (node) { TiXmlElement* nodeElement = new TiXmlElement("node"); std::string filenameHint( node->GetName() ); filenameHint = itksys::SystemTools::MakeCindentifier(filenameHint.c_str()); // escape filename <-- only allow [A-Za-z0-9_], replace everything else with _ // store dependencies UIDMapType::iterator searchUIDIter = nodeUIDs.find(node); if ( searchUIDIter != nodeUIDs.end() ) { // store this node's ID nodeElement->SetAttribute("UID", searchUIDIter->second.c_str() ); } SourcesMapType::iterator searchSourcesIter = sourceUIDs.find(node); if ( searchSourcesIter != sourceUIDs.end() ) { // store all source IDs for ( std::list::iterator sourceUIDIter = searchSourcesIter->second.begin(); sourceUIDIter != searchSourcesIter->second.end(); ++sourceUIDIter ) { TiXmlElement* uidElement = new TiXmlElement("source"); uidElement->SetAttribute("UID", sourceUIDIter->c_str() ); nodeElement->LinkEndChild( uidElement ); } } // store basedata if ( BaseData* data = node->GetData() ) { //std::string filenameHint( node->GetName() ); bool error(false); TiXmlElement* dataElement( SaveBaseData( data, filenameHint, error ) ); // returns a reference to a file if (error) { m_FailedNodes->push_back( node ); } // store basedata properties PropertyList* propertyList = data->GetPropertyList(); if (propertyList && !propertyList->IsEmpty() ) { TiXmlElement* baseDataPropertiesElement( SavePropertyList( propertyList, filenameHint + "-data") ); // returns a reference to a file dataElement->LinkEndChild( baseDataPropertiesElement ); } nodeElement->LinkEndChild( dataElement ); } // store all renderwindow specific propertylists const RenderingManager::RenderWindowVector& allRenderWindows( RenderingManager::GetInstance()->GetAllRegisteredRenderWindows() ); for ( RenderingManager::RenderWindowVector::const_iterator rw = allRenderWindows.begin(); rw != allRenderWindows.end(); ++rw) { if (vtkRenderWindow* renderWindow = *rw) { std::string renderWindowName( mitk::BaseRenderer::GetInstance(renderWindow)->GetName() ); BaseRenderer* renderer = mitk::BaseRenderer::GetInstance(renderWindow); PropertyList* propertyList = node->GetPropertyList(renderer); if ( propertyList && !propertyList->IsEmpty() ) { TiXmlElement* renderWindowPropertiesElement( SavePropertyList( propertyList, filenameHint + "-" + renderWindowName) ); // returns a reference to a file renderWindowPropertiesElement->SetAttribute("renderwindow", renderWindowName); nodeElement->LinkEndChild( renderWindowPropertiesElement ); } } } // don't forget the renderwindow independent list PropertyList* propertyList = node->GetPropertyList(); if ( propertyList && !propertyList->IsEmpty() ) { TiXmlElement* propertiesElement( SavePropertyList( propertyList, filenameHint + "-node") ); // returns a reference to a file nodeElement->LinkEndChild( propertiesElement ); } document.LinkEndChild( nodeElement ); } else { MITK_WARN << "Ignoring NULL node during scene serialization."; } ProgressBar::GetInstance()->Progress(); } // end for all nodes } // end if sceneNodes if ( !document.SaveFile( m_WorkingDirectory + Poco::Path::separator() + "index.xml" ) ) { MITK_ERROR << "Could not write scene to " << m_WorkingDirectory << Poco::Path::separator() << "index.xml" << "\nTinyXML reports '" << document.ErrorDesc() << "'"; return false; } else { try { Poco::File deleteFile( filename.c_str() ); if (deleteFile.exists()) { deleteFile.remove(); } // create zip at filename std::ofstream file( filename.c_str(), std::ios::binary | std::ios::out); if (!file.good()) { MITK_ERROR << "Could not open a zip file for writing: '" << filename << "'"; } else { Poco::Zip::Compress zipper( file, true ); Poco::Path tmpdir( m_WorkingDirectory ); zipper.addRecursive( tmpdir ); zipper.close(); } try { Poco::File deleteDir( m_WorkingDirectory ); deleteDir.remove(true); // recursive } catch(...) { MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory; return false; // ok? } } catch(std::exception& e) { MITK_ERROR << "Could not create ZIP file from " << m_WorkingDirectory << "\nReason: " << e.what(); return false; } return true; } } catch(std::exception& e) { MITK_ERROR << "Caught exception during saving temporary files to disk. Error description: '" << e.what() << "'"; return false; } } TiXmlElement* mitk::SceneIO::SaveBaseData( BaseData* data, const std::string& filenamehint, bool& error ) { assert(data); error = true; // find correct serializer // the serializer must // - create a file containing all information to recreate the BaseData object --> needs to know where to put this file (and a filename?) // - TODO what to do about writers that creates one file per timestep? TiXmlElement* element = new TiXmlElement("data"); element->SetAttribute( "type", data->GetNameOfClass() ); // construct name of serializer class std::string serializername(data->GetNameOfClass()); serializername += "Serializer"; std::list thingsThatCanSerializeThis = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); if (thingsThatCanSerializeThis.size() < 1) { MITK_ERROR << "No serializer found for " << data->GetNameOfClass() << ". Skipping object"; } for ( std::list::iterator iter = thingsThatCanSerializeThis.begin(); iter != thingsThatCanSerializeThis.end(); ++iter ) { if (BaseDataSerializer* serializer = dynamic_cast( iter->GetPointer() ) ) { serializer->SetData(data); serializer->SetFilenameHint(filenamehint); serializer->SetWorkingDirectory( m_WorkingDirectory ); try { std::string writtenfilename = serializer->Serialize(); element->SetAttribute("file", writtenfilename); error = false; } catch (std::exception& e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); } break; } } return element; } TiXmlElement* mitk::SceneIO::SavePropertyList( PropertyList* propertyList, const std::string& filenamehint) { assert(propertyList); // - TODO what to do about shared properties (same object in two lists or behind several keys)? TiXmlElement* element = new TiXmlElement("properties"); // construct name of serializer class PropertyListSerializer::Pointer serializer = PropertyListSerializer::New(); serializer->SetPropertyList(propertyList); serializer->SetFilenameHint(filenamehint); serializer->SetWorkingDirectory( m_WorkingDirectory ); try { std::string writtenfilename = serializer->Serialize(); element->SetAttribute("file", writtenfilename); PropertyList::Pointer failedProperties = serializer->GetFailedProperties(); if (failedProperties.IsNotNull()) { // move failed properties to global list m_FailedProperties->ConcatenatePropertyList( failedProperties, true ); } } catch (std::exception& e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); } return element; } const mitk::SceneIO::FailedBaseDataListType* mitk::SceneIO::GetFailedNodes() { return m_FailedNodes.GetPointer(); } const mitk::PropertyList* mitk::SceneIO::GetFailedProperties() { return m_FailedProperties; } void mitk::SceneIO::OnUnzipError(const void* /*pSender*/, std::pair& info) { ++m_UnzipErrors; MITK_ERROR << "Error while unzipping: " << info.second; } void mitk::SceneIO::OnUnzipOk(const void* /*pSender*/, std::pair& /*info*/) { // MITK_INFO << "Unzipped ok: " << info.second.toString(); } diff --git a/Modules/SceneSerialization/mitkSceneReader.cpp b/Modules/SceneSerialization/mitkSceneReader.cpp index f94bc1cf0a..4b9c2673f5 100644 --- a/Modules/SceneSerialization/mitkSceneReader.cpp +++ b/Modules/SceneSerialization/mitkSceneReader.cpp @@ -1,63 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSceneReader.h" bool mitk::SceneReader::LoadScene( TiXmlDocument& document, const std::string& workingDirectory, DataStorage* storage ) { // find version node --> note version in some variable int fileVersion = 1; TiXmlElement* versionObject = document.FirstChildElement("Version"); if (versionObject) { if ( versionObject->QueryIntAttribute( "FileVersion", &fileVersion ) != TIXML_SUCCESS ) { MITK_ERROR << "Scene file " << workingDirectory + "/index.xml" << " does not contain version information! Trying version 1 format." << std::endl; } } std::stringstream sceneReaderClassName; sceneReaderClassName << "SceneReaderV" << fileVersion; std::list sceneReaders = itk::ObjectFactoryBase::CreateAllInstance(sceneReaderClassName.str().c_str()); if (sceneReaders.size() < 1) { MITK_ERROR << "No scene reader found for scene file version " << fileVersion; } if (sceneReaders.size() > 1) { MITK_WARN << "Multiple scene readers found for scene file version " << fileVersion << ". Using arbitrary first one."; } for ( std::list::iterator iter = sceneReaders.begin(); iter != sceneReaders.end(); ++iter ) { if (SceneReader* reader = dynamic_cast( iter->GetPointer() ) ) { if ( !reader->LoadScene( document, workingDirectory, storage ) ) { - MITK_ERROR << "There were errors while loding scene file " << workingDirectory + "/index.xml. Your data may be corrupted"; + MITK_ERROR << "There were errors while loading scene file " << workingDirectory + "/index.xml. Your data may be corrupted"; return false; } else { return true; } } } return false; } diff --git a/Modules/SceneSerialization/mitkSceneReaderV1.cpp b/Modules/SceneSerialization/mitkSceneReaderV1.cpp index 6d0d7bde62..af539f7591 100644 --- a/Modules/SceneSerialization/mitkSceneReaderV1.cpp +++ b/Modules/SceneSerialization/mitkSceneReaderV1.cpp @@ -1,370 +1,392 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSceneReaderV1.h" #include "mitkSerializerMacros.h" #include "mitkDataNodeFactory.h" #include "mitkBaseRenderer.h" #include "mitkPropertyListDeserializer.h" #include "mitkProgressBar.h" #include "Poco/Path.h" +#include MITK_REGISTER_SERIALIZER(SceneReaderV1) bool mitk::SceneReaderV1::LoadScene( TiXmlDocument& document, const std::string& workingDirectory, DataStorage* storage ) { assert(storage); bool error(false); // TODO prepare to detect errors (such as cycles) from wrongly written or edited xml files //Get number of elements to initialze progress bar // 1. if there is a element, // - construct a name for the appropriate serializer // - try to instantiate this serializer via itk object factory // - if serializer could be created, use it to read the file into a BaseData object // - if successful, call the new node's SetData(..) // create a node for the tag "data" and test if node was created typedef std::vector DataNodeVector; DataNodeVector DataNodes; unsigned int listSize = 0; for( TiXmlElement* element = document.FirstChildElement("node"); element != NULL; element = element->NextSiblingElement("node") ) { ++listSize; DataNodes.push_back( LoadBaseDataFromDataTag( element->FirstChildElement("data"), workingDirectory, error ) ); } OrderedLayers orderedLayers; this->GetLayerOrder(document, workingDirectory, DataNodes, orderedLayers); ProgressBar::GetInstance()->AddStepsToDo( listSize ); // iterate all nodes // first level nodes should be elements DataNodeVector::iterator nit = DataNodes.begin(); for( TiXmlElement* element = document.FirstChildElement("node"); element != NULL || nit != DataNodes.end(); element = element->NextSiblingElement("node"), ++nit ) { mitk::DataNode::Pointer node = *nit; // in case dataXmlElement is valid test whether it containts the "properties" child tag // and process further if and only if yes TiXmlElement *dataXmlElement = element->FirstChildElement("data"); if( dataXmlElement && dataXmlElement->FirstChildElement("properties") ) { TiXmlElement *baseDataElement = dataXmlElement->FirstChildElement("properties"); if ( node->GetData() ) { DecorateBaseDataWithProperties( node->GetData(), baseDataElement, workingDirectory); } else { MITK_WARN << "BaseData properties stored in scene file, but BaseData can't be read" << std::endl; } } // 2. check child nodes const char* uida = element->Attribute("UID"); std::string uid(""); if (uida) { uid = uida; m_NodeForID[uid] = node.GetPointer(); m_IDForNode[ node.GetPointer() ] = uid; } else { MITK_ERROR << "No UID found for current node. Node will have no parents."; error = true; } // 3. if there are nodes, // - instantiate the appropriate PropertyListDeSerializer // - use them to construct PropertyList objects // - add these properties to the node (if necessary, use renderwindow name) bool success = DecorateNodeWithProperties(node, element, workingDirectory); if (!success) { MITK_ERROR << "Could not load properties for node."; error = true; } // remember node for later adding to DataStorage //node->GetIntProperty("layer", layer); int layer; OrderedLayers::iterator it = orderedLayers.find(uid); layer = (*it).second; m_OrderedNodePairs.insert( std::make_pair( layer, std::make_pair( node, std::list() ) ) ); // 4. if there are elements, remember parent objects for( TiXmlElement* source = element->FirstChildElement("source"); source != NULL; source = source->NextSiblingElement("source") ) { const char* sourceUID = source->Attribute("UID"); if (sourceUID) { m_OrderedNodePairs[layer].second.push_back( std::string(sourceUID) ); } } ProgressBar::GetInstance()->Progress(); } // end for all // remove all unknown parent UIDs for (LayerPropertyMapType::iterator nodesIter = m_OrderedNodePairs.begin(); nodesIter != m_OrderedNodePairs.end(); ++nodesIter) { for (std::list::iterator parentsIter = nodesIter->second.second.begin(); parentsIter != nodesIter->second.second.end();) { if (m_NodeForID.find( *parentsIter ) == m_NodeForID.end()) { parentsIter = nodesIter->second.second.erase( parentsIter ); MITK_WARN << "Found a DataNode with unknown parents. Will add it to DataStorage without any parent objects."; error = true; } else { ++parentsIter; } } } // repeat // for all created nodes unsigned int lastMapSize(0); while ( lastMapSize != m_OrderedNodePairs.size()) // this is to prevent infinite loops; each iteration must at least add one node to DataStorage { lastMapSize = m_OrderedNodePairs.size(); for (LayerPropertyMapType::iterator nodesIter = m_OrderedNodePairs.begin(); nodesIter != m_OrderedNodePairs.end(); ++nodesIter) { bool addNow(true); // if any parent node is not yet in DataStorage, skip node for now and check later for (std::list::iterator parentsIter = nodesIter->second.second.begin(); parentsIter != nodesIter->second.second.end(); ++parentsIter) { if ( !storage->Exists( m_NodeForID[ *parentsIter ] ) ) { addNow = false; break; } } if (addNow) { DataStorage::SetOfObjects::Pointer parents = DataStorage::SetOfObjects::New(); for (std::list::iterator parentsIter = nodesIter->second.second.begin(); parentsIter != nodesIter->second.second.end(); ++parentsIter) { parents->push_back( m_NodeForID[ *parentsIter ] ); } // if all parents are found in datastorage (or are unknown), add node to DataStorage storage->Add( nodesIter->second.first, parents ); // remove this node from m_OrderedNodePairs m_OrderedNodePairs.erase( nodesIter ); // break this for loop because iterators are probably invalid break; } } } // All nodes that are still in m_OrderedNodePairs at this point are not part of a proper directed graph structure. We'll add such nodes without any parent information. for (LayerPropertyMapType::iterator nodesIter = m_OrderedNodePairs.begin(); nodesIter != m_OrderedNodePairs.end(); ++nodesIter) { storage->Add( nodesIter->second.first ); MITK_WARN << "Encountered node that is not part of a directed graph structure. Will be added to DataStorage without parents."; error = true; } return !error; } void mitk::SceneReaderV1::GetLayerOrder(TiXmlDocument& document, const std::string& workingDirectory, std::vector DataNodes, OrderedLayers& order) { typedef std::vector DataNodeVector; DataNodeVector::iterator nit = DataNodes.begin(); for( TiXmlElement* element = document.FirstChildElement("node"); element != NULL || nit != DataNodes.end(); element = element->NextSiblingElement("node"), ++nit ) { bool error(false); DataNode::Pointer node = *nit; DecorateNodeWithProperties(node, element, workingDirectory); int layer; node->GetIntProperty("layer", layer); std::string uid = element->Attribute("UID"); this->m_UnorderedLayers.insert( std::make_pair( layer, uid ) ); } int lastLayer = itk::NumericTraits::min(); UnorderedLayers::iterator it; for (it = m_UnorderedLayers.begin(); it != m_UnorderedLayers.end(); it++) { int currentLayer = (*it).first; if (currentLayer == lastLayer) { ++currentLayer; } order.insert( std::make_pair( (*it).second, currentLayer ) ); lastLayer = currentLayer; } } mitk::DataNode::Pointer mitk::SceneReaderV1::LoadBaseDataFromDataTag( TiXmlElement* dataElement, const std::string& workingDirectory, bool& error ) { DataNode::Pointer node; if (dataElement) { const char* filename( dataElement->Attribute("file") ); if ( filename ) { DataNodeFactory::Pointer factory = DataNodeFactory::New(); factory->SetFileName( workingDirectory + Poco::Path::separator() + filename ); try { factory->Update(); node = factory->GetOutput(); } catch (std::exception& e) { MITK_ERROR << "Error during attempt to read '" << filename << "'. Exception says: " << e.what(); error = true; } if (node.IsNull()) { MITK_ERROR << "Error during attempt to read '" << filename << "'. Factory returned NULL object."; error = true; } } } // in case there was no element we create a new empty node (for appending a propertylist later) if (node.IsNull()) { node = DataNode::New(); } return node; } bool mitk::SceneReaderV1::DecorateNodeWithProperties(DataNode* node, TiXmlElement* nodeElement, const std::string& workingDirectory) { assert(node); assert(nodeElement); bool error(false); for( TiXmlElement* properties = nodeElement->FirstChildElement("properties"); properties != NULL; properties = properties->NextSiblingElement("properties") ) { const char* propertiesfilea( properties->Attribute("file") ); std::string propertiesfile( propertiesfilea ? propertiesfilea : "" ); const char* renderwindowa( properties->Attribute("renderwindow") ); std::string renderwindow( renderwindowa ? renderwindowa : "" ); BaseRenderer* renderer = BaseRenderer::GetByName( renderwindow ); if (renderer || renderwindow.empty()) { PropertyList::Pointer propertyList = node->GetPropertyList(renderer); // DataNode implementation always returns a propertylist // clear all properties from node that might be set by DataNodeFactory during loading propertyList->Clear(); // use deserializer to construct new properties PropertyListDeserializer::Pointer deserializer = PropertyListDeserializer::New(); deserializer->SetFilename(workingDirectory + Poco::Path::separator() + propertiesfile); bool success = deserializer->Deserialize(); error |= !success; PropertyList::Pointer readProperties = deserializer->GetOutput(); if (readProperties.IsNotNull()) { + //'use color' is deprecated since 2013.03 release. It was replaced by + //'Image Rendering.Mode' in bug #12056. This code is for legacy support + //of old scene files containing the property 'use color'. The code should + //be removed in one of the upcomng releases. + if(readProperties->GetProperty("Image Rendering.Mode") == NULL ) + { + mitk::BaseProperty* useColorProperty = readProperties->GetProperty("use color"); + if(mitk::BoolProperty* boolProp = dynamic_cast(useColorProperty)) + { + bool useColor = boolProp->GetValue(); + readProperties->DeleteProperty("use color"); + mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); + if(useColor) + renderingMode->SetValue( mitk::RenderingModeProperty::LEVELWINDOW_COLOR ); + else + renderingMode->SetValue( mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR ); + readProperties->SetProperty("Image Rendering.Mode", renderingMode); + MITK_WARN << "The property 'use color' has been found in a scene file and was replaced by 'Image Rendering.Mode'. 'use color' is deprecated since 2013.03 release."; + } + + } propertyList->ConcatenatePropertyList( readProperties, true ); // true = replace } else { MITK_ERROR << "Property list reader did not return a property list. This is an implementation error. Please tell your developer."; error = true; } } else { MITK_ERROR << "Found properties for renderer " << renderwindow << " but there is no such renderer in current application. Ignoring those properties"; error = true; } } return !error; } bool mitk::SceneReaderV1::DecorateBaseDataWithProperties(BaseData::Pointer data, TiXmlElement *baseDataNodeElem, const std::string &workingDir) { // check given variables, initialize error variable assert(baseDataNodeElem); bool error(false); // get the file name stored in the tag const char* baseDataPropertyFile( baseDataNodeElem->Attribute("file") ); // check if the filename was found if(baseDataPropertyFile) { //PropertyList::Pointer dataPropList = data->GetPropertyList(); PropertyListDeserializer::Pointer propertyDeserializer = PropertyListDeserializer::New(); // initialize the property reader propertyDeserializer->SetFilename(workingDir + Poco::Path::separator() + baseDataPropertyFile); bool ioSuccess = propertyDeserializer->Deserialize(); error = !ioSuccess; // get the output PropertyList::Pointer inProperties = propertyDeserializer->GetOutput(); // store the read-in properties to the given node or throw error otherwise if( inProperties.IsNotNull() ) { data->SetPropertyList( inProperties ); } else { MITK_ERROR << "The property deserializer did not return a (valid) property list."; error = true; } } else { MITK_ERROR << "Function DecorateBaseDataWithProperties(...) called with false TiXmlElement. \n \t ->Given element does not contain a 'file' attribute. \n"; error = true; } return !error; } diff --git a/Modules/SceneSerializationBase/BasePropertySerializer/mitkEnumerationSubclassesSerializer.cpp b/Modules/SceneSerializationBase/BasePropertySerializer/mitkEnumerationSubclassesSerializer.cpp index 65b0f90409..e36daf2d06 100644 --- a/Modules/SceneSerializationBase/BasePropertySerializer/mitkEnumerationSubclassesSerializer.cpp +++ b/Modules/SceneSerializationBase/BasePropertySerializer/mitkEnumerationSubclassesSerializer.cpp @@ -1,75 +1,78 @@ /*=================================================================== 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 mitkEnumerationSubclassesSerializer_h_included #define mitkEnumerationSubclassesSerializer_h_included #include "mitkEnumerationPropertySerializer.h" #include "mitkPlaneOrientationProperty.h" #include "mitkShaderProperty.h" #include "mitkVtkInterpolationProperty.h" #include "mitkVtkRepresentationProperty.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkVtkScalarModeProperty.h" #include "mitkVtkVolumeRenderingProperty.h" #include "mitkModalityProperty.h" +#include "mitkRenderingModeProperty.h" #define MITK_REGISTER_ENUM_SUB_SERIALIZER(classname) \ \ namespace mitk \ { \ \ class SceneSerializationBase_EXPORT classname ## Serializer : public EnumerationPropertySerializer \ { \ public: \ \ mitkClassMacro( classname ## Serializer, EnumerationPropertySerializer ); \ itkNewMacro(Self); \ \ virtual BaseProperty::Pointer Deserialize(TiXmlElement* element) \ { \ if (!element) return NULL; \ const char* sa( element->Attribute("value") ); \ \ std::string s(sa?sa:""); \ classname::Pointer property = classname::New(); \ property->SetValue( s ); \ \ return property.GetPointer(); \ } \ \ protected: \ \ classname ## Serializer () {} \ virtual ~classname ## Serializer () {} \ }; \ \ } \ \ MITK_REGISTER_SERIALIZER( classname ## Serializer ); MITK_REGISTER_ENUM_SUB_SERIALIZER(PlaneOrientationProperty); MITK_REGISTER_ENUM_SUB_SERIALIZER(ShaderProperty); MITK_REGISTER_ENUM_SUB_SERIALIZER(VtkInterpolationProperty); MITK_REGISTER_ENUM_SUB_SERIALIZER(VtkRepresentationProperty); MITK_REGISTER_ENUM_SUB_SERIALIZER(VtkResliceInterpolationProperty); MITK_REGISTER_ENUM_SUB_SERIALIZER(VtkScalarModeProperty); MITK_REGISTER_ENUM_SUB_SERIALIZER(VtkVolumeRenderingProperty); MITK_REGISTER_ENUM_SUB_SERIALIZER(ModalityProperty); +MITK_REGISTER_ENUM_SUB_SERIALIZER(RenderingModeProperty); + #endif diff --git a/Modules/SceneSerializationBase/mitkPropertyListSerializer.cpp b/Modules/SceneSerializationBase/mitkPropertyListSerializer.cpp index 6c23d175ae..16577c8b7a 100644 --- a/Modules/SceneSerializationBase/mitkPropertyListSerializer.cpp +++ b/Modules/SceneSerializationBase/mitkPropertyListSerializer.cpp @@ -1,166 +1,172 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPropertyListSerializer.h" #include "mitkBasePropertySerializer.h" #include #include "mitkStandardFileLocations.h" #include mitk::PropertyListSerializer::PropertyListSerializer() : m_FilenameHint("unnamed") , m_WorkingDirectory("") { } mitk::PropertyListSerializer::~PropertyListSerializer() { } std::string mitk::PropertyListSerializer::Serialize() { m_FailedProperties = PropertyList::New(); if ( m_PropertyList.IsNull() || m_PropertyList->IsEmpty() ) { MITK_ERROR << "Not serializing NULL or empty PropertyList"; return ""; } // tmpname static unsigned long count = 1; unsigned long n = count++; std::ostringstream name; for (int i = 0; i < 6; ++i) { name << char('a' + (n % 26)); n /= 26; } std::string filename; filename.append(name.str()); std::string fullname(m_WorkingDirectory); fullname += "/"; fullname += filename; fullname = itksys::SystemTools::ConvertToOutputPath(fullname.c_str()); + // Trim quotes + std::string::size_type length = fullname.length(); + + if (length >= 2 && fullname[0] == '"' && fullname[length - 1] == '"') + fullname = fullname.substr(1, length - 2); + TiXmlDocument document; TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); // TODO what to write here? encoding? etc.... document.LinkEndChild( decl ); TiXmlElement* version = new TiXmlElement("Version"); version->SetAttribute("Writer", __FILE__ ); version->SetAttribute("Revision", "$Revision: 17055 $" ); version->SetAttribute("FileVersion", 1 ); document.LinkEndChild(version); // add XML contents const PropertyList::PropertyMap* propmap = m_PropertyList->GetMap(); for ( PropertyList::PropertyMap::const_iterator iter = propmap->begin(); iter != propmap->end(); ++iter ) { std::string key = iter->first; const BaseProperty* property = iter->second; TiXmlElement* element = SerializeOneProperty( key, property ); if (element) { document.LinkEndChild( element ); // TODO test serializer for error } else { m_FailedProperties->ReplaceProperty( key, const_cast(property) ); } } // save XML file if ( !document.SaveFile( fullname ) ) { MITK_ERROR << "Could not write PropertyList to " << fullname << "\nTinyXML reports '" << document.ErrorDesc() << "'"; return ""; } return filename; } TiXmlElement* mitk::PropertyListSerializer::SerializeOneProperty( const std::string& key, const BaseProperty* property ) { TiXmlElement* keyelement = new TiXmlElement("property"); keyelement->SetAttribute("key", key); keyelement->SetAttribute("type", property->GetNameOfClass()); // construct name of serializer class std::string serializername(property->GetNameOfClass()); serializername += "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); if (allSerializers.size() < 1) { MITK_ERROR << "No serializer found for " << property->GetNameOfClass() << ". Skipping object"; m_FailedProperties->ReplaceProperty( key, const_cast(property) ); } if (allSerializers.size() > 1) { MITK_WARN << "Multiple serializers found for " << property->GetNameOfClass() << "Using arbitrarily the first one."; } for ( std::list::iterator iter = allSerializers.begin(); iter != allSerializers.end(); ++iter ) { if (BasePropertySerializer* serializer = dynamic_cast( iter->GetPointer() ) ) { serializer->SetProperty(property); try { TiXmlElement* valueelement = serializer->Serialize(); if (valueelement) { keyelement->LinkEndChild( valueelement ); // \TODO: put 'return keyelement;' here? } else { m_FailedProperties->ReplaceProperty( key, const_cast(property) ); } } catch (std::exception& e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); m_FailedProperties->ReplaceProperty( key, const_cast(property) ); // \TODO: log only if all potential serializers fail? } break; } } return keyelement; } mitk::PropertyList* mitk::PropertyListSerializer::GetFailedProperties() { if (m_FailedProperties.IsNotNull() && !m_FailedProperties->IsEmpty()) { return m_FailedProperties; } else { return NULL; } } diff --git a/Modules/Segmentation/Controllers/mitkSurfaceInterpolationController.cpp b/Modules/Segmentation/Controllers/mitkSurfaceInterpolationController.cpp index 770f81f72b..8456529a5e 100644 --- a/Modules/Segmentation/Controllers/mitkSurfaceInterpolationController.cpp +++ b/Modules/Segmentation/Controllers/mitkSurfaceInterpolationController.cpp @@ -1,266 +1,270 @@ /*=================================================================== 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 "mitkSurfaceInterpolationController.h" #include "mitkMemoryUtilities.h" mitk::SurfaceInterpolationController::SurfaceInterpolationController() :m_SelectedSegmentation(0) { m_ReduceFilter = ReduceContourSetFilter::New(); m_NormalsFilter = ComputeContourSetNormalsFilter::New(); m_InterpolateSurfaceFilter = CreateDistanceImageFromSurfaceFilter::New(); m_ReduceFilter->SetUseProgressBar(false); m_NormalsFilter->SetUseProgressBar(false); m_InterpolateSurfaceFilter->SetUseProgressBar(false); m_Contours = Surface::New(); m_PolyData = vtkSmartPointer::New(); m_PolyData->SetPoints(vtkPoints::New()); m_InterpolationResult = 0; m_CurrentNumberOfReducedContours = 0; } mitk::SurfaceInterpolationController::~SurfaceInterpolationController() { for (ContourListMap::iterator it = m_MapOfContourLists.begin(); it != m_MapOfContourLists.end(); it++) { for (unsigned int j = 0; j < m_MapOfContourLists[(*it).first].size(); ++j) { delete(m_MapOfContourLists[(*it).first].at(j).position); } m_MapOfContourLists.erase(it); } } mitk::SurfaceInterpolationController* mitk::SurfaceInterpolationController::GetInstance() { static mitk::SurfaceInterpolationController* m_Instance; if ( m_Instance == 0) { m_Instance = new SurfaceInterpolationController(); } return m_Instance; } void mitk::SurfaceInterpolationController::AddNewContour (mitk::Surface::Pointer newContour ,RestorePlanePositionOperation* op) { AffineTransform3D::Pointer transform = AffineTransform3D::New(); transform = op->GetTransform(); mitk::Vector3D direction = op->GetDirectionVector(); int pos (-1); for (unsigned int i = 0; i < m_MapOfContourLists[m_SelectedSegmentation].size(); i++) { itk::Matrix diffM = transform->GetMatrix()-m_MapOfContourLists[m_SelectedSegmentation].at(i).position->GetTransform()->GetMatrix(); bool isSameMatrix(true); for (unsigned int j = 0; j < 3; j++) { if (fabs(diffM[j][0]) > 0.0001 && fabs(diffM[j][1]) > 0.0001 && fabs(diffM[j][2]) > 0.0001) { isSameMatrix = false; break; } } itk::Vector diffV = m_MapOfContourLists[m_SelectedSegmentation].at(i).position->GetTransform()->GetOffset()-transform->GetOffset(); if ( isSameMatrix && m_MapOfContourLists[m_SelectedSegmentation].at(i).position->GetPos() == op->GetPos() && (fabs(diffV[0]) < 0.0001 && fabs(diffV[1]) < 0.0001 && fabs(diffV[2]) < 0.0001) ) { pos = i; break; } } - if (pos == -1) + //Don't save a new empty contour + if (pos == -1 && newContour->GetVtkPolyData()->GetNumberOfPoints() > 0) { - //MITK_INFO<<"New Contour"; mitk::RestorePlanePositionOperation* newOp = new mitk::RestorePlanePositionOperation (OpRESTOREPLANEPOSITION, op->GetWidth(), op->GetHeight(), op->GetSpacing(), op->GetPos(), direction, transform); ContourPositionPair newData; newData.contour = newContour; newData.position = newOp; m_ReduceFilter->SetInput(m_MapOfContourLists[m_SelectedSegmentation].size(), newContour); m_MapOfContourLists[m_SelectedSegmentation].push_back(newData); } - else + //Edit a existing contour. If the contour is empty, edit it anyway so that the interpolation will always be consistent + else if (pos != -1) { - //MITK_INFO<<"Modified Contour"; m_MapOfContourLists[m_SelectedSegmentation].at(pos).contour = newContour; m_ReduceFilter->SetInput(pos, newContour); } m_ReduceFilter->Update(); m_CurrentNumberOfReducedContours = m_ReduceFilter->GetNumberOfOutputs(); for (unsigned int i = 0; i < m_CurrentNumberOfReducedContours; i++) { m_NormalsFilter->SetInput(i, m_ReduceFilter->GetOutput(i)); m_InterpolateSurfaceFilter->SetInput(i, m_NormalsFilter->GetOutput(i)); } this->Modified(); } void mitk::SurfaceInterpolationController::Interpolate() { if (m_CurrentNumberOfReducedContours< 2) + { + //If no interpolation is possible reset the interpolation result + m_InterpolationResult = 0; return; + } //Setting up progress bar /* * Removed due to bug 12441. ProgressBar messes around with Qt event queue which is fatal for segmentation */ //mitk::ProgressBar::GetInstance()->AddStepsToDo(8); m_InterpolateSurfaceFilter->Update(); Image::Pointer distanceImage = m_InterpolateSurfaceFilter->GetOutput(); vtkSmartPointer mcFilter = vtkSmartPointer::New(); mcFilter->SetInput(distanceImage->GetVtkImageData()); mcFilter->SetValue(0,0); mcFilter->Update(); m_InterpolationResult = 0; m_InterpolationResult = mitk::Surface::New(); m_InterpolationResult->SetVtkPolyData(mcFilter->GetOutput()); m_InterpolationResult->GetGeometry()->SetOrigin(distanceImage->GetGeometry()->GetOrigin()); vtkSmartPointer polyDataAppender = vtkSmartPointer::New(); for (unsigned int i = 0; i < m_ReduceFilter->GetNumberOfOutputs(); i++) { polyDataAppender->AddInput(m_ReduceFilter->GetOutput(i)->GetVtkPolyData()); } polyDataAppender->Update(); m_Contours->SetVtkPolyData(polyDataAppender->GetOutput()); //Last progress step /* * Removed due to bug 12441. ProgressBar messes around with Qt event queue which is fatal for segmentation */ //mitk::ProgressBar::GetInstance()->Progress(8); m_InterpolationResult->DisconnectPipeline(); } mitk::Surface::Pointer mitk::SurfaceInterpolationController::GetInterpolationResult() { return m_InterpolationResult; } mitk::Surface* mitk::SurfaceInterpolationController::GetContoursAsSurface() { return m_Contours; } void mitk::SurfaceInterpolationController::SetDataStorage(DataStorage &ds) { m_DataStorage = &ds; } void mitk::SurfaceInterpolationController::SetMinSpacing(double minSpacing) { m_ReduceFilter->SetMinSpacing(minSpacing); } void mitk::SurfaceInterpolationController::SetMaxSpacing(double maxSpacing) { m_ReduceFilter->SetMaxSpacing(maxSpacing); m_NormalsFilter->SetMaxSpacing(maxSpacing); } void mitk::SurfaceInterpolationController::SetDistanceImageVolume(unsigned int distImgVolume) { m_InterpolateSurfaceFilter->SetDistanceImageVolume(distImgVolume); } void mitk::SurfaceInterpolationController::SetSegmentationImage(Image* workingImage) { m_NormalsFilter->SetSegmentationBinaryImage(workingImage); } mitk::Image* mitk::SurfaceInterpolationController::GetImage() { return m_InterpolateSurfaceFilter->GetOutput(); } double mitk::SurfaceInterpolationController::EstimatePortionOfNeededMemory() { double numberOfPointsAfterReduction = m_ReduceFilter->GetNumberOfPointsAfterReduction()*3; double sizeOfPoints = pow(numberOfPointsAfterReduction,2)*sizeof(double); double totalMem = mitk::MemoryUtilities::GetTotalSizeOfPhysicalRam(); double percentage = sizeOfPoints/totalMem; return percentage; } void mitk::SurfaceInterpolationController::SetCurrentSegmentationInterpolationList(mitk::Image* segmentation) { if (segmentation == m_SelectedSegmentation) return; if (segmentation == 0) return; ContourListMap::iterator it = m_MapOfContourLists.find(segmentation); m_SelectedSegmentation = segmentation; m_ReduceFilter->Reset(); m_NormalsFilter->Reset(); m_InterpolateSurfaceFilter->Reset(); if (it == m_MapOfContourLists.end()) { ContourPositionPairList newList; m_MapOfContourLists.insert(std::pair(segmentation, newList)); m_InterpolationResult = 0; m_CurrentNumberOfReducedContours = 0; } else { for (unsigned int i = 0; i < m_MapOfContourLists[m_SelectedSegmentation].size(); i++) { m_ReduceFilter->SetInput(i, m_MapOfContourLists[m_SelectedSegmentation].at(i).contour); } m_ReduceFilter->Update(); m_CurrentNumberOfReducedContours = m_ReduceFilter->GetNumberOfOutputs(); for (unsigned int i = 0; i < m_CurrentNumberOfReducedContours; i++) { m_NormalsFilter->SetInput(i, m_ReduceFilter->GetOutput(i)); m_InterpolateSurfaceFilter->SetInput(i, m_NormalsFilter->GetOutput(i)); } } Modified(); } void mitk::SurfaceInterpolationController::RemoveSegmentationFromContourList(mitk::Image *segmentation) { if (segmentation != 0) { m_MapOfContourLists.erase(segmentation); } } diff --git a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp index 6f7af0d543..739ed49b80 100644 --- a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp +++ b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp @@ -1,373 +1,373 @@ /*=================================================================== 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 "mitkSegTool2D.h" #include "mitkToolManager.h" #include "mitkDataStorage.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkExtractImageFilter.h" #include "mitkExtractDirectedPlaneImageFilter.h" //Include of the new ImageExtractor #include "mitkExtractDirectedPlaneImageFilterNew.h" #include "mitkPlanarCircle.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkOverwriteDirectedPlaneImageFilter.h" #include "mitkGetModuleContext.h" //Includes for 3DSurfaceInterpolation #include "mitkImageToContourFilter.h" #include "mitkSurfaceInterpolationController.h" //includes for resling and overwriting #include #include #include #include #include #include "mitkOperationEvent.h" #include "mitkUndoController.h" #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) mitk::SegTool2D::SegTool2D(const char* type) :Tool(type), m_LastEventSender(NULL), m_LastEventSlice(0), m_Contourmarkername ("Position"), m_ShowMarkerNodes (false), m_3DInterpolationEnabled(true) { } mitk::SegTool2D::~SegTool2D() { } float mitk::SegTool2D::CanHandleEvent( StateEvent const *stateEvent) const { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return 0.0; if ( positionEvent->GetSender()->GetMapperID() != BaseRenderer::Standard2D ) return 0.0; // we don't want anything but 2D //This are the mouse event that are used by the statemachine patterns for zooming and panning. This must be possible although a tool is activ if (stateEvent->GetId() == EIDRIGHTMOUSEBTN || stateEvent->GetId() == EIDMIDDLEMOUSEBTN || stateEvent->GetId() == EIDRIGHTMOUSEBTNANDCTRL || stateEvent->GetId() == EIDMIDDLEMOUSERELEASE || stateEvent->GetId() == EIDRIGHTMOUSERELEASE || stateEvent->GetId() == EIDRIGHTMOUSEBTNANDMOUSEMOVE || stateEvent->GetId() == EIDMIDDLEMOUSEBTNANDMOUSEMOVE || stateEvent->GetId() == EIDCTRLANDRIGHTMOUSEBTNANDMOUSEMOVE || stateEvent->GetId() == EIDCTRLANDRIGHTMOUSEBTNRELEASE ) { //Since the usual segmentation tools currently do not need right click interaction but the mitkDisplayVectorInteractor return 0.0; } else { return 1.0; } } bool mitk::SegTool2D::DetermineAffectedImageSlice( const Image* image, const PlaneGeometry* plane, int& affectedDimension, int& affectedSlice ) { assert(image); assert(plane); // compare normal of plane to the three axis vectors of the image Vector3D normal = plane->GetNormal(); Vector3D imageNormal0 = image->GetSlicedGeometry()->GetAxisVector(0); Vector3D imageNormal1 = image->GetSlicedGeometry()->GetAxisVector(1); Vector3D imageNormal2 = image->GetSlicedGeometry()->GetAxisVector(2); normal.Normalize(); imageNormal0.Normalize(); imageNormal1.Normalize(); imageNormal2.Normalize(); imageNormal0.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal0.Get_vnl_vector()) ); imageNormal1.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal1.Get_vnl_vector()) ); imageNormal2.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal2.Get_vnl_vector()) ); double eps( 0.00001 ); // axial if ( imageNormal2.GetNorm() <= eps ) { affectedDimension = 2; } // sagittal else if ( imageNormal1.GetNorm() <= eps ) { affectedDimension = 1; } // frontal else if ( imageNormal0.GetNorm() <= eps ) { affectedDimension = 0; } else { affectedDimension = -1; // no idea return false; } // determine slice number in image Geometry3D* imageGeometry = image->GetGeometry(0); Point3D testPoint = imageGeometry->GetCenter(); Point3D projectedPoint; plane->Project( testPoint, projectedPoint ); Point3D indexPoint; imageGeometry->WorldToIndex( projectedPoint, indexPoint ); affectedSlice = ROUND( indexPoint[affectedDimension] ); MITK_DEBUG << "indexPoint " << indexPoint << " affectedDimension " << affectedDimension << " affectedSlice " << affectedSlice; // check if this index is still within the image if ( affectedSlice < 0 || affectedSlice >= static_cast(image->GetDimension(affectedDimension)) ) return false; return true; } mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImage(const PositionEvent* positionEvent, const Image* image) { if (!positionEvent) return NULL; assert( positionEvent->GetSender() ); // sure, right? unsigned int timeStep = positionEvent->GetSender()->GetTimeStep( image ); // get the timestep of the visible part (time-wise) of the image // first, we determine, which slice is affected const PlaneGeometry* planeGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) ); if ( !image || !planeGeometry ) return NULL; //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); //set to false to extract a slice reslice->SetOverwriteMode(false); reslice->Modified(); //use ExtractSliceFilter with our specific vtkImageReslice for overwriting and extracting mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( image ); extractor->SetTimeStep( timeStep ); extractor->SetWorldGeometry( planeGeometry ); extractor->SetVtkOutputRequest(false); extractor->SetResliceTransformByGeometry( image->GetTimeSlicedGeometry()->GetGeometry3D( timeStep ) ); extractor->Modified(); extractor->Update(); Image::Pointer slice = extractor->GetOutput(); /*============= BEGIN undo feature block ========================*/ //specify the undo operation with the non edited slice m_undoOperation = new DiffSliceOperation(const_cast(image), extractor->GetVtkOutput(), slice->GetGeometry(), timeStep, const_cast(planeGeometry)); /*============= END undo feature block ========================*/ return slice; } mitk::Image::Pointer mitk::SegTool2D::GetAffectedWorkingSlice(const PositionEvent* positionEvent) { DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if ( !workingNode ) return NULL; Image* workingImage = dynamic_cast(workingNode->GetData()); if ( !workingImage ) return NULL; return GetAffectedImageSliceAs2DImage( positionEvent, workingImage ); } mitk::Image::Pointer mitk::SegTool2D::GetAffectedReferenceSlice(const PositionEvent* positionEvent) { DataNode* referenceNode( m_ToolManager->GetReferenceData(0) ); if ( !referenceNode ) return NULL; Image* referenceImage = dynamic_cast(referenceNode->GetData()); if ( !referenceImage ) return NULL; return GetAffectedImageSliceAs2DImage( positionEvent, referenceImage ); } void mitk::SegTool2D::WriteBackSegmentationResult (const PositionEvent* positionEvent, Image* slice) { const PlaneGeometry* planeGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) ); DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); Image* image = dynamic_cast(workingNode->GetData()); unsigned int timeStep = positionEvent->GetSender()->GetTimeStep( image ); //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); //Set the slice as 'input' reslice->SetInputSlice(slice->GetVtkImageData()); //set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( image ); extractor->SetTimeStep( timeStep ); extractor->SetWorldGeometry( planeGeometry ); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry( image->GetTimeSlicedGeometry()->GetGeometry3D( timeStep ) ); extractor->Modified(); extractor->Update(); //the image was modified within the pipeline, but not marked so image->Modified(); image->GetVtkImageData()->Modified(); /*============= BEGIN undo feature block ========================*/ //specify the undo operation with the edited slice m_doOperation = new DiffSliceOperation(image, extractor->GetVtkOutput(),slice->GetGeometry(), timeStep, const_cast(planeGeometry)); //create an operation event for the undo stack OperationEvent* undoStackItem = new OperationEvent( DiffSliceOperationApplier::GetInstance(), m_doOperation, m_undoOperation, "Segmentation" ); //add it to the undo controller UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); //clear the pointers as the operation are stored in the undocontroller and also deleted from there m_undoOperation = NULL; m_doOperation = NULL; /*============= END undo feature block ========================*/ slice->DisconnectPipeline(); ImageToContourFilter::Pointer contourExtractor = ImageToContourFilter::New(); contourExtractor->SetInput(slice); contourExtractor->Update(); mitk::Surface::Pointer contour = contourExtractor->GetOutput(); - if (m_3DInterpolationEnabled && contour->GetVtkPolyData()->GetNumberOfPoints() > 0 ) + if (m_3DInterpolationEnabled) { unsigned int pos = this->AddContourmarker(positionEvent); mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); mitk::SurfaceInterpolationController::GetInstance()->AddNewContour( contour, service->GetPlanePosition(pos)); contour->DisconnectPipeline(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::SegTool2D::SetShowMarkerNodes(bool status) { m_ShowMarkerNodes = status; } void mitk::SegTool2D::SetEnable3DInterpolation(bool enabled) { m_3DInterpolationEnabled = enabled; } unsigned int mitk::SegTool2D::AddContourmarker ( const PositionEvent* positionEvent ) { const mitk::Geometry2D* plane = dynamic_cast (dynamic_cast< const mitk::SlicedGeometry3D*>( positionEvent->GetSender()->GetSliceNavigationController()->GetCurrentGeometry3D())->GetGeometry2D(0)); mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); unsigned int size = service->GetNumberOfPlanePositions(); unsigned int id = service->AddNewPlanePosition(plane, positionEvent->GetSender()->GetSliceNavigationController()->GetSlice()->GetPos()); mitk::PlanarCircle::Pointer contourMarker = mitk::PlanarCircle::New(); mitk::Point2D p1; plane->Map(plane->GetCenter(), p1); mitk::Point2D p2 = p1; p2[0] -= plane->GetSpacing()[0]; p2[1] -= plane->GetSpacing()[1]; contourMarker->PlaceFigure( p1 ); contourMarker->SetCurrentControlPoint( p1 ); contourMarker->SetGeometry2D( const_cast(plane)); std::stringstream markerStream; mitk::DataNode* workingNode (m_ToolManager->GetWorkingData(0)); markerStream << m_Contourmarkername ; markerStream << " "; markerStream << id+1; DataNode::Pointer rotatedContourNode = DataNode::New(); rotatedContourNode->SetData(contourMarker); rotatedContourNode->SetProperty( "name", StringProperty::New(markerStream.str()) ); rotatedContourNode->SetProperty( "isContourMarker", BoolProperty::New(true)); rotatedContourNode->SetBoolProperty( "PlanarFigureInitializedWindow", true, positionEvent->GetSender() ); rotatedContourNode->SetProperty( "includeInBoundingBox", BoolProperty::New(false)); rotatedContourNode->SetProperty( "helper object", mitk::BoolProperty::New(!m_ShowMarkerNodes)); rotatedContourNode->SetProperty( "planarfigure.drawcontrolpoints", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawname", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawoutline", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawshadow", BoolProperty::New(false)); if (plane) { if ( id == size ) { m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); } else { mitk::NodePredicateProperty::Pointer isMarker = mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true)); mitk::DataStorage::SetOfObjects::ConstPointer markers = m_ToolManager->GetDataStorage()->GetDerivations(workingNode,isMarker); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = markers->begin(); iter != markers->end(); ++iter) { std::string nodeName = (*iter)->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int markerId = atof(nodeName.substr(t+1).c_str())-1; if(id == markerId) { return id; } } m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); } } return id; } void mitk::SegTool2D::InteractiveSegmentationBugMessage( const std::string& message ) { MITK_ERROR << "********************************************************************************" << std::endl << " " << message << std::endl << "********************************************************************************" << std::endl << " " << std::endl << " If your image is rotated or the 2D views don't really contain the patient image, try to press the button next to the image selection. " << std::endl << " " << std::endl << " Please file a BUG REPORT: " << std::endl << " http://bugs.mitk.org" << std::endl << " Contain the following information:" << std::endl << " - What image were you working on?" << std::endl << " - Which region of the image?" << std::endl << " - Which tool did you use?" << std::endl << " - What did you do?" << std::endl << " - What happened (not)? What did you expect?" << std::endl; } diff --git a/Modules/US/USFilters/mitkUSImageVideoSource.cpp b/Modules/US/USFilters/mitkUSImageVideoSource.cpp index 7c70e1e21c..ace4e5b8fa 100644 --- a/Modules/US/USFilters/mitkUSImageVideoSource.cpp +++ b/Modules/US/USFilters/mitkUSImageVideoSource.cpp @@ -1,155 +1,168 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // MITK HEADER #include "mitkUSImageVideoSource.h" #include "mitkImage.h" //OpenCV HEADER #include #include //Other #include mitk::USImageVideoSource::USImageVideoSource() -: itk::Object() +: itk::Object(), +m_VideoCapture(new cv::VideoCapture()), +m_IsVideoReady(false), +m_IsGreyscale(false), +m_OpenCVToMitkFilter(mitk::OpenCVToMitkImageFilter::New()), +m_ResolutionOverrideWidth(0), +m_ResolutionOverrideHeight(0), +m_ResolutionOverride(false) { - m_VideoCapture = new cv::VideoCapture(); - m_IsVideoReady = false; - m_IsGreyscale = false; - this->m_OpenCVToMitkFilter = mitk::OpenCVToMitkImageFilter::New(); - m_ResolutionOverrideWidth = 0; - m_ResolutionOverrideHeight = 0; - m_ResolutionOverride = false; + m_OpenCVToMitkFilter->SetCopyBuffer(false); } mitk::USImageVideoSource::~USImageVideoSource() { } void mitk::USImageVideoSource::SetVideoFileInput(std::string path) { m_VideoCapture->open(path.c_str()); if(!m_VideoCapture->isOpened()) // check if we succeeded m_IsVideoReady = false; else m_IsVideoReady = true; // If Override is enabled, use it if (m_ResolutionOverride) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, this->m_ResolutionOverrideWidth); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, this->m_ResolutionOverrideHeight); } } void mitk::USImageVideoSource::SetCameraInput(int deviceID) { m_VideoCapture->open(deviceID); if(!m_VideoCapture->isOpened()) // check if we succeeded m_IsVideoReady = false; else m_IsVideoReady = true; // If Override is enabled, use it if (m_ResolutionOverride) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, this->m_ResolutionOverrideWidth); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, this->m_ResolutionOverrideHeight); } } void mitk::USImageVideoSource::SetColorOutput(bool isColor){ m_IsGreyscale = !isColor; } +int mitk::USImageVideoSource::GetImageHeight() +{ +if (m_VideoCapture) return m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT); +else return 0; +} + +int mitk::USImageVideoSource::GetImageWidth() +{ +if (m_VideoCapture) return m_VideoCapture->get(CV_CAP_PROP_FRAME_WIDTH); +else return 0; +} + void mitk::USImageVideoSource::SetRegionOfInterest(int topLeftX, int topLeftY, int bottomRightX, int bottomRightY) { // First, let's do some basic checks to make sure rectangle is inside of actual image if (topLeftX < 0) topLeftX = 0; if (topLeftY < 0) topLeftY = 0; // We can try and correct too large boundaries if (bottomRightX > m_VideoCapture->get(CV_CAP_PROP_FRAME_WIDTH)) bottomRightX = m_VideoCapture->get(CV_CAP_PROP_FRAME_WIDTH); - if (bottomRightX > m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT)) bottomRightY = m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT); + if (bottomRightY > m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT)) bottomRightY = m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT); // Nothing to save, throw an exception if (topLeftX > bottomRightX) mitkThrow() << "Invalid boundaries supplied to USImageVideoSource::SetRegionOfInterest()"; if (topLeftY > bottomRightY) mitkThrow() << "Invalid boundaries supplied to USImageVideoSource::SetRegionOfInterest()"; m_CropRegion = cv::Rect(topLeftX, topLeftY, bottomRightX - topLeftX, bottomRightY - topLeftY); } void mitk::USImageVideoSource::RemoveRegionOfInterest(){ m_CropRegion.width = 0; m_CropRegion.height = 0; } mitk::USImage::Pointer mitk::USImageVideoSource::GetNextImage() { // Loop video if necessary if (m_VideoCapture->get(CV_CAP_PROP_POS_AVI_RATIO) >= 0.99 ) m_VideoCapture->set(CV_CAP_PROP_POS_AVI_RATIO, 0); // Setup pointers cv::Mat image; cv::Mat buffer; // Retrieve image *m_VideoCapture >> image; // get a new frame from camera // if Region of interest is set, crop image if (m_CropRegion.width > 0){ buffer = image(m_CropRegion); image.release(); image = buffer; } // If this source is set to deliver greyscale images, convert it if (m_IsGreyscale) { cv::cvtColor(image, buffer, CV_RGB2GRAY, 1); image.release(); image = buffer; } // Convert to MITK-Image IplImage ipl_img = image; this->m_OpenCVToMitkFilter->SetOpenCVImage(&ipl_img); this->m_OpenCVToMitkFilter->Update(); // OpenCVToMitkImageFilter returns a standard mitk::image. We then transform it into an USImage mitk::USImage::Pointer result = mitk::USImage::New(this->m_OpenCVToMitkFilter->GetOutput(0)); // Clean up buffer.release(); image.release(); return result; } void mitk::USImageVideoSource::OverrideResolution(int width, int height){ this->m_ResolutionOverrideHeight = height; this->m_ResolutionOverrideWidth = width; if (m_VideoCapture != 0) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, width); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, height); } } diff --git a/Modules/US/USFilters/mitkUSImageVideoSource.h b/Modules/US/USFilters/mitkUSImageVideoSource.h index c34509c033..bdbd2af224 100644 --- a/Modules/US/USFilters/mitkUSImageVideoSource.h +++ b/Modules/US/USFilters/mitkUSImageVideoSource.h @@ -1,139 +1,144 @@ /*=================================================================== 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 MITKUSImageVideoSource_H_HEADER_INCLUDED_ #define MITKUSImageVideoSource_H_HEADER_INCLUDED_ // ITK #include // MITK #include "mitkUSImage.h" #include "mitkOpenCVToMitkImageFilter.h" // OpenCV #include namespace mitk { /**Documentation * \brief This class can be pointed to a video file or a videodevice and delivers USImages. * * Images are in color by default, but can be set to greyscale via SetColorOutput(false), * which significantly improves performance. * * Images can also be cropped to a region of interest, further increasing performance. * * \ingroup US */ class MitkUS_EXPORT USImageVideoSource : public itk::Object { public: mitkClassMacro(USImageVideoSource, itk::ProcessObject); itkNewMacro(Self); /** * \brief Opens a video file for streaming. If nothing goes wrong, the * VideoSource is ready to deliver images after calling this function. */ void SetVideoFileInput(std::string path); /** * \brief Opens a video device for streaming. Takes the Device id. Try -1 for "grab the first you can get" * which works quite well if only one device is available. If nothing goes wrong, the * VideoSource is ready to deliver images after calling this function. */ void SetCameraInput(int deviceID); /** * \brief Sets the output image to rgb or grayscale. * Output is color by default * and can be set to color by passing true, or to grayscale again by passing false. */ void SetColorOutput(bool isColor); /** * /brief Defines the cropping area. The rectangle will be justified to the image borders * if the given rectangle is larger than the video source. If a correct rectangle is given, * The dimensions of the output image will be equal to those of the rectangle. */ void SetRegionOfInterest(int topLeftX, int topLeftY, int bottomRightX, int bottomRightY); /** * /brief Removes the region of interest. Produced images will be uncropped after call. */ void RemoveRegionOfInterest(); /** * \brief Retrieves the next frame. This will typically be the next frame in a file * or the last cached file in a device. */ mitk::USImage::Pointer GetNextImage(); /** * \brief This is a workaround for a problem that happens with some video device drivers. * * If you encounter OpenCV Warnings that buffer sizes do not match while calling getNextFrame, * then do the following: Using the drivers control panel to force a certain resolution, then call * this method with the same Dimensions after opening the device. */ void OverrideResolution(int width, int height); // Getter & Setter itkGetMacro(IsVideoReady, bool); itkGetMacro(ResolutionOverride, bool); itkSetMacro(ResolutionOverride, bool); + itkGetMacro(IsGreyscale,bool); + itkGetMacro(ResolutionOverrideWidth,int); + itkGetMacro(ResolutionOverrideHeight,int); + int GetImageHeight(); + int GetImageWidth(); protected: USImageVideoSource(); virtual ~USImageVideoSource(); /** * \brief The source of the video, managed internally */ cv::VideoCapture* m_VideoCapture; /** * \brief If true, a frame can be grabbed anytime. */ bool m_IsVideoReady; /** * \brief If true, image output will be greyscale. */ bool m_IsGreyscale; /** * \brief If values inside are nonzero, this rectangle will be cropped from the stream and used as an output. * Used to mark Region of Interest. */ cv::Rect m_CropRegion; /** * \brief Used to convert from OpenCV Images to MITK Images. */ mitk::OpenCVToMitkImageFilter::Pointer m_OpenCVToMitkFilter; /** * These Variables determined whether Resolution Override is on, what dimensions to use. */ int m_ResolutionOverrideWidth; int m_ResolutionOverrideHeight; bool m_ResolutionOverride; }; } // namespace mitk #endif /* MITKUSImageVideoSource_H_HEADER_INCLUDED_ */ diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index 1d8634c802..386d973f56 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,294 +1,319 @@ /*=================================================================== 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 "mitkUSDevice.h" -#include "mitkUSImageMetadata.h" //Microservices #include #include #include #include "mitkModuleContext.h" const std::string mitk::USDevice::US_INTERFACE_NAME = "org.mitk.services.UltrasoundDevice"; const std::string mitk::USDevice::US_PROPKEY_LABEL = US_INTERFACE_NAME + ".label"; const std::string mitk::USDevice::US_PROPKEY_ISACTIVE = US_INTERFACE_NAME + ".isActive"; const std::string mitk::USDevice::US_PROPKEY_CLASS = US_INTERFACE_NAME + ".class"; +mitk::USDevice::USImageCropArea mitk::USDevice::GetCropArea() +{ + MITK_INFO << "Return Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; + return m_CropArea; +} mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource() { // Initialize Members m_Metadata = mitk::USImageMetadata::New(); m_Metadata->SetDeviceManufacturer(manufacturer); m_Metadata->SetDeviceModel(model); m_IsActive = false; + USImageCropArea empty; + empty.cropBottom = 0; + empty.cropTop = 0; + empty.cropLeft = 0; + empty.cropRight = 0; + this->m_CropArea = empty; + m_IsConnected = false; //set number of outputs this->SetNumberOfOutputs(1); //create a new output mitk::USImage::Pointer newOutput = mitk::USImage::New(); this->SetNthOutput(0,newOutput); } mitk::USDevice::USDevice(mitk::USImageMetadata::Pointer metadata) : mitk::ImageSource() { m_Metadata = metadata; m_IsActive = false; + m_IsConnected = false; + + USImageCropArea empty; + empty.cropBottom = 0; + empty.cropTop = 0; + empty.cropLeft = 0; + empty.cropRight = 0; + this->m_CropArea = empty; //set number of outputs this->SetNumberOfOutputs(1); //create a new output mitk::USImage::Pointer newOutput = mitk::USImage::New(); this->SetNthOutput(0,newOutput); } mitk::USDevice::~USDevice() { } mitk::ServiceProperties mitk::USDevice::ConstructServiceProperties() { ServiceProperties props; std::string yes = "true"; std::string no = "false"; if(this->GetIsActive()) props[mitk::USDevice::US_PROPKEY_ISACTIVE] = yes; else props[mitk::USDevice::US_PROPKEY_ISACTIVE] = no; std::string isActive; if (GetIsActive()) isActive = " (Active)"; else isActive = " (Inactive)"; // e.g.: Zonare MyLab5 (Active) props[ mitk::USDevice::US_PROPKEY_LABEL] = m_Metadata->GetDeviceManufacturer() + " " + m_Metadata->GetDeviceModel() + isActive; if( m_Calibration.IsNotNull() ) props[ mitk::USImageMetadata::PROP_DEV_ISCALIBRATED ] = yes; else props[ mitk::USImageMetadata::PROP_DEV_ISCALIBRATED ] = no; props[ mitk::USDevice::US_PROPKEY_CLASS ] = GetDeviceClass(); props[ mitk::USImageMetadata::PROP_DEV_MANUFACTURER ] = m_Metadata->GetDeviceManufacturer(); props[ mitk::USImageMetadata::PROP_DEV_MODEL ] = m_Metadata->GetDeviceModel(); props[ mitk::USImageMetadata::PROP_DEV_COMMENT ] = m_Metadata->GetDeviceComment(); props[ mitk::USImageMetadata::PROP_PROBE_NAME ] = m_Metadata->GetProbeName(); props[ mitk::USImageMetadata::PROP_PROBE_FREQUENCY ] = m_Metadata->GetProbeFrequency(); props[ mitk::USImageMetadata::PROP_ZOOM ] = m_Metadata->GetZoom(); return props; } bool mitk::USDevice::Connect() { if (GetIsConnected()) { MITK_WARN << "Tried to connect an ultrasound device that was already connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (! this->OnConnection()) return false; + // Update state + m_IsConnected = true; + // Get Context and Module mitk::ModuleContext* context = GetModuleContext(); ServiceProperties props = ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); // This makes sure that the SmartPointer to this device does not invalidate while the device is connected this->Register(); return true; } bool mitk::USDevice::Disconnect() { if ( ! GetIsConnected()) { MITK_WARN << "Tried to disconnect an ultrasound device that was not connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (! this->OnDisconnection()) return false; + // Update state + m_IsConnected = false; + // Unregister m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; // Undo the manual registration done in Connect(). Pointer will invalidte, if no one holds a reference to this object anymore. this->UnRegister(); return true; } bool mitk::USDevice::Activate() { if (! this->GetIsConnected()) return false; m_IsActive = true; // <- Necessary to safely allow Subclasses to start threading based on activity state m_IsActive = OnActivation(); ServiceProperties props = ConstructServiceProperties(); this->m_ServiceRegistration.SetProperties(props); return m_IsActive; } void mitk::USDevice::Deactivate() { m_IsActive= false; ServiceProperties props = ConstructServiceProperties(); this->m_ServiceRegistration.SetProperties(props); OnDeactivation(); } void mitk::USDevice::AddProbe(mitk::USProbe::Pointer probe) { for(int i = 0; i < m_ConnectedProbes.size(); i++) { if (m_ConnectedProbes[i]->IsEqualToProbe(probe)) return; } this->m_ConnectedProbes.push_back(probe); } void mitk::USDevice::ActivateProbe(mitk::USProbe::Pointer probe){ // currently, we may just add the probe. This behaviour should be changed, should more complicated SDK applications emerge AddProbe(probe); int index = -1; for(int i = 0; i < m_ConnectedProbes.size(); i++) { if (m_ConnectedProbes[i]->IsEqualToProbe(probe)) index = i; } // index now contains the position of the original instance of this probe m_ActiveProbe = m_ConnectedProbes[index]; } void mitk::USDevice::DeactivateProbe(){ m_ActiveProbe = 0; } mitk::USImage* mitk::USDevice::GetOutput() { if (this->GetNumberOfOutputs() < 1) return NULL; return static_cast(this->ProcessObject::GetOutput(0)); } mitk::USImage* mitk::USDevice::GetOutput(unsigned int idx) { if (this->GetNumberOfOutputs() < 1) return NULL; return static_cast(this->ProcessObject::GetOutput(idx)); } void mitk::USDevice::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::USDevice::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter only has " << this->GetNumberOfOutputs() << " 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 USImage to copy member data output->Graft( graft ); } itk::ProcessObject::DataObjectPointer mitk::USDevice::MakeOutput( unsigned int /*idx */) { mitk::USImage::Pointer p = mitk::USImage::New(); return static_cast(p.GetPointer()); } bool mitk::USDevice::ApplyCalibration(mitk::USImage::Pointer image){ if ( m_Calibration.IsNull() ) return false; image->GetGeometry()->SetIndexToWorldTransform(m_Calibration); return true; } //########### GETTER & SETTER ##################// void mitk::USDevice::setCalibration (mitk::AffineTransform3D::Pointer calibration){ if (calibration.IsNull()) { MITK_ERROR << "Null pointer passed to SetCalibration of mitk::USDevice. Ignoring call."; return; } m_Calibration = calibration; m_Metadata->SetDeviceIsCalibrated(true); if (m_ServiceRegistration != 0) { ServiceProperties props = ConstructServiceProperties(); this->m_ServiceRegistration.SetProperties(props); } } bool mitk::USDevice::GetIsActive() { return m_IsActive; } bool mitk::USDevice::GetIsConnected() { // a device is connected if it is registered with the Microservice Registry return (m_ServiceRegistration != 0); } std::string mitk::USDevice::GetDeviceManufacturer(){ return this->m_Metadata->GetDeviceManufacturer(); } std::string mitk::USDevice::GetDeviceModel(){ return this->m_Metadata->GetDeviceModel(); } std::string mitk::USDevice::GetDeviceComment(){ return this->m_Metadata->GetDeviceComment(); } std::vector mitk::USDevice::GetConnectedProbes() { return m_ConnectedProbes; } diff --git a/Modules/US/USModel/mitkUSDevice.h b/Modules/US/USModel/mitkUSDevice.h index c982eadca9..ffb9aa1501 100644 --- a/Modules/US/USModel/mitkUSDevice.h +++ b/Modules/US/USModel/mitkUSDevice.h @@ -1,298 +1,313 @@ /*=================================================================== 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 MITKUSDevice_H_HEADER_INCLUDED_ #define MITKUSDevice_H_HEADER_INCLUDED_ // STL #include // MitkUS #include "mitkUSProbe.h" #include "mitkUSImageMetadata.h" #include "mitkUSImage.h" #include // MITK #include #include // ITK #include // Microservices #include #include #include namespace mitk { /**Documentation * \brief A device holds information about it's model, make and the connected probes. It is the * common super class for all devices and acts as an image source for mitkUSImages. It is the base class * for all US Devices, and every new device should extend it. * * US Devices support output of calibrated images, i.e. images that include a specific geometry. * To achieve this, call SetCalibration, and make sure that the subclass also calls apply * transformation at some point (The USDevice does not automatically apply the transformation to the image) * * Note that SmartPointers to USDevices will not invalidate while the device is still connected. * \ingroup US */ class MitkUS_EXPORT USDevice : public mitk::ImageSource { public: mitkClassMacro(USDevice, mitk::ImageSource); + struct USImageCropArea + { + int cropLeft; + int cropRight; + int cropBottom; + int cropTop; + }; + /** *\brief These constants are used in conjunction with Microservices */ static const std::string US_INTERFACE_NAME; // Common Interface name of all US Devices. Used to refer to this device via Microservices static const std::string US_PROPKEY_LABEL; // Human readable text represntation of this device static const std::string US_PROPKEY_ISACTIVE; // Whether this Device is active or not. static const std::string US_PROPKEY_CLASS; // Class Name of this Object /** * \brief Connects this device. A connected device is ready to deliver images (i.e. be Activated). A Connected Device can be active. A disconnected Device cannot be active. * Internally calls onConnect and then registers the device with the service. A device usually should * override the OnConnection() method, but never the Connect() method, since this will possibly exclude the device * from normal service management. The exact flow of events is: * 0. Check if the device is already connected. If yes, return true anyway, but don't do anything. * 1. Call OnConnection() Here, a device should establish it's connection with the hardware Afterwards, it should be ready to start transmitting images at any time. * 2. If OnConnection() returns true ("successful"), then the device is registered with the service. * 3. if not, it the method itself returns false or may throw an expection, depeneding on the device implementation. * */ bool Connect(); /** * \brief Works analogously to mitk::USDevice::Connect(). Don't override this Method, but onDisconnection instead. */ bool Disconnect(); /** * \brief Activates this device. After the activation process, the device will start to produce images. This Method will fail, if the device is not connected. */ bool Activate(); /** * \brief Deactivates this device. After the deactivation process, the device will no longer produce images, but still be connected. */ void Deactivate(); /** * \brief Add a probe to the device without connecting to it. * This should usually be done before connecting to the probe. */ virtual void AddProbe(mitk::USProbe::Pointer probe); /** * \brief Connect to a probe and activate it. The probe should be added first. * Usually, a VideoDevice will simply add a probe it wants to connect to, * but an SDK Device might require adding a probe first. */ virtual void ActivateProbe(mitk::USProbe::Pointer probe); /** * \brief Deactivates the currently active probe. */ virtual void DeactivateProbe(); /** * \brief Removes a probe from the ist of currently added probes. */ //virtual void removeProbe(mitk::USProbe::Pointer probe); /** * \brief Returns a vector containing all connected probes. */ std::vector GetConnectedProbes(); /** *\brief return the output (output with id 0) of the filter */ USImage* GetOutput(void); /** *\brief return the output with id idx of the filter */ USImage* GetOutput(unsigned int idx); /** *\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); /** * \brief Make a DataObject of the correct type to used as the specified output. * * This method is automatically called when DataObject::DisconnectPipeline() * is called. DataObject::DisconnectPipeline, disconnects a data object * from being an output of its current source. When the data object * is disconnected, the ProcessObject needs to construct a replacement * output data object so that the ProcessObject is in a valid state. * Subclasses of USImageVideoSource that have outputs of different * data types must overwrite this method so that proper output objects * are created. */ virtual DataObjectPointer MakeOutput(unsigned int idx); //########### GETTER & SETTER ##################// /** * \brief Returns the Class of the Device. This Method must be reimplemented by every Inheriting Class. */ virtual std::string GetDeviceClass() = 0; /** * \brief True, if the device is currently generating image data, false otherwise. */ bool GetIsActive(); /** * \brief True, if the device is currently ready to start transmitting image data or is already * transmitting image data. A disconnected device cannot be activated. */ bool GetIsConnected(); /** * \brief Sets a transformation as Calibration data. It also marks the device as Calibrated. This data is not automatically applied to the image. Subclasses must call ApplyTransformation * to achieve this. */ void setCalibration (mitk::AffineTransform3D::Pointer calibration); /** * \brief Returns the current Calibration */ itkGetMacro(Calibration, mitk::AffineTransform3D::Pointer); /** * \brief Returns the currently active probe or null, if none is active */ itkGetMacro(ActiveProbe, mitk::USProbe::Pointer); + /* @return Returns the area that will be cropped from the US image. Is disabled / [0,0,0,0] by default. */ + mitk::USDevice::USImageCropArea GetCropArea(); + std::string GetDeviceManufacturer(); std::string GetDeviceModel(); std::string GetDeviceComment(); protected: mitk::USProbe::Pointer m_ActiveProbe; std::vector m_ConnectedProbes; bool m_IsActive; + bool m_IsConnected; + + /* @brief defines the area that should be cropped from the US image */ + USImageCropArea m_CropArea; /* * \brief This Method constructs the service properties which can later be used to * register the object with the Microservices * Return service properties */ mitk::ServiceProperties ConstructServiceProperties(); /** * \brief Is called during the connection process. Override this method in your subclass to handle the actual connection. * Return true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ virtual bool OnConnection() = 0; /** * \brief Is called during the disconnection process. Override this method in your subclass to handle the actual disconnection. * Return true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ virtual bool OnDisconnection() = 0; /** * \brief Is called during the activation process. After this method is finished, the device should be generating images */ virtual bool OnActivation() = 0; /** * \brief Is called during the deactivation process. After a call to this method the device should still be connected, but not producing images anymore. */ virtual void OnDeactivation() = 0; /** * \brief This metadata set is privately used to imprint USImages with Metadata later. * At instantiation time, it only contains Information about the Device, * At scan time, it integrates this data with the probe information and imprints it on * the produced images. This field is intentionally hidden from outside interference. */ mitk::USImageMetadata::Pointer m_Metadata; /** * \brief Enforces minimal Metadata to be set. */ USDevice(std::string manufacturer, std::string model); /** * \brief Constructs a device with the given Metadata. Make sure the Metadata contains meaningful content! */ USDevice(mitk::USImageMetadata::Pointer metadata); virtual ~USDevice(); /** * \brief Grabs the next frame from the Video input. This method is called internally, whenever Update() is invoked by an Output. */ void GenerateData() = 0; /** * \brief The Calibration Transformation of this US-Device. This will automatically be written into the image once */ mitk::AffineTransform3D::Pointer m_Calibration; /** * \brief Convenience method that can be used by subclasses to apply the Calibration Data to the image. A subclass has to call * this method or set the transformation itself for the output to be calibrated! Returns true if a Calibration was set and false otherwise * (Usually happens when no transformation was set yet). */ bool ApplyCalibration(mitk::USImage::Pointer image); private: /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ mitk::ServiceRegistration m_ServiceRegistration; }; } // namespace mitk // This is the microservice declaration. Do not meddle! US_DECLARE_SERVICE_INTERFACE(mitk::USDevice, "org.mitk.services.UltrasoundDevice") #endif \ No newline at end of file diff --git a/Modules/US/USModel/mitkUSVideoDevice.cpp b/Modules/US/USModel/mitkUSVideoDevice.cpp index 5729d2004f..7cbe2e126b 100644 --- a/Modules/US/USModel/mitkUSVideoDevice.cpp +++ b/Modules/US/USModel/mitkUSVideoDevice.cpp @@ -1,135 +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 "mitkUSVideoDevice.h" mitk::USVideoDevice::USVideoDevice(int videoDeviceNumber, std::string manufacturer, std::string model) : mitk::USDevice(manufacturer, model) { Init(); m_SourceIsFile = false; m_DeviceID = videoDeviceNumber; + m_FilePath = ""; } mitk::USVideoDevice::USVideoDevice(std::string videoFilePath, std::string manufacturer, std::string model) : mitk::USDevice(manufacturer, model) { Init(); m_SourceIsFile = true; m_FilePath = videoFilePath; } mitk::USVideoDevice::USVideoDevice(int videoDeviceNumber, mitk::USImageMetadata::Pointer metadata) : mitk::USDevice(metadata) { Init(); m_SourceIsFile = false; m_DeviceID = videoDeviceNumber; + m_FilePath = ""; } mitk::USVideoDevice::USVideoDevice(std::string videoFilePath, mitk::USImageMetadata::Pointer metadata) : mitk::USDevice(metadata) { Init(); m_SourceIsFile = true; m_FilePath = videoFilePath; } mitk::USVideoDevice::~USVideoDevice() { } void mitk::USVideoDevice::Init() { m_Source = mitk::USImageVideoSource::New(); //this->SetNumberOfInputs(1); this->SetNumberOfOutputs(1); // mitk::USImage::Pointer output = mitk::USImage::New(); // output->Initialize(); this->SetNthOutput(0, this->MakeOutput(0)); this->m_MultiThreader = itk::MultiThreader::New(); this->m_ImageMutex = itk::FastMutexLock::New(); this->m_CameraActiveMutex= itk::FastMutexLock::New(); m_IsActive = false; } std::string mitk::USVideoDevice::GetDeviceClass(){ return "org.mitk.modules.us.USVideoDevice"; } bool mitk::USVideoDevice::OnConnection() { if (m_SourceIsFile){ m_Source->SetVideoFileInput(m_FilePath); } else { m_Source->SetCameraInput(m_DeviceID); } + SetSourceCropArea(); return true; } bool mitk::USVideoDevice::OnDisconnection() { if (m_IsActive) this->Deactivate(); return true; } bool mitk::USVideoDevice::OnActivation() { MITK_INFO << "Activated UsVideoDevice!"; this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); return true; } void mitk::USVideoDevice::OnDeactivation() { // happens automatically when m_Active is set to false } void mitk::USVideoDevice::GenerateData() { mitk::USImage::Pointer result; result = m_Image; // Set Metadata result->SetMetadata(this->m_Metadata); //Apply Transformation this->ApplyCalibration(result); // Set Output this->SetNthOutput(0, result); } void mitk::USVideoDevice::GrabImage() { m_Image = m_Source->GetNextImage(); //this->SetNthOutput(0, m_Image); //this->Modified(); } +void mitk::USVideoDevice::SetSourceCropArea() +{ +if (this->m_Source.IsNotNull()) + { + if((m_CropArea.cropBottom==0)&& + (m_CropArea.cropTop==0)&& + (m_CropArea.cropLeft==0)&& + (m_CropArea.cropRight==0)) + {this->m_Source->RemoveRegionOfInterest();} + else + { + int right = m_Source->GetImageWidth() - m_CropArea.cropRight; + int bottom = m_Source->GetImageHeight() - m_CropArea.cropBottom; + this->m_Source->SetRegionOfInterest(m_CropArea.cropLeft, + m_CropArea.cropTop, + right, + bottom); + } + + } +else + {MITK_WARN << "Cannot set crop are, source is not initialized!";} + +} + +void mitk::USVideoDevice::SetCropArea(mitk::USDevice::USImageCropArea newArea) +{ +m_CropArea = newArea; +MITK_INFO << "Set Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; +if (m_IsConnected) SetSourceCropArea(); +} + ITK_THREAD_RETURN_TYPE mitk::USVideoDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USVideoDevice * device = (mitk::USVideoDevice *) pInfo->UserData; while (device->GetIsActive()) { device->GrabImage(); } return ITK_THREAD_RETURN_VALUE; } diff --git a/Modules/US/USModel/mitkUSVideoDevice.h b/Modules/US/USModel/mitkUSVideoDevice.h index c04e13e1a4..fa7ef2f703 100644 --- a/Modules/US/USModel/mitkUSVideoDevice.h +++ b/Modules/US/USModel/mitkUSVideoDevice.h @@ -1,148 +1,154 @@ /*=================================================================== 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 MITKUSVideoDevice_H_HEADER_INCLUDED_ #define MITKUSVideoDevice_H_HEADER_INCLUDED_ #include #include #include "mitkUSDevice.h" #include #include "mitkUSImageVideoSource.h" namespace mitk { /**Documentation * \brief A VideoDevice is the common class for video only devices. They capture Video Input either from * a file or from a device, and transform the output into an mitkUSImage with attached Metadata. * This simple implementation does only capture and display 2D Images without cropping or registration. * One can simply inherit from this class and overwrite the handle2D and handle 3Dmethods to get full access to the data * \ingroup US */ class MitkUS_EXPORT USVideoDevice : public mitk::USDevice { public: mitkClassMacro(USVideoDevice, mitk::USDevice); // To open a device (DeviceID, Manufacturer, Model) mitkNewMacro3Param(Self, int, std::string, std::string); // To open A VideoFile (Path, Manufacturer, Model) mitkNewMacro3Param(Self, std::string, std::string, std::string); // To open a device (DeviceID, Metadata) mitkNewMacro2Param(Self, int, mitk::USImageMetadata::Pointer); // To open A VideoFile (Path, Metadata) mitkNewMacro2Param(Self, std::string, mitk::USImageMetadata::Pointer); + /*@brief Sets the area that will be cropped from the US image. Set [0,0,0,0] to disable it, which is also default. */ + void SetCropArea(mitk::USDevice::USImageCropArea newArea); /** * \brief Returns the qualified name of this class. Be sure to override this when inheriting from VideoDevice! */ virtual std::string GetDeviceClass(); void GenerateData(); itkGetMacro(Source, mitk::USImageVideoSource::Pointer); itkGetMacro(Image, mitk::USImage::Pointer); + itkGetMacro(DeviceID,int); + itkGetMacro(FilePath,std::string); void GrabImage(); protected: static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); /** * \brief Creates a new device that will deliver USImages taken from a video device. * under windows, try -1 for device number, which will grab the first available one * (Open CV functionality) */ USVideoDevice(int videoDeviceNumber, std::string manufacturer, std::string model); /** * \brief Creates a new device that will deliver USImages taken from a video file. */ USVideoDevice(std::string videoFilePath, std::string manufacturer, std::string model); /** * \brief Creates a new device that will deliver USImages taken from a video device. * under windows, try -1 for device number, which will grab the first available one * (Open CV functionality) */ USVideoDevice(int videoDeviceNumber, mitk::USImageMetadata::Pointer metadata); /** * \brief Creates a new device that will deliver USImages taken from a video file. */ USVideoDevice(std::string videoFilePath, mitk::USImageMetadata::Pointer metadata); virtual ~USVideoDevice(); /** * \brief Initializes common properties for all constructors. */ void Init(); /** * \brief Is called during the connection process. * Returns true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ virtual bool OnConnection(); /** * \brief Is called during the disconnection process. * Returns true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ virtual bool OnDisconnection(); /** * \brief Is called during the activation process. After this method is finsihed, the device should be generating images */ virtual bool OnActivation(); /** * \brief Is called during the deactivation process. After a call to this method the device should still be connected, but not producing images anymore. */ virtual void OnDeactivation(); /** * \brief The image source that we use to aquire data */ mitk::USImageVideoSource::Pointer m_Source; /** * \brief True, if this source plays back a file, false if it recieves data from a device */ bool m_SourceIsFile; /** * \brief The device id to connect to. Undefined, if m_SourceIsFile == true; */ int m_DeviceID; /** * \brief The Filepath id to connect to. Undefined, if m_SourceIsFile == false; */ std::string m_FilePath; + void SetSourceCropArea(); + // Threading-Related itk::MultiThreader::Pointer m_MultiThreader; ///< itk::MultiThreader used for thread handling itk::FastMutexLock::Pointer m_ImageMutex; ///< mutex for images provided by the range camera itk::FastMutexLock::Pointer m_CameraActiveMutex; ///< mutex for the cameraActive flag int m_ThreadID; ///< ID of the started thread mitk::USImage::Pointer m_Image; }; } // namespace mitk #endif diff --git a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.cpp b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.cpp index 527a551ae0..69eef55116 100644 --- a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.cpp @@ -1,101 +1,116 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //#define _USE_MATH_DEFINES #include +#include +#include const std::string QmitkUSDeviceManagerWidget::VIEW_ID = "org.mitk.views.QmitkUSDeviceManagerWidget"; QmitkUSDeviceManagerWidget::QmitkUSDeviceManagerWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { m_Controls = NULL; CreateQtPartControl(this); } QmitkUSDeviceManagerWidget::~QmitkUSDeviceManagerWidget() { } //////////////////// INITIALIZATION ///////////////////// void QmitkUSDeviceManagerWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkUSDeviceManagerWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } // Initializations std::string empty = ""; m_Controls->m_ConnectedDevices->Initialize(mitk::USDevice::US_PROPKEY_LABEL, empty); } void QmitkUSDeviceManagerWidget::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_BtnActivate, SIGNAL( clicked() ), this, SLOT(OnClickedActivateDevice()) ); connect( m_Controls->m_BtnDisconnect, SIGNAL( clicked() ), this, SLOT(OnClickedDisconnectDevice()) ); connect( m_Controls->m_ConnectedDevices, SIGNAL( ServiceSelectionChanged(mitk::ServiceReference) ), this, SLOT(OnDeviceSelectionChanged(mitk::ServiceReference)) ); } } ///////////// Methods & Slots Handling Direct Interaction ///////////////// void QmitkUSDeviceManagerWidget::OnClickedActivateDevice() { mitk::USDevice::Pointer device = m_Controls->m_ConnectedDevices->GetSelectedService(); if (device.IsNull()) return; if (device->GetIsActive()) device->Deactivate(); else device->Activate(); // Manually reevaluate Button logic OnDeviceSelectionChanged(m_Controls->m_ConnectedDevices->GetSelectedServiceReference()); } void QmitkUSDeviceManagerWidget::OnClickedDisconnectDevice(){ mitk::USDevice::Pointer device = m_Controls->m_ConnectedDevices->GetSelectedService(); if (device.IsNull()) return; device->Disconnect(); } void QmitkUSDeviceManagerWidget::OnDeviceSelectionChanged(mitk::ServiceReference reference){ if (! reference) { m_Controls->m_BtnActivate->setEnabled(false); m_Controls->m_BtnDisconnect->setEnabled(false); return; } std::string isActive = reference.GetProperty( mitk::USDevice::US_PROPKEY_ISACTIVE ).ToString(); if (isActive.compare("true") == 0) { m_Controls->m_BtnActivate->setEnabled(true); m_Controls->m_BtnDisconnect->setEnabled(false); m_Controls->m_BtnActivate->setText("Deactivate"); } else { m_Controls->m_BtnActivate->setEnabled(true); m_Controls->m_BtnDisconnect->setEnabled(true); m_Controls->m_BtnActivate->setText("Activate"); } } +void QmitkUSDeviceManagerWidget::DisconnectAllDevices() +{ +//at the moment disconnects ALL devices. Maybe we only want to disconnect the devices handled by this widget? +mitk::ModuleContext* thisContext = mitk::GetModuleContext(); +std::list services = thisContext->GetServiceReferences(); +for(std::list::iterator it = services.begin(); it != services.end(); ++it) + { + mitk::USDevice::Pointer currentDevice = thisContext->GetService(*it); + currentDevice->Disconnect(); + } +MITK_INFO << "Disconnected ALL US devises!"; +} + diff --git a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.h b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.h index 7eaaaea8be..90f6ab757f 100644 --- a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.h +++ b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.h @@ -1,85 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _QmitkUSDeviceManagerWidget_H_INCLUDED #define _QmitkUSDeviceManagerWidget_H_INCLUDED #include "MitkUSUIExports.h" #include "ui_QmitkUSDeviceManagerWidgetControls.h" #include "mitkUSDevice.h" #include //QT headers #include #include /** * @brief This Widget is used to manage available Ultrasound Devices. * * It allows activation, deactivation and disconnection of connected devices. * * @ingroup USUI */ class MitkUSUI_EXPORT QmitkUSDeviceManagerWidget :public QWidget { //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkUSDeviceManagerWidget(QWidget* p = 0, Qt::WindowFlags f1 = 0); virtual ~QmitkUSDeviceManagerWidget(); /* @brief This method is part of the widget an needs not to be called seperately. */ virtual void CreateQtPartControl(QWidget *parent); /* @brief This method is part of the widget an needs not to be called seperately. (Creation of the connections of main and control widget.)*/ virtual void CreateConnections(); + /* @brief Disconnects all devices immediately. */ + virtual void DisconnectAllDevices(); public slots: protected slots: /* \brief Called, when the button "Activate Device" was clicked. */ void OnClickedActivateDevice(); /* \brief Called, when the button "Disconnect Device" was clicked. */ void OnClickedDisconnectDevice(); /* \brief Called, when the selection in the devicelist changes. */ void OnDeviceSelectionChanged(mitk::ServiceReference reference); protected: Ui::QmitkUSDeviceManagerWidgetControls* m_Controls; ///< member holding the UI elements of this widget private: }; #endif // _QmitkUSDeviceManagerWidget_H_INCLUDED diff --git a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp index dd66bcc330..738643af9a 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp @@ -1,162 +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. ===================================================================*/ //#define _USE_MATH_DEFINES #include //QT headers //mitk headers //itk headers const std::string QmitkUSNewVideoDeviceWidget::VIEW_ID = "org.mitk.views.QmitkUSNewVideoDeviceWidget"; QmitkUSNewVideoDeviceWidget::QmitkUSNewVideoDeviceWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { m_Controls = NULL; CreateQtPartControl(this); + + //disable a few UI components which are not needed at the moment + m_Controls->probe_label->setVisible(false); + m_Controls->probe_label2->setVisible(false); + m_Controls->zoom_label->setVisible(false); + m_Controls->m_Probe->setVisible(false); + m_Controls->m_Zoom->setVisible(false); } QmitkUSNewVideoDeviceWidget::~QmitkUSNewVideoDeviceWidget() { } //////////////////// INITIALIZATION ///////////////////// void QmitkUSNewVideoDeviceWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkUSNewVideoDeviceWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkUSNewVideoDeviceWidget::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedDone()) ); connect( m_Controls->m_BtnCancel, SIGNAL(clicked()), this, SLOT(OnClickedCancel()) ); connect( m_Controls->m_RadioDeviceSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection()) ); connect( m_Controls->m_RadioFileSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection()) ); } // Hide & show stuff m_Controls->m_FilePathSelector->setVisible(false); } ///////////// Methods & Slots Handling Direct Interaction ///////////////// void QmitkUSNewVideoDeviceWidget::OnClickedDone(){ m_Active = false; // Assemble Metadata mitk::USImageMetadata::Pointer metadata = mitk::USImageMetadata::New(); metadata->SetDeviceComment(m_Controls->m_Comment->text().toStdString()); metadata->SetDeviceModel(m_Controls->m_Model->text().toStdString()); metadata->SetDeviceManufacturer(m_Controls->m_Manufacturer->text().toStdString()); metadata->SetProbeName(m_Controls->m_Probe->text().toStdString()); metadata->SetZoom(m_Controls->m_Zoom->text().toStdString()); // Create Device mitk::USVideoDevice::Pointer newDevice; if (m_Controls->m_RadioDeviceSource->isChecked()){ int deviceID = m_Controls->m_DeviceSelector->value(); newDevice = mitk::USVideoDevice::New(deviceID, metadata); } else { std::string filepath = m_Controls->m_FilePathSelector->text().toStdString(); newDevice = mitk::USVideoDevice::New(filepath, metadata); } // Set Video Options newDevice->GetSource()->SetColorOutput(! m_Controls->m_CheckGreyscale->isChecked()); // If Resolution override is activated, apply it if (m_Controls->m_CheckResolutionOverride->isChecked()) { int width = m_Controls->m_ResolutionWidth->value(); int height = m_Controls->m_ResolutionHeight->value(); newDevice->GetSource()->OverrideResolution(width, height); newDevice->GetSource()->SetResolutionOverride(true); } newDevice->Connect(); emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnClickedCancel(){ m_TargetDevice = 0; m_Active = false; emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnDeviceTypeSelection(){ m_Controls->m_FilePathSelector->setVisible(m_Controls->m_RadioFileSource->isChecked()); m_Controls->m_DeviceSelector->setVisible(m_Controls->m_RadioDeviceSource->isChecked()); } ///////////////// Methods & Slots Handling Logic ////////////////////////// void QmitkUSNewVideoDeviceWidget::EditDevice(mitk::USDevice::Pointer device) { // If no VideoDevice is given, throw an exception if (device->GetDeviceClass().compare("org.mitk.modules.us.USVideoDevice") != 0){ // TODO Alert if bad path - mitkThrow() << "NewVideoDevcieWidget recieved an incompatible Device Type to edit. Devicetype was: " << device->GetDeviceClass(); + mitkThrow() << "NewVideoDeviceWidget recieved an incompatible Device Type to edit. Devicetype was: " << device->GetDeviceClass(); } m_TargetDevice = static_cast (device.GetPointer()); m_Active = true; } void QmitkUSNewVideoDeviceWidget::CreateNewDevice() { m_TargetDevice = 0; InitFields(mitk::USImageMetadata::New()); m_Active = true; } /////////////////////// HOUSEHOLDING CODE /////////////////////////////// QListWidgetItem* QmitkUSNewVideoDeviceWidget::ConstructItemFromDevice(mitk::USDevice::Pointer device){ QListWidgetItem *result = new QListWidgetItem; std::string text = device->GetDeviceManufacturer() + "|" + device->GetDeviceModel(); result->setText(text.c_str()); return result; } void QmitkUSNewVideoDeviceWidget::InitFields(mitk::USImageMetadata::Pointer metadata){ this->m_Controls->m_Manufacturer->setText (metadata->GetDeviceManufacturer().c_str()); this->m_Controls->m_Model->setText (metadata->GetDeviceModel().c_str()); this->m_Controls->m_Comment->setText (metadata->GetDeviceComment().c_str()); this->m_Controls->m_Probe->setText (metadata->GetProbeName().c_str()); this->m_Controls->m_Zoom->setText (metadata->GetZoom().c_str()); } diff --git a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidgetControls.ui b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidgetControls.ui index d9458881a4..9e0e6663a0 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidgetControls.ui +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidgetControls.ui @@ -1,292 +1,292 @@ QmitkUSNewVideoDeviceWidgetControls 0 0 405 - 569 + 595 0 0 QmitkUSNewVideoDeviceWidget Metadata: 50 false true Device Information: Manufacturer Model Comment - + true Probe Information: - + Probe - + Zoom - GroupBox: + Video Source: -1 10 -1 From Device: true From File: Cancel Override: If you encounter problems with devices (e.g. Images of uniform color and error messages in the log window), then try to set the resolution externally using the device's driver panel and then enter the same resolution here. true Enable Resolution Override 10 2048 10 640 10 2048 10 480 Width: Height: Qt::Vertical 20 40 Add Device Video Options: Greyscale Image (Significantly faster) true m_Manufacturer m_Model m_Comment m_Probe m_Zoom m_RadioDeviceSource m_DeviceSelector m_RadioFileSource m_FilePathSelector m_BtnCancel m_CheckResolutionOverride m_ResolutionWidth m_ResolutionHeight diff --git a/Modules/USUI/Qmitk/mitkUSDevicePersistence.cpp b/Modules/USUI/Qmitk/mitkUSDevicePersistence.cpp new file mode 100644 index 0000000000..fae0a09fe9 --- /dev/null +++ b/Modules/USUI/Qmitk/mitkUSDevicePersistence.cpp @@ -0,0 +1,186 @@ +/*=================================================================== + +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 "mitkUSDevicePersistence.h" + +//Microservices +#include "usServiceReference.h" +#include "usModuleContext.h" +#include +#include + + +mitk::USDevicePersistence::USDevicePersistence() : m_devices("MITK US","Device Settings") + { + } + +void mitk::USDevicePersistence::StoreCurrentDevices() + { + mitk::ModuleContext* thisContext = mitk::GetModuleContext(); + + std::list services = thisContext->GetServiceReferences(); + MITK_INFO << "Trying to save " << services.size() << " US devices."; + int numberOfSavedDevices = 0; + for(std::list::iterator it = services.begin(); it != services.end(); ++it) + { + mitk::USDevice::Pointer currentDevice = thisContext->GetService(*it); + //check if it is a USVideoDevice + if (currentDevice->GetDeviceClass()=="org.mitk.modules.us.USVideoDevice") + { + mitk::USVideoDevice::Pointer currentVideoDevice = dynamic_cast(currentDevice.GetPointer()); + QString identifier = "device" + QString::number(numberOfSavedDevices); + m_devices.setValue(identifier,USVideoDeviceToString(currentVideoDevice)); + numberOfSavedDevices++; + } + + else + { + MITK_WARN << "Saving of US devices of the type " << currentDevice->GetDeviceClass() << " is not supported at the moment. Skipping device."; + } + } + m_devices.setValue("numberOfSavedDevices",numberOfSavedDevices); + MITK_INFO << "Successfully saved " << numberOfSavedDevices << " US devices."; + } + +void mitk::USDevicePersistence::RestoreLastDevices() + { + int numberOfSavedDevices = m_devices.value("numberOfSavedDevices").toInt(); + + for(int i=0; iConnect(); + } + + MITK_INFO << "Restoring " << numberOfSavedDevices << " US devices."; + } + +QString mitk::USDevicePersistence::USVideoDeviceToString(mitk::USVideoDevice::Pointer d) +{ + +QString manufacturer = d->GetDeviceManufacturer().c_str(); +QString model = d->GetDeviceModel().c_str(); +QString comment = d->GetDeviceComment().c_str(); +int source = d->GetDeviceID(); +std::string file = d->GetFilePath(); +if (file == "") file = "none"; +int greyscale = d->GetSource()->GetIsGreyscale(); +int resOverride = d->GetSource()->GetResolutionOverride(); +int resWidth = d->GetSource()->GetResolutionOverrideWidth(); +int resHight = d->GetSource()->GetResolutionOverrideHeight(); +int cropRight = d->GetCropArea().cropRight; +int cropLeft = d->GetCropArea().cropLeft; +int cropBottom = d->GetCropArea().cropBottom; +int cropTop = d->GetCropArea().cropTop; +char seperator = '|'; + +QString returnValue = manufacturer + seperator + + model + seperator + + comment + seperator + + QString::number(source) + seperator + + file.c_str() + seperator + + QString::number(greyscale) + seperator + + QString::number(resOverride) + seperator + + QString::number(resWidth) + seperator + + QString::number(resHight) + seperator + + QString::number(cropRight) + seperator + + QString::number(cropLeft) + seperator + + QString::number(cropBottom) + seperator + + QString::number(cropTop) + ; + +MITK_INFO << "Output String: " << returnValue.toStdString(); +return returnValue; +} + +mitk::USVideoDevice::Pointer mitk::USDevicePersistence::StringToUSVideoDevice(QString s) +{ +MITK_INFO << "Input String: " << s.toStdString(); +std::vector data; +std::string seperators = "|"; +std::string text = s.toStdString(); +split(text,seperators,data); +if(data.size() != 13) + { + MITK_ERROR << "Cannot parse US device! (Size: " << data.size() << ")"; + return mitk::USVideoDevice::New("INVALID","INVALID","INVALID"); + } + +std::string manufacturer = data.at(0); +std::string model = data.at(1); +std::string comment = data.at(2); +int source = (QString(data.at(3).c_str())).toInt(); +std::string file = data.at(4); +bool greyscale = (QString(data.at(5).c_str())).toInt(); +bool resOverride = (QString(data.at(6).c_str())).toInt(); +int resWidth = (QString(data.at(7).c_str())).toInt(); +int resHight = (QString(data.at(8).c_str())).toInt(); +mitk::USDevice::USImageCropArea cropArea; +cropArea.cropRight = (QString(data.at(9).c_str())).toInt(); +cropArea.cropLeft = (QString(data.at(10).c_str())).toInt(); +cropArea.cropBottom = (QString(data.at(11).c_str())).toInt(); +cropArea.cropTop = (QString(data.at(12).c_str())).toInt(); + +// Assemble Metadata +mitk::USImageMetadata::Pointer metadata = mitk::USImageMetadata::New(); +metadata->SetDeviceManufacturer(manufacturer); +metadata->SetDeviceComment(comment); +metadata->SetDeviceModel(model); +metadata->SetProbeName(""); +metadata->SetZoom(""); + +// Create Device +mitk::USVideoDevice::Pointer returnValue; +if (file == "none") + { + returnValue = mitk::USVideoDevice::New(source, metadata); + } +else + { + returnValue = mitk::USVideoDevice::New(file, metadata); + } + +// Set Video Options +returnValue->GetSource()->SetColorOutput(!greyscale); + +// If Resolution override is activated, apply it +if (resOverride) + { + returnValue->GetSource()->OverrideResolution(resWidth, resHight); + returnValue->GetSource()->SetResolutionOverride(true); + } + +// Set Crop Area +returnValue->SetCropArea(cropArea); + +return returnValue; +} + +void mitk::USDevicePersistence::split(std::string& text, std::string& separators, std::vector& words) + { + int n = text.length(); + int start, stop; + + start = text.find_first_not_of(separators); + while ((start >= 0) && (start < n)) + { + stop = text.find_first_of(separators, start); + if ((stop < 0) || (stop > n)) stop = n; + words.push_back(text.substr(start, stop - start)); + start = text.find_first_not_of(separators, stop+1); + } + } diff --git a/Modules/USUI/Qmitk/mitkUSDevicePersistence.h b/Modules/USUI/Qmitk/mitkUSDevicePersistence.h new file mode 100644 index 0000000000..eb6d757537 --- /dev/null +++ b/Modules/USUI/Qmitk/mitkUSDevicePersistence.h @@ -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. + +===================================================================*/ + + +#ifndef MITKUSDevicePersistence_H_HEADER_INCLUDED_ +#define MITKUSDevicePersistence_H_HEADER_INCLUDED_ + +// MITK +#include "MitkUSUIExports.h" +#include +#include + +// ITK +#include + +// QT + #include + + +namespace mitk { + + /**Documentation + * TODO + */ + + class MitkUSUI_EXPORT USDevicePersistence : public itk::Object + { + public: + mitkClassMacro(USDevicePersistence, itk::Object); + itkNewMacro(Self); + + void StoreCurrentDevices(); + + void RestoreLastDevices(); + + protected: + + USDevicePersistence(); + virtual ~USDevicePersistence(){} + + QString USVideoDeviceToString(mitk::USVideoDevice::Pointer d); + mitk::USVideoDevice::Pointer StringToUSVideoDevice(QString s); + + QSettings m_devices; + + void split(std::string& text, std::string& separators, std::vector& words); + + + }; +} // namespace mitk + + +#endif diff --git a/Modules/USUI/files.cmake b/Modules/USUI/files.cmake index 0747fcff17..9d8fd3d4e3 100644 --- a/Modules/USUI/files.cmake +++ b/Modules/USUI/files.cmake @@ -1,19 +1,20 @@ set(CPP_FILES Qmitk/QmitkUSDeviceManagerWidget.cpp Qmitk/QmitkUSNewVideoDeviceWidget.cpp + Qmitk/mitkUSDevicePersistence.cpp ) set(UI_FILES Qmitk/QmitkUSDeviceManagerWidgetControls.ui Qmitk/QmitkUSNewVideoDeviceWidgetControls.ui ) set(MOC_H_FILES Qmitk/QmitkUSDeviceManagerWidget.h Qmitk/QmitkUSNewVideoDeviceWidget.h ) # uncomment the following line if you want to use Qt resources set(QRC_FILES # resources/QmitkToFUtilWidget.qrc ) diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 2aaa7a7689..4e4182cfbb 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,46 +1,46 @@ # 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.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.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.dtiatlasapp:OFF org.mitk.gui.qt.examples:OFF org.mitk.gui.qt.examplesopencv:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.meshdecimation:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF - org.mitk.gui.qt.python.console:OFF + org.mitk.gui.qt.python:OFF org.mitk.gui.qt.registration:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.simulation: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 ) diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.cpp b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.cpp index 66a79ded25..4698874ace 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.cpp +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.cpp @@ -1,332 +1,336 @@ /*=================================================================== 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 #include #include #include #include #include #include "berryFileEditorInput.h" // Qmitk #include "QmitkDicomEditor.h" #include "mitkPluginActivator.h" #include //#include "mitkProgressBar.h" // Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include //CTK #include #include #include #include #include const std::string QmitkDicomEditor::EDITOR_ID = "org.mitk.editors.dicomeditor"; const QString QmitkDicomEditor::TEMP_DICOM_FOLDER_SUFFIX="TmpDicomFolder"; QmitkDicomEditor::QmitkDicomEditor() : m_Thread(new QThread()) , m_DicomDirectoryListener(new QmitkDicomDirectoryListener()) , m_StoreSCPLauncher(new QmitkStoreSCPLauncher(&m_Builder)) , m_Publisher(new QmitkDicomDataEventPublisher()) { } QmitkDicomEditor::~QmitkDicomEditor() { m_Thread.quit(); m_Thread.wait(1000); delete m_DicomDirectoryListener; delete m_StoreSCPLauncher; delete m_Handler; delete m_Publisher; delete m_ImportDialog; } void QmitkDicomEditor::CreateQtPartControl(QWidget *parent ) { m_Controls.setupUi( parent ); m_Controls.LocalStorageButton->setIcon(QIcon(":/org.mitk.gui.qt.dicom/drive-harddisk_32.png")); m_Controls.FolderButton->setIcon(QIcon(":/org.mitk.gui.qt.dicom/folder_32.png")); m_Controls.CDButton->setIcon(QIcon(":/org.mitk.gui.qt.dicom/media-optical_32.png")); m_Controls.QueryRetrieveButton->setIcon(QIcon(":/org.mitk.gui.qt.dicom/network-workgroup_32.png")); m_Controls.StoreSCPStatusLabel->setTextFormat(Qt::RichText); m_Controls.StoreSCPStatusLabel->setText(""); TestHandler(); SetPluginDirectory(); SetDatabaseDirectory("DatabaseDirectory"); CreateTemporaryDirectory(); StartDicomDirectoryListener(); SetupImportDialog(); SetupProgressDialog(parent); m_Controls.m_ctkDICOMQueryRetrieveWidget->useProgressDialog(false); connect(m_Controls.externalDataWidget,SIGNAL(SignalStartDicomImport(const QStringList&)),m_Controls.internalDataWidget,SLOT(OnStartDicomImport(const QStringList&))); connect(m_Controls.externalDataWidget,SIGNAL(SignalDicomToDataManager(QHash)),this,SLOT(OnViewButtonAddToDataManager(QHash))); connect(m_Controls.externalDataWidget,SIGNAL(SignalChangePage(int)), this, SLOT(OnChangePage(int))); connect(m_Controls.internalDataWidget,SIGNAL(SignalFinishedImport()),this,SLOT(OnDicomImportFinished())); connect(m_Controls.internalDataWidget,SIGNAL(SignalDicomToDataManager(QHash)),this,SLOT(OnViewButtonAddToDataManager(QHash))); connect(m_Controls.CDButton, SIGNAL(clicked()), this, SLOT(OnFolderCDImport())); connect(m_Controls.FolderButton, SIGNAL(clicked()), this, SLOT(OnFolderCDImport())); connect(m_Controls.QueryRetrieveButton, SIGNAL(clicked()), this, SLOT(OnQueryRetrieve())); connect(m_Controls.LocalStorageButton, SIGNAL(clicked()), this, SLOT(OnLocalStorage())); } void QmitkDicomEditor::SetupProgressDialog(QWidget* parent) { m_ProgressDialog = new QProgressDialog("DICOM Import", "Cancel", 0, 100, parent,Qt::WindowTitleHint | Qt::WindowSystemMenuHint); m_ProgressDialogLabel = new QLabel(tr("Initialization...")); m_ProgressDialog->setLabel(m_ProgressDialogLabel); #ifdef Q_WS_MAC // BUG: avoid deadlock of dialogs on mac m_ProgressDialog->setWindowModality(Qt::NonModal); #else m_ProgressDialog->setWindowModality(Qt::ApplicationModal); #endif connect(m_ProgressDialog, SIGNAL(canceled()), m_Controls.internalDataWidget, SIGNAL(SignalCancelImport())); connect(m_Controls.internalDataWidget, SIGNAL(SignalProcessingFile(QString)),m_ProgressDialogLabel, SLOT(setText(QString))); connect(m_Controls.internalDataWidget, SIGNAL(SignalProgress(int)),m_ProgressDialog, SLOT(setValue(int))); connect(m_Controls.internalDataWidget, SIGNAL(SignalProgress(int)),this, SLOT(OnImportProgress(int))); + connect(m_Controls.internalDataWidget, SIGNAL(SignalFinishedImport()),this, SLOT(OnDicomImportFinished())); connect(m_ProgressDialog, SIGNAL(canceled()), m_Controls.externalDataWidget, SIGNAL(SignalCancelImport())); connect(m_Controls.externalDataWidget, SIGNAL(SignalProcessingFile(QString)),m_ProgressDialogLabel, SLOT(setText(QString))); connect(m_Controls.externalDataWidget, SIGNAL(SignalProgress(int)),m_ProgressDialog, SLOT(setValue(int))); connect(m_Controls.externalDataWidget, SIGNAL(SignalProgress(int)),this, SLOT(OnImportProgress(int))); + connect(m_Controls.externalDataWidget, SIGNAL(SignalFinishedImport()),this, SLOT(OnDicomImportFinished())); + } void QmitkDicomEditor::SetupImportDialog() { //Initialize import widget m_ImportDialog = new ctkFileDialog(); QCheckBox* importCheckbox = new QCheckBox("Copy on import", m_ImportDialog); m_ImportDialog->setBottomWidget(importCheckbox); m_ImportDialog->setFileMode(QFileDialog::Directory); m_ImportDialog->setLabelText(QFileDialog::Accept,"Import"); m_ImportDialog->setWindowTitle("Import DICOM files from directory ..."); m_ImportDialog->setWindowModality(Qt::ApplicationModal); connect(m_ImportDialog, SIGNAL(fileSelected(QString)),this,SLOT(OnFileSelected(QString))); } void QmitkDicomEditor::OnImportProgress(int progress) { Q_UNUSED(progress); QApplication::processEvents(); } void QmitkDicomEditor::Init(berry::IEditorSite::Pointer site, berry::IEditorInput::Pointer input) { this->SetSite(site); this->SetInput(input); } void QmitkDicomEditor::SetFocus() { } berry::IPartListener::Events::Types QmitkDicomEditor::GetPartEventTypes() const { return Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void QmitkDicomEditor::OnQueryRetrieve() { OnChangePage(2); QString storagePort = m_Controls.m_ctkDICOMQueryRetrieveWidget->getServerParameters()["StoragePort"].toString(); QString storageAET = m_Controls.m_ctkDICOMQueryRetrieveWidget->getServerParameters()["StorageAETitle"].toString(); if(!((m_Builder.GetAETitle()->compare(storageAET,Qt::CaseSensitive)==0)&& (m_Builder.GetPort()->compare(storagePort,Qt::CaseSensitive)==0))) { StopStoreSCP(); StartStoreSCP(); } } void QmitkDicomEditor::OnFileSelected(QString directory) { if (QDir(directory).exists()) { QCheckBox* copyOnImport = qobject_cast(m_ImportDialog->bottomWidget()); if (copyOnImport->isChecked()) { connect(this,SIGNAL(SignalStartDicomImport(const QString&)),m_Controls.internalDataWidget,SLOT(OnStartDicomImport(const QString&))); disconnect(this,SIGNAL(SignalStartDicomImport(const QString&)),m_Controls.externalDataWidget,SLOT(OnStartDicomImport(const QString&))); OnChangePage(0); } else { disconnect(this,SIGNAL(SignalStartDicomImport(const QString&)),m_Controls.internalDataWidget,SLOT(OnStartDicomImport(const QString&))); connect(this,SIGNAL(SignalStartDicomImport(const QString&)),m_Controls.externalDataWidget,SLOT(OnStartDicomImport(const QString&))); OnChangePage(1); } m_ProgressDialog->setMinimumDuration(0); m_ProgressDialog->setValue(0); m_ProgressDialog->show(); emit SignalStartDicomImport(directory); } } void QmitkDicomEditor::OnFolderCDImport() { m_ImportDialog->show(); m_ImportDialog->raise(); } void QmitkDicomEditor::OnLocalStorage() { OnChangePage(0); } void QmitkDicomEditor::OnChangePage(int page) { try{ m_Controls.stackedWidget->setCurrentIndex(page); }catch(std::exception e){ MITK_ERROR <<"error: "<< e.what(); return; } } void QmitkDicomEditor::OnDicomImportFinished() { + m_ProgressDialog->close(); } void QmitkDicomEditor::StartDicomDirectoryListener() { if(!m_Thread.isRunning()) { m_DicomDirectoryListener->SetDicomListenerDirectory(m_TempDirectory); m_DicomDirectoryListener->SetDicomFolderSuffix(TEMP_DICOM_FOLDER_SUFFIX); connect(m_DicomDirectoryListener,SIGNAL(SignalStartDicomImport(const QStringList&)),m_Controls.internalDataWidget,SLOT(OnStartDicomImport(const QStringList&)),Qt::DirectConnection); //connect(m_Controls.internalDataWidget,SIGNAL(SignalFinishedImport()),m_DicomDirectoryListener,SLOT(OnImportFinished()),Qt::DirectConnection); m_DicomDirectoryListener->moveToThread(&m_Thread); m_Thread.start(); } } void QmitkDicomEditor::TestHandler() { m_Handler = new DicomEventHandler(); m_Handler->SubscribeSlots(); } void QmitkDicomEditor::OnViewButtonAddToDataManager(QHash eventProperties) { ctkDictionary properties; properties["PatientName"] = eventProperties["PatientName"]; properties["StudyUID"] = eventProperties["StudyUID"]; properties["StudyName"] = eventProperties["StudyName"]; properties["SeriesUID"] = eventProperties["SeriesUID"]; properties["SeriesName"] = eventProperties["SeriesName"]; properties["FilesForSeries"] = eventProperties["FilesForSeries"]; m_Publisher->PublishSignals(mitk::PluginActivator::getContext()); m_Publisher->AddSeriesToDataManagerEvent(properties); } void QmitkDicomEditor::StartStoreSCP() { QString storagePort = m_Controls.m_ctkDICOMQueryRetrieveWidget->getServerParameters()["StoragePort"].toString(); QString storageAET = m_Controls.m_ctkDICOMQueryRetrieveWidget->getServerParameters()["StorageAETitle"].toString(); m_Builder.AddPort(storagePort)->AddAETitle(storageAET)->AddTransferSyntax()->AddOtherNetworkOptions()->AddMode()->AddOutputDirectory(m_TempDirectory); m_StoreSCPLauncher = new QmitkStoreSCPLauncher(&m_Builder); connect(m_StoreSCPLauncher, SIGNAL(SignalStatusOfStoreSCP(const QString&)), this, SLOT(OnStoreSCPStatusChanged(const QString&))); connect(m_StoreSCPLauncher ,SIGNAL(SignalStartImport(const QStringList&)),m_Controls.internalDataWidget,SLOT(OnStartDicomImport(const QStringList&))); connect(m_StoreSCPLauncher ,SIGNAL(SignalStoreSCPError(const QString&)),m_Controls.internalDataWidget,SLOT(SignalCancelImport())); connect(m_StoreSCPLauncher ,SIGNAL(SignalStoreSCPError(const QString&)),m_DicomDirectoryListener,SLOT(OnDicomNetworkError(const QString&)),Qt::DirectConnection); connect(m_StoreSCPLauncher ,SIGNAL(SignalStoreSCPError(const QString&)),this,SLOT(OnDicomNetworkError(const QString&)),Qt::DirectConnection); m_StoreSCPLauncher->StartStoreSCP(); } void QmitkDicomEditor::OnStoreSCPStatusChanged(const QString& status) { m_Controls.StoreSCPStatusLabel->setText(" "+status); } void QmitkDicomEditor::OnDicomNetworkError(const QString& status) { m_Controls.StoreSCPStatusLabel->setText(" "+status); } void QmitkDicomEditor::StopStoreSCP() { delete m_StoreSCPLauncher; } void QmitkDicomEditor::SetPluginDirectory() { m_PluginDirectory = mitk::PluginActivator::getContext()->getDataFile("").absolutePath(); m_PluginDirectory.append("/"); } void QmitkDicomEditor::SetDatabaseDirectory(const QString& databaseDirectory) { m_DatabaseDirectory.clear(); m_DatabaseDirectory.append(m_PluginDirectory); m_DatabaseDirectory.append(databaseDirectory); m_Controls.internalDataWidget->SetDatabaseDirectory(m_DatabaseDirectory); } void QmitkDicomEditor::CreateTemporaryDirectory() { QDir tmp; QString tmpPath = QDir::tempPath(); m_TempDirectory.clear(); m_TempDirectory.append(tmpPath); m_TempDirectory.append(QString("/")); m_TempDirectory.append(TEMP_DICOM_FOLDER_SUFFIX); m_TempDirectory.append(QString(".")); m_TempDirectory.append(QTime::currentTime().toString("hhmmsszzz")); m_TempDirectory.append(QString::number(QCoreApplication::applicationPid())); tmp.mkdir(QDir::toNativeSeparators( m_TempDirectory )); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/Fiberfox-Fiducial.png b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/Fiberfox-Fiducial.png new file mode 100644 index 0000000000..0911a6721f Binary files /dev/null and b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/Fiberfox-Fiducial.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/Fiberfox.png b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/Fiberfox.png index a49a84de10..1a5e3fae3e 100644 Binary files a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/Fiberfox.png and b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/Fiberfox.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingUserManual.dox index 7f7502b2d2..97a399a1ca 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingUserManual.dox @@ -1,140 +1,140 @@ /** \page org_mitk_gui_qt_diffusionimaging MITK Diffusion Imaging (MITK-DI) This module provides means to diffusion weighted image reconstruction, visualization and quantification. Diffusion tensors as well as different q-ball reconstruction schemes are supported. Q-ball imaging aims at recovering more detailed information about the orientations of fibers from diffusion MRI measurements and, in particular, to resolve the orientations of crossing fibers. Available sections: - \ref QmitkDiffusionImagingUserManualIssues - \ref QmitkDiffusionImagingUserManualPreprocessing - \ref QmitkDiffusionImagingUserManualTensorReconstruction - \ref QmitkDiffusionImagingUserManualQBallReconstruction - \ref QmitkDiffusionImagingUserManualDicomImport - \ref QmitkDiffusionImagingUserManualFslImport - \ref QmitkDiffusionImagingUserManualQuantification - \ref QmitkDiffusionImagingUserManualVisualizationSettings - \ref QmitkDiffusionImagingUserManualReferences - \ref QmitkDiffusionImagingUserManualTechnicalDetail - \ref QmitkDiffusionImagingUserManualSubManuals \section QmitkDiffusionImagingUserManualIssues Known Issues \li Dicom Import: The dicom import has so far only been implemented for Siemens dicom images. MITK-DI is capable of reading the nrrd format, which is documented elsewhere [1, 2]. These files can be created by combining the raw image data with a corresponding textual header file. The file extension should be changed from *.nrrd to *.dwi or from *.nhdr to *.hdwi respectively in order to let MITK-DI recognize the diffusion related header information provided in the files. \section QmitkDiffusionImagingUserManualPreprocessing Preprocessing The preprocessing view gives an overview over the important features of a diffusion weighted image like the number of gradient directions, b-value and the measurement frame. Additionally it allows the extraction of the B0 image, reduction of gradient directions and the generation of a binary brain mask. The image volume can be modified by applying a new mesurement frame, which is useful if the measurement frame is not set correctly in the image header, or by averaging redundant gradient directions. \image html prepro1.png Preprocessing \section QmitkDiffusionImagingUserManualTensorReconstruction Tensor Reconstruction The tensor reconstruction view allows ITK based tensor reconstruction [3]. The advanced settings for ITK reconstruction let you configure a manual threshold on the non-diffusion weighted image. All voxels below this threshold will not be reconstructed and left blank. It is also possible to check for negative eigenvalues. The according voxels are also left blank. \image html tensor1.png ITK tensor reconstruction A few seconds (depending on the image size) after the reconstruction button is hit, a colored image should appear in the main window. \image html tensor4.png Tensor image after reconstruction To assess the quality of the tensor fit it has been proposed to calculate the model residual [9]. This calculates the residual between the measured signal and the signal predicted by the model. Large residuals indicate an inadequacy of the model or the presence of artefacts in the signal intensity (noise, head motion, etc.). To use this option: Select a DWI dataset, estimate a tensor, select both the DWI node and the tensor node in the datamanager and press Residual Image Calculation. MITK-Diffusion can show the residual for every voxel averaged over all volumes or (in the plot widget) summarized per volume or for every slice in every volume. Clicking in the widget where the residual is shown per slice will automatically let the cross-hair jump to that position in the DWI dataset. If Percentage of outliers is checked, the per volume plot will show the percentage of outliers per volume. Otherwise it will show the mean together with the first and third quantile of residuals. See [9] for more information. \image html residuals.png The residual widget The view also allows the generation of artificial diffusion weighted or Q-Ball images from the selected tensor image. The ODFs of the Q-Ball image are directly initialized from the tensor values and afterwards normalized. The diffusion weighted image is estimated using the l2-norm image of the tensor image as B0. The gradient images are afterwards generated using the standard tensor equation. \section QmitkDiffusionImagingUserManualQBallReconstruction Q-Ball Reconstruction The q-ball reonstruction view implements a variety of reconstruction methods. The different reconstruction methods are described in the following: \li Numerical: The original, numerical q-ball reconstruction presented by Tuch et al. [5] \li Standard (SH): Descoteaux's reconstruction based on spherical harmonic basis functions [6] \li Solid Angle (SH): Aganj's reconstruction with solid angle consideration [7] \li ADC-profile only: The ADC-profile reconstructed with spherical harmonic basis functions \li Raw signal only: The raw signal reconstructed with spherical harmonic basis functions \image html qballs1.png The q-ball resonstruction view B0 threshold works the same as in tensor reconstruction. The maximum l-level configures the size of the spherical harmonics basis. Larger l-values (e.g. l=8) allow higher levels of detail, lower levels are more stable against noise (e.g. l=4). Lambda is a regularisation parameter. Set it to 0 for no regularisation. lambda = 0.006 has proven to be a stable choice under various settings. \image html qballs2.png Advanced q-ball reconstruction settings This is how a q-ball image should initially look after reconstruction. Standard q-balls feature a relatively low GFA and thus appear rather dark. Adjust the level-window to solve this. \image html qballs3.png q-ball image after reconstruction \section QmitkDiffusionImagingUserManualDicomImport Dicom Import The dicom import does not cover all hardware manufacturers but only Siemens dicom images. MITK-DI is also capable of reading the nrrd format, which is documented elsewhere [1, 2]. These files can be created by combining the raw image data with a corresponding textual header file. The file extension should be changed from *.nrrd to *.dwi or from *.nhdr to *.hdwi respectively in order to let MITK-DI recognize the diffusion related header information provided in the files. In case your dicom images are readable by MITK-DI, select one or more input dicom folders and click import. Each input folder must only contain DICOM-images that can be combined into one vector-valued 3D output volume. Different patients must be loaded from different input-folders. The folders must not contain other acquisitions (e.g. T1,T2,localizer). In case many imports are performed at once, it is recommended to set the the optional output folder argument. This prevents the images from being kept in memory. \image html dicom1.png Dicom import The option "Average duplicate gradients" accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "blur radius" > 0 is configured. \section QmitkDiffusionImagingUserManualFslImport FSL Import -FSL diffusion data can be imported with MITK Diffusion. FSL diffusion datasets consist of 3 files: a nifty file (filename.nii.gz or filename.nii), a bvecs file (filename.bvecs), which is a text file containing the gradient vectors, and a bvals file (filename.bvecs), containing the b-values. Due to the system that selects suitable file readers, MITK will not recognize these files as diffusion datasets. In order to make MITK recognize it as diffusion, the extension must be changed from .nii.gz to .fslgz (so the new name is filename.fslgz) or from filename.nii to filename.fsl. The bvecs and bvals files have to be renamed as well(to filename.fsl.bvecs/filenames.fsl.bvecs or to filename.fslgz.bvecs/filename.fslgz.bvals). +FSL diffusion data can be imported with MITK Diffusion. FSL diffusion datasets consist of 3 files: a nifty file (filename.nii.gz or filename.nii), a bvecs file (filename.bvecs), which is a text file containing the gradient vectors, and a bvals file (filename.bvecs), containing the b-values. Due to the system that selects suitable file readers, MITK will not recognize these files as diffusion datasets. In order to make MITK recognize it as diffusion, the extension must be changed from .nii.gz to .fslgz (so the new name is filename.fslgz) or from filename.nii to filename.fsl. The bvecs and bvals files have to be renamed as well(to filename.fsl.bvecs/filenames.fsl.bvecs or to filename.fslgz.bvecs/filename.fslgz.bvals). MITK can also save diffusion weighted images in FSL format. To do this the extension of the new file should be changed to .fsl or .fslgz upon saving the file. \image html fslsave.png Save a dwi dataset as fsl \section QmitkDiffusionImagingUserManualQuantification Quantification The quantification view allows the derivation of different scalar anisotropy measures for the reconstructed tensors (Fractional Anisotropy, Relative Anisotropy, Axial Diffusivity, Radial Diffusivity) or q-balls (Generalized Fractional Anisotropy). \image html quantification.png Anisotropy quantification \section QmitkDiffusionImagingUserManualVisualizationSettings ODF Visualization Setting In this small view, the visualization of ODFs and diffusion images can be configured. Depending on the selected image in the data storage, different options are shown here. For tensor or q-ball images, the visibility of glyphs in the different render windows (T)ransversal, (S)agittal, and (C)oronal can be configured here. The maximal number of glyphs to display can also be configured here for. This is usefull to keep the system response time during rendering feasible. The other options configure normalization and scaling of the glyphs. In diffusion images, a slider lets you choose the desired image channel from the vector of images (each gradient direction one image) for rendering. Furthermore reinit can be performed and texture interpolation toggled. This is how a visualization with activated glyphs should look like: \image html visualization3.png Q-ball image with ODF glyph visibility toggled ON \section QmitkDiffusionImagingUserManualReferences References 1. http://teem.sourceforge.net/nrrd/format.html 2. http://www.cmake.org/Wiki/Getting_Started_with_the_NRRD_Format 3. C.F.Westin, S.E.Maier, H.Mamata, A.Nabavi, F.A.Jolesz, R.Kikinis, "Processing and visualization for Diffusion tensor MRI", Medical image Analysis, 2002, pp 93-108 5. Tuch, D.S., 2004. Q-ball imaging. Magn Reson Med 52, 1358-1372. 6. Descoteaux, M., Angelino, E., Fitzgibbons, S., Deriche, R., 2007. Regularized, fast, and robust analytical Q-ball imaging. Magn Reson Med 58, 497-510. 7. Aganj, I., Lenglet, C., Sapiro, G., 2009. ODF reconstruction in q-ball imaging with solid angle consideration. Proceedings of the Sixth IEEE International Symposium on Biomedical Imaging Boston, MA. 8. Goh, A., Lenglet, C., Thompson, P.M., Vidal, R., 2009. Estimating Orientation Distribution Functions with Probability Density Constraints and Spatial Regularity. Med Image Comput Comput Assist Interv Int Conf Med Image Comput Comput Assist Interv LNCS 5761, 877 ff. 9. J.-D. Tournier, S. Mori, A. Leemans., 2011. Diffusion Tensor Imaging and Beyond. Magn Reson Med 65, 1532-1556. \section QmitkDiffusionImagingUserManualTechnicalDetail Technical Information for Developers The diffusion imaging module uses additional properties beside the ones in use in other modules, for further information see \ref DiffusionImagingPropertiesPage . \section QmitkDiffusionImagingUserManualSubManuals Manuals of componentes The MITK Diffusion tools consist of further components, which have their own documentation, see: \li \subpage org_mitk_views_fiberprocessing \li \subpage org_mitk_views_gibbstracking \li \subpage org_mitk_views_odfdetails \li \subpage org_mitk_views_partialvolumeanalysisview \li \subpage org_mitk_views_screenshotmaker \li \subpage org_mitk_views_stochasticfibertracking \li \subpage org_mitk_views_ivim \li \subpage org_mitk_diffusionimagingapp_perspectives_connectomics \li \subpage org_mitk_views_tractbasedspatialstatistics \li \subpage org_mitk_views_odfmaximaextraction \li \subpage org_mitk_views_streamlinetracking - \li \subpage org_mitk_views_dwisoftwarephantomview + \li \subpage org_mitk_views_fiberfoxview */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDwiSoftwarePhantomViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDwiSoftwarePhantomViewUserManual.dox deleted file mode 100644 index 5ac78a6fd3..0000000000 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDwiSoftwarePhantomViewUserManual.dox +++ /dev/null @@ -1,43 +0,0 @@ -/** -\page org_mitk_views_dwisoftwarephantomview DWI Software Phantoms View - -This view provides the user interface to generate artificial diffusion weighted images. This view is regarded as experimental and it has not been tested extensively! - -Available sections: - - \ref SwpUserManualInputData - - \ref SwpUserManualParameters - - \ref SwpUserManualOutputData - -\section SwpUserManualInputData Input Data - -The input of the algorithm consists of an arbitrary number of binary masks. For each mask, the according parameters of the diffusion tensor used to generate the artificial diffusion signal can be specified. If no mask is set, the whole image is filled with an isotropic default signal plus the specified noise. To generate for example a crossing situation one would use two masks with different directions of the respective diffusion tensor. - -\image html sw_phantom_rois.png Possible ROIs to generate a 90° crossing situation. -\image html dwisoftwarephantomsview.png Parameters to generate a phantom image using the ROIs illustrated above while adding a small amount of noise. Note the perpendicular tensor directions for the two ROIs! -\image html sw_phantom_crossing_qballs.png Q-Ball reconstruction of the signal generated with the configuration illustrated above. - -\section SwpUserManualParameters Input Parameters - -\li Image Name: Name of the resulting data node containing the generated phantom image. -\li B-Value: B-Value of the resulting DWI -\li #Gradient Directions: Number of gradient directions of the resulting DWI. -\li SNR: Signal to noise ratio. For values > 99, no noise at all is added to the image. The noise values are sampled from a rician distribution. -\li Grey Matter ADC: Define ADC for isotropic reagions (liquor, air, ...). -\li Scale of the baseline image values: Usually there is no need to change the dafault value. -\li Image Dimensions: Size of the resulting DWI (x,y,z) -\li Image spacing: Spacing of the resulting DWI - -Parameters per mask image: - -\li FA of the tensor used to generate the artificial signal. -\li ADC of the tensor used to generate the artificial signal. -\li Direction of the tensors main eigenvector (x,y and z component). -\li Weighting factor for the signal generated from this tensor. - -\section SwpUserManualOutputData Additional Output - -\li Visualize tensor directions. -\li #Directions per Voxel: Image containing the number of directions per voxel as image value. -\li Direction Images: One image for each signal region. Each voxel contains one direction vector as image value. - -*/ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox index 1d3a3db411..22ba4ed943 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox @@ -1,52 +1,106 @@ /** \page org_mitk_views_fiberfoxview Fiberfox -This view provides the user interface for Fiberfox, an interactive simulation tool for the generation of complex white matter tissue models and corresponding DW-MRI. Arbitrary fiber configurations like bended, crossing, kissing, twisting, and fanning bundles can be intuitively defined by positioning only a few 3D waypoints to trigger the automated generation of synthetic fibers. From these fibers, a DW-MRI signal is simulated according to the specified acquisition settings such as gradient direction, b-value, signal-to-noise ratio, image size, and resolution. Fiberfox incorporates different models of diffusion, noise, and artifacts to simulate realistic images. +This view provides the user interface for Fiberfox [1], an interactive simulation tool for defining artificial white matter fibers and generating corresponding diffusion weighted images. Arbitrary fiber configurations like bent, crossing, kissing, twisting, and fanning bundles can be intuitively defined by positioning only a few 3D waypoints to trigger the automated generation of synthetic fibers. From these fibers a diffusion weighted signal is simulated using a flexible combination of various diffusion models. It can be modified using specified acquisition settings such as gradient direction, b-value, signal-to-noise ratio, image size, and resolution. -Available sections: - - \ref QmitkGibbsTrackingUserManualFiberDefinition - - \ref QmitkGibbsTrackingUserManualSignalGeneration - - \ref QmitkGibbsTrackingUserManualReferences +Available sections: + - \ref QmitkFiberfoxViewUserManualFiberDefinition + - \ref QmitkFiberfoxViewUserManualSignalGeneration + - \ref QmitkFiberfoxViewUserManualKnownIssues + - \ref QmitkFiberfoxViewUserManualReferences +\image html Fiberfox.png Fig. 1: Screenshot of the Fiberfox framework. The four render windows display an axial (top left), sagittal (top right) and coronal (bottom left) 2D cut as well as a 3D view of a synthetic fiber helix and the fiducials used to define its shape. In the 2D views the helix is superimposing the baseline volume of the corresponding diffusion weighted image. The sagittal render window shows a close-up view on one of the circular fiducials. -\image html Fiberfox.png Screenshot of the Fiberfox framework. The four render windows display an axial, sagittal and coronal 2D cut as well as a 3D view of a synthetic fiber helix and the fiducials used to define its shape. In the 2D views the helix is superimposing the baseline volume of the corresponding diffusion weighted image. The sagittal render window shows a closeup view on one of the circular fiducials. - -\section QmitkGibbsTrackingUserManualFiberDefinition Fiber Definition +\section QmitkFiberfoxViewUserManualFiberDefinition Fiber Definition Fiber strands are defined simply by placing markers in a 3D image volume. The fibers are then interpolated between these fiducials. -Example: -\li Chose an image volume to place the markers used to define the fiber pathway. If you don't have such an image available switch to the "Signal Generation" tab, define the size and spacing of the desired image ang click "Generate Image". If no fiber bundle is selected, this will generate a dummy image that can be used to place the fiducials. -\li Start placing fiducials at the desired positions to define the fiber pathway. To do that, click on the button with the circle pictogram, then click at the desired position and plane in the image volume and drag your mouse while keeping the button pressed to generate a circular shape. Adjust the shape using the control points. The position of the control point with the attached line connecting it to the center of the fiducial introduces a twist of the fibers between two successive fiducials. The actual fiber generation is triggered automatically as soon as you place the third control point. -\li In some cases the fibers are entangled in a way that can't be resolved by introducing an additional fiber twist. Fiberfox tries to avoid these situations, which arise from different normal orientations of succeeding fiducials, automatically. In rare cases this is not successful. Use the PICTURE button to flip the fiber positions of the selected fiducial in one dimension. Either the problem is resolved now or you can resolve it manually by adjusting the twist-control point. -Parameters: -If not self-explanatory please refer to TODO. +Example: +\li Chose an image volume to place the markers used to define the fiber pathway. If you don't have such an image available switch to the "Signal Generation" tab, define the size and spacing of the desired image and click "Generate Image". If no fiber bundle is selected, this will generate a dummy image that can be used to place the fiducials. +\li Start placing fiducials at the desired positions to define the fiber pathway. To do that, click on the button with the circle pictogram, then click at the desired position and plane in the image volume and drag your mouse while keeping the button pressed to generate a circular shape. Adjust the shape using the control points (Fig. 2). The position of control point D introduces a twist of the fibers between two successive fiducials. The actual fiber generation is triggered automatically as soon as you place the second control point. +\li In some cases the fibers are entangled in a way that can't be resolved by introducing an additional fiber twist. Fiberfox tries to avoid these situations, which arise from different normal orientations of succeeding fiducials, automatically. In rare cases this is not successful. Use the double-arrow button to flip the fiber positions of the selected fiducial in one dimension. Either the problem is resolved now or you can resolve it manually by adjusting the twist-control point. + +\image html Fiberfox-Fiducial.png Fig. 2: Control points defining the actual shape of the fiducial. A specifies the fiducials position in space, B and C the two ellipse radii and D the twisting angle between two successive fiducials. + +Fiber Options: +\li Real Time Fibers: If checked, each parameter adjustment (fiducial position, number of fibers, ...) will be directly applied to the selected fiber bundle. If unchecked, the fibers will only be generated if the corresponding button "Generate Fibers" is clicked. +\li Advanced Options: Show/hide advanced options +\li #Fibers: Specifies the number of fibers that will be generated for the selected bundle. +\li Fiber Sampling: Adjusts the number of points per cm that make up the fiber. A higher sampling rate is needed if high curvatures are modeled. +\li Tension, Continuity, Bias: Parameters controlling the shape of the splines interpolation the fiducials. See Wikipedia for details. + + +Fiducial Options: +\li Use Constant Fiducial Radius: If checked, all fiducials are treated as circles with the same radius. The first fiducial of the bundle defines the radius of all other fiducials. +\li Align with grid: Click to shift all fiducial center points to the next voxel center. + +Operations: +\li Rotation: Define the rotation of the selected fiber bundle around each axis (in degree). +\li Translation: Define the translation of the selected fiber bundle along each axis (in mm). +\li Scaling: Define a scaling factor for the selected fiber bundle in each dimension. +\li Transform Selection: Apply specified rotation, translation and scaling to the selected Bundle/Fiducial +\li Copy Bundles: Add copies of the selected fiber bundles to the datamanager. +\li Join Bundles: Add new bundle to the datamanager that contains all fibers from the selected bundles. +\li Include Fiducials: If checked, the specified transformation is also applied to the fiducials belonging to the selected fiber bundle and the fiducials are also copied. + +\image html FiberfoxExamples.png Fig. 3: Examples of artificial crossing (a,b), fanning (c,d), highly curved (e,f), kissing (g,h) and twisting (i,j) fibers as well as of the corresponding tensor images generated with Fiberfox. + + +\section QmitkFiberfoxViewUserManualSignalGeneration Signal Generation + +To generate an artificial signal from the input fibers we follow the concepts recently presented by Panagiotaki et al. in a review and taxonomy of different compartment models [2]: a flexible model combining multiple compartments is used to simulate the anisotropic diffusion inside (intra-axonal compartment) and between axons (inter-axonal compartment), isotropic diffusion outside of the axons (extra-axonal compartment 1) and the restricted diffusion in other cell types (extra-axonal compartment 2) weighted according to their respective volume fraction. + +A diffusion weighted image is generated from the fibers by selecting the according fiber bundle in the datamanager and clicking "Generate Image". If some other diffusion weighted image is selected together with the fiber bundle, Fiberfox directly uses the parameters of the selected image (size, spacing, gradient directions, b-values) for the signal generation process. Additionally a binary image can be selected that defines the tissue area. Voxels outside of this mask will contain no signal, only noise. + + +Basic Image Settings: +\li Image Dimensions: Specifies actual image size (number of voxels in each dimension). +\li Image Spacing: Specifies voxel size in mm. Beware that changing the voxel size also changes the signal strength, e.g. increasing the resolution from 2x2x2 mm to 1x1x1 mm decreases the signal obtained for each voxel by a factor 8. +\li Gradient Directions: Number of gradients directions distributed equally over the half sphere. 10% baseline images are automatically added. +\li b-Value: Diffusion weighting in s/mm². If an existing diffusion weighted image is used to set the basic parameters, the b-value is defined by the gradient direction magnitudes of this image, which also enables the use of multiple b-values. + + +Advanced Image Settings (activate checkbox "Advanced Options"): +\li Repetitions: Specifies the number of averages used for the acquisition to reduce noise. +\li Signal Scale: Additional scaling factor for the signal in each voxel. The default value of 125 results in a maximum signal amplitude of 1000 for 2x2x2 mm voxels. Beware that changing this value without changing the noise variance results in a changed SNR. Adjustment of this value might be needed if the overall signal values are much too high or much too low (depends on a variety of factors like voxel size and relaxation times). +\li Echo Time TE: Time between the 90° excitation pulse and the first spin echo. Increasing this time results in a stronger T2-relaxation effect (Wikipedia). +\li Line Readout Time: Time to read one line in k-space. Increasing this time results in a stronger T2* effect which causes an attenuation of the higher frequencies in phase direction (here along y-axis) which again results in a blurring effect of sharp edges perpendicular to the phase direction. +\li Tinhom Relaxation: Time constant specifying the signal decay due to magnetic field inhomogeneities (also called T2'). Together with the tissue specific relaxation time constant T2 this defines the T2* decay constant: T2*=(T2 T2')/(T2+T2') +\li Fiber Radius (in µm): Used to calculate the volume fractions of the used compartments (fiber, water, etc.). If set to 0 (default) the fiber radius is set automatically so that the voxel containing the most fibers is filled completely. A realistic axon radius ranges from about 5 to 20 microns. Using the automatic estimation the resulting value might very well be much larger or smaller than this range. +\li Interpolation Shrink: The signal generated at each position along the fibers is distributed on the surrounding voxels using an interpolation scheme shaped like an arctangent function. Large values result in a steeper interpolation scheme approximating a nearest neighbor interpolation. Very small values result in an almost linear interpolation. +\li Enforce Pure Fiber Voxels: If checked, the actual volume fractions of the single compartments are ignored. A voxel will either be filled by the intra axonal compartment completely or will contain no fiber at all. +\li Output k-Space Image: Some of the effects simulated in our framework are modeled in the k-space representation of the actual image. Checking this box will output this frequency representation (amplitude spectrum). + + +Compartment Settings: + +The group-boxes "Intra-axonal Compartment", "Inter-axonal Compartment" and "Extra-axonal Compartments" allow the specification which model to use and the corresponding model parameters. Currently the following models are implemented: +\li Stick: The “stick†model describes diffusion in an idealized cylinder with zero radius. Parameter: Diffusivity d +\li Zeppelin: Cylindrically symmetric diffusion tensor. Parameters: Parallel diffusivity d|| and perpendicular diffusivity d⊥ +\li Tensor: Full diffusion tensor. Parameters: Parallel diffusivity d|| and perpendicular diffusivity constants d⊥1 and d⊥2 +\li Ball: Isotropic compartment. Parameter: Diffusivity d +\li Astrosticks: Consists of multiple stick models pointing in different directions. The single stick orientations can either be distributed equally over the sphere or are sampled randomly. The model represents signal coming from a type of glial cell called astrocytes, or populations of axons with arbitrary orientation. Parameters: randomization of the stick orientations and diffusivity of the sticks d. +\li Dot: Isotropically restricted compartment. No parameter. + +For a detailed description of the single models, please refer to Panagiotaki et al. "Compartment models of the diffusion MR signal in brain white matter: A taxonomy and comparison."[2]. Additionally to the model parameters, each compartment has its own T2 signal relaxation constant (in ms). + + +Noise and Artifacts: +\li Variance: Adds Rician noise with the specified variance to the signal. +\li Gibbs Ringing: Ringing artifacts occurring on edges in the image due to the frequency low-pass filtering caused by the limited size of the k-space. The higher the oversampling factor, the larger the distance from the corresponding edge in which the ringing is still visible. -\image html FiberfoxExamples.png Examples of artificial crossing, fanning, highly curved, kissing and twisting fibers as well as of the corresponding tensor images generated with Fiberfox. +\section QmitkFiberfoxViewUserManualKnownIssues Known Issues -\section QmitkGibbsTrackingUserManualSignalGeneration Signal Generation +\li If fiducials are created in one of the marginal slices of the underlying image, a position change of the fiducial can be observed upon selection/deselection. If the fiducial is created in any other slice this bug does not occur. +\li If a scaling factor is applied to the selcted fiber bundle, the corresponding fiducials are not scaled accordingly. +\li In some cases the automatic update of the selected fiber bundle is not triggered even if "Real Time Fibers" is checked, e.g. if a fiducial is deleted. If this happens on can always force an update by pressing the "Generate Fibers" button. -Fiberfox uses a ball-zeppelin model to generate the artificial signal. For details about the signal generation process please refer to TODO. -A diffusion weighted image is generated from the fibers by selecting the according fiber bundle in the datamanager and clicking "Generate Image". Additionally to the fiber bundle a binary mask can be specified that defines the tissue area. Voxels outside of this mask will contain no signal, only noise. If no tissue mask is selected, the whole image volume is regarded as tissue. Fiberfox allows the addition of artifcats often present in EPI based diffusion weighted datasets like rician noise, Gibbs ringing and blurring introduced by the T2 signal decay. +If any other issues or feature requests arises during the use of Fiberfox, please don't hesitate to send us an e-mail or directly report the issue in our bugtracker: http://bugs.mitk.org/ -Image and Compartment Settings: -\li Enforce Pure Fiber Voxels: Disable partial voluming. All voxels touched by at least one fiber are treated as pure fiber voxles. -\li Output k-Space Image: Output an image of the fourier transformed baseline signal. -\li Image Dimensions: The number of voxels in each image dimension. -\li Image Spacing: The voxel size (in mm) in each dimension. -\li #Gradient Directions: The number of gradient directions distributed over the half-sphere. -\li b-value: The b-value (in mm/s²) used for the diffusion signal generation. -\li Repetitions: Number of averaged repetitions. Used to suppress noise in real acquisitions. -\li Volume Accuracy: The higher the value, the more accurate the volume fraction estimation for the compartments. Corresponds to the number of sampling points on a fiber over a distance of the minimum spacing value. -\li Fractional anisotropy: Determins anisotropy of the zeppelin compartment. -\li Diffusivity: Diffusivity parameter of the ball compartment. -\li Signal Scale: Scaling factor for the raw signal. +\section QmitkFiberfoxViewUserManualReferences References -Noise and Artifacts: -\li SNR: The signal-to-noise ratio relative to the fiber signal sacling factor. A rician noise model is used. If the SNR is larger than 99, no noise is added to the image. -\li T2 Blurring: Simulate the exponential signal decay occurring during the application of the readout gradient. This is dependent on the tissue specific T2 relaxation times. The defaults correspond to values for white matter and water taken from literature. -\li Gibbs Ringing: Ringing artifacts occurring on edges in the image due to the frequency low-pass filtering caused by the limited size of the k-space. The higher the oversampling factor, the larger the distance from the corresponding edge in which the ringing is still visible. +[1] Peter F. Neher, Bram Stieltjes, Frederik B. Laun, Hans-Peter Meinzer, and Klaus H. Fritzsche: Fiberfox: A novel tool to generate software phantoms of complex fiber geometries. In proceedings: ISMRM 2013 -If you want to use the same parameters (b-value, gradient directions, image geometry) as used for an already acquired dataset, simply select it additionally to the other input nodes. Fiberfox will automatically use these parameters for the signal generation. +[2] Panagiotaki, E., Schneider, T., Siow, B., Hall, M.G., Lythgoe, M.F., Alexander, D.C.: Compartment models of the diffusion mr signal in brain white matter: A taxonomy and comparison. Neuroimage 59 (2012) 2241–2254 */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/dwisoftwarephantomsview.png b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/dwisoftwarephantomsview.png deleted file mode 100644 index e95502464e..0000000000 Binary files a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/dwisoftwarephantomsview.png and /dev/null differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake index 815b4ac00f..32b8b924c9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake @@ -1,148 +1,169 @@ set(SRC_CPP_FILES QmitkODFDetailsWidget.cpp QmitkODFRenderWidget.cpp QmitkPartialVolumeAnalysisWidget.cpp QmitkIVIMWidget.cpp QmitkTbssRoiAnalysisWidget.cpp QmitkResidualAnalysisWidget.cpp QmitkResidualViewWidget.cpp + QmitkTensorModelParametersWidget.cpp + QmitkZeppelinModelParametersWidget.cpp + QmitkStickModelParametersWidget.cpp + QmitkDotModelParametersWidget.cpp + QmitkBallModelParametersWidget.cpp + QmitkAstrosticksModelParametersWidget.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkQBallReconstructionView.cpp QmitkPreprocessingView.cpp QmitkDiffusionDicomImportView.cpp QmitkDiffusionQuantificationView.cpp QmitkTensorReconstructionView.cpp QmitkDiffusionImagingPublicPerspective.cpp QmitkControlVisualizationPropertiesView.cpp QmitkODFDetailsView.cpp QmitkGibbsTrackingView.cpp QmitkStochasticFiberTrackingView.cpp QmitkStreamlineTrackingView.cpp QmitkFiberProcessingView.cpp QmitkFiberBundleDeveloperView.cpp QmitkPartialVolumeAnalysisView.cpp QmitkIVIMView.cpp QmitkTractbasedSpatialStatisticsView.cpp QmitkTbssTableModel.cpp QmitkTbssMetaTableModel.cpp QmitkTbssSkeletonizationView.cpp Connectomics/QmitkConnectomicsDataView.cpp Connectomics/QmitkConnectomicsNetworkOperationsView.cpp Connectomics/QmitkConnectomicsStatisticsView.cpp Connectomics/QmitkNetworkHistogramCanvas.cpp QmitkDwiSoftwarePhantomView.cpp QmitkOdfMaximaExtractionView.cpp QmitkFiberfoxView.cpp + QmitkFiberExtractionView.cpp ) set(UI_FILES src/internal/QmitkQBallReconstructionViewControls.ui src/internal/QmitkPreprocessingViewControls.ui src/internal/QmitkDiffusionDicomImportViewControls.ui src/internal/QmitkDiffusionQuantificationViewControls.ui src/internal/QmitkTensorReconstructionViewControls.ui src/internal/QmitkControlVisualizationPropertiesViewControls.ui src/internal/QmitkODFDetailsViewControls.ui src/internal/QmitkGibbsTrackingViewControls.ui src/internal/QmitkStochasticFiberTrackingViewControls.ui src/internal/QmitkStreamlineTrackingViewControls.ui src/internal/QmitkFiberProcessingViewControls.ui src/internal/QmitkFiberBundleDeveloperViewControls.ui src/internal/QmitkPartialVolumeAnalysisViewControls.ui src/internal/QmitkIVIMViewControls.ui src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui src/internal/QmitkTbssSkeletonizationViewControls.ui src/internal/Connectomics/QmitkConnectomicsDataViewControls.ui src/internal/Connectomics/QmitkConnectomicsNetworkOperationsViewControls.ui src/internal/Connectomics/QmitkConnectomicsStatisticsViewControls.ui src/internal/QmitkDwiSoftwarePhantomViewControls.ui src/internal/QmitkOdfMaximaExtractionViewControls.ui src/internal/QmitkFiberfoxViewControls.ui + src/internal/QmitkFiberExtractionViewControls.ui + src/QmitkTensorModelParametersWidgetControls.ui + src/QmitkZeppelinModelParametersWidgetControls.ui + src/QmitkStickModelParametersWidgetControls.ui + src/QmitkDotModelParametersWidgetControls.ui + src/QmitkBallModelParametersWidgetControls.ui + src/QmitkAstrosticksModelParametersWidgetControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkQBallReconstructionView.h src/internal/QmitkPreprocessingView.h src/internal/QmitkDiffusionDicomImportView.h src/internal/QmitkDiffusionImagingPublicPerspective.h src/internal/QmitkDiffusionQuantificationView.h src/internal/QmitkTensorReconstructionView.h src/internal/QmitkControlVisualizationPropertiesView.h src/internal/QmitkODFDetailsView.h src/QmitkODFRenderWidget.h src/QmitkODFDetailsWidget.h src/internal/QmitkGibbsTrackingView.h src/internal/QmitkStochasticFiberTrackingView.h src/internal/QmitkStreamlineTrackingView.h src/internal/QmitkFiberProcessingView.h src/internal/QmitkFiberBundleDeveloperView.h src/internal/QmitkPartialVolumeAnalysisView.h src/QmitkPartialVolumeAnalysisWidget.h src/internal/QmitkIVIMView.h src/internal/QmitkTractbasedSpatialStatisticsView.h src/internal/QmitkTbssSkeletonizationView.h src/QmitkTbssRoiAnalysisWidget.h src/QmitkResidualAnalysisWidget.h src/QmitkResidualViewWidget.h src/internal/Connectomics/QmitkConnectomicsDataView.h src/internal/Connectomics/QmitkConnectomicsNetworkOperationsView.h src/internal/Connectomics/QmitkConnectomicsStatisticsView.h src/internal/Connectomics/QmitkNetworkHistogramCanvas.h src/internal/QmitkDwiSoftwarePhantomView.h src/internal/QmitkOdfMaximaExtractionView.h src/internal/QmitkFiberfoxView.h + src/internal/QmitkFiberExtractionView.h + src/QmitkTensorModelParametersWidget.h + src/QmitkZeppelinModelParametersWidget.h + src/QmitkStickModelParametersWidget.h + src/QmitkDotModelParametersWidget.h + src/QmitkBallModelParametersWidget.h + src/QmitkAstrosticksModelParametersWidget.h ) set(CACHED_RESOURCE_FILES # 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 plugin.xml resources/preprocessing.png resources/dwiimport.png resources/quantification.png resources/reconodf.png resources/recontensor.png resources/vizControls.png resources/OdfDetails.png resources/GibbsTracking.png resources/FiberBundleOperations.png resources/PartialVolumeAnalysis_24.png resources/IVIM_48.png resources/stochFB.png resources/tbss.png resources/connectomics/QmitkConnectomicsDataViewIcon_48.png resources/connectomics/QmitkConnectomicsNetworkOperationsViewIcon_48.png resources/connectomics/QmitkConnectomicsStatisticsViewIcon_48.png resources/arrow.png resources/qball_peaks.png resources/phantom.png resources/tensor.png resources/qball.png resources/StreamlineTracking.png resources/dwi2.png resources/refresh.xpm ) set(QRC_FILES # uncomment the following line if you want to use Qt resources resources/QmitkDiffusionImaging.qrc #resources/QmitkTractbasedSpatialStatisticsView.qrc ) 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.diffusionimaging/plugin.xml b/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml index 28045e4f00..662563552d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml @@ -1,167 +1,167 @@ + + + + - - - - + icon="resources/phantom.png" /> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/resources/phantom.png b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/old-phantom.png similarity index 100% copy from Plugins/org.mitk.gui.qt.diffusionimaging/resources/phantom.png copy to Plugins/org.mitk.gui.qt.diffusionimaging/resources/old-phantom.png diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/resources/phantom.png b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/phantom.png index 3890968f0e..ae592d88bb 100644 Binary files a/Plugins/org.mitk.gui.qt.diffusionimaging/resources/phantom.png and b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/phantom.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidget.cpp new file mode 100644 index 0000000000..7eb05e2ad6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidget.cpp @@ -0,0 +1,42 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//Qmitk headers +#include "QmitkAstrosticksModelParametersWidget.h" +#include + +const std::string QmitkAstrosticksModelParametersWidget::VIEW_ID = "org.mitk.views.AstrosticksModelParametersWidget"; + +QmitkAstrosticksModelParametersWidget::QmitkAstrosticksModelParametersWidget( QWidget * parent, Qt::WindowFlags f ) + : QWidget(parent) +{ + m_Controls = NULL; + this->CreateQtPartControl(this); +} + +QmitkAstrosticksModelParametersWidget::~QmitkAstrosticksModelParametersWidget() +{ +} + +void QmitkAstrosticksModelParametersWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkAstrosticksModelParametersWidgetControls; + m_Controls->setupUi(parent); + } +} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidget.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidget.h new file mode 100644 index 0000000000..c3190454ff --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidget.h @@ -0,0 +1,58 @@ +/*=================================================================== + +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 _QMITKAstrosticksModelParametersWidget_H_INCLUDED +#define _QMITKAstrosticksModelParametersWidget_H_INCLUDED + +//QT headers +#include +#include +#include "ui_QmitkAstrosticksModelParametersWidgetControls.h" +#include + +class QmitkStdMultiWidget; + +/** @brief + */ +class DIFFUSIONIMAGING_EXPORT QmitkAstrosticksModelParametersWidget : public QWidget +{ + //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + QmitkAstrosticksModelParametersWidget (QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~QmitkAstrosticksModelParametersWidget(); + + virtual void CreateQtPartControl(QWidget *parent); + + double GetD(){ return m_Controls->m_D1box->value(); } + unsigned int GetT2(){ return m_Controls->m_T2box->value(); } + bool GetRandomizeSticks(){ return m_Controls->m_RandomCheck->isChecked(); } + +public slots: + +protected: + // member variables + Ui::QmitkAstrosticksModelParametersWidgetControls* m_Controls; + +private: + +}; + +#endif // _QMITKAstrosticksModelParametersWidget_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidgetControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidgetControls.ui new file mode 100644 index 0000000000..5c051077b9 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkAstrosticksModelParametersWidgetControls.ui @@ -0,0 +1,109 @@ + + + QmitkAstrosticksModelParametersWidgetControls + + + + 0 + 0 + 410 + 106 + + + + + 0 + 0 + + + + Form + + + + 0 + + + + + Use random number and orientation of sticks. + + + Randomize Sticks + + + true + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + + + <html><head/><body><p><span style=" font-style:italic;">T2</span> - Relaxation:</p></body></html> + + + + + + + T2 relaxation time of this compartment (in milliseconds). + + + 10000 + + + 100 + + + + + + + <html><head/><body><p><span style=" font-style:italic;">d</span>:</p></body></html> + + + + + + + Diffusivity along sticks. + + + 5 + + + 1.000000000000000 + + + 0.000100000000000 + + + 0.001000000000000 + + + + + + + + + + m_T2box + m_D1box + m_RandomCheck + + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidget.cpp new file mode 100644 index 0000000000..0fa9b4a09e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidget.cpp @@ -0,0 +1,42 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//Qmitk headers +#include "QmitkBallModelParametersWidget.h" +#include + +const std::string QmitkBallModelParametersWidget::VIEW_ID = "org.mitk.views.BallModelParametersWidget"; + +QmitkBallModelParametersWidget::QmitkBallModelParametersWidget( QWidget * parent, Qt::WindowFlags f ) + : QWidget(parent) +{ + m_Controls = NULL; + this->CreateQtPartControl(this); +} + +QmitkBallModelParametersWidget::~QmitkBallModelParametersWidget() +{ +} + +void QmitkBallModelParametersWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkBallModelParametersWidgetControls; + m_Controls->setupUi(parent); + } +} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidget.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidget.h new file mode 100644 index 0000000000..a7bdbfcd20 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidget.h @@ -0,0 +1,57 @@ +/*=================================================================== + +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 _QMITKBallModelParametersWidget_H_INCLUDED +#define _QMITKBallModelParametersWidget_H_INCLUDED + +//QT headers +#include +#include +#include "ui_QmitkBallModelParametersWidgetControls.h" +#include + +class QmitkStdMultiWidget; + +/** @brief + */ +class DIFFUSIONIMAGING_EXPORT QmitkBallModelParametersWidget : public QWidget +{ + //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + QmitkBallModelParametersWidget (QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~QmitkBallModelParametersWidget(); + + virtual void CreateQtPartControl(QWidget *parent); + + double GetD(){ return m_Controls->m_D1box->value(); } + unsigned int GetT2(){ return m_Controls->m_T2box->value(); } + +public slots: + +protected: + // member variables + Ui::QmitkBallModelParametersWidgetControls* m_Controls; + +private: + +}; + +#endif // _QMITKBallModelParametersWidget_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidgetControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidgetControls.ui new file mode 100644 index 0000000000..dd132ce030 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkBallModelParametersWidgetControls.ui @@ -0,0 +1,80 @@ + + + QmitkBallModelParametersWidgetControls + + + + 0 + 0 + 410 + 78 + + + + + 0 + 0 + + + + Form + + + + 0 + + + + + <html><head/><body><p><span style=" font-style:italic;">d</span>:</p></body></html> + + + + + + + <html><head/><body><p><span style=" font-style:italic;">T2</span> - Relaxation:</p></body></html> + + + + + + + T2 relaxation time of this compartment (in milliseconds). + + + 10000 + + + 100 + + + + + + + Diffusivity along stick. + + + 5 + + + 1.000000000000000 + + + 0.000100000000000 + + + 0.001000000000000 + + + + + + + m_T2box + m_D1box + + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidget.cpp new file mode 100644 index 0000000000..76a1cfd69b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidget.cpp @@ -0,0 +1,42 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//Qmitk headers +#include "QmitkDotModelParametersWidget.h" +#include + +const std::string QmitkDotModelParametersWidget::VIEW_ID = "org.mitk.views.DotModelParametersWidget"; + +QmitkDotModelParametersWidget::QmitkDotModelParametersWidget( QWidget * parent, Qt::WindowFlags f ) + : QWidget(parent) +{ + m_Controls = NULL; + this->CreateQtPartControl(this); +} + +QmitkDotModelParametersWidget::~QmitkDotModelParametersWidget() +{ +} + +void QmitkDotModelParametersWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkDotModelParametersWidgetControls; + m_Controls->setupUi(parent); + } +} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidget.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidget.h new file mode 100644 index 0000000000..af3d1a098b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidget.h @@ -0,0 +1,56 @@ +/*=================================================================== + +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 _QMITKDotModelParametersWidget_H_INCLUDED +#define _QMITKDotModelParametersWidget_H_INCLUDED + +//QT headers +#include +#include +#include "ui_QmitkDotModelParametersWidgetControls.h" +#include + +class QmitkStdMultiWidget; + +/** @brief + */ +class DIFFUSIONIMAGING_EXPORT QmitkDotModelParametersWidget : public QWidget +{ + //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + QmitkDotModelParametersWidget (QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~QmitkDotModelParametersWidget(); + + virtual void CreateQtPartControl(QWidget *parent); + + unsigned int GetT2(){ return m_Controls->m_T2box->value(); } + +public slots: + +protected: + // member variables + Ui::QmitkDotModelParametersWidgetControls* m_Controls; + +private: + +}; + +#endif // _QMITKDotModelParametersWidget_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidgetControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidgetControls.ui new file mode 100644 index 0000000000..35fb44cd99 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkDotModelParametersWidgetControls.ui @@ -0,0 +1,50 @@ + + + QmitkDotModelParametersWidgetControls + + + + 0 + 0 + 410 + 45 + + + + + 0 + 0 + + + + Form + + + + 0 + + + + + <html><head/><body><p><span style=" font-style:italic;">T2</span> - Relaxation:</p></body></html> + + + + + + + T2 relaxation time of this compartment (in milliseconds). + + + 10000 + + + 100 + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidget.cpp new file mode 100644 index 0000000000..852bf79f5a --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidget.cpp @@ -0,0 +1,42 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//Qmitk headers +#include "QmitkStickModelParametersWidget.h" +#include + +const std::string QmitkStickModelParametersWidget::VIEW_ID = "org.mitk.views.StickModelParametersWidget"; + +QmitkStickModelParametersWidget::QmitkStickModelParametersWidget( QWidget * parent, Qt::WindowFlags f ) + : QWidget(parent) +{ + m_Controls = NULL; + this->CreateQtPartControl(this); +} + +QmitkStickModelParametersWidget::~QmitkStickModelParametersWidget() +{ +} + +void QmitkStickModelParametersWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkStickModelParametersWidgetControls; + m_Controls->setupUi(parent); + } +} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidget.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidget.h new file mode 100644 index 0000000000..ead2f66299 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidget.h @@ -0,0 +1,57 @@ +/*=================================================================== + +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 _QMITKStickModelParametersWidget_H_INCLUDED +#define _QMITKStickModelParametersWidget_H_INCLUDED + +//QT headers +#include +#include +#include "ui_QmitkStickModelParametersWidgetControls.h" +#include + +class QmitkStdMultiWidget; + +/** @brief + */ +class DIFFUSIONIMAGING_EXPORT QmitkStickModelParametersWidget : public QWidget +{ + //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + QmitkStickModelParametersWidget (QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~QmitkStickModelParametersWidget(); + + virtual void CreateQtPartControl(QWidget *parent); + + double GetD(){ return m_Controls->m_D1box->value(); } + unsigned int GetT2(){ return m_Controls->m_T2box->value(); } + +public slots: + +protected: + // member variables + Ui::QmitkStickModelParametersWidgetControls* m_Controls; + +private: + +}; + +#endif // _QMITKStickModelParametersWidget_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidgetControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidgetControls.ui new file mode 100644 index 0000000000..67fa97782d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkStickModelParametersWidgetControls.ui @@ -0,0 +1,80 @@ + + + QmitkStickModelParametersWidgetControls + + + + 0 + 0 + 410 + 78 + + + + + 0 + 0 + + + + Form + + + + 0 + + + + + <html><head/><body><p><span style=" font-style:italic;">d</span>:</p></body></html> + + + + + + + <html><head/><body><p><span style=" font-style:italic;">T2</span> - Relaxation:</p></body></html> + + + + + + + T2 relaxation time of this compartment (in milliseconds). + + + 10000 + + + 200 + + + + + + + Diffusivity along stick. + + + 5 + + + 1.000000000000000 + + + 0.000100000000000 + + + 0.001000000000000 + + + + + + + m_T2box + m_D1box + + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidget.cpp new file mode 100644 index 0000000000..01eaed16b6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidget.cpp @@ -0,0 +1,63 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//Qmitk headers +#include "QmitkTensorModelParametersWidget.h" +#include + +const std::string QmitkTensorModelParametersWidget::VIEW_ID = "org.mitk.views.tensormodelparameterswidget"; + +QmitkTensorModelParametersWidget::QmitkTensorModelParametersWidget( QWidget * parent, Qt::WindowFlags f ) + : QWidget(parent) +{ + m_Controls = NULL; + this->CreateQtPartControl(this); +} + +QmitkTensorModelParametersWidget::~QmitkTensorModelParametersWidget() +{ +} + +void QmitkTensorModelParametersWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkTensorModelParametersWidgetControls; + m_Controls->setupUi(parent); + + connect((QObject*) m_Controls->m_D1box, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(DChanged(double))); + connect((QObject*) m_Controls->m_D2box, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(DChanged(double))); + connect((QObject*) m_Controls->m_D3box, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(DChanged(double))); + + UpdateUi(); + } +} + +void QmitkTensorModelParametersWidget::UpdateUi() +{ + itk::DiffusionTensor3D tensor; + tensor.Fill(0); + tensor.SetElement(0,m_Controls->m_D1box->value()); + tensor.SetElement(3,m_Controls->m_D2box->value()); + tensor.SetElement(5,m_Controls->m_D3box->value()); + m_Controls->m_FaLabel->setText(QString::number(tensor.GetFractionalAnisotropy())); +} + +void QmitkTensorModelParametersWidget::DChanged( double value ) +{ + UpdateUi(); +} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidget.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidget.h new file mode 100644 index 0000000000..f09273c18c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidget.h @@ -0,0 +1,62 @@ +/*=================================================================== + +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 _QMITKTensorModelParametersWidget_H_INCLUDED +#define _QMITKTensorModelParametersWidget_H_INCLUDED + +//QT headers +#include +#include +#include "ui_QmitkTensorModelParametersWidgetControls.h" +#include + +class QmitkStdMultiWidget; + +/** @brief + */ +class DIFFUSIONIMAGING_EXPORT QmitkTensorModelParametersWidget : public QWidget +{ + //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + QmitkTensorModelParametersWidget (QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~QmitkTensorModelParametersWidget(); + + virtual void CreateQtPartControl(QWidget *parent); + + double GetD1(){ return m_Controls->m_D1box->value(); } + double GetD2(){ return m_Controls->m_D2box->value(); } + double GetD3(){ return m_Controls->m_D3box->value(); } + unsigned int GetT2(){ return m_Controls->m_T2box->value(); } + +public slots: + + void DChanged( double value ); + +protected: + // member variables + Ui::QmitkTensorModelParametersWidgetControls* m_Controls; + void UpdateUi(); + +private: + +}; + +#endif // _QMITKTensorModelParametersWidget_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidgetControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidgetControls.ui new file mode 100644 index 0000000000..b2320d4f41 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTensorModelParametersWidgetControls.ui @@ -0,0 +1,151 @@ + + + QmitkTensorModelParametersWidgetControls + + + + 0 + 0 + 410 + 167 + + + + + 0 + 0 + + + + Form + + + + 0 + + + + + <html><head/><body><p><span style=" font-style:italic;">FA</span>:</p></body></html> + + + + + + + <html><head/><body><p><span style=" font-style:italic;">d</span><span style=" vertical-align:sub;">⟂1</span>:</p></body></html> + + + + + + + Diffusivity along second eigenvector. + + + 5 + + + 1.000000000000000 + + + 0.000100000000000 + + + 0.000250000000000 + + + + + + + <html><head/><body><p><span style=" font-style:italic;">d</span><span style=" vertical-align:sub;">||</span>:</p></body></html> + + + + + + + Diffusivity along largest eigenvector. + + + 5 + + + 1.000000000000000 + + + 0.000100000000000 + + + 0.001000000000000 + + + + + + + Diffusivity along third eigenvector. + + + 5 + + + 1.000000000000000 + + + 0.000100000000000 + + + 0.000250000000000 + + + + + + + <html><head/><body><p><span style=" font-style:italic;">d</span><span style=" vertical-align:sub;">⟂2</span>:</p></body></html> + + + + + + + Fractional anisotropy of resulting tensor. + + + <html><head/><body><p>-</p></body></html> + + + + + + + <html><head/><body><p><span style=" font-style:italic;">T2</span> - Relaxation:</p></body></html> + + + + + + + T2 relaxation time of this compartment (in milliseconds). + + + 10000 + + + 100 + + + + + + + m_T2box + m_D1box + m_D2box + m_D3box + + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidget.cpp new file mode 100644 index 0000000000..e40f787825 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidget.cpp @@ -0,0 +1,62 @@ +/*=================================================================== + +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. + +===================================================================*/ + +//Qmitk headers +#include "QmitkZeppelinModelParametersWidget.h" +#include + +const std::string QmitkZeppelinModelParametersWidget::VIEW_ID = "org.mitk.views.ZeppelinModelParameterswidget"; + +QmitkZeppelinModelParametersWidget::QmitkZeppelinModelParametersWidget( QWidget * parent, Qt::WindowFlags f ) + : QWidget(parent) +{ + m_Controls = NULL; + this->CreateQtPartControl(this); +} + +QmitkZeppelinModelParametersWidget::~QmitkZeppelinModelParametersWidget() +{ +} + +void QmitkZeppelinModelParametersWidget::CreateQtPartControl(QWidget *parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkZeppelinModelParametersWidgetControls; + m_Controls->setupUi(parent); + + connect((QObject*) m_Controls->m_D1box, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(DChanged(double))); + connect((QObject*) m_Controls->m_D2box, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(DChanged(double))); + + UpdateUi(); + } +} + +void QmitkZeppelinModelParametersWidget::UpdateUi() +{ + itk::DiffusionTensor3D tensor; + tensor.Fill(0); + tensor.SetElement(0,m_Controls->m_D1box->value()); + tensor.SetElement(3,m_Controls->m_D2box->value()); + tensor.SetElement(5,m_Controls->m_D2box->value()); + m_Controls->m_FaLabel->setText(QString::number(tensor.GetFractionalAnisotropy())); +} + +void QmitkZeppelinModelParametersWidget::DChanged( double value ) +{ + UpdateUi(); +} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidget.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidget.h new file mode 100644 index 0000000000..583cf21c80 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidget.h @@ -0,0 +1,61 @@ +/*=================================================================== + +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 _QMITKZeppelinModelParametersWidget_H_INCLUDED +#define _QMITKZeppelinModelParametersWidget_H_INCLUDED + +//QT headers +#include +#include +#include "ui_QmitkZeppelinModelParametersWidgetControls.h" +#include + +class QmitkStdMultiWidget; + +/** @brief + */ +class DIFFUSIONIMAGING_EXPORT QmitkZeppelinModelParametersWidget : public QWidget +{ + //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + QmitkZeppelinModelParametersWidget (QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~QmitkZeppelinModelParametersWidget(); + + virtual void CreateQtPartControl(QWidget *parent); + + double GetD1(){ return m_Controls->m_D1box->value(); } + double GetD2(){ return m_Controls->m_D2box->value(); } + unsigned int GetT2(){ return m_Controls->m_T2box->value(); } + +public slots: + + void DChanged( double value ); + +protected: + // member variables + Ui::QmitkZeppelinModelParametersWidgetControls* m_Controls; + void UpdateUi(); + +private: + +}; + +#endif // _QMITKZeppelinModelParametersWidget_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidgetControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidgetControls.ui new file mode 100644 index 0000000000..418098a551 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkZeppelinModelParametersWidgetControls.ui @@ -0,0 +1,124 @@ + + + QmitkZeppelinModelParametersWidgetControls + + + + 0 + 0 + 410 + 116 + + + + + 0 + 0 + + + + Form + + + + 0 + + + + + Fractional anisotropy of resulting tensor. + + + <html><head/><body><p>-</p></body></html> + + + + + + + Diffusivity along second and third eigenvector. + + + 5 + + + 1.000000000000000 + + + 0.000100000000000 + + + 0.000250000000000 + + + + + + + T2 relaxation time of this compartment (in milliseconds). + + + 10000 + + + 100 + + + + + + + Diffusivity along largest eigenvector. + + + 5 + + + 1.000000000000000 + + + 0.000100000000000 + + + 0.001000000000000 + + + + + + + <html><head/><body><p><span style=" font-style:italic;">d</span><span style=" vertical-align:sub;">⟂</span>:</p></body></html> + + + + + + + <html><head/><body><p><span style=" font-style:italic;">d</span><span style=" vertical-align:sub;">||</span>:</p></body></html> + + + + + + + <html><head/><body><p><span style=" font-style:italic;">T2</span> - Relaxation:</p></body></html> + + + + + + + <html><head/><body><p><span style=" font-style:italic;">FA</span>:</p></body></html> + + + + + + + m_T2box + m_D1box + m_D2box + + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp index 5d29a5b71d..eec63e7d6c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp @@ -1,774 +1,800 @@ /*=================================================================== 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 "QmitkDiffusionDicomImportView.h" // qt includes #include // itk includes #include "itkTimeProbesCollectorBase.h" #include "itkGDCMSeriesFileNames.h" #include "itksys/SystemTools.hxx" // mitk includes #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkMemoryUtilities.h" // diffusion module includes #include "mitkDicomDiffusionImageHeaderReader.h" #include "mitkGroupDiffusionHeadersFilter.h" #include "mitkDicomDiffusionImageReader.h" #include "mitkDiffusionImage.h" #include "mitkNrrdDiffusionImageWriter.h" #include "gdcmDirectory.h" #include "gdcmScanner.h" #include "gdcmSorter.h" #include "gdcmIPPSorter.h" #include "gdcmAttribute.h" #include "gdcmVersion.h" #include const std::string QmitkDiffusionDicomImport::VIEW_ID = "org.mitk.views.diffusiondicomimport"; QmitkDiffusionDicomImport::QmitkDiffusionDicomImport(QObject* /*parent*/, const char* /*name*/) : QmitkFunctionality(), m_Controls(NULL), m_MultiWidget(NULL), m_OutputFolderName(""), m_OutputFolderNameSet(false) { } QmitkDiffusionDicomImport::QmitkDiffusionDicomImport(const QmitkDiffusionDicomImport& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } QmitkDiffusionDicomImport::~QmitkDiffusionDicomImport() {} void QmitkDiffusionDicomImport::CreateQtPartControl(QWidget *parent) { m_Parent = parent; if (m_Controls == NULL) { m_Controls = new Ui::QmitkDiffusionDicomImportControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_DicomLoadRecursiveCheckbox->setChecked(true); m_Controls->m_DicomLoadAverageDuplicatesCheckbox->setChecked(false); m_Controls->m_DicomLoadRecursiveCheckbox->setVisible(false); m_Controls->m_OverrideOptionCheckbox->setVisible(false); AverageClicked(); } } void QmitkDiffusionDicomImport::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_AddFoldersButton, SIGNAL(clicked()), this, SLOT(DicomLoadAddFolderNames()) ); connect( m_Controls->m_DeleteFoldersButton, SIGNAL(clicked()), this, SLOT(DicomLoadDeleteFolderNames()) ); connect( m_Controls->m_DicomLoadStartLoadButton, SIGNAL(clicked()), this, SLOT(DicomLoadStartLoad()) ); connect( m_Controls->m_DicomLoadAverageDuplicatesCheckbox, SIGNAL(clicked()), this, SLOT(AverageClicked()) ); connect( m_Controls->m_OutputSetButton, SIGNAL(clicked()), this, SLOT(OutputSet()) ); connect( m_Controls->m_OutputClearButton, SIGNAL(clicked()), this, SLOT(OutputClear()) ); connect( m_Controls->m_Remove, SIGNAL(clicked()), this, SLOT(Remove()) ); } } void QmitkDiffusionDicomImport::Remove() { int i = m_Controls->listWidget->currentRow(); m_Controls->listWidget->takeItem(i); } void QmitkDiffusionDicomImport::OutputSet() { // SELECT FOLDER DIALOG QFileDialog* w = new QFileDialog( m_Parent, QString("Select folders containing DWI data") ); w->setFileMode( QFileDialog::Directory ); // RETRIEVE SELECTION if ( w->exec() != QDialog::Accepted ) return; m_OutputFolderName = w->selectedFiles()[0]; m_OutputFolderNameSet = true; m_Controls->m_OutputLabel->setText(m_OutputFolderName); // show file override option checkbox m_Controls->m_OverrideOptionCheckbox->setVisible(true); } void QmitkDiffusionDicomImport::OutputClear() { m_OutputFolderName = ""; m_OutputFolderNameSet = false; m_Controls->m_OutputLabel->setText("... optional out-folder ..."); // hide file override option checkbox - no output specified m_Controls->m_OverrideOptionCheckbox->setVisible(false); } void QmitkDiffusionDicomImport::AverageClicked() { m_Controls->m_Blur->setEnabled(m_Controls->m_DicomLoadAverageDuplicatesCheckbox->isChecked()); } void QmitkDiffusionDicomImport::Activated() { QmitkFunctionality::Activated(); } void QmitkDiffusionDicomImport::DicomLoadDeleteFolderNames() { m_Controls->listWidget->clear(); } void QmitkDiffusionDicomImport::DicomLoadAddFolderNames() { // SELECT FOLDER DIALOG QFileDialog* w = new QFileDialog( m_Parent, QString("Select folders containing DWI data") ); w->setFileMode( QFileDialog::Directory ); // RETRIEVE SELECTION if ( w->exec() != QDialog::Accepted ) return; m_Controls->listWidget->addItems(w->selectedFiles()); } bool SortBySeriesUID(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0020,0x000e> at1; at1.Set( ds1 ); gdcm::Attribute<0x0020,0x000e> at2; at2.Set( ds2 ); return at1 < at2; } bool SortByAcquisitionNumber(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0020,0x0012> at1; at1.Set( ds1 ); gdcm::Attribute<0x0020,0x0012> at2; at2.Set( ds2 ); return at1 < at2; } bool SortBySeqName(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0018, 0x0024> at1; at1.Set( ds1 ); gdcm::Attribute<0x0018, 0x0024> at2; at2.Set( ds2 ); std::string str1 = at1.GetValue().Trim(); std::string str2 = at2.GetValue().Trim(); return std::lexicographical_compare(str1.begin(), str1.end(), str2.begin(), str2.end() ); } void QmitkDiffusionDicomImport::Status(QString status) { mitk::StatusBar::GetInstance()->DisplayText(status.toAscii()); MITK_INFO << status.toStdString().c_str(); } void QmitkDiffusionDicomImport::Status(std::string status) { mitk::StatusBar::GetInstance()->DisplayText(status.c_str()); MITK_INFO << status.c_str(); } void QmitkDiffusionDicomImport::Status(const char* status) { mitk::StatusBar::GetInstance()->DisplayText(status); MITK_INFO << status; } void QmitkDiffusionDicomImport::Error(QString status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status.toAscii()); MITK_ERROR << status.toStdString().c_str(); } void QmitkDiffusionDicomImport::Error(std::string status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status.c_str()); MITK_ERROR << status.c_str(); } void QmitkDiffusionDicomImport::Error(const char* status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status); MITK_ERROR << status; } void QmitkDiffusionDicomImport::PrintMemoryUsage() { size_t processSize = mitk::MemoryUtilities::GetProcessMemoryUsage(); size_t totalSize = mitk::MemoryUtilities::GetTotalSizeOfPhysicalRam(); float percentage = ( (float) processSize / (float) totalSize ) * 100.0; MITK_INFO << "Current memory usage: " << GetMemoryDescription( processSize, percentage ); } std::string QmitkDiffusionDicomImport::FormatMemorySize( size_t size ) { double val = size; std::string descriptor("B"); if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "KB"; } if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "MB"; } if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "GB"; } std::ostringstream str; str << std::fixed << std::setprecision(2) << val << " " << descriptor; return str.str(); } std::string QmitkDiffusionDicomImport::FormatPercentage( double val ) { std::ostringstream str; str << std::fixed << std::setprecision(2) << val << " " << "%"; return str.str(); } std::string QmitkDiffusionDicomImport::GetMemoryDescription( size_t processSize, float percentage ) { std::ostringstream str; str << FormatMemorySize(processSize) << " (" << FormatPercentage( percentage ) <<")" ; return str.str(); } void QmitkDiffusionDicomImport::DicomLoadStartLoad() { itk::TimeProbesCollectorBase clock; bool imageSuccessfullySaved = true; try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { try { MITK_INFO << " ** Changing locale from " << setlocale(LC_ALL, NULL) << " to '" << locale << "'"; setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } int nrFolders = m_Controls->listWidget->count(); if(!nrFolders) { Error(QString("No input folders were selected. ABORTING.")); return; } Status(QString("GDCM %1 used for DICOM parsing and sorting!").arg(gdcm::Version::GetVersion())); PrintMemoryUsage(); QString status; mitk::DataNode::Pointer node; mitk::ProgressBar::GetInstance()->AddStepsToDo(2*nrFolders); std::string folder = m_Controls->m_OutputLabel->text().toStdString(); if(berry::Platform::IsWindows()) { folder.append("\\import.log"); } else { folder.append("/import.log"); } ofstream logfile; if(m_OutputFolderNameSet) logfile.open(folder.c_str()); while(m_Controls->listWidget->count()) { // RETREIVE FOLDERNAME QListWidgetItem * item = m_Controls->listWidget->takeItem(0); QString folderName = item->text(); if(m_OutputFolderNameSet) logfile << "Reading " << folderName.toStdString() << '\n'; // PARSING DIRECTORY PrintMemoryUsage(); clock.Start(folderName.toAscii()); std::vector seriesUIDs(0); std::vector > seriesFilenames(0); Status("== Initial Directory Scan =="); if(m_OutputFolderNameSet) logfile << "== Initial Directory Scan ==\n"; gdcm::Directory d; d.Load( folderName.toStdString().c_str(), true ); // recursive ! const gdcm::Directory::FilenamesType &l1 = d.GetFilenames(); const unsigned int ntotalfiles = l1.size(); Status(QString(" ... found %1 different files").arg(ntotalfiles)); if(m_OutputFolderNameSet)logfile << "...found " << ntotalfiles << " different files\n"; Status("Scanning Headers"); if(m_OutputFolderNameSet) logfile << "Scanning Headers\n"; gdcm::Scanner s; const gdcm::Tag t1(0x0020,0x000d); // Study Instance UID const gdcm::Tag t2(0x0020,0x000e); // Series Instance UID const gdcm::Tag t5(0x0028, 0x0010); // number rows const gdcm::Tag t6(0x0028, 0x0011); // number cols s.AddTag( t1 ); s.AddTag( t2 ); s.AddTag( t5 ); s.AddTag( t6 ); bool b = s.Scan( d.GetFilenames() ); if( !b ) { Error("Scanner failed"); if(m_OutputFolderNameSet )logfile << "ERROR: scanner failed\n"; continue; } // Only get the DICOM files: gdcm::Directory::FilenamesType l2 = s.GetKeys(); const int nfiles = l2.size(); if(nfiles < 1) { Error("No DICOM files found"); if(m_OutputFolderNameSet)logfile << "ERROR: No DICOM files found\n"; continue; } Status(QString(" ... successfully scanned %1 headers.").arg(nfiles)); if(m_OutputFolderNameSet) logfile << "...succesfully scanned " << nfiles << " headers\n"; Status("Sorting"); if(m_OutputFolderNameSet) logfile << "Sorting\n"; const gdcm::Scanner::ValuesType &values1 = s.GetValues(t1); int nvalues; if(m_Controls->m_DuplicateID->isChecked()) { nvalues = 1; } else { nvalues = values1.size(); } if(nvalues>1) { Error("Multiple sSeries tudies found. Please limit to 1 study per folder"); if(m_OutputFolderNameSet) logfile << "Multiple series found. Limit to one. If you are convinced this is an error use the merge duplicate study IDs option \n"; continue; } const gdcm::Scanner::ValuesType &values5 = s.GetValues(t5); const gdcm::Scanner::ValuesType &values6 = s.GetValues(t6); if(values5.size()>1 || values6.size()>1) { Error("Folder contains images of unequal dimensions that cannot be combined in one 3d volume. ABORTING."); if(m_OutputFolderNameSet) logfile << "Folder contains images of unequal dimensions that cannot be combined in one 3d volume. ABORTING\n."; continue; } const gdcm::Scanner::ValuesType &values2 = s.GetValues(t2); int nSeries; if(m_Controls->m_DuplicateID->isChecked()) { nSeries = 1; } else { nSeries = values2.size(); } gdcm::Directory::FilenamesType files; if(nSeries > 1) { gdcm::Sorter sorter; sorter.SetSortFunction( SortBySeriesUID ); sorter.StableSort( l2 ); files = sorter.GetFilenames(); } else { files = l2; } unsigned int nTotalAcquis = 0; if(nfiles % nSeries != 0) { Error("Number of files in series not equal, ABORTING"); if(m_OutputFolderNameSet) logfile << "Number of files in series not equal, Some volumes are probably incomplete. ABORTING \n"; continue; } int filesPerSeries = nfiles / nSeries; gdcm::Scanner::ValuesType::const_iterator it2 = values2.begin(); for(int i=0; i 1) // More than one element must have this tag (Not != ) { subsorter.SetSortFunction( SortByAcquisitionNumber ); it = values3.begin(); } - else + else if (values4.size() > 1) { nAcquis = values4.size(); subsorter.SetSortFunction( SortBySeqName ); it = values4.begin(); } + // Hotfix for Bug 14758, better fix by selecting always availible tags. + else + { + Error("Sorting tags (0x0020,0x0012) and (0x0018,0x0024) missing, ABORTING"); + if(m_OutputFolderNameSet) logfile << "Sorting tags (0x0020,0x0012) and (0x0018,0x0024) missing, ABORTING\n"; + continue; + } nTotalAcquis += nAcquis; subsorter.Sort( sub ); if(filesPerSeries % nAcquis != 0) { Error("Number of files per acquisition not equal, ABORTING"); if(m_OutputFolderNameSet) logfile << "Number of files per acquisition not equal, ABORTING \n"; continue; } int filesPerAcqu = filesPerSeries / nAcquis; gdcm::Directory::FilenamesType subfiles = subsorter.GetFilenames(); for ( unsigned int j = 0 ; j < nAcquis ; ++j ) { std::string identifier = "serie_" + *it2 + "_acquis_" + *it++; gdcm::IPPSorter ippsorter; gdcm::Directory::FilenamesType ipplist((j)*filesPerAcqu+subfiles.begin(),(j+1)*filesPerAcqu+subfiles.begin()); ippsorter.SetComputeZSpacing( true ); if( !ippsorter.Sort( ipplist ) ) { Error(QString("Failed to sort acquisition %1, ABORTING").arg(identifier.c_str())); if(m_OutputFolderNameSet) logfile << "Failed to sort acquisition " << identifier.c_str() << " , Aborting\n"; continue; } const std::vector & list = ippsorter.GetFilenames(); seriesFilenames.push_back(list); seriesUIDs.push_back(identifier.c_str()); } ++it2; } + // Hot Fix for Bug 14758, checking if no file is acuired. + if (nTotalAcquis < 1) // Test if zero, if true than error because no file was selected + { + Error("Nno files in acquisitions, ABORTING"); + if(m_OutputFolderNameSet) logfile << "Nno files in acquisitions, ABORTING \n"; + continue; + } + if(nfiles % nTotalAcquis != 0) { Error("Number of files per acquisition differs between series, ABORTING"); if(m_OutputFolderNameSet) logfile << "Number of files per acquisition differs between series, ABORTING \n"; continue; } int slices = nfiles/nTotalAcquis; Status(QString("Series is composed of %1 different 3D volumes with %2 slices.").arg(nTotalAcquis).arg(slices)); if(m_OutputFolderNameSet) logfile << "Series is composed of " << nTotalAcquis << " different 3D volumes with " << slices << " slices\n"; // READING HEADER-INFOS PrintMemoryUsage(); Status(QString("Reading Headers %1").arg(folderName)); if(m_OutputFolderNameSet) logfile << "Reading Headers "<< folderName.toStdString() << "\n"; mitk::DicomDiffusionImageHeaderReader::Pointer headerReader; mitk::GroupDiffusionHeadersFilter::InputType inHeaders; unsigned int size2 = seriesUIDs.size(); for ( unsigned int i = 0 ; i < size2 ; ++i ) { - Status(QString("Reading header image #%1/%2").arg(i+1).arg(size2)); - headerReader = mitk::DicomDiffusionImageHeaderReader::New(); - headerReader->SetSeriesDicomFilenames(seriesFilenames[i]); - headerReader->Update(); - inHeaders.push_back(headerReader->GetOutput()); + // Hot Fix for Bug 14459, catching if no valid data in datafile. + try + { + Status(QString("Reading header image #%1/%2").arg(i+1).arg(size2)); + headerReader = mitk::DicomDiffusionImageHeaderReader::New(); + headerReader->SetSeriesDicomFilenames(seriesFilenames[i]); + headerReader->Update(); + inHeaders.push_back(headerReader->GetOutput()); + } + catch (mitk::Exception e) + { + Error("Could not read file header, ABORTING"); + if(m_OutputFolderNameSet) logfile << e; + continue; + } + //Status(std::endl; } mitk::ProgressBar::GetInstance()->Progress(); // // GROUP HEADERS // mitk::GroupDiffusionHeadersFilter::Pointer grouper // = mitk::GroupDiffusionHeadersFilter::New(); // mitk::GroupDiffusionHeadersFilter::OutputType outHeaders; // grouper->SetInput(inHeaders); // grouper->Update(); // outHeaders = grouper->GetOutput(); // READ VOLUMES PrintMemoryUsage(); if(m_OutputFolderNameSet) logfile << "Loading volumes\n"; Status(QString("Loading Volumes %1").arg(folderName)); typedef short PixelValueType; typedef mitk::DicomDiffusionImageReader< PixelValueType, 3 > VolumesReader; VolumesReader::Pointer vReader = VolumesReader::New(); VolumesReader::HeaderContainer hc = inHeaders; // hc.insert(hc.end(), outHeaders[1].begin(), outHeaders[1].end() ); // hc.insert(hc.end(), outHeaders[2].begin(), outHeaders[2].end() ); if(hc.size()>1) { vReader->SetHeaders(hc); vReader->Update(); VolumesReader::OutputImageType::Pointer vecImage; vecImage = vReader->GetOutput(); Status(QString("Volumes Loaded (%1)").arg(folderName)); // CONSTRUCT CONTAINER WITH DIRECTIONS typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; GradientDirectionContainerType::Pointer directions = GradientDirectionContainerType::New(); std::vector b_vals; double maxb = 0; for(unsigned int i=0; ibValue; if(maxb vect = hc[i]->DiffusionVector; vect.normalize(); vect *= sqrt(b_vals[i]/maxb); directions->push_back(vect); } // DWI TO DATATREE PrintMemoryUsage(); Status(QString("Initializing Diffusion Image")); if(m_OutputFolderNameSet) logfile << "Initializing Diffusion Image\n"; typedef mitk::DiffusionImage DiffVolumesType; DiffVolumesType::Pointer diffImage = DiffVolumesType::New(); diffImage->SetDirections(directions); diffImage->SetVectorImage(vecImage); diffImage->SetB_Value(maxb); diffImage->InitializeFromVectorImage(); diffImage->UpdateBValueList(); Status(QString("Diffusion Image initialized")); if(m_OutputFolderNameSet) logfile << "Diffusion Image initialized\n"; if(m_Controls->m_DicomLoadAverageDuplicatesCheckbox->isChecked()) { PrintMemoryUsage(); Status(QString("Averaging gradient directions")); logfile << "Averaging gradient directions\n"; diffImage->AverageRedundantGradients(m_Controls->m_Blur->value()); } QString descr = QString("%1_%2_%3") .arg(((inHeaders)[0])->seriesDescription.c_str()) .arg(((inHeaders)[0])->seriesNumber) .arg(((inHeaders)[0])->patientName.c_str()); descr = descr.trimmed(); descr = descr.replace(" ", "_"); if(!m_OutputFolderNameSet) { node=mitk::DataNode::New(); node->SetData( diffImage ); GetDefaultDataStorage()->Add(node); SetDwiNodeProperties(node, descr.toStdString().c_str()); Status(QString("Image %1 added to datastorage").arg(descr)); } else { typedef mitk::NrrdDiffusionImageWriter WriterType; WriterType::Pointer writer = WriterType::New(); QString fullpath = QString("%1/%2.dwi") .arg(m_OutputFolderName) .arg(descr); // if the override option is not checked, we need to make sure that the current filepath // does not point to an existing file if( !(m_Controls->m_OverrideOptionCheckbox->isChecked()) ) { QFile outputFile( fullpath ); // generate new filename if file exists int file_counter = 0; while( outputFile.exists() ) { // copy base name QString newdescr = descr; file_counter++; MITK_WARN << "The file "<< fullpath.toStdString() << " exists already."; QString appendix = QString("_%1").arg( QString::number(file_counter) ); newdescr.append(appendix); fullpath = QString("%1/%2.dwi") .arg(m_OutputFolderName) .arg(newdescr); // set the new generated filename for next check outputFile.setFileName( fullpath ); } } writer->SetFileName(fullpath.toStdString()); writer->SetInput(diffImage); try { writer->Update(); } catch (itk::ExceptionObject &ex) { imageSuccessfullySaved = false; Error(QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription())); logfile << QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription()).toStdString() << "\n"; node=mitk::DataNode::New(); node->SetData( diffImage ); GetDefaultDataStorage()->Add(node); SetDwiNodeProperties(node, descr.toStdString().c_str()); Status(QString("Image %1 added to datastorage").arg(descr)); logfile << "Image " << descr.toStdString() << " added to datastorage\n"; continue ; } Status(QString("Image %1 written to disc (%1)").arg(fullpath.toStdString().c_str())); logfile << "Image " << fullpath.toStdString() << "\n"; } } else { Status(QString("No diffusion information found (%1)").arg(folderName)); if(m_OutputFolderNameSet) logfile << "No diffusion information found "<< folderName.toStdString(); } Status(QString("Finished processing %1 with memory:").arg(folderName)); if(m_OutputFolderNameSet) logfile << "Finished processing " << folderName.toStdString() << "\n"; PrintMemoryUsage(); clock.Stop(folderName.toAscii()); mitk::ProgressBar::GetInstance()->Progress(); int lwidget = m_Controls->listWidget->count(); std::cout << lwidget <GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); try { MITK_INFO << " ** Changing locale back from " << setlocale(LC_ALL, NULL) << " to '" << currLocale << "'"; setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } } catch (itk::ExceptionObject &ex) { Error(QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription())); return ; } if (!imageSuccessfullySaved) QMessageBox::warning(NULL,"WARNING","One or more files could not be saved! The according files where moved to the datastorage."); Status(QString("Finished import with memory:")); PrintMemoryUsage(); } void QmitkDiffusionDicomImport::SetDwiNodeProperties(mitk::DataNode::Pointer node, std::string name) { node->SetProperty( "IsDWIRawVolume", mitk::BoolProperty::New( true ) ); // set foldername as string property mitk::StringProperty::Pointer nameProp = mitk::StringProperty::New( name ); node->SetProperty( "name", nameProp ); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.cpp similarity index 76% copy from Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp copy to Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.cpp index dfa9bd2b38..214cb0f0b9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.cpp @@ -1,1703 +1,1370 @@ /*=================================================================== 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 "QmitkFiberProcessingView.h" +#include "QmitkFiberExtractionView.h" #include // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include #include #include // ITK #include #include #include #include #include #include #include #include -const std::string QmitkFiberProcessingView::VIEW_ID = "org.mitk.views.fiberprocessing"; +const std::string QmitkFiberExtractionView::VIEW_ID = "org.mitk.views.fiberextraction"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace mitk; -QmitkFiberProcessingView::QmitkFiberProcessingView() +QmitkFiberExtractionView::QmitkFiberExtractionView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_CircleCounter(0) , m_PolygonCounter(0) , m_UpsamplingFactor(5) { } // Destructor -QmitkFiberProcessingView::~QmitkFiberProcessingView() +QmitkFiberExtractionView::~QmitkFiberExtractionView() { } -void QmitkFiberProcessingView::CreateQtPartControl( QWidget *parent ) +void QmitkFiberExtractionView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file - m_Controls = new Ui::QmitkFiberProcessingViewControls; + m_Controls = new Ui::QmitkFiberExtractionViewControls; m_Controls->setupUi( parent ); m_Controls->doExtractFibersButton->setDisabled(true); m_Controls->PFCompoANDButton->setDisabled(true); m_Controls->PFCompoORButton->setDisabled(true); m_Controls->PFCompoNOTButton->setDisabled(true); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_RectangleButton->setVisible(false); - connect( m_Controls->doExtractFibersButton, SIGNAL(clicked()), this, SLOT(DoFiberExtraction()) ); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ), this, SLOT( OnDrawCircle() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ), this, SLOT( OnDrawPolygon() ) ); connect(m_Controls->PFCompoANDButton, SIGNAL(clicked()), this, SLOT(GenerateAndComposite()) ); connect(m_Controls->PFCompoORButton, SIGNAL(clicked()), this, SLOT(GenerateOrComposite()) ); connect(m_Controls->PFCompoNOTButton, SIGNAL(clicked()), this, SLOT(GenerateNotComposite()) ); connect(m_Controls->m_JoinBundles, SIGNAL(clicked()), this, SLOT(JoinBundles()) ); connect(m_Controls->m_SubstractBundles, SIGNAL(clicked()), this, SLOT(SubstractBundles()) ); connect(m_Controls->m_GenerateRoiImage, SIGNAL(clicked()), this, SLOT(GenerateRoiImage()) ); - connect(m_Controls->m_Extract3dButton, SIGNAL(clicked()), this, SLOT(Extract3d())); - connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); - connect( m_Controls->m_ResampleFibersButton, SIGNAL(clicked()), this, SLOT(ResampleSelectedBundles()) ); - connect(m_Controls->m_FaColorFibersButton, SIGNAL(clicked()), this, SLOT(DoImageColorCoding())); - connect( m_Controls->m_PruneFibersButton, SIGNAL(clicked()), this, SLOT(PruneBundle()) ); - connect( m_Controls->m_CurvatureThresholdButton, SIGNAL(clicked()), this, SLOT(ApplyCurvatureThreshold()) ); - connect( m_Controls->m_MirrorFibersButton, SIGNAL(clicked()), this, SLOT(MirrorFibers()) ); - - connect( m_Controls->m_ExtractMask, SIGNAL(clicked()), this, SLOT(ExtractMask()) ); + + connect(m_Controls->m_Extract3dButton, SIGNAL(clicked()), this, SLOT(ExtractPassingMask())); + connect( m_Controls->m_ExtractMask, SIGNAL(clicked()), this, SLOT(ExtractEndingInMask()) ); + connect( m_Controls->doExtractFibersButton, SIGNAL(clicked()), this, SLOT(DoFiberExtraction()) ); } } -void QmitkFiberProcessingView::ExtractMask() +void QmitkFiberExtractionView::ExtractEndingInMask() { if (m_MaskImageNode.IsNull()) return; mitk::Image::Pointer mitkMask = dynamic_cast(m_MaskImageNode->GetData()); for (int i=0; i(m_SelectedFB.at(i)->GetData()); QString name(m_SelectedFB.at(i)->GetName().c_str()); itkUCharImageType::Pointer mask = itkUCharImageType::New(); mitk::CastToItkImage(mitkMask, mask); mitk::FiberBundleX::Pointer newFib = fib->ExtractFiberSubset(mask, false); + if (newFib->GetNumFibers()<=0) + { + QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); + continue; + } + DataNode::Pointer newNode = DataNode::New(); newNode->SetData(newFib); name += "_ending-in-mask"; newNode->SetName(name.toStdString()); GetDefaultDataStorage()->Add(newNode); + m_SelectedFB.at(i)->SetVisibility(false); } } -void QmitkFiberProcessingView::Extract3d() +void QmitkFiberExtractionView::ExtractPassingMask() { if (m_MaskImageNode.IsNull()) return; mitk::Image::Pointer mitkMask = dynamic_cast(m_MaskImageNode->GetData()); for (int i=0; i(m_SelectedFB.at(i)->GetData()); QString name(m_SelectedFB.at(i)->GetName().c_str()); itkUCharImageType::Pointer mask = itkUCharImageType::New(); mitk::CastToItkImage(mitkMask, mask); mitk::FiberBundleX::Pointer newFib = fib->ExtractFiberSubset(mask, true); + if (newFib->GetNumFibers()<=0) + { + QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); + continue; + } DataNode::Pointer newNode = DataNode::New(); newNode->SetData(newFib); name += "_passing-mask"; newNode->SetName(name.toStdString()); GetDefaultDataStorage()->Add(newNode); + m_SelectedFB.at(i)->SetVisibility(false); } } -void QmitkFiberProcessingView::GenerateRoiImage(){ +void QmitkFiberExtractionView::GenerateRoiImage(){ if (m_SelectedPF.empty()) return; mitk::Geometry3D::Pointer geometry; if (!m_SelectedFB.empty()) { mitk::FiberBundleX::Pointer fib = dynamic_cast(m_SelectedFB.front()->GetData()); geometry = fib->GetGeometry(); } else return; mitk::Vector3D spacing = geometry->GetSpacing(); spacing /= m_UpsamplingFactor; mitk::Point3D newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); newOrigin[0] += bounds.GetElement(0); newOrigin[1] += bounds.GetElement(2); newOrigin[2] += bounds.GetElement(4); itk::Matrix direction; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction[j][i] = geometry->GetMatrixColumn(i)[j]/spacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); imageRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); imageRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); m_PlanarFigureImage = itkUCharImageType::New(); m_PlanarFigureImage->SetSpacing( spacing ); // Set the image spacing m_PlanarFigureImage->SetOrigin( newOrigin ); // Set the image origin m_PlanarFigureImage->SetDirection( direction ); // Set the image direction m_PlanarFigureImage->SetRegions( imageRegion ); m_PlanarFigureImage->Allocate(); m_PlanarFigureImage->FillBuffer( 0 ); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); for (int i=0; iInitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); node->SetData(tmpImage); node->SetName("ROI Image"); this->GetDefaultDataStorage()->Add(node); } -void QmitkFiberProcessingView::CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image) +void QmitkFiberExtractionView::CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image) { if (dynamic_cast(node.GetPointer()->GetData()) && !dynamic_cast(node.GetPointer()->GetData())) { m_PlanarFigure = dynamic_cast(node.GetPointer()->GetData()); AccessFixedDimensionByItk_2( image, InternalReorientImagePlane, 3, m_PlanarFigure->GetGeometry(), -1); - // itk::Image< unsigned char, 3 >::Pointer outimage = itk::Image< unsigned char, 3 >::New(); - - // outimage->SetSpacing( m_PlanarFigure->GetGeometry()->GetSpacing()/m_UpsamplingFactor ); // Set the image spacing - - // mitk::Point3D origin = m_PlanarFigure->GetGeometry()->GetOrigin(); - // mitk::Point3D indexOrigin; - // m_PlanarFigure->GetGeometry()->WorldToIndex(origin, indexOrigin); - // indexOrigin[0] = indexOrigin[0] - .5 * (1.0-1.0/m_UpsamplingFactor); - // indexOrigin[1] = indexOrigin[1] - .5 * (1.0-1.0/m_UpsamplingFactor); - // indexOrigin[2] = indexOrigin[2] - .5 * (1.0-1.0/m_UpsamplingFactor); - // mitk::Point3D newOrigin; - // m_PlanarFigure->GetGeometry()->IndexToWorld(indexOrigin, newOrigin); - - // outimage->SetOrigin( newOrigin ); // Set the image origin - // itk::Matrix matrix; - // for (int i=0; i<3; i++) - // for (int j=0; j<3; j++) - // matrix[j][i] = m_PlanarFigure->GetGeometry()->GetMatrixColumn(i)[j]/m_PlanarFigure->GetGeometry()->GetSpacing().GetElement(i); - // outimage->SetDirection( matrix ); // Set the image direction - - // itk::ImageRegion<3> upsampledRegion; - // upsampledRegion.SetSize(0, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(0)/m_PlanarFigure->GetGeometry()->GetSpacing()[0]); - // upsampledRegion.SetSize(1, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(1)/m_PlanarFigure->GetGeometry()->GetSpacing()[1]); - // upsampledRegion.SetSize(2, 1); - - // typename itk::Image< unsigned char, 3 >::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); - // for (unsigned int n = 0; n < 2; n++) - // { - // upsampledSize[n] = upsampledSize[n] * m_UpsamplingFactor; - // } - // upsampledRegion.SetSize( upsampledSize ); - // outimage->SetRegions( upsampledRegion ); - - // outimage->Allocate(); - - // this->m_InternalImage = mitk::Image::New(); - // this->m_InternalImage->InitializeByItk( outimage.GetPointer() ); - // this->m_InternalImage->SetVolume( outimage->GetBufferPointer() ); - AccessFixedDimensionByItk_2( m_InternalImage, InternalCalculateMaskFromPlanarFigure, 3, 2, node->GetName() ); } } template < typename TPixel, unsigned int VImageDimension > -void QmitkFiberProcessingView::InternalReorientImagePlane( - const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ) +void QmitkFiberExtractionView::InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ) { MITK_DEBUG << "InternalReorientImagePlane() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< float, VImageDimension > FloatImageType; typedef itk::ResampleImageFilter ResamplerType; typename ResamplerType::Pointer resampler = ResamplerType::New(); mitk::PlaneGeometry* planegeo = dynamic_cast(planegeo3D); float upsamp = m_UpsamplingFactor; float gausssigma = 0.5; // Spacing typename ResamplerType::SpacingType spacing = planegeo->GetSpacing(); spacing[0] = image->GetSpacing()[0] / upsamp; spacing[1] = image->GetSpacing()[1] / upsamp; spacing[2] = image->GetSpacing()[2]; resampler->SetOutputSpacing( spacing ); // Size typename ResamplerType::SizeType size; size[0] = planegeo->GetParametricExtentInMM(0) / spacing[0]; size[1] = planegeo->GetParametricExtentInMM(1) / spacing[1]; size[2] = 1; resampler->SetSize( size ); // Origin typename mitk::Point3D orig = planegeo->GetOrigin(); typename mitk::Point3D corrorig; planegeo3D->WorldToIndex(orig,corrorig); corrorig[0] += 0.5/upsamp; corrorig[1] += 0.5/upsamp; corrorig[2] += 0; planegeo3D->IndexToWorld(corrorig,corrorig); resampler->SetOutputOrigin(corrorig ); // Direction typename ResamplerType::DirectionType direction; typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix(); for(int c=0; cSetOutputDirection( direction ); // Gaussian interpolation if(gausssigma != 0) { double sigma[3]; for( unsigned int d = 0; d < 3; d++ ) { sigma[d] = gausssigma * image->GetSpacing()[d]; } double alpha = 2.0; typedef itk::GaussianInterpolateImageFunction GaussianInterpolatorType; typename GaussianInterpolatorType::Pointer interpolator = GaussianInterpolatorType::New(); interpolator->SetInputImage( image ); interpolator->SetParameters( sigma, alpha ); resampler->SetInterpolator( interpolator ); } else { // typedef typename itk::BSplineInterpolateImageFunction // InterpolatorType; typedef typename itk::LinearInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetInputImage( image ); resampler->SetInterpolator( interpolator ); } // Other resampling options resampler->SetInput( image ); resampler->SetDefaultPixelValue(0); MITK_DEBUG << "Resampling requested image plane ... "; resampler->Update(); MITK_DEBUG << " ... done"; if(additionalIndex < 0) { this->m_InternalImage = mitk::Image::New(); this->m_InternalImage->InitializeByItk( resampler->GetOutput() ); this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() ); } } template < typename TPixel, unsigned int VImageDimension > -void QmitkFiberProcessingView::InternalCalculateMaskFromPlanarFigure( - itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ) +void QmitkFiberExtractionView::InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ) { MITK_DEBUG << "InternalCalculateMaskFromPlanarFigure() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::CastImageFilter< ImageType, itkUCharImageType > CastFilterType; // Generate mask image as new image with same header as input image and // initialize with "1". itkUCharImageType::Pointer newMaskImage = itkUCharImageType::New(); newMaskImage->SetSpacing( image->GetSpacing() ); // Set the image spacing newMaskImage->SetOrigin( image->GetOrigin() ); // Set the image origin newMaskImage->SetDirection( image->GetDirection() ); // Set the image direction newMaskImage->SetRegions( image->GetLargestPossibleRegion() ); newMaskImage->Allocate(); newMaskImage->FillBuffer( 1 ); // Generate VTK polygon from (closed) PlanarFigure polyline // (The polyline points are shifted by -0.5 in z-direction to make sure // that the extrusion filter, which afterwards elevates all points by +0.5 // in z-direction, creates a 3D object which is cut by the the plane z=0) const Geometry2D *planarFigureGeometry2D = m_PlanarFigure->GetGeometry2D(); const PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 ); const Geometry3D *imageGeometry3D = m_InternalImage->GetGeometry( 0 ); vtkPolyData *polyline = vtkPolyData::New(); polyline->Allocate( 1, 1 ); // Determine x- and y-dimensions depending on principal axis int i0, i1; switch ( axis ) { case 0: i0 = 1; i1 = 2; break; case 1: i0 = 0; i1 = 2; break; case 2: default: i0 = 0; i1 = 1; break; } // Create VTK polydata object of polyline contour vtkPoints *points = vtkPoints::New(); PlanarFigure::PolyLineType::const_iterator it; std::vector indices; unsigned int numberOfPoints = 0; for ( it = planarFigurePolyline.begin(); it != planarFigurePolyline.end(); ++it ) { Point3D point3D; // Convert 2D point back to the local index coordinates of the selected // image Point2D point2D = it->Point; planarFigureGeometry2D->WorldToIndex(point2D, point2D); point2D[0] -= 0.5/m_UpsamplingFactor; point2D[1] -= 0.5/m_UpsamplingFactor; planarFigureGeometry2D->IndexToWorld(point2D, point2D); planarFigureGeometry2D->Map( point2D, point3D ); // Polygons (partially) outside of the image bounds can not be processed // further due to a bug in vtkPolyDataToImageStencil if ( !imageGeometry3D->IsInside( point3D ) ) { float bounds[2] = {0,0}; bounds[0] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i0); bounds[1] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i1); imageGeometry3D->WorldToIndex( point3D, point3D ); // if (point3D[i0]<0) // point3D[i0] = 0.5; // else if (point3D[i0]>bounds[0]) // point3D[i0] = bounds[0]-0.5; // if (point3D[i1]<0) // point3D[i1] = 0.5; // else if (point3D[i1]>bounds[1]) // point3D[i1] = bounds[1]-0.5; if (point3D[i0]<0) point3D[i0] = 0.0; else if (point3D[i0]>bounds[0]) point3D[i0] = bounds[0]-0.001; if (point3D[i1]<0) point3D[i1] = 0.0; else if (point3D[i1]>bounds[1]) point3D[i1] = bounds[1]-0.001; points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } else { imageGeometry3D->WorldToIndex( point3D, point3D ); // Add point to polyline array points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } } polyline->SetPoints( points ); points->Delete(); vtkIdType *ptIds = new vtkIdType[numberOfPoints]; for ( vtkIdType i = 0; i < numberOfPoints; ++i ) { ptIds[i] = i; } polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds ); // Extrude the generated contour polygon vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New(); extrudeFilter->SetInput( polyline ); extrudeFilter->SetScaleFactor( 1 ); extrudeFilter->SetExtrusionTypeToNormalExtrusion(); extrudeFilter->SetVector( 0.0, 0.0, 1.0 ); // Make a stencil from the extruded polygon vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New(); polyDataToImageStencil->SetInput( extrudeFilter->GetOutput() ); // Export from ITK to VTK (to use a VTK filter) typedef itk::VTKImageImport< itkUCharImageType > ImageImportType; typedef itk::VTKImageExport< itkUCharImageType > ImageExportType; typename ImageExportType::Pointer itkExporter = ImageExportType::New(); itkExporter->SetInput( newMaskImage ); vtkImageImport *vtkImporter = vtkImageImport::New(); this->ConnectPipelines( itkExporter, vtkImporter ); vtkImporter->Update(); // Apply the generated image stencil to the input image vtkImageStencil *imageStencilFilter = vtkImageStencil::New(); imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() ); imageStencilFilter->SetStencil( polyDataToImageStencil->GetOutput() ); imageStencilFilter->ReverseStencilOff(); imageStencilFilter->SetBackgroundValue( 0 ); imageStencilFilter->Update(); // Export from VTK back to ITK vtkImageExport *vtkExporter = vtkImageExport::New(); vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() ); vtkExporter->Update(); typename ImageImportType::Pointer itkImporter = ImageImportType::New(); this->ConnectPipelines( vtkExporter, itkImporter ); itkImporter->Update(); // calculate cropping bounding box m_InternalImageMask3D = itkImporter->GetOutput(); m_InternalImageMask3D->SetDirection(image->GetDirection()); itk::ImageRegionConstIterator itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion()); itk::ImageRegionIterator itimage(image, image->GetLargestPossibleRegion()); itmask = itmask.Begin(); itimage = itimage.Begin(); typename ImageType::SizeType lowersize = {{9999999999,9999999999,9999999999}}; typename ImageType::SizeType uppersize = {{0,0,0}}; while( !itmask.IsAtEnd() ) { if(itmask.Get() == 0) { itimage.Set(0); } else { typename ImageType::IndexType index = itimage.GetIndex(); typename ImageType::SizeType signedindex; signedindex[0] = index[0]; signedindex[1] = index[1]; signedindex[2] = index[2]; lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0]; lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1]; lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2]; uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0]; uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1]; uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2]; } ++itmask; ++itimage; } typename ImageType::IndexType index; index[0] = lowersize[0]; index[1] = lowersize[1]; index[2] = lowersize[2]; typename ImageType::SizeType size; size[0] = uppersize[0] - lowersize[0] + 1; size[1] = uppersize[1] - lowersize[1] + 1; size[2] = uppersize[2] - lowersize[2] + 1; itk::ImageRegion<3> cropRegion = itk::ImageRegion<3>(index, size); // crop internal mask typedef itk::RegionOfInterestImageFilter< itkUCharImageType, itkUCharImageType > ROIMaskFilterType; typename ROIMaskFilterType::Pointer roi2 = ROIMaskFilterType::New(); roi2->SetRegionOfInterest(cropRegion); roi2->SetInput(m_InternalImageMask3D); roi2->Update(); m_InternalImageMask3D = roi2->GetOutput(); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_InternalImageMask3D.GetPointer()); tmpImage->SetVolume(m_InternalImageMask3D->GetBufferPointer()); Image::Pointer tmpImage2 = Image::New(); tmpImage2->InitializeByItk(m_PlanarFigureImage.GetPointer()); const Geometry3D *pfImageGeometry3D = tmpImage2->GetGeometry( 0 ); const Geometry3D *intImageGeometry3D = tmpImage->GetGeometry( 0 ); typedef itk::ImageRegionIteratorWithIndex IteratorType; IteratorType imageIterator (m_InternalImageMask3D, m_InternalImageMask3D->GetRequestedRegion()); imageIterator.GoToBegin(); while ( !imageIterator.IsAtEnd() ) { unsigned char val = imageIterator.Value(); if (val>0) { itk::Index<3> index = imageIterator.GetIndex(); Point3D point; point[0] = index[0]; point[1] = index[1]; point[2] = index[2]; intImageGeometry3D->IndexToWorld(point, point); pfImageGeometry3D->WorldToIndex(point, point); point[i0] += 0.5; point[i1] += 0.5; index[0] = point[0]; index[1] = point[1]; index[2] = point[2]; if (pfImageGeometry3D->IsIndexInside(index)) m_PlanarFigureImage->SetPixel(index, 1); } ++imageIterator; } // Clean up VTK objects polyline->Delete(); extrudeFilter->Delete(); polyDataToImageStencil->Delete(); vtkImporter->Delete(); imageStencilFilter->Delete(); //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak?? delete[] ptIds; } -void QmitkFiberProcessingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) +void QmitkFiberExtractionView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } -void QmitkFiberProcessingView::StdMultiWidgetNotAvailable() +void QmitkFiberExtractionView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ -void QmitkFiberProcessingView::UpdateGui() +void QmitkFiberExtractionView::UpdateGui() { m_Controls->m_Extract3dButton->setEnabled(false); m_Controls->m_ExtractMask->setEnabled(false); // are fiber bundles selected? if ( m_SelectedFB.empty() ) { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); - m_Controls->m_ProcessFiberBundleButton->setEnabled(false); m_Controls->doExtractFibersButton->setEnabled(false); - m_Controls->m_ResampleFibersButton->setEnabled(false); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); - m_Controls->m_FaColorFibersButton->setEnabled(false); - m_Controls->m_PruneFibersButton->setEnabled(false); - m_Controls->m_CurvatureThresholdButton->setEnabled(false); - - if (m_SelectedSurfaces.size()>0) - m_Controls->m_MirrorFibersButton->setEnabled(true); - else - m_Controls->m_MirrorFibersButton->setEnabled(false); } else { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); - m_Controls->m_ProcessFiberBundleButton->setEnabled(true); - m_Controls->m_ResampleFibersButton->setEnabled(true); - m_Controls->m_PruneFibersButton->setEnabled(true); - m_Controls->m_CurvatureThresholdButton->setEnabled(true); - m_Controls->m_MirrorFibersButton->setEnabled(true); // one bundle and one planar figure needed to extract fibers if (!m_SelectedPF.empty()) - { m_Controls->doExtractFibersButton->setEnabled(true); - } // more than two bundles needed to join/subtract if (m_SelectedFB.size() > 1) { m_Controls->m_JoinBundles->setEnabled(true); m_Controls->m_SubstractBundles->setEnabled(true); } else { m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); } - if (m_SelectedImage.IsNotNull()) - m_Controls->m_FaColorFibersButton->setEnabled(true); - if (m_MaskImageNode.IsNotNull()) { m_Controls->m_Extract3dButton->setEnabled(true); m_Controls->m_ExtractMask->setEnabled(true); } } // are planar figures selected? if ( m_SelectedPF.empty() ) { m_Controls->doExtractFibersButton->setEnabled(false); m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(false); m_Controls->m_GenerateRoiImage->setEnabled(false); } else { if ( !m_SelectedFB.empty() ) m_Controls->m_GenerateRoiImage->setEnabled(true); else m_Controls->m_GenerateRoiImage->setEnabled(false); if (m_SelectedPF.size() > 1) { m_Controls->PFCompoANDButton->setEnabled(true); m_Controls->PFCompoORButton->setEnabled(true); m_Controls->PFCompoNOTButton->setEnabled(false); } else { m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(true); } } } -void QmitkFiberProcessingView::OnSelectionChanged( std::vector nodes ) +void QmitkFiberExtractionView::OnSelectionChanged( std::vector nodes ) { //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); m_SelectedPF.clear(); m_SelectedSurfaces.clear(); m_SelectedImage = NULL; m_MaskImageNode = NULL; m_Controls->m_FibLabel->setText("mandatory"); m_Controls->m_PfLabel->setText("needed for extraction"); for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( dynamic_cast(node->GetData()) ) { m_Controls->m_FibLabel->setText(node->GetName().c_str()); m_SelectedFB.push_back(node); } else if (dynamic_cast(node->GetData())) { m_Controls->m_PfLabel->setText(node->GetName().c_str()); m_SelectedPF.push_back(node); } else if (dynamic_cast(node->GetData())) { m_SelectedImage = dynamic_cast(node->GetData()); bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) + { m_MaskImageNode = node; + m_Controls->m_PfLabel->setText(node->GetName().c_str()); + } } else if (dynamic_cast(node->GetData())) { m_Controls->m_PfLabel->setText(node->GetName().c_str()); m_SelectedSurfaces.push_back(dynamic_cast(node->GetData())); } } UpdateGui(); GenerateStats(); } -void QmitkFiberProcessingView::OnDrawPolygon() +void QmitkFiberExtractionView::OnDrawPolygon() { // bool checked = m_Controls->m_PolygonButton->isChecked(); // if(!this->AssertDrawingIsPossible(checked)) // return; mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); this->AddFigureToDataStorage(figure, QString("Polygon%1").arg(++m_PolygonCounter)); MITK_DEBUG << "PlanarPolygon created ..."; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figureP = dynamic_cast(node->GetData()); if(figureP) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } -void QmitkFiberProcessingView::OnDrawCircle() +void QmitkFiberExtractionView::OnDrawCircle() { mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_CircleCounter)); this->GetDataStorage()->Modified(); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End(); it++) { node = const_cast(it->Value().GetPointer()); figureP = dynamic_cast(node->GetData()); if(figureP) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } -void QmitkFiberProcessingView::Activated() +void QmitkFiberExtractionView::Activated() { } -void QmitkFiberProcessingView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, +void QmitkFiberExtractionView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { // initialize figure's geometry with empty geometry mitk::PlaneGeometry::Pointer emptygeometry = mitk::PlaneGeometry::New(); figure->SetGeometry2D( emptygeometry ); //set desired data to DataNode where Planarfigure is stored mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,0.0,0.0)); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true)); newNode->AddProperty( "selected", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawoutline", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(false) ); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(3.0) ); newNode->AddProperty( "planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.outline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.helperline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(0.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.marker.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.marker.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.line.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.outline.opacity", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.helperline.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.marker.opacity",mitk::FloatProperty::New(2.0)); // figure drawn on the topmost layer / image newNode->SetColor(1.0,1.0,1.0); newNode->SetOpacity(0.8); GetDataStorage()->Add(newNode ); std::vector selectedNodes = GetDataManagerSelection(); for(unsigned int i = 0; i < selectedNodes.size(); i++) { selectedNodes[i]->SetSelected(false); } newNode->SetSelected(true); } -void QmitkFiberProcessingView::DoFiberExtraction() +void QmitkFiberExtractionView::DoFiberExtraction() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); - MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; + MITK_WARN("QmitkFiberExtractionView") << "no fibe bundle selected"; return; } for (int i=0; i(m_SelectedFB.at(i)->GetData()); mitk::PlanarFigure::Pointer roi = dynamic_cast (m_SelectedPF.at(0)->GetData()); mitk::FiberBundleX::Pointer extFB = fib->ExtractFiberSubset(roi); - if (extFB->GetNumFibers()<=0) + { + QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); continue; + } mitk::DataNode::Pointer node; node = mitk::DataNode::New(); node->SetData(extFB); QString name(m_SelectedFB.at(i)->GetName().c_str()); name += "_"; name += m_SelectedPF.at(0)->GetName().c_str(); node->SetName(name.toStdString()); GetDataStorage()->Add(node); m_SelectedFB.at(i)->SetVisibility(false); } } -void QmitkFiberProcessingView::GenerateAndComposite() +void QmitkFiberExtractionView::GenerateAndComposite() { mitk::PlanarFigureComposite::Pointer PFCAnd = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCAnd->SetGeometry2D(currentGeometry2D); PFCAnd->setOperationType(mitk::PFCOMPOSITION_AND_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCAnd->addPlanarFigure( tmpPF ); PFCAnd->addDataNode( nodePF ); PFCAnd->setDisplayName("AND_COMPO"); } AddCompositeToDatastorage(PFCAnd, NULL); } -void QmitkFiberProcessingView::GenerateOrComposite() +void QmitkFiberExtractionView::GenerateOrComposite() { mitk::PlanarFigureComposite::Pointer PFCOr = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCOr->SetGeometry2D(currentGeometry2D); PFCOr->setOperationType(mitk::PFCOMPOSITION_OR_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCOr->addPlanarFigure( tmpPF ); PFCOr->addDataNode( nodePF ); PFCOr->setDisplayName("OR_COMPO"); } AddCompositeToDatastorage(PFCOr, NULL); } -void QmitkFiberProcessingView::GenerateNotComposite() +void QmitkFiberExtractionView::GenerateNotComposite() { mitk::PlanarFigureComposite::Pointer PFCNot = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCNot->SetGeometry2D(currentGeometry2D); PFCNot->setOperationType(mitk::PFCOMPOSITION_NOT_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCNot->addPlanarFigure( tmpPF ); PFCNot->addDataNode( nodePF ); PFCNot->setDisplayName("NOT_COMPO"); } AddCompositeToDatastorage(PFCNot, NULL); } /* CLEANUP NEEDED */ -void QmitkFiberProcessingView::AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer pfcomp, mitk::DataNode::Pointer parentDataNode ) +void QmitkFiberExtractionView::AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer pfcomp, mitk::DataNode::Pointer parentDataNode ) { mitk::DataNode::Pointer newPFCNode; newPFCNode = mitk::DataNode::New(); newPFCNode->SetName( pfcomp->getDisplayName() ); newPFCNode->SetData(pfcomp); newPFCNode->SetVisibility(true); switch (pfcomp->getOperationType()) { case 0: { if (!parentDataNode.IsNull()) { GetDataStorage()->Add(newPFCNode, parentDataNode); } else { GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; } else { MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 1: { if (!parentDataNode.IsNull()) { MITK_DEBUG << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_DEBUG << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 2: { if (!parentDataNode.IsNull()) { MITK_DEBUG << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_DEBUG << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // makeRemoveBundle new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } default: MITK_DEBUG << "we have an UNDEFINED composition... ERROR" ; break; } } -void QmitkFiberProcessingView::JoinBundles() +void QmitkFiberExtractionView::JoinBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); - MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; + MITK_WARN("QmitkFiberExtractionView") << "Select at least two fiber bundles!"; return; } - std::vector::const_iterator it = m_SelectedFB.begin(); - mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); + mitk::FiberBundleX::Pointer newBundle = dynamic_cast(m_SelectedFB.at(0)->GetData()); + m_SelectedFB.at(0)->SetVisibility(false); QString name(""); - name += QString((*it)->GetName().c_str()); - ++it; - for (it; it!=m_SelectedFB.end(); ++it) + name += QString(m_SelectedFB.at(0)->GetName().c_str()); + for (int i=1; iAddBundle(dynamic_cast((*it)->GetData())); - name += "+"+QString((*it)->GetName().c_str()); + newBundle = newBundle->AddBundle(dynamic_cast(m_SelectedFB.at(i)->GetData())); + name += "+"+QString(m_SelectedFB.at(i)->GetName().c_str()); + m_SelectedFB.at(i)->SetVisibility(false); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } -void QmitkFiberProcessingView::SubstractBundles() +void QmitkFiberExtractionView::SubstractBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); - MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; + MITK_WARN("QmitkFiberExtractionView") << "Select at least two fiber bundles!"; return; } - std::vector::const_iterator it = m_SelectedFB.begin(); - mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); + mitk::FiberBundleX::Pointer newBundle = dynamic_cast(m_SelectedFB.at(0)->GetData()); + m_SelectedFB.at(0)->SetVisibility(false); QString name(""); - name += QString((*it)->GetName().c_str()); - ++it; - for (it; it!=m_SelectedFB.end(); ++it) + name += QString(m_SelectedFB.at(0)->GetName().c_str()); + for (int i=1; iSubtractBundle(dynamic_cast((*it)->GetData())); + newBundle = newBundle->SubtractBundle(dynamic_cast(m_SelectedFB.at(i)->GetData())); if (newBundle.IsNull()) break; - name += "-"+QString((*it)->GetName().c_str()); + name += "-"+QString(m_SelectedFB.at(i)->GetName().c_str()); + m_SelectedFB.at(i)->SetVisibility(false); } if (newBundle.IsNull()) { QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers. Did you select the fiber bundles in the correct order? X-Y is not equal to Y-X!"); return; } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } -void QmitkFiberProcessingView::PruneBundle() -{ - int minLength = this->m_Controls->m_PruneFibersSpinBox->value(); - int maxLength = this->m_Controls->m_MaxPruneFibersSpinBox->value(); - for (int i=0; i(m_SelectedFB.at(i)->GetData()); - if (!fib->RemoveShortFibers(minLength)) - QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); - else if (!fib->RemoveLongFibers(maxLength)) - QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); - } - GenerateStats(); - RenderingManager::GetInstance()->RequestUpdateAll(); -} - - -void QmitkFiberProcessingView::ApplyCurvatureThreshold() -{ - int mm = this->m_Controls->m_MinCurvatureRadiusBox->value(); - for (int i=0; i(m_SelectedFB.at(i)->GetData()); - if (!fib->ApplyCurvatureThreshold(mm, this->m_Controls->m_RemoveFiberDueToCurvatureCheckbox->isChecked())) - QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); - } - GenerateStats(); - RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkFiberProcessingView::GenerateStats() +void QmitkFiberExtractionView::GenerateStats() { if ( m_SelectedFB.empty() ) return; QString stats(""); for( int i=0; i(node->GetData())) { if (i>0) stats += "\n-----------------------------\n"; stats += QString(node->GetName().c_str()) + "\n"; mitk::FiberBundleX::Pointer fib = dynamic_cast(node->GetData()); stats += "Number of fibers: "+ QString::number(fib->GetNumFibers()) + "\n"; stats += "Min. length: "+ QString::number(fib->GetMinFiberLength(),'f',1) + " mm\n"; stats += "Max. length: "+ QString::number(fib->GetMaxFiberLength(),'f',1) + " mm\n"; stats += "Mean length: "+ QString::number(fib->GetMeanFiberLength(),'f',1) + " mm\n"; stats += "Median length: "+ QString::number(fib->GetMedianFiberLength(),'f',1) + " mm\n"; stats += "Standard deviation: "+ QString::number(fib->GetLengthStDev(),'f',1) + " mm\n"; } } this->m_Controls->m_StatsTextEdit->setText(stats); } - -void QmitkFiberProcessingView::ProcessSelectedBundles() -{ - if ( m_SelectedFB.empty() ){ - QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); - MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; - return; - } - - int generationMethod = m_Controls->m_GenerationBox->currentIndex(); - - for( int i=0; i(node->GetData())) - { - mitk::FiberBundleX::Pointer fib = dynamic_cast(node->GetData()); - QString name(node->GetName().c_str()); - DataNode::Pointer newNode = NULL; - switch(generationMethod){ - case 0: - newNode = GenerateTractDensityImage(fib, false, true); - name += "_TDI"; - break; - case 1: - newNode = GenerateTractDensityImage(fib, false, false); - name += "_TDI"; - break; - case 2: - newNode = GenerateTractDensityImage(fib, true, false); - name += "_envelope"; - break; - case 3: - newNode = GenerateColorHeatmap(fib); - break; - case 4: - newNode = GenerateFiberEndingsImage(fib); - name += "_fiber_endings"; - break; - case 5: - newNode = GenerateFiberEndingsPointSet(fib); - name += "_fiber_endings"; - break; - } - if (newNode.IsNotNull()) - { - newNode->SetName(name.toStdString()); - GetDataStorage()->Add(newNode); - } - } - } -} - -// generate pointset displaying the fiber endings -mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib) -{ - mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); - vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); - vtkSmartPointer vLines = fiberPolyData->GetLines(); - vLines->InitTraversal(); - - int count = 0; - int numFibers = fib->GetNumFibers(); - for( int i=0; iGetNextCell ( numPoints, points ); - - if (numPoints>0) - { - double* point = fiberPolyData->GetPoint(points[0]); - itk::Point itkPoint; - itkPoint[0] = point[0]; - itkPoint[1] = point[1]; - itkPoint[2] = point[2]; - pointSet->InsertPoint(count, itkPoint); - count++; - } - if (numPoints>2) - { - double* point = fiberPolyData->GetPoint(points[numPoints-1]); - itk::Point itkPoint; - itkPoint[0] = point[0]; - itkPoint[1] = point[1]; - itkPoint[2] = point[2]; - pointSet->InsertPoint(count, itkPoint); - count++; - } - } - - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData( pointSet ); - return node; -} - -// generate image displaying the fiber endings -mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib) -{ - typedef unsigned char OutPixType; - typedef itk::Image OutImageType; - - typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; - ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); - generator->SetFiberBundle(fib); - generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); - if (m_SelectedImage.IsNotNull()) - { - OutImageType::Pointer itkImage = OutImageType::New(); - CastToItkImage(m_SelectedImage, itkImage); - generator->SetInputImage(itkImage); - generator->SetUseImageGeometry(true); - } - generator->Update(); - - // get output image - OutImageType::Pointer outImg = generator->GetOutput(); - mitk::Image::Pointer img = mitk::Image::New(); - img->InitializeByItk(outImg.GetPointer()); - img->SetVolume(outImg->GetBufferPointer()); - - // init data node - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData(img); - return node; -} - -// generate rgba heatmap from fiber bundle -mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib) -{ - typedef itk::RGBAPixel OutPixType; - typedef itk::Image OutImageType; - typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; - ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); - generator->SetFiberBundle(fib); - generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); - if (m_SelectedImage.IsNotNull()) - { - itk::Image::Pointer itkImage = itk::Image::New(); - CastToItkImage(m_SelectedImage, itkImage); - generator->SetInputImage(itkImage); - generator->SetUseImageGeometry(true); - } - generator->Update(); - - // get output image - typedef itk::Image OutType; - OutType::Pointer outImg = generator->GetOutput(); - mitk::Image::Pointer img = mitk::Image::New(); - img->InitializeByItk(outImg.GetPointer()); - img->SetVolume(outImg->GetBufferPointer()); - - // init data node - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData(img); - return node; -} - -// generate tract density image from fiber bundle -mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary, bool absolute) -{ - const mitk::Geometry2D* bla = GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D(); - typedef float OutPixType; - typedef itk::Image OutImageType; - - itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); - generator->SetFiberBundle(fib); - generator->SetBinaryOutput(binary); - generator->SetOutputAbsoluteValues(absolute); - generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); - if (m_SelectedImage.IsNotNull()) - { - OutImageType::Pointer itkImage = OutImageType::New(); - CastToItkImage(m_SelectedImage, itkImage); - generator->SetInputImage(itkImage); - generator->SetUseImageGeometry(true); - - } - generator->Update(); - - // get output image - typedef itk::Image OutType; - OutType::Pointer outImg = generator->GetOutput(); - mitk::Image::Pointer img = mitk::Image::New(); - img->InitializeByItk(outImg.GetPointer()); - img->SetVolume(outImg->GetBufferPointer()); - - // init data node - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData(img); - return node; -} - -void QmitkFiberProcessingView::ResampleSelectedBundles() -{ - int factor = this->m_Controls->m_ResampleFibersSpinBox->value(); - for (int i=0; i(m_SelectedFB.at(i)->GetData()); - fib->DoFiberSmoothing(factor); - } - GenerateStats(); - RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkFiberProcessingView::MirrorFibers() -{ - unsigned int axis = this->m_Controls->m_AxisSelectionBox->currentIndex(); - for (int i=0; i(m_SelectedFB.at(i)->GetData()); - fib->MirrorFibers(axis); - } - if (m_SelectedFB.size()>0) - GenerateStats(); - - if (m_SelectedSurfaces.size()>0) - { - for (int i=0; i poly = surf->GetVtkPolyData(); - vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); - - for (int i=0; iGetNumberOfPoints(); i++) - { - double* point = poly->GetPoint(i); - point[axis] *= -1; - vtkNewPoints->InsertNextPoint(point); - } - poly->SetPoints(vtkNewPoints); - surf->CalculateBoundingBox(); - } - } - - RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkFiberProcessingView::DoImageColorCoding() -{ - if (m_SelectedImage.IsNull()) - return; - - for( int i=0; i(m_SelectedFB.at(i)->GetData()); - fib->SetFAMap(m_SelectedImage); - fib->SetColorCoding(mitk::FiberBundleX::COLORCODING_FA_BASED); - fib->DoColorCodingFaBased(); - } - - if(m_MultiWidget) - m_MultiWidget->RequestUpdate(); -} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.h similarity index 87% copy from Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h copy to Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.h index 806782e4d0..cc411a0a94 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.h @@ -1,178 +1,172 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QmitkFiberProcessingView_h -#define QmitkFiberProcessingView_h +#ifndef QmitkFiberExtractionView_h +#define QmitkFiberExtractionView_h #include -#include "ui_QmitkFiberProcessingViewControls.h" +#include "ui_QmitkFiberExtractionViewControls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! \brief View to process fiber bundles. Supplies methods to extract fibers from the bundle, join and subtract bundles, generate images from the selected bundle and much more. \sa QmitkFunctionality \ingroup Functionalities */ -class QmitkFiberProcessingView : public QmitkFunctionality +class QmitkFiberExtractionView : public QmitkFunctionality { // 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: typedef itk::Image< unsigned char, 3 > itkUCharImageType; static const std::string VIEW_ID; - QmitkFiberProcessingView(); - virtual ~QmitkFiberProcessingView(); + QmitkFiberExtractionView(); + virtual ~QmitkFiberExtractionView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Activated(); protected slots: void OnDrawCircle(); ///< add circle interactors etc. void OnDrawPolygon(); ///< add circle interactors etc. void DoFiberExtraction(); ///< Extract fibers from selected bundle void GenerateAndComposite(); void GenerateOrComposite(); void GenerateNotComposite(); - void PruneBundle(); ///< remove too short/too long fibers - void MirrorFibers(); ///< mirror bundle on the specified plane void JoinBundles(); ///< merge selected fiber bundles void SubstractBundles(); ///< subtract bundle A from bundle B. Not commutative! Defined by order of selection. void GenerateRoiImage(); ///< generate binary image of selected planar figures. - void ProcessSelectedBundles(); ///< start selected operation on fiber bundle (e.g. tract density image generation) - void ResampleSelectedBundles(); ///< smooth fiber bundle using the specified number of sampling points per cm. - void DoImageColorCoding(); ///< color fibers by selected scalar image - void Extract3d(); ///< extract all fibers passing the selected surface mesh - void ApplyCurvatureThreshold(); ///< remove/split fibers with a too high curvature threshold - void ExtractMask(); ///< extract all fibers passing the selected surface mesh + void ExtractPassingMask(); ///< extract all fibers passing the selected surface mesh + void ExtractEndingInMask(); ///< extract all fibers passing the selected surface mesh virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); - Ui::QmitkFiberProcessingViewControls* m_Controls; + Ui::QmitkFiberExtractionViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** Connection from VTK to ITK */ template void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ); void GenerateStats(); ///< generate statistics of selected fiber bundles void UpdateGui(); ///< update button activity etc. dpending on current datamanager selection int m_CircleCounter; ///< used for data node naming int m_PolygonCounter; ///< used for data node naming std::vector m_SelectedFB; ///< selected fiber bundle nodes std::vector m_SelectedPF; ///< selected planar figure nodes std::vector m_SelectedSurfaces; mitk::Image::Pointer m_SelectedImage; mitk::Image::Pointer m_InternalImage; mitk::PlanarFigure::Pointer m_PlanarFigure; itkUCharImageType::Pointer m_InternalImageMask3D; itkUCharImageType::Pointer m_PlanarFigureImage; float m_UpsamplingFactor; ///< upsampling factor for all image generations mitk::DataNode::Pointer m_MaskImageNode; void AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer, mitk::DataNode::Pointer); void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int ); void CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image); mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary, bool absolute); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionViewControls.ui similarity index 58% copy from Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui copy to Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionViewControls.ui index f6417c6711..3d376dae84 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionViewControls.ui @@ -1,984 +1,565 @@ - QmitkFiberProcessingViewControls - + QmitkFiberExtractionViewControls + 0 0 492 866 Form Please Select Input Data <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> Input DTI Fiber Bundle: Binary seed ROI. If not specified, the whole image area is seeded. ROI: + + + + Qt::Vertical + + + + 20 + 40 + + + + Fiber Extraction 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 30 30 Draw circular ROI. Select reference fiber bundle to execute. :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true 30 30 Draw rectangular ROI. Select reference fiber bundle to execute. :/QmitkDiffusionImaging/rectangle.png:/QmitkDiffusionImaging/rectangle.png 32 32 true true 30 30 Draw polygonal ROI. Select reference fiber bundle to execute. :/QmitkDiffusionImaging/polygon.png:/QmitkDiffusionImaging/polygon.png 32 32 true true Qt::Horizontal 40 20 QFrame::NoFrame QFrame::Raised 0 false 0 0 200 16777215 11 Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute. Substract false 0 0 200 16777215 11 Extract fibers starting/ending inside of the selected binary mask. Ending in Mask Qt::Horizontal 40 20 false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Join false 0 0 200 16777215 11 Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute. Extract false 0 0 16777215 16777215 11 Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image. ROI Image false 0 0 200 16777215 11 Extract fibers passing through the selected binary mask. Passing Mask 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 Qt::Horizontal 40 20 false 60 16777215 Create AND composition with selected ROIs. AND false 60 16777215 Create OR composition with selected ROIs. OR false 60 16777215 Create NOT composition from selected ROI. NOT - - - Fiber Processing - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Perform selected operation on all selected fiber bundles. - - - Generate Image - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - 0 - - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - Tract Density Image (TDI) - - - - - Normalized TDI - - - - - Binary Envelope - - - - - Fiber Bundle Image - - - - - Fiber Endings Image - - - - - Fiber Endings Pointset - - - - - - - - Upsampling factor - - - 1 - - - 0.100000000000000 - - - 10.000000000000000 - - - 0.100000000000000 - - - 1.000000000000000 - - - - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Resample fibers using a Kochanek spline interpolation. - - - Smooth Fibers - - - - - - - Points per cm - - - 1 - - - 50 - - - 5 - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Remove fibers shorter/longer than the specified length (in mm). - - - Length Threshold - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - - - Minimum fiber length in mm - - - 0 - - - 1000 - - - 20 - - - - - - - Maximum fiber length in mm - - - 0 - - - 10000 - - - 500 - - - - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Remove fibers with a too high curvature - - - Curvature Threshold - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 6 - - - 0 - - - 0 - - - - - Minimum radius of circle created by three consecutive points of a fiber - - - 100.000000000000000 - - - 0.100000000000000 - - - 2.000000000000000 - - - - - - - Remove whole fiber if it is exceeding the curvature threshold, otherwise remove only high curvature part. - - - Remove Fiber - - - true - - - - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Mirror fibers around specified axis. - - - Mirror Fibers - - - - - - - 0 - - - 3 - - - 3 - - - - Sagittal - - - - - Coronal - - - - - Axial - - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Apply float image values (0-1) as color coding to the selected fiber bundle. - - - Color By Scalar Map - - - - - - - Fiber Statistics Courier 10 Pitch false true - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp index dfa9bd2b38..2bd20830af 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp @@ -1,1703 +1,469 @@ /*=================================================================== 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 "QmitkFiberProcessingView.h" #include // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include #include #include // ITK #include #include #include #include #include #include #include #include const std::string QmitkFiberProcessingView::VIEW_ID = "org.mitk.views.fiberprocessing"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace mitk; QmitkFiberProcessingView::QmitkFiberProcessingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) - , m_CircleCounter(0) - , m_PolygonCounter(0) , m_UpsamplingFactor(5) { } // Destructor QmitkFiberProcessingView::~QmitkFiberProcessingView() { } void QmitkFiberProcessingView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberProcessingViewControls; m_Controls->setupUi( parent ); - m_Controls->doExtractFibersButton->setDisabled(true); - m_Controls->PFCompoANDButton->setDisabled(true); - m_Controls->PFCompoORButton->setDisabled(true); - m_Controls->PFCompoNOTButton->setDisabled(true); - m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); - m_Controls->m_RectangleButton->setVisible(false); - connect( m_Controls->doExtractFibersButton, SIGNAL(clicked()), this, SLOT(DoFiberExtraction()) ); - connect( m_Controls->m_CircleButton, SIGNAL( clicked() ), this, SLOT( OnDrawCircle() ) ); - connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ), this, SLOT( OnDrawPolygon() ) ); - connect(m_Controls->PFCompoANDButton, SIGNAL(clicked()), this, SLOT(GenerateAndComposite()) ); - connect(m_Controls->PFCompoORButton, SIGNAL(clicked()), this, SLOT(GenerateOrComposite()) ); - connect(m_Controls->PFCompoNOTButton, SIGNAL(clicked()), this, SLOT(GenerateNotComposite()) ); - connect(m_Controls->m_JoinBundles, SIGNAL(clicked()), this, SLOT(JoinBundles()) ); - connect(m_Controls->m_SubstractBundles, SIGNAL(clicked()), this, SLOT(SubstractBundles()) ); - connect(m_Controls->m_GenerateRoiImage, SIGNAL(clicked()), this, SLOT(GenerateRoiImage()) ); - connect(m_Controls->m_Extract3dButton, SIGNAL(clicked()), this, SLOT(Extract3d())); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ResampleFibersButton, SIGNAL(clicked()), this, SLOT(ResampleSelectedBundles()) ); connect(m_Controls->m_FaColorFibersButton, SIGNAL(clicked()), this, SLOT(DoImageColorCoding())); connect( m_Controls->m_PruneFibersButton, SIGNAL(clicked()), this, SLOT(PruneBundle()) ); connect( m_Controls->m_CurvatureThresholdButton, SIGNAL(clicked()), this, SLOT(ApplyCurvatureThreshold()) ); connect( m_Controls->m_MirrorFibersButton, SIGNAL(clicked()), this, SLOT(MirrorFibers()) ); - - connect( m_Controls->m_ExtractMask, SIGNAL(clicked()), this, SLOT(ExtractMask()) ); - } -} - -void QmitkFiberProcessingView::ExtractMask() -{ - if (m_MaskImageNode.IsNull()) - return; - - mitk::Image::Pointer mitkMask = dynamic_cast(m_MaskImageNode->GetData()); - for (int i=0; i(m_SelectedFB.at(i)->GetData()); - QString name(m_SelectedFB.at(i)->GetName().c_str()); - - itkUCharImageType::Pointer mask = itkUCharImageType::New(); - mitk::CastToItkImage(mitkMask, mask); - mitk::FiberBundleX::Pointer newFib = fib->ExtractFiberSubset(mask, false); - DataNode::Pointer newNode = DataNode::New(); - newNode->SetData(newFib); - name += "_ending-in-mask"; - newNode->SetName(name.toStdString()); - GetDefaultDataStorage()->Add(newNode); - } -} - -void QmitkFiberProcessingView::Extract3d() -{ - if (m_MaskImageNode.IsNull()) - return; - - mitk::Image::Pointer mitkMask = dynamic_cast(m_MaskImageNode->GetData()); - for (int i=0; i(m_SelectedFB.at(i)->GetData()); - QString name(m_SelectedFB.at(i)->GetName().c_str()); - - itkUCharImageType::Pointer mask = itkUCharImageType::New(); - mitk::CastToItkImage(mitkMask, mask); - mitk::FiberBundleX::Pointer newFib = fib->ExtractFiberSubset(mask, true); - DataNode::Pointer newNode = DataNode::New(); - newNode->SetData(newFib); - name += "_passing-mask"; - newNode->SetName(name.toStdString()); - GetDefaultDataStorage()->Add(newNode); - } -} -void QmitkFiberProcessingView::GenerateRoiImage(){ - - if (m_SelectedPF.empty()) - return; - - mitk::Geometry3D::Pointer geometry; - if (!m_SelectedFB.empty()) - { - mitk::FiberBundleX::Pointer fib = dynamic_cast(m_SelectedFB.front()->GetData()); - geometry = fib->GetGeometry(); - } - else - return; - - mitk::Vector3D spacing = geometry->GetSpacing(); - spacing /= m_UpsamplingFactor; - - mitk::Point3D newOrigin = geometry->GetOrigin(); - mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); - newOrigin[0] += bounds.GetElement(0); - newOrigin[1] += bounds.GetElement(2); - newOrigin[2] += bounds.GetElement(4); - - itk::Matrix direction; - itk::ImageRegion<3> imageRegion; - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - direction[j][i] = geometry->GetMatrixColumn(i)[j]/spacing[j]; - imageRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); - imageRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); - imageRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); - - m_PlanarFigureImage = itkUCharImageType::New(); - m_PlanarFigureImage->SetSpacing( spacing ); // Set the image spacing - m_PlanarFigureImage->SetOrigin( newOrigin ); // Set the image origin - m_PlanarFigureImage->SetDirection( direction ); // Set the image direction - m_PlanarFigureImage->SetRegions( imageRegion ); - m_PlanarFigureImage->Allocate(); - m_PlanarFigureImage->FillBuffer( 0 ); - - Image::Pointer tmpImage = Image::New(); - tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); - tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); - - for (int i=0; iInitializeByItk(m_PlanarFigureImage.GetPointer()); - tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); - node->SetData(tmpImage); - node->SetName("ROI Image"); - this->GetDefaultDataStorage()->Add(node); -} - -void QmitkFiberProcessingView::CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image) -{ - if (dynamic_cast(node.GetPointer()->GetData()) && !dynamic_cast(node.GetPointer()->GetData())) - { - m_PlanarFigure = dynamic_cast(node.GetPointer()->GetData()); - AccessFixedDimensionByItk_2( - image, - InternalReorientImagePlane, 3, - m_PlanarFigure->GetGeometry(), -1); - - // itk::Image< unsigned char, 3 >::Pointer outimage = itk::Image< unsigned char, 3 >::New(); - - // outimage->SetSpacing( m_PlanarFigure->GetGeometry()->GetSpacing()/m_UpsamplingFactor ); // Set the image spacing - - // mitk::Point3D origin = m_PlanarFigure->GetGeometry()->GetOrigin(); - // mitk::Point3D indexOrigin; - // m_PlanarFigure->GetGeometry()->WorldToIndex(origin, indexOrigin); - // indexOrigin[0] = indexOrigin[0] - .5 * (1.0-1.0/m_UpsamplingFactor); - // indexOrigin[1] = indexOrigin[1] - .5 * (1.0-1.0/m_UpsamplingFactor); - // indexOrigin[2] = indexOrigin[2] - .5 * (1.0-1.0/m_UpsamplingFactor); - // mitk::Point3D newOrigin; - // m_PlanarFigure->GetGeometry()->IndexToWorld(indexOrigin, newOrigin); - - // outimage->SetOrigin( newOrigin ); // Set the image origin - // itk::Matrix matrix; - // for (int i=0; i<3; i++) - // for (int j=0; j<3; j++) - // matrix[j][i] = m_PlanarFigure->GetGeometry()->GetMatrixColumn(i)[j]/m_PlanarFigure->GetGeometry()->GetSpacing().GetElement(i); - // outimage->SetDirection( matrix ); // Set the image direction - - // itk::ImageRegion<3> upsampledRegion; - // upsampledRegion.SetSize(0, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(0)/m_PlanarFigure->GetGeometry()->GetSpacing()[0]); - // upsampledRegion.SetSize(1, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(1)/m_PlanarFigure->GetGeometry()->GetSpacing()[1]); - // upsampledRegion.SetSize(2, 1); - - // typename itk::Image< unsigned char, 3 >::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); - // for (unsigned int n = 0; n < 2; n++) - // { - // upsampledSize[n] = upsampledSize[n] * m_UpsamplingFactor; - // } - // upsampledRegion.SetSize( upsampledSize ); - // outimage->SetRegions( upsampledRegion ); - - // outimage->Allocate(); - - // this->m_InternalImage = mitk::Image::New(); - // this->m_InternalImage->InitializeByItk( outimage.GetPointer() ); - // this->m_InternalImage->SetVolume( outimage->GetBufferPointer() ); - - AccessFixedDimensionByItk_2( - m_InternalImage, - InternalCalculateMaskFromPlanarFigure, - 3, 2, node->GetName() ); - } -} - -template < typename TPixel, unsigned int VImageDimension > -void QmitkFiberProcessingView::InternalReorientImagePlane( - const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ) -{ - - MITK_DEBUG << "InternalReorientImagePlane() start"; - - typedef itk::Image< TPixel, VImageDimension > ImageType; - typedef itk::Image< float, VImageDimension > FloatImageType; - - typedef itk::ResampleImageFilter ResamplerType; - typename ResamplerType::Pointer resampler = ResamplerType::New(); - - mitk::PlaneGeometry* planegeo = dynamic_cast(planegeo3D); - - float upsamp = m_UpsamplingFactor; - float gausssigma = 0.5; - - // Spacing - typename ResamplerType::SpacingType spacing = planegeo->GetSpacing(); - spacing[0] = image->GetSpacing()[0] / upsamp; - spacing[1] = image->GetSpacing()[1] / upsamp; - spacing[2] = image->GetSpacing()[2]; - resampler->SetOutputSpacing( spacing ); - - // Size - typename ResamplerType::SizeType size; - size[0] = planegeo->GetParametricExtentInMM(0) / spacing[0]; - size[1] = planegeo->GetParametricExtentInMM(1) / spacing[1]; - size[2] = 1; - resampler->SetSize( size ); - - // Origin - typename mitk::Point3D orig = planegeo->GetOrigin(); - typename mitk::Point3D corrorig; - planegeo3D->WorldToIndex(orig,corrorig); - corrorig[0] += 0.5/upsamp; - corrorig[1] += 0.5/upsamp; - corrorig[2] += 0; - planegeo3D->IndexToWorld(corrorig,corrorig); - resampler->SetOutputOrigin(corrorig ); - - // Direction - typename ResamplerType::DirectionType direction; - typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix(); - for(int c=0; cSetOutputDirection( direction ); - - // Gaussian interpolation - if(gausssigma != 0) - { - double sigma[3]; - for( unsigned int d = 0; d < 3; d++ ) - { - sigma[d] = gausssigma * image->GetSpacing()[d]; - } - double alpha = 2.0; - - typedef itk::GaussianInterpolateImageFunction - GaussianInterpolatorType; - - typename GaussianInterpolatorType::Pointer interpolator - = GaussianInterpolatorType::New(); - - interpolator->SetInputImage( image ); - interpolator->SetParameters( sigma, alpha ); - - resampler->SetInterpolator( interpolator ); - } - else - { - // typedef typename itk::BSplineInterpolateImageFunction - // InterpolatorType; - typedef typename itk::LinearInterpolateImageFunction InterpolatorType; - - typename InterpolatorType::Pointer interpolator - = InterpolatorType::New(); - - interpolator->SetInputImage( image ); - - resampler->SetInterpolator( interpolator ); - - } - - // Other resampling options - resampler->SetInput( image ); - resampler->SetDefaultPixelValue(0); - - MITK_DEBUG << "Resampling requested image plane ... "; - resampler->Update(); - MITK_DEBUG << " ... done"; - - if(additionalIndex < 0) - { - this->m_InternalImage = mitk::Image::New(); - this->m_InternalImage->InitializeByItk( resampler->GetOutput() ); - this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() ); - } -} - -template < typename TPixel, unsigned int VImageDimension > -void QmitkFiberProcessingView::InternalCalculateMaskFromPlanarFigure( - itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ) -{ - - MITK_DEBUG << "InternalCalculateMaskFromPlanarFigure() start"; - - typedef itk::Image< TPixel, VImageDimension > ImageType; - typedef itk::CastImageFilter< ImageType, itkUCharImageType > CastFilterType; - - // Generate mask image as new image with same header as input image and - // initialize with "1". - itkUCharImageType::Pointer newMaskImage = itkUCharImageType::New(); - newMaskImage->SetSpacing( image->GetSpacing() ); // Set the image spacing - newMaskImage->SetOrigin( image->GetOrigin() ); // Set the image origin - newMaskImage->SetDirection( image->GetDirection() ); // Set the image direction - newMaskImage->SetRegions( image->GetLargestPossibleRegion() ); - newMaskImage->Allocate(); - newMaskImage->FillBuffer( 1 ); - - // Generate VTK polygon from (closed) PlanarFigure polyline - // (The polyline points are shifted by -0.5 in z-direction to make sure - // that the extrusion filter, which afterwards elevates all points by +0.5 - // in z-direction, creates a 3D object which is cut by the the plane z=0) - const Geometry2D *planarFigureGeometry2D = m_PlanarFigure->GetGeometry2D(); - const PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 ); - const Geometry3D *imageGeometry3D = m_InternalImage->GetGeometry( 0 ); - - vtkPolyData *polyline = vtkPolyData::New(); - polyline->Allocate( 1, 1 ); - - // Determine x- and y-dimensions depending on principal axis - int i0, i1; - switch ( axis ) - { - case 0: - i0 = 1; - i1 = 2; - break; - - case 1: - i0 = 0; - i1 = 2; - break; - - case 2: - default: - i0 = 0; - i1 = 1; - break; - } - - // Create VTK polydata object of polyline contour - vtkPoints *points = vtkPoints::New(); - PlanarFigure::PolyLineType::const_iterator it; - std::vector indices; - - unsigned int numberOfPoints = 0; - - for ( it = planarFigurePolyline.begin(); - it != planarFigurePolyline.end(); - ++it ) - { - Point3D point3D; - - // Convert 2D point back to the local index coordinates of the selected - // image - Point2D point2D = it->Point; - planarFigureGeometry2D->WorldToIndex(point2D, point2D); - point2D[0] -= 0.5/m_UpsamplingFactor; - point2D[1] -= 0.5/m_UpsamplingFactor; - planarFigureGeometry2D->IndexToWorld(point2D, point2D); - planarFigureGeometry2D->Map( point2D, point3D ); - - // Polygons (partially) outside of the image bounds can not be processed - // further due to a bug in vtkPolyDataToImageStencil - if ( !imageGeometry3D->IsInside( point3D ) ) - { - float bounds[2] = {0,0}; - bounds[0] = - this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i0); - bounds[1] = - this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i1); - - imageGeometry3D->WorldToIndex( point3D, point3D ); - - // if (point3D[i0]<0) - // point3D[i0] = 0.5; - // else if (point3D[i0]>bounds[0]) - // point3D[i0] = bounds[0]-0.5; - - // if (point3D[i1]<0) - // point3D[i1] = 0.5; - // else if (point3D[i1]>bounds[1]) - // point3D[i1] = bounds[1]-0.5; - - if (point3D[i0]<0) - point3D[i0] = 0.0; - else if (point3D[i0]>bounds[0]) - point3D[i0] = bounds[0]-0.001; - - if (point3D[i1]<0) - point3D[i1] = 0.0; - else if (point3D[i1]>bounds[1]) - point3D[i1] = bounds[1]-0.001; - - points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); - numberOfPoints++; - } - else - { - imageGeometry3D->WorldToIndex( point3D, point3D ); - - // Add point to polyline array - points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); - numberOfPoints++; - } - } - polyline->SetPoints( points ); - points->Delete(); - - vtkIdType *ptIds = new vtkIdType[numberOfPoints]; - for ( vtkIdType i = 0; i < numberOfPoints; ++i ) - { - ptIds[i] = i; } - polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds ); - - - // Extrude the generated contour polygon - vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New(); - extrudeFilter->SetInput( polyline ); - extrudeFilter->SetScaleFactor( 1 ); - extrudeFilter->SetExtrusionTypeToNormalExtrusion(); - extrudeFilter->SetVector( 0.0, 0.0, 1.0 ); - - // Make a stencil from the extruded polygon - vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New(); - polyDataToImageStencil->SetInput( extrudeFilter->GetOutput() ); - - - - // Export from ITK to VTK (to use a VTK filter) - typedef itk::VTKImageImport< itkUCharImageType > ImageImportType; - typedef itk::VTKImageExport< itkUCharImageType > ImageExportType; - - typename ImageExportType::Pointer itkExporter = ImageExportType::New(); - itkExporter->SetInput( newMaskImage ); - - vtkImageImport *vtkImporter = vtkImageImport::New(); - this->ConnectPipelines( itkExporter, vtkImporter ); - vtkImporter->Update(); - - - // Apply the generated image stencil to the input image - vtkImageStencil *imageStencilFilter = vtkImageStencil::New(); - imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() ); - imageStencilFilter->SetStencil( polyDataToImageStencil->GetOutput() ); - imageStencilFilter->ReverseStencilOff(); - imageStencilFilter->SetBackgroundValue( 0 ); - imageStencilFilter->Update(); - - - // Export from VTK back to ITK - vtkImageExport *vtkExporter = vtkImageExport::New(); - vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() ); - vtkExporter->Update(); - - typename ImageImportType::Pointer itkImporter = ImageImportType::New(); - this->ConnectPipelines( vtkExporter, itkImporter ); - itkImporter->Update(); - - // calculate cropping bounding box - m_InternalImageMask3D = itkImporter->GetOutput(); - m_InternalImageMask3D->SetDirection(image->GetDirection()); - - itk::ImageRegionConstIterator - itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion()); - itk::ImageRegionIterator - itimage(image, image->GetLargestPossibleRegion()); - - itmask = itmask.Begin(); - itimage = itimage.Begin(); - - typename ImageType::SizeType lowersize = {{9999999999,9999999999,9999999999}}; - typename ImageType::SizeType uppersize = {{0,0,0}}; - while( !itmask.IsAtEnd() ) - { - if(itmask.Get() == 0) - { - itimage.Set(0); - } - else - { - typename ImageType::IndexType index = itimage.GetIndex(); - typename ImageType::SizeType signedindex; - signedindex[0] = index[0]; - signedindex[1] = index[1]; - signedindex[2] = index[2]; - - lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0]; - lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1]; - lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2]; - - uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0]; - uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1]; - uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2]; - } - - ++itmask; - ++itimage; - } - - typename ImageType::IndexType index; - index[0] = lowersize[0]; - index[1] = lowersize[1]; - index[2] = lowersize[2]; - - typename ImageType::SizeType size; - size[0] = uppersize[0] - lowersize[0] + 1; - size[1] = uppersize[1] - lowersize[1] + 1; - size[2] = uppersize[2] - lowersize[2] + 1; - - itk::ImageRegion<3> cropRegion = itk::ImageRegion<3>(index, size); - - // crop internal mask - typedef itk::RegionOfInterestImageFilter< itkUCharImageType, itkUCharImageType > ROIMaskFilterType; - typename ROIMaskFilterType::Pointer roi2 = ROIMaskFilterType::New(); - roi2->SetRegionOfInterest(cropRegion); - roi2->SetInput(m_InternalImageMask3D); - roi2->Update(); - m_InternalImageMask3D = roi2->GetOutput(); - - Image::Pointer tmpImage = Image::New(); - tmpImage->InitializeByItk(m_InternalImageMask3D.GetPointer()); - tmpImage->SetVolume(m_InternalImageMask3D->GetBufferPointer()); - - Image::Pointer tmpImage2 = Image::New(); - tmpImage2->InitializeByItk(m_PlanarFigureImage.GetPointer()); - const Geometry3D *pfImageGeometry3D = tmpImage2->GetGeometry( 0 ); - - const Geometry3D *intImageGeometry3D = tmpImage->GetGeometry( 0 ); - - typedef itk::ImageRegionIteratorWithIndex IteratorType; - IteratorType imageIterator (m_InternalImageMask3D, m_InternalImageMask3D->GetRequestedRegion()); - imageIterator.GoToBegin(); - while ( !imageIterator.IsAtEnd() ) - { - unsigned char val = imageIterator.Value(); - if (val>0) - { - itk::Index<3> index = imageIterator.GetIndex(); - Point3D point; - point[0] = index[0]; - point[1] = index[1]; - point[2] = index[2]; - - intImageGeometry3D->IndexToWorld(point, point); - pfImageGeometry3D->WorldToIndex(point, point); - - point[i0] += 0.5; - point[i1] += 0.5; - - index[0] = point[0]; - index[1] = point[1]; - index[2] = point[2]; - - if (pfImageGeometry3D->IsIndexInside(index)) - m_PlanarFigureImage->SetPixel(index, 1); - } - ++imageIterator; - } - - // Clean up VTK objects - polyline->Delete(); - extrudeFilter->Delete(); - polyDataToImageStencil->Delete(); - vtkImporter->Delete(); - imageStencilFilter->Delete(); - //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak?? - delete[] ptIds; - } void QmitkFiberProcessingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } - void QmitkFiberProcessingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } -/* OnSelectionChanged is registered to SelectionService, therefore no need to - implement SelectionService Listener explicitly */ - void QmitkFiberProcessingView::UpdateGui() { - m_Controls->m_Extract3dButton->setEnabled(false); - m_Controls->m_ExtractMask->setEnabled(false); - // are fiber bundles selected? if ( m_SelectedFB.empty() ) { - m_Controls->m_InputData->setTitle("Please Select Input Data"); - - m_Controls->m_JoinBundles->setEnabled(false); - m_Controls->m_SubstractBundles->setEnabled(false); m_Controls->m_ProcessFiberBundleButton->setEnabled(false); - m_Controls->doExtractFibersButton->setEnabled(false); m_Controls->m_ResampleFibersButton->setEnabled(false); - m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_FaColorFibersButton->setEnabled(false); m_Controls->m_PruneFibersButton->setEnabled(false); m_Controls->m_CurvatureThresholdButton->setEnabled(false); if (m_SelectedSurfaces.size()>0) m_Controls->m_MirrorFibersButton->setEnabled(true); else m_Controls->m_MirrorFibersButton->setEnabled(false); } else { - m_Controls->m_InputData->setTitle("Input Data"); - - m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_ProcessFiberBundleButton->setEnabled(true); m_Controls->m_ResampleFibersButton->setEnabled(true); m_Controls->m_PruneFibersButton->setEnabled(true); m_Controls->m_CurvatureThresholdButton->setEnabled(true); m_Controls->m_MirrorFibersButton->setEnabled(true); - // one bundle and one planar figure needed to extract fibers - if (!m_SelectedPF.empty()) - { - m_Controls->doExtractFibersButton->setEnabled(true); - } - - // more than two bundles needed to join/subtract - if (m_SelectedFB.size() > 1) - { - m_Controls->m_JoinBundles->setEnabled(true); - m_Controls->m_SubstractBundles->setEnabled(true); - } - else - { - m_Controls->m_JoinBundles->setEnabled(false); - m_Controls->m_SubstractBundles->setEnabled(false); - } - if (m_SelectedImage.IsNotNull()) m_Controls->m_FaColorFibersButton->setEnabled(true); - - if (m_MaskImageNode.IsNotNull()) - { - m_Controls->m_Extract3dButton->setEnabled(true); - m_Controls->m_ExtractMask->setEnabled(true); - } - } - - // are planar figures selected? - if ( m_SelectedPF.empty() ) - { - m_Controls->doExtractFibersButton->setEnabled(false); - m_Controls->PFCompoANDButton->setEnabled(false); - m_Controls->PFCompoORButton->setEnabled(false); - m_Controls->PFCompoNOTButton->setEnabled(false); - m_Controls->m_GenerateRoiImage->setEnabled(false); - } - else - { - if ( !m_SelectedFB.empty() ) - m_Controls->m_GenerateRoiImage->setEnabled(true); - else - m_Controls->m_GenerateRoiImage->setEnabled(false); - - if (m_SelectedPF.size() > 1) - { - m_Controls->PFCompoANDButton->setEnabled(true); - m_Controls->PFCompoORButton->setEnabled(true); - m_Controls->PFCompoNOTButton->setEnabled(false); - } - else - { - m_Controls->PFCompoANDButton->setEnabled(false); - m_Controls->PFCompoORButton->setEnabled(false); - m_Controls->PFCompoNOTButton->setEnabled(true); - } } } void QmitkFiberProcessingView::OnSelectionChanged( std::vector nodes ) { //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); - m_SelectedPF.clear(); m_SelectedSurfaces.clear(); m_SelectedImage = NULL; - m_MaskImageNode = NULL; - - m_Controls->m_FibLabel->setText("mandatory"); - m_Controls->m_PfLabel->setText("needed for extraction"); for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( dynamic_cast(node->GetData()) ) { - m_Controls->m_FibLabel->setText(node->GetName().c_str()); m_SelectedFB.push_back(node); } - else if (dynamic_cast(node->GetData())) - { - m_Controls->m_PfLabel->setText(node->GetName().c_str()); - m_SelectedPF.push_back(node); - } else if (dynamic_cast(node->GetData())) - { m_SelectedImage = dynamic_cast(node->GetData()); - - bool isBinary = false; - node->GetPropertyValue("binary", isBinary); - if (isBinary) - m_MaskImageNode = node; - } else if (dynamic_cast(node->GetData())) { - m_Controls->m_PfLabel->setText(node->GetName().c_str()); m_SelectedSurfaces.push_back(dynamic_cast(node->GetData())); } } UpdateGui(); GenerateStats(); } -void QmitkFiberProcessingView::OnDrawPolygon() -{ - // bool checked = m_Controls->m_PolygonButton->isChecked(); - // if(!this->AssertDrawingIsPossible(checked)) - // return; - - mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); - figure->ClosedOn(); - this->AddFigureToDataStorage(figure, QString("Polygon%1").arg(++m_PolygonCounter)); - - MITK_DEBUG << "PlanarPolygon created ..."; - - mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); - mitk::DataNode* node = 0; - mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; - mitk::PlanarFigure* figureP = 0; - - for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() - ; it++) - { - node = const_cast(it->Value().GetPointer()); - figureP = dynamic_cast(node->GetData()); - - if(figureP) - { - figureInteractor = dynamic_cast(node->GetInteractor()); - - if(figureInteractor.IsNull()) - figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); - - mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); - } - } - -} - -void QmitkFiberProcessingView::OnDrawCircle() -{ - mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); - - this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_CircleCounter)); - - this->GetDataStorage()->Modified(); - - mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); - mitk::DataNode* node = 0; - mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; - mitk::PlanarFigure* figureP = 0; - - for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End(); it++) - { - node = const_cast(it->Value().GetPointer()); - figureP = dynamic_cast(node->GetData()); - - if(figureP) - { - figureInteractor = dynamic_cast(node->GetInteractor()); - - if(figureInteractor.IsNull()) - figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); - - mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); - } - } -} - void QmitkFiberProcessingView::Activated() { } -void QmitkFiberProcessingView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, - const char *propertyKey, mitk::BaseProperty *property ) -{ - // initialize figure's geometry with empty geometry - mitk::PlaneGeometry::Pointer emptygeometry = mitk::PlaneGeometry::New(); - figure->SetGeometry2D( emptygeometry ); - - //set desired data to DataNode where Planarfigure is stored - mitk::DataNode::Pointer newNode = mitk::DataNode::New(); - newNode->SetName(name.toStdString()); - newNode->SetData(figure); - - newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,0.0,0.0)); - newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(2.0)); - newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true)); - - newNode->AddProperty( "selected", mitk::BoolProperty::New(true) ); - newNode->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); - newNode->AddProperty( "planarfigure.drawoutline", mitk::BoolProperty::New(true) ); - newNode->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(false) ); - newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true) ); - - newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(3.0) ); - newNode->AddProperty( "planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.outline.width", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.helperline.width", mitk::FloatProperty::New(2.0) ); - - newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); - newNode->AddProperty( "planarfigure.default.line.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.default.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.default.outline.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.default.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.default.helperline.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(0.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.default.markerline.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); - newNode->AddProperty( "planarfigure.default.marker.opacity",mitk::FloatProperty::New(2.0) ); - - newNode->AddProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.hover.line.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.hover.outline.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.hover.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.hover.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.hover.marker.opacity", mitk::FloatProperty::New(2.0) ); - - newNode->AddProperty( "planarfigure.selected.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.selected.line.opacity",mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.selected.outline.opacity", mitk::FloatProperty::New(2.0)); - newNode->AddProperty( "planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.selected.helperline.opacity",mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(2.0) ); - newNode->AddProperty( "planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); - newNode->AddProperty( "planarfigure.selected.marker.opacity",mitk::FloatProperty::New(2.0)); - - // figure drawn on the topmost layer / image - newNode->SetColor(1.0,1.0,1.0); - newNode->SetOpacity(0.8); - GetDataStorage()->Add(newNode ); - - std::vector selectedNodes = GetDataManagerSelection(); - for(unsigned int i = 0; i < selectedNodes.size(); i++) - { - selectedNodes[i]->SetSelected(false); - } - - newNode->SetSelected(true); -} - -void QmitkFiberProcessingView::DoFiberExtraction() -{ - if ( m_SelectedFB.empty() ){ - QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); - MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; - return; - } - - for (int i=0; i(m_SelectedFB.at(i)->GetData()); - mitk::PlanarFigure::Pointer roi = dynamic_cast (m_SelectedPF.at(0)->GetData()); - - mitk::FiberBundleX::Pointer extFB = fib->ExtractFiberSubset(roi); - - if (extFB->GetNumFibers()<=0) - continue; - - mitk::DataNode::Pointer node; - node = mitk::DataNode::New(); - node->SetData(extFB); - QString name(m_SelectedFB.at(i)->GetName().c_str()); - name += "_"; - name += m_SelectedPF.at(0)->GetName().c_str(); - node->SetName(name.toStdString()); - GetDataStorage()->Add(node); - m_SelectedFB.at(i)->SetVisibility(false); - } -} - -void QmitkFiberProcessingView::GenerateAndComposite() -{ - mitk::PlanarFigureComposite::Pointer PFCAnd = mitk::PlanarFigureComposite::New(); - - mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); - PFCAnd->SetGeometry2D(currentGeometry2D); - PFCAnd->setOperationType(mitk::PFCOMPOSITION_AND_OPERATION); - - for( std::vector::iterator it = m_SelectedPF.begin(); - it != m_SelectedPF.end(); ++it ) - { - mitk::DataNode::Pointer nodePF = *it; - mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); - PFCAnd->addPlanarFigure( tmpPF ); - PFCAnd->addDataNode( nodePF ); - PFCAnd->setDisplayName("AND_COMPO"); - } - - AddCompositeToDatastorage(PFCAnd, NULL); -} - -void QmitkFiberProcessingView::GenerateOrComposite() -{ - mitk::PlanarFigureComposite::Pointer PFCOr = mitk::PlanarFigureComposite::New(); - mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); - PFCOr->SetGeometry2D(currentGeometry2D); - PFCOr->setOperationType(mitk::PFCOMPOSITION_OR_OPERATION); - - for( std::vector::iterator it = m_SelectedPF.begin(); - it != m_SelectedPF.end(); ++it ) - { - mitk::DataNode::Pointer nodePF = *it; - mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); - PFCOr->addPlanarFigure( tmpPF ); - PFCOr->addDataNode( nodePF ); - PFCOr->setDisplayName("OR_COMPO"); - } - - AddCompositeToDatastorage(PFCOr, NULL); -} - -void QmitkFiberProcessingView::GenerateNotComposite() -{ - mitk::PlanarFigureComposite::Pointer PFCNot = mitk::PlanarFigureComposite::New(); - mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); - PFCNot->SetGeometry2D(currentGeometry2D); - PFCNot->setOperationType(mitk::PFCOMPOSITION_NOT_OPERATION); - - for( std::vector::iterator it = m_SelectedPF.begin(); - it != m_SelectedPF.end(); ++it ) - { - mitk::DataNode::Pointer nodePF = *it; - mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); - PFCNot->addPlanarFigure( tmpPF ); - PFCNot->addDataNode( nodePF ); - PFCNot->setDisplayName("NOT_COMPO"); - } - - AddCompositeToDatastorage(PFCNot, NULL); -} - -/* CLEANUP NEEDED */ -void QmitkFiberProcessingView::AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer pfcomp, mitk::DataNode::Pointer parentDataNode ) -{ - mitk::DataNode::Pointer newPFCNode; - newPFCNode = mitk::DataNode::New(); - newPFCNode->SetName( pfcomp->getDisplayName() ); - newPFCNode->SetData(pfcomp); - newPFCNode->SetVisibility(true); - - switch (pfcomp->getOperationType()) { - case 0: - { - if (!parentDataNode.IsNull()) { - GetDataStorage()->Add(newPFCNode, parentDataNode); - - } else { - GetDataStorage()->Add(newPFCNode); - } - - //iterate through its childs - for(int i=0; igetNumberOfChildren(); ++i) - { - mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); - mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); - - mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); - if ( !pfcompcast.IsNull() ) - { - // child is of type planar Figure composite - // make new node of the child, cuz later the child has to be removed of its old position in datamanager - // feed new dataNode with information of the savedDataNode, which is gonna be removed soon - mitk::DataNode::Pointer newChildPFCNode; - newChildPFCNode = mitk::DataNode::New(); - newChildPFCNode->SetData(tmpPFchild); - newChildPFCNode->SetName( savedPFchildNode->GetName() ); - pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user - - //update inside vector the dataNodePointer - pfcomp->replaceDataNodeAt(i, newChildPFCNode); - - AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent - - // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager - // without having its parent anymore - //GetDataStorage()->Remove(savedPFchildNode); - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; - - }else{ - MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); - } - // remove old child position in dataStorage - GetDataStorage()->Remove(savedPFchildNode); - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; - } - } - else - { - // child is not of type PlanarFigureComposite, so its one of the planarFigures - // create new dataNode containing the data of the old dataNode, but position in dataManager will be - // modified cuz we re setting a (new) parent. - mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); - newPFchildNode->SetName(savedPFchildNode->GetName() ); - newPFchildNode->SetData(tmpPFchild); - newPFchildNode->SetVisibility(true); - - // replace the dataNode in PFComp DataNodeVector - pfcomp->replaceDataNodeAt(i, newPFchildNode); - - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; - - } - else - { - MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); - } - // remove old child position in dataStorage - GetDataStorage()->Remove(savedPFchildNode); - - if ( GetDataStorage()->Exists(savedPFchildNode)) - { - MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; - } - - MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); - //add new child to datamanager with its new position as child of newPFCNode parent - GetDataStorage()->Add(newPFchildNode, newPFCNode); - } - } - GetDataStorage()->Modified(); - break; - } - case 1: - { - if (!parentDataNode.IsNull()) { - MITK_DEBUG << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; - GetDataStorage()->Add(newPFCNode, parentDataNode); - - } else { - MITK_DEBUG << "adding " << newPFCNode->GetName(); - GetDataStorage()->Add(newPFCNode); - - } - - for(int i=0; igetNumberOfChildren(); ++i) - { - mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); - mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); - - mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); - if ( !pfcompcast.IsNull() ) - { // child is of type planar Figure composite - // make new node of the child, cuz later the child has to be removed of its old position in datamanager - // feed new dataNode with information of the savedDataNode, which is gonna be removed soon - mitk::DataNode::Pointer newChildPFCNode; - newChildPFCNode = mitk::DataNode::New(); - newChildPFCNode->SetData(tmpPFchild); - newChildPFCNode->SetName( savedPFchildNode->GetName() ); - pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user - - //update inside vector the dataNodePointer - pfcomp->replaceDataNodeAt(i, newChildPFCNode); - - AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent - - - // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager - // without having its parent anymore - //GetDataStorage()->Remove(savedPFchildNode); - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; - - }else{ - MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); - - } - // remove old child position in dataStorage - GetDataStorage()->Remove(savedPFchildNode); - - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; - } - } else { - - // child is not of type PlanarFigureComposite, so its one of the planarFigures - // create new dataNode containing the data of the old dataNode, but position in dataManager will be - // modified cuz we re setting a (new) parent. - mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); - newPFchildNode->SetName(savedPFchildNode->GetName() ); - newPFchildNode->SetData(tmpPFchild); - newPFchildNode->SetVisibility(true); - - // replace the dataNode in PFComp DataNodeVector - pfcomp->replaceDataNodeAt(i, newPFchildNode); - - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; - - }else{ - MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); - - } - // remove old child position in dataStorage - GetDataStorage()->Remove(savedPFchildNode); - - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; - } - - MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); - //add new child to datamanager with its new position as child of newPFCNode parent - GetDataStorage()->Add(newPFchildNode, newPFCNode); - } - } - GetDataStorage()->Modified(); - break; - } - case 2: - { - if (!parentDataNode.IsNull()) { - MITK_DEBUG << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; - GetDataStorage()->Add(newPFCNode, parentDataNode); - } - else - { - MITK_DEBUG << "adding " << newPFCNode->GetName(); - GetDataStorage()->Add(newPFCNode); - } - - - //iterate through its childs - - for(int i=0; igetNumberOfChildren(); ++i) - { - mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); - mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); - - mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); - if ( !pfcompcast.IsNull() ) - { // child is of type planar Figure composite - // makeRemoveBundle new node of the child, cuz later the child has to be removed of its old position in datamanager - // feed new dataNode with information of the savedDataNode, which is gonna be removed soon - mitk::DataNode::Pointer newChildPFCNode; - newChildPFCNode = mitk::DataNode::New(); - newChildPFCNode->SetData(tmpPFchild); - newChildPFCNode->SetName( savedPFchildNode->GetName() ); - pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user - - //update inside vector the dataNodePointer - pfcomp->replaceDataNodeAt(i, newChildPFCNode); - - AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent - - - // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager - // without having its parent anymore - //GetDataStorage()->Remove(savedPFchildNode); - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; - - }else{ - MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); - } - // remove old child position in dataStorage - GetDataStorage()->Remove(savedPFchildNode); - - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; - } - - - } else { - - // child is not of type PlanarFigureComposite, so its one of the planarFigures - // create new dataNode containing the data of the old dataNode, but position in dataManager will be - // modified cuz we re setting a (new) parent. - mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); - newPFchildNode->SetName(savedPFchildNode->GetName() ); - newPFchildNode->SetData(tmpPFchild); - newPFchildNode->SetVisibility(true); - - // replace the dataNode in PFComp DataNodeVector - pfcomp->replaceDataNodeAt(i, newPFchildNode); - - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; - - }else{ - MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); - - } - // remove old child position in dataStorage - GetDataStorage()->Remove(savedPFchildNode); - - - if ( GetDataStorage()->Exists(savedPFchildNode)) { - MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; - } - - MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); - //add new child to datamanager with its new position as child of newPFCNode parent - GetDataStorage()->Add(newPFchildNode, newPFCNode); - } - } - GetDataStorage()->Modified(); - break; - } - default: - MITK_DEBUG << "we have an UNDEFINED composition... ERROR" ; - break; - } -} - - -void QmitkFiberProcessingView::JoinBundles() -{ - if ( m_SelectedFB.size()<2 ){ - QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); - MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; - return; - } - - std::vector::const_iterator it = m_SelectedFB.begin(); - mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); - QString name(""); - name += QString((*it)->GetName().c_str()); - ++it; - for (it; it!=m_SelectedFB.end(); ++it) - { - newBundle = newBundle->AddBundle(dynamic_cast((*it)->GetData())); - name += "+"+QString((*it)->GetName().c_str()); - } - - mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); - fbNode->SetData(newBundle); - fbNode->SetName(name.toStdString()); - fbNode->SetVisibility(true); - GetDataStorage()->Add(fbNode); -} - -void QmitkFiberProcessingView::SubstractBundles() -{ - if ( m_SelectedFB.size()<2 ){ - QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); - MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; - return; - } - - std::vector::const_iterator it = m_SelectedFB.begin(); - mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); - QString name(""); - name += QString((*it)->GetName().c_str()); - ++it; - for (it; it!=m_SelectedFB.end(); ++it) - { - newBundle = newBundle->SubtractBundle(dynamic_cast((*it)->GetData())); - if (newBundle.IsNull()) - break; - name += "-"+QString((*it)->GetName().c_str()); - } - if (newBundle.IsNull()) - { - QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers. Did you select the fiber bundles in the correct order? X-Y is not equal to Y-X!"); - return; - } - - mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); - fbNode->SetData(newBundle); - fbNode->SetName(name.toStdString()); - fbNode->SetVisibility(true); - GetDataStorage()->Add(fbNode); -} - void QmitkFiberProcessingView::PruneBundle() { int minLength = this->m_Controls->m_PruneFibersSpinBox->value(); int maxLength = this->m_Controls->m_MaxPruneFibersSpinBox->value(); for (int i=0; i(m_SelectedFB.at(i)->GetData()); if (!fib->RemoveShortFibers(minLength)) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); else if (!fib->RemoveLongFibers(maxLength)) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); } GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::ApplyCurvatureThreshold() { int mm = this->m_Controls->m_MinCurvatureRadiusBox->value(); for (int i=0; i(m_SelectedFB.at(i)->GetData()); if (!fib->ApplyCurvatureThreshold(mm, this->m_Controls->m_RemoveFiberDueToCurvatureCheckbox->isChecked())) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); } GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::GenerateStats() { if ( m_SelectedFB.empty() ) return; QString stats(""); for( int i=0; i(node->GetData())) { if (i>0) stats += "\n-----------------------------\n"; stats += QString(node->GetName().c_str()) + "\n"; mitk::FiberBundleX::Pointer fib = dynamic_cast(node->GetData()); stats += "Number of fibers: "+ QString::number(fib->GetNumFibers()) + "\n"; stats += "Min. length: "+ QString::number(fib->GetMinFiberLength(),'f',1) + " mm\n"; stats += "Max. length: "+ QString::number(fib->GetMaxFiberLength(),'f',1) + " mm\n"; stats += "Mean length: "+ QString::number(fib->GetMeanFiberLength(),'f',1) + " mm\n"; stats += "Median length: "+ QString::number(fib->GetMedianFiberLength(),'f',1) + " mm\n"; stats += "Standard deviation: "+ QString::number(fib->GetLengthStDev(),'f',1) + " mm\n"; } } this->m_Controls->m_StatsTextEdit->setText(stats); } void QmitkFiberProcessingView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( int i=0; i(node->GetData())) { mitk::FiberBundleX::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = NULL; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false, true); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, false, false); name += "_TDI"; break; case 2: newNode = GenerateTractDensityImage(fib, true, false); name += "_envelope"; break; case 3: newNode = GenerateColorHeatmap(fib); break; case 4: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 5: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); vtkSmartPointer vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; iGetNextCell ( numPoints, points ); if (numPoints>0) { double* point = fiberPolyData->GetPoint(points[0]); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = fiberPolyData->GetPoint(points[numPoints-1]); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib) { typedef itk::RGBAPixel OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image::Pointer itkImage = itk::Image::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary, bool absolute) { - const mitk::Geometry2D* bla = GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D(); typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } void QmitkFiberProcessingView::ResampleSelectedBundles() { int factor = this->m_Controls->m_ResampleFibersSpinBox->value(); for (int i=0; i(m_SelectedFB.at(i)->GetData()); fib->DoFiberSmoothing(factor); } GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::MirrorFibers() { unsigned int axis = this->m_Controls->m_AxisSelectionBox->currentIndex(); for (int i=0; i(m_SelectedFB.at(i)->GetData()); fib->MirrorFibers(axis); } if (m_SelectedFB.size()>0) GenerateStats(); if (m_SelectedSurfaces.size()>0) { for (int i=0; i poly = surf->GetVtkPolyData(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); for (int i=0; iGetNumberOfPoints(); i++) { double* point = poly->GetPoint(i); point[axis] *= -1; vtkNewPoints->InsertNextPoint(point); } poly->SetPoints(vtkNewPoints); surf->CalculateBoundingBox(); } } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::DoImageColorCoding() { if (m_SelectedImage.IsNull()) return; for( int i=0; i(m_SelectedFB.at(i)->GetData()); fib->SetFAMap(m_SelectedImage); fib->SetColorCoding(mitk::FiberBundleX::COLORCODING_FA_BASED); fib->DoColorCodingFaBased(); } if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h index 806782e4d0..b9a9aa22dd 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h @@ -1,178 +1,154 @@ /*=================================================================== 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 QmitkFiberProcessingView_h #define QmitkFiberProcessingView_h #include #include "ui_QmitkFiberProcessingViewControls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! \brief View to process fiber bundles. Supplies methods to extract fibers from the bundle, join and subtract bundles, generate images from the selected bundle and much more. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFiberProcessingView : public QmitkFunctionality { // 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: typedef itk::Image< unsigned char, 3 > itkUCharImageType; static const std::string VIEW_ID; QmitkFiberProcessingView(); virtual ~QmitkFiberProcessingView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Activated(); protected slots: - void OnDrawCircle(); ///< add circle interactors etc. - void OnDrawPolygon(); ///< add circle interactors etc. - void DoFiberExtraction(); ///< Extract fibers from selected bundle - void GenerateAndComposite(); - void GenerateOrComposite(); - void GenerateNotComposite(); void PruneBundle(); ///< remove too short/too long fibers void MirrorFibers(); ///< mirror bundle on the specified plane - void JoinBundles(); ///< merge selected fiber bundles - void SubstractBundles(); ///< subtract bundle A from bundle B. Not commutative! Defined by order of selection. - void GenerateRoiImage(); ///< generate binary image of selected planar figures. void ProcessSelectedBundles(); ///< start selected operation on fiber bundle (e.g. tract density image generation) void ResampleSelectedBundles(); ///< smooth fiber bundle using the specified number of sampling points per cm. void DoImageColorCoding(); ///< color fibers by selected scalar image - void Extract3d(); ///< extract all fibers passing the selected surface mesh void ApplyCurvatureThreshold(); ///< remove/split fibers with a too high curvature threshold - void ExtractMask(); ///< extract all fibers passing the selected surface mesh - - virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); Ui::QmitkFiberProcessingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** Connection from VTK to ITK */ template void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ); void GenerateStats(); ///< generate statistics of selected fiber bundles void UpdateGui(); ///< update button activity etc. dpending on current datamanager selection - int m_CircleCounter; ///< used for data node naming - int m_PolygonCounter; ///< used for data node naming std::vector m_SelectedFB; ///< selected fiber bundle nodes - std::vector m_SelectedPF; ///< selected planar figure nodes - std::vector m_SelectedSurfaces; mitk::Image::Pointer m_SelectedImage; - mitk::Image::Pointer m_InternalImage; - mitk::PlanarFigure::Pointer m_PlanarFigure; - itkUCharImageType::Pointer m_InternalImageMask3D; - itkUCharImageType::Pointer m_PlanarFigureImage; float m_UpsamplingFactor; ///< upsampling factor for all image generations - mitk::DataNode::Pointer m_MaskImageNode; + std::vector m_SelectedSurfaces; - void AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer, mitk::DataNode::Pointer); - void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int ); - void CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image); mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary, bool absolute); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui index f6417c6711..ed85cb7d95 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,984 +1,477 @@ QmitkFiberProcessingViewControls 0 0 492 866 Form - - - - Please Select Input Data - - - - - - <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> - - - - - - - <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> - - - - - - - Input DTI - - - Fiber Bundle: - - - - - - - Binary seed ROI. If not specified, the whole image area is seeded. - - - ROI: - - - - - - - + - Fiber Extraction + Fiber Statistics - + - - - - 0 - 0 - - - - - 200 - 0 - - - - - 16777215 - 60 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - - - - 30 - 30 - - - - Draw circular ROI. Select reference fiber bundle to execute. - - - - - - - :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png - - - - 32 - 32 - - - - false - - - true - - - - - - - - 30 - 30 - - - - Draw rectangular ROI. Select reference fiber bundle to execute. - - - - - - - :/QmitkDiffusionImaging/rectangle.png:/QmitkDiffusionImaging/rectangle.png - - - - 32 - 32 - - - - true - - - true - - - - - - - - 30 - 30 - - - - Draw polygonal ROI. Select reference fiber bundle to execute. - - - - - - - :/QmitkDiffusionImaging/polygon.png:/QmitkDiffusionImaging/polygon.png - - - - 32 - 32 - - - - true - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute. - - - Substract - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Extract fibers starting/ending inside of the selected binary mask. - - - Ending in Mask - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Merge selected fiber bundles. Select at least two fiber bundles to execute. - - - Join - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute. - - - Extract - - - - - - - false - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - 11 - - - - Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image. - - - ROI Image - - - - - - - false - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 11 - - - - Extract fibers passing through the selected binary mask. - - - Passing Mask - - - - - - - - - - - 0 - 0 - - - - - 200 - 0 - - - - - 16777215 - 60 - + + + + Courier 10 Pitch + - - QFrame::NoFrame + + false - - QFrame::Raised + + true - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - - 60 - 16777215 - - - - Create AND composition with selected ROIs. - - - AND - - - - - - - false - - - - 60 - 16777215 - - - - Create OR composition with selected ROIs. - - - OR - - - - - - - false - - - - 60 - 16777215 - - - - Create NOT composition from selected ROI. - - - NOT - - - - + + + Qt::Vertical + + + + 20 + 40 + + + + + Fiber Processing QFormLayout::AllNonFixedFieldsGrow false 0 0 200 16777215 11 Perform selected operation on all selected fiber bundles. Generate Image QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Tract Density Image (TDI) Normalized TDI Binary Envelope Fiber Bundle Image Fiber Endings Image Fiber Endings Pointset Upsampling factor 1 0.100000000000000 10.000000000000000 0.100000000000000 1.000000000000000 false 0 0 200 16777215 11 Resample fibers using a Kochanek spline interpolation. Smooth Fibers Points per cm 1 50 5 false 0 0 200 16777215 11 Remove fibers shorter/longer than the specified length (in mm). Length Threshold QFrame::NoFrame QFrame::Raised 0 0 Minimum fiber length in mm 0 1000 20 Maximum fiber length in mm 0 10000 500 false 0 0 200 16777215 11 Remove fibers with a too high curvature Curvature Threshold QFrame::NoFrame QFrame::Raised 6 0 0 Minimum radius of circle created by three consecutive points of a fiber 100.000000000000000 0.100000000000000 2.000000000000000 Remove whole fiber if it is exceeding the curvature threshold, otherwise remove only high curvature part. Remove Fiber true false 0 0 200 16777215 11 Mirror fibers around specified axis. Mirror Fibers 0 3 3 Sagittal Coronal Axial false 0 0 200 16777215 11 Apply float image values (0-1) as color coding to the selected fiber bundle. Color By Scalar Map - - - - Fiber Statistics - - - - - - - Courier 10 Pitch - - - - false - - - true - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp index 8100f533a3..23b8a8c7ab 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp @@ -1,1312 +1,1594 @@ /*=================================================================== 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. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk #include "QmitkFiberfoxView.h" // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include #include #include -#include +#include #include +#include #include #define _USE_MATH_DEFINES #include const std::string QmitkFiberfoxView::VIEW_ID = "org.mitk.views.fiberfoxview"; QmitkFiberfoxView::QmitkFiberfoxView() : QmitkAbstractView() , m_Controls( 0 ) , m_SelectedImage( NULL ) - , m_SelectedBundle( NULL ) { } // Destructor QmitkFiberfoxView::~QmitkFiberfoxView() { } void QmitkFiberfoxView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberfoxViewControls; m_Controls->setupUi( parent ); - m_Controls->m_VarianceBox->setVisible(false); - m_Controls->m_GeometryMessage->setVisible(false); + m_Controls->m_StickWidget1->setVisible(true); + m_Controls->m_StickWidget2->setVisible(false); + m_Controls->m_ZeppelinWidget1->setVisible(false); + m_Controls->m_ZeppelinWidget2->setVisible(false); + m_Controls->m_TensorWidget1->setVisible(false); + m_Controls->m_TensorWidget2->setVisible(false); + + m_Controls->m_BallWidget1->setVisible(true); + m_Controls->m_BallWidget2->setVisible(false); + m_Controls->m_AstrosticksWidget1->setVisible(false); + m_Controls->m_AstrosticksWidget2->setVisible(false); + m_Controls->m_DotWidget1->setVisible(false); + m_Controls->m_DotWidget2->setVisible(false); + + m_Controls->m_Comp4FractionFrame->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); - m_Controls->m_T2bluringParamFrame->setVisible(false); - m_Controls->m_KspaceParamFrame->setVisible(false); - m_Controls->m_StickModelFrame->setVisible(false); - m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); + m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); + m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); + m_Controls->m_VarianceBox->setVisible(false); + m_Controls->m_KspaceParamFrame->setVisible(false); connect((QObject*) m_Controls->m_GenerateImageButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateImage())); connect((QObject*) m_Controls->m_GenerateFibersButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateFibers())); connect((QObject*) m_Controls->m_CircleButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnDrawROI())); connect((QObject*) m_Controls->m_FlipButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnFlipButton())); connect((QObject*) m_Controls->m_JoinBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(JoinBundles())); connect((QObject*) m_Controls->m_VarianceBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnVarianceChanged(double))); connect((QObject*) m_Controls->m_DistributionBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnDistributionChanged(int))); connect((QObject*) m_Controls->m_FiberDensityBox, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(OnFiberDensityChanged(int))); connect((QObject*) m_Controls->m_FiberSamplingBox, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(OnFiberSamplingChanged(int))); connect((QObject*) m_Controls->m_TensionBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnTensionChanged(double))); connect((QObject*) m_Controls->m_ContinuityBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnContinuityChanged(double))); connect((QObject*) m_Controls->m_BiasBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnBiasChanged(double))); connect((QObject*) m_Controls->m_AddGibbsRinging, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddGibbsRinging(int))); connect((QObject*) m_Controls->m_ConstantRadiusBox, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnConstantRadius(int))); connect((QObject*) m_Controls->m_CopyBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(CopyBundles())); connect((QObject*) m_Controls->m_TransformBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(ApplyTransform())); connect((QObject*) m_Controls->m_AlignOnGrid, SIGNAL(clicked()), (QObject*) this, SLOT(AlignOnGrid())); - connect((QObject*) m_Controls->m_FiberCompartmentModelBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(FiberModelFrameVisibility(int))); - connect((QObject*) m_Controls->m_NonFiberCompartmentModelBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(FiberModelFrameVisibility(int))); + + connect((QObject*) m_Controls->m_Compartment1Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp1ModelFrameVisibility(int))); + connect((QObject*) m_Controls->m_Compartment2Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp2ModelFrameVisibility(int))); + connect((QObject*) m_Controls->m_Compartment3Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp3ModelFrameVisibility(int))); + connect((QObject*) m_Controls->m_Compartment4Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp4ModelFrameVisibility(int))); + connect((QObject*) m_Controls->m_AdvancedOptionsBox, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); connect((QObject*) m_Controls->m_AdvancedOptionsBox_2, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); } } void QmitkFiberfoxView::ShowAdvancedOptions(int state) { if (state) { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(true); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(true); + m_Controls->m_AdvancedOptionsBox->setChecked(true); + m_Controls->m_AdvancedOptionsBox_2->setChecked(true); } else { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); + m_Controls->m_AdvancedOptionsBox->setChecked(false); + m_Controls->m_AdvancedOptionsBox_2->setChecked(false); } } -void QmitkFiberfoxView::FiberModelFrameVisibility(int index) +void QmitkFiberfoxView::Comp1ModelFrameVisibility(int index) { - m_Controls->m_TensorModelFrame->setVisible(false); - m_Controls->m_StickModelFrame->setVisible(false); + m_Controls->m_StickWidget1->setVisible(false); + m_Controls->m_ZeppelinWidget1->setVisible(false); + m_Controls->m_TensorWidget1->setVisible(false); + switch (index) { case 0: - m_Controls->m_TensorModelFrame->setVisible(true); + m_Controls->m_StickWidget1->setVisible(true); break; case 1: - m_Controls->m_StickModelFrame->setVisible(true); + m_Controls->m_ZeppelinWidget1->setVisible(true); + break; + case 2: + m_Controls->m_TensorWidget1->setVisible(true); break; - default: - m_Controls->m_TensorModelFrame->setVisible(true); } } -void QmitkFiberfoxView::NonFiberModelFrameVisibility(int index) +void QmitkFiberfoxView::Comp2ModelFrameVisibility(int index) { + m_Controls->m_StickWidget2->setVisible(false); + m_Controls->m_ZeppelinWidget2->setVisible(false); + m_Controls->m_TensorWidget2->setVisible(false); + switch (index) + { + case 0: + break; + case 1: + m_Controls->m_StickWidget2->setVisible(true); + break; + case 2: + m_Controls->m_ZeppelinWidget2->setVisible(true); + break; + case 3: + m_Controls->m_TensorWidget2->setVisible(true); + break; + } +} + +void QmitkFiberfoxView::Comp3ModelFrameVisibility(int index) +{ + m_Controls->m_BallWidget1->setVisible(false); + m_Controls->m_AstrosticksWidget1->setVisible(false); + m_Controls->m_DotWidget1->setVisible(false); + + switch (index) + { + case 0: + m_Controls->m_BallWidget1->setVisible(true); + break; + case 1: + m_Controls->m_AstrosticksWidget1->setVisible(true); + break; + case 2: + m_Controls->m_DotWidget1->setVisible(true); + break; + } +} + +void QmitkFiberfoxView::Comp4ModelFrameVisibility(int index) +{ + m_Controls->m_BallWidget2->setVisible(false); + m_Controls->m_AstrosticksWidget2->setVisible(false); + m_Controls->m_DotWidget2->setVisible(false); + m_Controls->m_Comp4FractionFrame->setVisible(false); + + switch (index) + { + case 0: + break; + case 1: + m_Controls->m_BallWidget2->setVisible(true); + m_Controls->m_Comp4FractionFrame->setVisible(true); + break; + case 2: + m_Controls->m_AstrosticksWidget2->setVisible(true); + m_Controls->m_Comp4FractionFrame->setVisible(true); + break; + case 3: + m_Controls->m_DotWidget2->setVisible(true); + m_Controls->m_Comp4FractionFrame->setVisible(true); + break; + } } void QmitkFiberfoxView::OnConstantRadius(int value) { if (value>0 && m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnAddGibbsRinging(int value) { if (value>0) m_Controls->m_KspaceParamFrame->setVisible(true); else m_Controls->m_KspaceParamFrame->setVisible(false); } void QmitkFiberfoxView::OnDistributionChanged(int value) { if (value==1) m_Controls->m_VarianceBox->setVisible(true); else m_Controls->m_VarianceBox->setVisible(false); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnVarianceChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberDensityChanged(int value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberSamplingChanged(int value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnTensionChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnContinuityChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnBiasChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::AlignOnGrid() { for (int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::DataStorage::SetOfObjects::ConstPointer parentFibs = GetDataStorage()->GetSources(m_SelectedFiducials.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = parentFibs->begin(); it != parentFibs->end(); ++it ) { mitk::DataNode::Pointer pFibNode = *it; if ( pFibNode.IsNotNull() && dynamic_cast(pFibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(pFibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { mitk::Image::Pointer img = dynamic_cast(pImgNode->GetData()); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); break; } } break; } } } for( int i=0; iGetSources(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it = sources->begin(); it != sources->end(); ++it ) { mitk::DataNode::Pointer imgNode = *it; if ( imgNode.IsNotNull() && dynamic_cast(imgNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Image::Pointer img = dynamic_cast(imgNode->GetData()); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } break; } } } for( int i=0; i(m_SelectedImages.at(i)->GetData()); mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations2 = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations2->begin(); it2 != derivations2->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFlipButton() { if (m_SelectedFiducial.IsNull()) return; std::map::iterator it = m_DataNodeToPlanarFigureData.find(m_SelectedFiducial.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; data.m_Flipped += 1; data.m_Flipped %= 2; } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } QmitkFiberfoxView::GradientListType QmitkFiberfoxView::GenerateHalfShell(int NPoints) { NPoints *= 2; GradientListType pointshell; - int numB0 = NPoints/10; + int numB0 = NPoints/20; if (numB0==0) numB0=1; GradientType g; g.Fill(0.0); for (int i=0; i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*M_PI); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i std::vector > QmitkFiberfoxView::MakeGradientList() { std::vector > retval; vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); // Add 0 vector for B0 int numB0 = ndirs/10; if (numB0==0) numB0=1; itk::Vector v; v.Fill(0.0); for (int i=0; i v; v[0] = U->get(0,i); v[1] = U->get(1,i); v[2] = U->get(2,i); retval.push_back(v); } return retval; } void QmitkFiberfoxView::OnAddBundle() { if (m_SelectedImage.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedImage); mitk::FiberBundleX::Pointer bundle = mitk::FiberBundleX::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( bundle ); QString name = QString("Bundle_%1").arg(children->size()); node->SetName(name.toStdString()); - m_SelectedBundle = node; m_SelectedBundles.push_back(node); UpdateGui(); GetDataStorage()->Add(node, m_SelectedImage); } void QmitkFiberfoxView::OnDrawROI() { - if (m_SelectedBundle.IsNull()) + if (m_SelectedBundles.empty()) OnAddBundle(); - if (m_SelectedBundle.IsNull()) + if (m_SelectedBundles.empty()) return; - mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedBundle); + mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedBundles.at(0)); mitk::PlanarEllipse::Pointer figure = mitk::PlanarEllipse::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( figure ); QList nodes = this->GetDataManagerSelection(); for( int i=0; iSetSelected(false); m_SelectedFiducial = node; QString name = QString("Fiducial_%1").arg(children->size()); node->SetName(name.toStdString()); node->SetSelected(true); - GetDataStorage()->Add(node, m_SelectedBundle); + GetDataStorage()->Add(node, m_SelectedBundles.at(0)); this->DisableCrosshairNavigation(); mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); UpdateGui(); } bool CompareLayer(mitk::DataNode::Pointer i,mitk::DataNode::Pointer j) { int li = -1; i->GetPropertyValue("layer", li); int lj = -1; j->GetPropertyValue("layer", lj); return liGetSources(m_SelectedFiducial); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) if(dynamic_cast((*it)->GetData())) m_SelectedBundles.push_back(*it); if (m_SelectedBundles.empty()) return; } vector< vector< mitk::PlanarEllipse::Pointer > > fiducials; vector< vector< unsigned int > > fliplist; for (int i=0; iGetDerivations(m_SelectedBundles.at(i)); std::vector< mitk::DataNode::Pointer > childVector; for( mitk::DataStorage::SetOfObjects::const_iterator it = children->begin(); it != children->end(); ++it ) childVector.push_back(*it); sort(childVector.begin(), childVector.end(), CompareLayer); vector< mitk::PlanarEllipse::Pointer > fib; vector< unsigned int > flip; float radius = 1; int count = 0; for( std::vector< mitk::DataNode::Pointer >::const_iterator it = childVector.begin(); it != childVector.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { mitk::PlanarEllipse* ellipse = dynamic_cast(node->GetData()); if (m_Controls->m_ConstantRadiusBox->isChecked()) { ellipse->SetTreatAsCircle(true); mitk::Point2D c = ellipse->GetControlPoint(0); mitk::Point2D p = ellipse->GetControlPoint(1); mitk::Vector2D v = p-c; if (count==0) { radius = v.GetVnlVector().magnitude(); ellipse->SetControlPoint(1, p); } else { v.Normalize(); v *= radius; ellipse->SetControlPoint(1, c+v); } } fib.push_back(ellipse); std::map::iterator it = m_DataNodeToPlanarFigureData.find(node.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; flip.push_back(data.m_Flipped); } else flip.push_back(0); } count++; } if (fib.size()>1) { fiducials.push_back(fib); fliplist.push_back(flip); } + else if (fib.size()>0) + m_SelectedBundles.at(i)->SetData( mitk::FiberBundleX::New() ); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - if (fib.size()<3) - return; } itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); filter->SetFiducials(fiducials); filter->SetFlipList(fliplist); switch(m_Controls->m_DistributionBox->currentIndex()){ case 0: filter->SetFiberDistribution(itk::FibersFromPlanarFiguresFilter::DISTRIBUTE_UNIFORM); break; case 1: filter->SetFiberDistribution(itk::FibersFromPlanarFiguresFilter::DISTRIBUTE_GAUSSIAN); filter->SetVariance(m_Controls->m_VarianceBox->value()); break; } filter->SetDensity(m_Controls->m_FiberDensityBox->value()); filter->SetTension(m_Controls->m_TensionBox->value()); filter->SetContinuity(m_Controls->m_ContinuityBox->value()); filter->SetBias(m_Controls->m_BiasBox->value()); filter->SetFiberSampling(m_Controls->m_FiberSamplingBox->value()); filter->Update(); vector< mitk::FiberBundleX::Pointer > fiberBundles = filter->GetFiberBundles(); for (int i=0; iSetData( fiberBundles.at(i) ); if (fiberBundles.at(i)->GetNumFibers()>50000) m_SelectedBundles.at(i)->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::GenerateImage() { itk::ImageRegion<3> imageRegion; imageRegion.SetSize(0, m_Controls->m_SizeX->value()); imageRegion.SetSize(1, m_Controls->m_SizeY->value()); imageRegion.SetSize(2, m_Controls->m_SizeZ->value()); mitk::Vector3D spacing; spacing[0] = m_Controls->m_SpacingX->value(); spacing[1] = m_Controls->m_SpacingY->value(); spacing[2] = m_Controls->m_SpacingZ->value(); mitk::Point3D origin; origin[0] = spacing[0]/2; origin[1] = spacing[1]/2; origin[2] = spacing[2]/2; itk::Matrix directionMatrix; directionMatrix.SetIdentity(); - if (m_SelectedBundle.IsNull()) + if (m_SelectedBundles.empty()) { mitk::Image::Pointer image = mitk::ImageGenerator::GenerateGradientImage( m_Controls->m_SizeX->value(), m_Controls->m_SizeY->value(), m_Controls->m_SizeZ->value(), m_Controls->m_SpacingX->value(), m_Controls->m_SpacingY->value(), m_Controls->m_SpacingZ->value()); mitk::Geometry3D* geom = image->GetGeometry(); geom->SetOrigin(origin); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Dummy"); + unsigned int window = m_Controls->m_SizeX->value()*m_Controls->m_SizeY->value()*m_Controls->m_SizeZ->value(); + unsigned int level = window/2; + mitk::LevelWindow lw; lw.SetLevelWindow(level, window); + node->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( lw ) ); GetDataStorage()->Add(node); m_SelectedImage = node; mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } UpdateGui(); return; } + if (m_SelectedImage.IsNotNull()) + { + mitk::Image* img = dynamic_cast(m_SelectedImage->GetData()); + itk::Image< float, 3 >::Pointer itkImg = itk::Image< float, 3 >::New(); + CastToItkImage< itk::Image< float, 3 > >(img, itkImg); + + imageRegion = itkImg->GetLargestPossibleRegion(); + spacing = itkImg->GetSpacing(); + origin = itkImg->GetOrigin(); + directionMatrix = itkImg->GetDirection(); + } + DiffusionSignalModel::GradientListType gradientList; double bVal = 1000; if (m_SelectedDWI.IsNull()) { gradientList = GenerateHalfShell(m_Controls->m_NumGradientsBox->value());; bVal = m_Controls->m_BvalueBox->value(); } else { mitk::DiffusionImage::Pointer dwi = dynamic_cast*>(m_SelectedDWI->GetData()); imageRegion = dwi->GetVectorImage()->GetLargestPossibleRegion(); spacing = dwi->GetVectorImage()->GetSpacing(); origin = dwi->GetVectorImage()->GetOrigin(); directionMatrix = dwi->GetVectorImage()->GetDirection(); bVal = dwi->GetB_Value(); mitk::DiffusionImage::GradientDirectionContainerType::Pointer dirs = dwi->GetDirections(); for (int i=0; iSize(); i++) { DiffusionSignalModel::GradientType g; g[0] = dirs->at(i)[0]; g[1] = dirs->at(i)[1]; g[2] = dirs->at(i)[2]; gradientList.push_back(g); } } for (int i=0; i tensorModel; - mitk::StickModel stickModel; - - // free diffusion - mitk::BallModel ballModel; - ballModel.SetGradientList(gradientList); - ballModel.SetBvalue(bVal); - ballModel.SetDiffusivity(m_Controls->m_BallD->value()); - ballModel.SetT2(m_Controls->m_NonFiberT2Box->value()); - nonFiberModelList.push_back(&ballModel); - - resultNode->AddProperty("Fiberfox.Ball.Diffusivity", DoubleProperty::New(m_Controls->m_BallD->value())); - resultNode->AddProperty("Fiberfox.Ball.T2", DoubleProperty::New(m_Controls->m_NonFiberT2Box->value())); - - // intra-axonal diffusion - switch (m_Controls->m_FiberCompartmentModelBox->currentIndex()) + double comp3Weight = 1; + double comp4Weight = 0; + if (m_Controls->m_Compartment4Box->currentIndex()>0) + { + comp4Weight = m_Controls->m_Comp4FractionBox->value(); + comp3Weight -= comp4Weight; + } + + mitk::StickModel stickModel1; + mitk::StickModel stickModel2; + mitk::TensorModel zeppelinModel1; + mitk::TensorModel zeppelinModel2; + mitk::TensorModel tensorModel1; + mitk::TensorModel tensorModel2; + mitk::BallModel ballModel1; + mitk::BallModel ballModel2; + mitk::AstroStickModel astrosticksModel1; + mitk::AstroStickModel astrosticksModel2; + mitk::DotModel dotModel1; + mitk::DotModel dotModel2; + + // compartment 1 + switch (m_Controls->m_Compartment1Box->currentIndex()) { case 0: + MITK_INFO << "Using stick model"; + stickModel1.SetGradientList(gradientList); + stickModel1.SetDiffusivity(m_Controls->m_StickWidget1->GetD()); + stickModel1.SetT2(m_Controls->m_StickWidget1->GetT2()); + fiberModelList.push_back(&stickModel1); + signalModelString += "Stick"; + resultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); + resultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Stick") ); + resultNode->AddProperty("Fiberfox.Compartment1.D", DoubleProperty::New(m_Controls->m_StickWidget1->GetD()) ); + resultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(stickModel1.GetT2()) ); + break; + case 1: MITK_INFO << "Using zeppelin model"; - tensorModel.SetGradientList(gradientList); - tensorModel.SetBvalue(bVal); - tensorModel.SetKernelFA(m_Controls->m_TensorFaBox->value()); - tensorModel.SetT2(m_Controls->m_FiberT2Box->value()); - fiberModelList.push_back(&tensorModel); - signalModelString += "-Zeppelin"; - resultNode->AddProperty("Fiberfox.Zeppelin.FA", DoubleProperty::New(m_Controls->m_TensorFaBox->value())); - resultNode->AddProperty("Fiberfox.Zeppelin.T2", DoubleProperty::New(m_Controls->m_FiberT2Box->value())); + zeppelinModel1.SetGradientList(gradientList); + zeppelinModel1.SetBvalue(bVal); + zeppelinModel1.SetDiffusivity1(m_Controls->m_ZeppelinWidget1->GetD1()); + zeppelinModel1.SetDiffusivity2(m_Controls->m_ZeppelinWidget1->GetD2()); + zeppelinModel1.SetDiffusivity3(m_Controls->m_ZeppelinWidget1->GetD2()); + zeppelinModel1.SetT2(m_Controls->m_ZeppelinWidget1->GetT2()); + fiberModelList.push_back(&zeppelinModel1); + signalModelString += "Zeppelin"; + resultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); + resultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Zeppelin") ); + resultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD1()) ); + resultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD2()) ); + resultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(zeppelinModel1.GetT2()) ); + break; + case 2: + MITK_INFO << "Using tensor model"; + tensorModel1.SetGradientList(gradientList); + tensorModel1.SetBvalue(bVal); + tensorModel1.SetDiffusivity1(m_Controls->m_TensorWidget1->GetD1()); + tensorModel1.SetDiffusivity2(m_Controls->m_TensorWidget1->GetD2()); + tensorModel1.SetDiffusivity3(m_Controls->m_TensorWidget1->GetD3()); + tensorModel1.SetT2(m_Controls->m_TensorWidget1->GetT2()); + fiberModelList.push_back(&tensorModel1); + signalModelString += "Tensor"; + resultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); + resultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Tensor") ); + resultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD1()) ); + resultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD2()) ); + resultNode->AddProperty("Fiberfox.Compartment1.D3", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD3()) ); + resultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(zeppelinModel1.GetT2()) ); + break; + } + + // compartment 2 + switch (m_Controls->m_Compartment2Box->currentIndex()) + { + case 0: break; case 1: - MITK_INFO << "Using stick model"; - stickModel.SetGradientList(gradientList); - stickModel.SetDiffusivity(m_Controls->m_StickDiffusivityBox->value()); - stickModel.SetT2(m_Controls->m_FiberT2Box->value()); - fiberModelList.push_back(&stickModel); - signalModelString += "-Stick"; - resultNode->AddProperty("Fiberfox.Stick.Diffusivity", DoubleProperty::New(m_Controls->m_StickDiffusivityBox->value())); - resultNode->AddProperty("Fiberfox.Stick.T2", DoubleProperty::New(m_Controls->m_FiberT2Box->value())); + stickModel2.SetGradientList(gradientList); + stickModel2.SetDiffusivity(m_Controls->m_StickWidget2->GetD()); + stickModel2.SetT2(m_Controls->m_StickWidget2->GetT2()); + fiberModelList.push_back(&stickModel2); + signalModelString += "Stick"; + resultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); + resultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Stick") ); + resultNode->AddProperty("Fiberfox.Compartment2.D", DoubleProperty::New(m_Controls->m_StickWidget2->GetD()) ); + resultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(stickModel2.GetT2()) ); + break; + case 2: + zeppelinModel2.SetGradientList(gradientList); + zeppelinModel2.SetBvalue(bVal); + zeppelinModel2.SetDiffusivity1(m_Controls->m_ZeppelinWidget2->GetD1()); + zeppelinModel2.SetDiffusivity2(m_Controls->m_ZeppelinWidget2->GetD2()); + zeppelinModel2.SetDiffusivity3(m_Controls->m_ZeppelinWidget2->GetD2()); + zeppelinModel2.SetT2(m_Controls->m_ZeppelinWidget2->GetT2()); + fiberModelList.push_back(&zeppelinModel2); + signalModelString += "Zeppelin"; + resultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); + resultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Zeppelin") ); + resultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD1()) ); + resultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD2()) ); + resultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(zeppelinModel2.GetT2()) ); + break; + case 3: + tensorModel2.SetGradientList(gradientList); + tensorModel2.SetBvalue(bVal); + tensorModel2.SetDiffusivity1(m_Controls->m_TensorWidget2->GetD1()); + tensorModel2.SetDiffusivity2(m_Controls->m_TensorWidget2->GetD2()); + tensorModel2.SetDiffusivity3(m_Controls->m_TensorWidget2->GetD3()); + tensorModel2.SetT2(m_Controls->m_TensorWidget2->GetT2()); + fiberModelList.push_back(&tensorModel2); + signalModelString += "Tensor"; + resultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); + resultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Tensor") ); + resultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD1()) ); + resultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD2()) ); + resultNode->AddProperty("Fiberfox.Compartment2.D3", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD3()) ); + resultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(zeppelinModel2.GetT2()) ); + break; + } + + // compartment 3 + switch (m_Controls->m_Compartment3Box->currentIndex()) + { + case 0: + ballModel1.SetGradientList(gradientList); + ballModel1.SetBvalue(bVal); + ballModel1.SetDiffusivity(m_Controls->m_BallWidget1->GetD()); + ballModel1.SetT2(m_Controls->m_BallWidget1->GetT2()); + ballModel1.SetWeight(comp3Weight); + nonFiberModelList.push_back(&ballModel1); + signalModelString += "Ball"; + resultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); + resultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Ball") ); + resultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_BallWidget1->GetD()) ); + resultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(ballModel1.GetT2()) ); + break; + case 1: + astrosticksModel1.SetGradientList(gradientList); + astrosticksModel1.SetBvalue(bVal); + astrosticksModel1.SetDiffusivity(m_Controls->m_AstrosticksWidget1->GetD()); + astrosticksModel1.SetT2(m_Controls->m_AstrosticksWidget1->GetT2()); + astrosticksModel1.SetRandomizeSticks(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()); + astrosticksModel1.SetWeight(comp3Weight); + nonFiberModelList.push_back(&astrosticksModel1); + signalModelString += "Astrosticks"; + resultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); + resultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Astrosticks") ); + resultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget1->GetD()) ); + resultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(astrosticksModel1.GetT2()) ); + resultNode->AddProperty("Fiberfox.Compartment3.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()) ); + break; + case 2: + dotModel1.SetGradientList(gradientList); + dotModel1.SetT2(m_Controls->m_DotWidget1->GetT2()); + dotModel1.SetWeight(comp3Weight); + nonFiberModelList.push_back(&dotModel1); + signalModelString += "Dot"; + resultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); + resultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Dot") ); + resultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(dotModel1.GetT2()) ); + break; + } + + // compartment 4 + switch (m_Controls->m_Compartment4Box->currentIndex()) + { + case 0: + break; + case 1: + ballModel2.SetGradientList(gradientList); + ballModel2.SetBvalue(bVal); + ballModel2.SetDiffusivity(m_Controls->m_BallWidget2->GetD()); + ballModel2.SetT2(m_Controls->m_BallWidget2->GetT2()); + ballModel2.SetWeight(comp4Weight); + nonFiberModelList.push_back(&ballModel2); + signalModelString += "Ball"; + resultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); + resultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Ball") ); + resultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_BallWidget2->GetD()) ); + resultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(ballModel2.GetT2()) ); + break; + case 2: + astrosticksModel2.SetGradientList(gradientList); + astrosticksModel2.SetBvalue(bVal); + astrosticksModel2.SetDiffusivity(m_Controls->m_AstrosticksWidget2->GetD()); + astrosticksModel2.SetT2(m_Controls->m_AstrosticksWidget2->GetT2()); + astrosticksModel2.SetRandomizeSticks(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()); + astrosticksModel2.SetWeight(comp4Weight); + nonFiberModelList.push_back(&astrosticksModel2); + signalModelString += "Astrosticks"; + resultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); + resultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Astrosticks") ); + resultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget2->GetD()) ); + resultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(astrosticksModel2.GetT2()) ); + resultNode->AddProperty("Fiberfox.Compartment4.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()) ); + break; + case 3: + dotModel2.SetGradientList(gradientList); + dotModel2.SetT2(m_Controls->m_DotWidget2->GetT2()); + dotModel2.SetWeight(comp4Weight); + nonFiberModelList.push_back(&dotModel2); + signalModelString += "Dot"; + resultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); + resultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Dot") ); + resultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(dotModel2.GetT2()) ); break; } itk::TractsToDWIImageFilter::KspaceArtifactList artifactList; // noise model double noiseVariance = m_Controls->m_NoiseLevel->value(); mitk::RicianNoiseModel noiseModel; noiseModel.SetNoiseVariance(noiseVariance); // artifact models QString artifactModelString(""); mitk::GibbsRingingArtifact gibbsModel; if (m_Controls->m_AddGibbsRinging->isChecked()) { artifactModelString += "_Gibbs-ringing"; resultNode->AddProperty("Fiberfox.k-Space-Undersampling", IntProperty::New(m_Controls->m_KspaceUndersamplingBox->currentText().toInt())); gibbsModel.SetKspaceCropping((double)m_Controls->m_KspaceUndersamplingBox->currentText().toInt()); artifactList.push_back(&gibbsModel); } - mitk::T2SmearingArtifact contrastModel; - contrastModel.SetT2star(this->m_Controls->m_T2starBox->value()); + if ( this->m_Controls->m_TEbox->value() < imageRegion.GetSize(1)*m_Controls->m_LineReadoutTimeBox->value() ) + { + this->m_Controls->m_TEbox->setValue( imageRegion.GetSize(1)*m_Controls->m_LineReadoutTimeBox->value() ); + QMessageBox::information( NULL, "Warning", "Echo time is too short! Time not sufficient to read slice. Automaticall adjusted to "+QString::number(this->m_Controls->m_TEbox->value())+" ms"); + } + + double lineReadoutTime = m_Controls->m_LineReadoutTimeBox->value(); + + // adjusting line readout time to the adapted image size needed for the FFT + int y=2; + while (yimageRegion.GetSize(1)) + lineReadoutTime *= (double)imageRegion.GetSize(1)/y; + + mitk::SignalDecay contrastModel; + contrastModel.SetTinhom(this->m_Controls->m_T2starBox->value()); contrastModel.SetTE(this->m_Controls->m_TEbox->value()); - contrastModel.SetTline(m_Controls->m_LineReadoutTimeBox->value()); + contrastModel.SetTline(lineReadoutTime); artifactList.push_back(&contrastModel); mitk::FiberBundleX::Pointer fiberBundle = dynamic_cast(m_SelectedBundles.at(i)->GetData()); if (fiberBundle->GetNumFibers()<=0) continue; itk::TractsToDWIImageFilter::Pointer filter = itk::TractsToDWIImageFilter::New(); filter->SetImageRegion(imageRegion); filter->SetSpacing(spacing); filter->SetOrigin(origin); filter->SetDirectionMatrix(directionMatrix); filter->SetFiberBundle(fiberBundle); filter->SetFiberModels(fiberModelList); filter->SetNonFiberModels(nonFiberModelList); filter->SetNoiseModel(&noiseModel); filter->SetKspaceArtifacts(artifactList); filter->SetNumberOfRepetitions(m_Controls->m_RepetitionsBox->value()); filter->SetEnforcePureFiberVoxels(m_Controls->m_EnforcePureFiberVoxelsBox->isChecked()); filter->SetInterpolationShrink(m_Controls->m_InterpolationShrink->value()); filter->SetFiberRadius(m_Controls->m_FiberRadius->value()); filter->SetSignalScale(m_Controls->m_SignalScaleBox->value()); if (m_TissueMask.IsNotNull()) { ItkUcharImgType::Pointer mask = ItkUcharImgType::New(); mitk::CastToItkImage(m_TissueMask, mask); filter->SetTissueMask(mask); } filter->Update(); mitk::DiffusionImage::Pointer image = mitk::DiffusionImage::New(); image->SetVectorImage( filter->GetOutput() ); image->SetB_Value(bVal); image->SetDirections(gradientList); image->InitializeFromVectorImage(); resultNode->SetData( image ); resultNode->SetName(m_SelectedBundles.at(i)->GetName() +"_D"+QString::number(imageRegion.GetSize(0)).toStdString() +"-"+QString::number(imageRegion.GetSize(1)).toStdString() +"-"+QString::number(imageRegion.GetSize(2)).toStdString() +"_S"+QString::number(spacing[0]).toStdString() +"-"+QString::number(spacing[1]).toStdString() +"-"+QString::number(spacing[2]).toStdString() +"_b"+QString::number(bVal).toStdString() +"_NOISE"+QString::number(noiseVariance).toStdString() +"_"+signalModelString.toStdString() +artifactModelString.toStdString()); GetDataStorage()->Add(resultNode, m_SelectedBundles.at(i)); + resultNode->AddProperty("Fiberfox.InterpolationShrink", IntProperty::New(m_Controls->m_InterpolationShrink->value())); + resultNode->AddProperty("Fiberfox.SignalScale", IntProperty::New(m_Controls->m_SignalScaleBox->value())); + resultNode->AddProperty("Fiberfox.FiberRadius", IntProperty::New(m_Controls->m_FiberRadius->value())); + resultNode->AddProperty("Fiberfox.Tinhom", IntProperty::New(m_Controls->m_T2starBox->value())); resultNode->AddProperty("Fiberfox.Noise-Variance", DoubleProperty::New(noiseVariance)); resultNode->AddProperty("Fiberfox.Repetitions", IntProperty::New(m_Controls->m_RepetitionsBox->value())); resultNode->AddProperty("Fiberfox.b-value", DoubleProperty::New(bVal)); resultNode->AddProperty("Fiberfox.Model", StringProperty::New(signalModelString.toStdString())); + resultNode->AddProperty("Fiberfox.PureFiberVoxels", BoolProperty::New(m_Controls->m_EnforcePureFiberVoxelsBox->isChecked())); + resultNode->AddProperty("binary", BoolProperty::New(false)); + resultNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New(filter->GetLevelWindow()) ); if (m_Controls->m_KspaceImageBox->isChecked()) { itk::Image::Pointer kspace = filter->GetKspaceImage(); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(kspace.GetPointer()); image->SetVolume(kspace->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName(m_SelectedBundles.at(i)->GetName()+"_k-space"); GetDataStorage()->Add(node, m_SelectedBundles.at(i)); } mitk::BaseData::Pointer basedata = resultNode->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void QmitkFiberfoxView::ApplyTransform() { vector< mitk::DataNode::Pointer > selectedBundles; for( int i=0; iGetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) selectedBundles.push_back(fibNode); } } if (selectedBundles.empty()) selectedBundles = m_SelectedBundles2; if (!selectedBundles.empty()) { std::vector::const_iterator it = selectedBundles.begin(); for (it; it!=selectedBundles.end(); ++it) { mitk::FiberBundleX::Pointer fib = dynamic_cast((*it)->GetData()); fib->RotateAroundAxis(m_Controls->m_XrotBox->value(), m_Controls->m_YrotBox->value(), m_Controls->m_ZrotBox->value()); fib->TranslateFibers(m_Controls->m_XtransBox->value(), m_Controls->m_YtransBox->value(), m_Controls->m_ZtransBox->value()); fib->ScaleFibers(m_Controls->m_XscaleBox->value(), m_Controls->m_YscaleBox->value(), m_Controls->m_ZscaleBox->value()); // handle child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse* pe = dynamic_cast(fiducialNode->GetData()); mitk::Geometry3D* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< float, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< float, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< float, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< float, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); // implicit translation mitk::Vector3D trans; trans[0] = geom->GetOrigin()[0]-fib->GetGeometry()->GetCenter()[0]; trans[1] = geom->GetOrigin()[1]-fib->GetGeometry()->GetCenter()[1]; trans[2] = geom->GetOrigin()[2]-fib->GetGeometry()->GetCenter()[2]; mitk::Vector3D newWc = rot*trans; newWc = newWc-trans; geom->Translate(newWc); } } } } } else { for (int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Geometry3D* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< float, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< float, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< float, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< float, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::CopyBundles() { if ( m_SelectedBundles.size()<1 ){ QMessageBox::information( NULL, "Warning", "Select at least one fiber bundle!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least one fiber bundle!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); for (it; it!=m_SelectedBundles.end(); ++it) { // find parent image mitk::DataNode::Pointer parentNode; mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { parentNode = pImgNode; break; } } mitk::FiberBundleX::Pointer fib = dynamic_cast((*it)->GetData()); mitk::FiberBundleX::Pointer newBundle = fib->GetDeepCopy(); QString name((*it)->GetName().c_str()); name += "_copy"; mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); if (parentNode.IsNotNull()) GetDataStorage()->Add(fbNode, parentNode); else GetDataStorage()->Add(fbNode); // copy child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = mitk::PlanarEllipse::New(); pe->DeepCopy(dynamic_cast(fiducialNode->GetData())); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pe); newNode->SetName(fiducialNode->GetName()); GetDataStorage()->Add(newNode, fbNode); } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::JoinBundles() { if ( m_SelectedBundles.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedBundles.end(); ++it) { newBundle = newBundle->AddBundle(dynamic_cast((*it)->GetData())); name += "+"+QString((*it)->GetName().c_str()); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::UpdateGui() { m_Controls->m_FiberBundleLabel->setText("mandatory"); m_Controls->m_GeometryFrame->setEnabled(true); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_FiberGenMessage->setVisible(true); m_Controls->m_TransformBundlesButton->setEnabled(false); m_Controls->m_CopyBundlesButton->setEnabled(false); m_Controls->m_GenerateFibersButton->setEnabled(false); m_Controls->m_FlipButton->setEnabled(false); m_Controls->m_CircleButton->setEnabled(false); m_Controls->m_BvalueBox->setEnabled(true); m_Controls->m_NumGradientsBox->setEnabled(true); m_Controls->m_JoinBundlesButton->setEnabled(false); m_Controls->m_AlignOnGrid->setEnabled(false); if (m_SelectedFiducial.IsNotNull()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_FlipButton->setEnabled(true); m_Controls->m_AlignOnGrid->setEnabled(true); } - if (m_SelectedImage.IsNotNull() || m_SelectedBundle.IsNotNull()) + if (m_SelectedImage.IsNotNull() || !m_SelectedBundles.empty()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_CircleButton->setEnabled(true); m_Controls->m_FiberGenMessage->setVisible(false); m_Controls->m_AlignOnGrid->setEnabled(true); } - if (m_TissueMask.IsNotNull()) + if (m_TissueMask.IsNotNull() || m_SelectedImage.IsNotNull()) { m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if (m_SelectedDWI.IsNotNull()) { m_Controls->m_DiffusionPropsMessage->setVisible(true); m_Controls->m_BvalueBox->setEnabled(false); m_Controls->m_NumGradientsBox->setEnabled(false); m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } - if (m_SelectedBundle.IsNotNull()) + if (!m_SelectedBundles.empty()) { m_Controls->m_CopyBundlesButton->setEnabled(true); m_Controls->m_GenerateFibersButton->setEnabled(true); - m_Controls->m_FiberBundleLabel->setText(m_SelectedBundle->GetName().c_str()); + m_Controls->m_FiberBundleLabel->setText(m_SelectedBundles.at(0)->GetName().c_str()); if (m_SelectedBundles.size()>1) m_Controls->m_JoinBundlesButton->setEnabled(true); } } void QmitkFiberfoxView::OnSelectionChanged( berry::IWorkbenchPart::Pointer, const QList& nodes ) { m_SelectedBundles2.clear(); m_SelectedImages.clear(); m_SelectedFiducials.clear(); m_SelectedFiducial = NULL; m_TissueMask = NULL; m_SelectedBundles.clear(); - m_SelectedBundle = NULL; m_SelectedImage = NULL; m_SelectedDWI = NULL; m_Controls->m_TissueMaskLabel->setText("optional"); // iterate all selected objects, adjust warning visibility for( int i=0; i*>(node->GetData()) ) { m_SelectedDWI = node; m_SelectedImage = node; m_SelectedImages.push_back(node); } else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedImages.push_back(node); m_SelectedImage = node; bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) { m_TissueMask = dynamic_cast(node->GetData()); m_Controls->m_TissueMaskLabel->setText(node->GetName().c_str()); } } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedBundles2.push_back(node); - if (m_Controls->m_RealTimeFibers->isChecked() && node!=m_SelectedBundle) + if (m_Controls->m_RealTimeFibers->isChecked()) { - m_SelectedBundle = node; m_SelectedBundles.push_back(node); mitk::FiberBundleX::Pointer newFib = dynamic_cast(node->GetData()); if (newFib->GetNumFibers()!=m_Controls->m_FiberDensityBox->value()) GenerateFibers(); } else - { - m_SelectedBundle = node; m_SelectedBundles.push_back(node); - } } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedFiducials.push_back(node); m_SelectedFiducial = node; m_SelectedBundles.clear(); mitk::DataStorage::SetOfObjects::ConstPointer parents = GetDataStorage()->GetSources(node); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) { mitk::DataNode::Pointer pNode = *it; if ( pNode.IsNotNull() && dynamic_cast(pNode->GetData()) ) - { - m_SelectedBundle = pNode; m_SelectedBundles.push_back(pNode); - } } } } UpdateGui(); } void QmitkFiberfoxView::EnableCrosshairNavigation() { MITK_DEBUG << "EnableCrosshairNavigation"; // enable the crosshair navigation if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MITK_DEBUG << "enabling linked navigation"; linkedRenderWindow->EnableLinkedNavigation(true); // linkedRenderWindow->EnableSlicingPlanes(true); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::DisableCrosshairNavigation() { MITK_DEBUG << "DisableCrosshairNavigation"; // disable the crosshair navigation during the drawing if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MITK_DEBUG << "disabling linked navigation"; linkedRenderWindow->EnableLinkedNavigation(false); // linkedRenderWindow->EnableSlicingPlanes(false); } } void QmitkFiberfoxView::NodeRemoved(const mitk::DataNode* node) { - if (node == m_SelectedImage) - m_SelectedImage = NULL; - if (node == m_SelectedBundle) - m_SelectedBundle = NULL; - mitk::DataNode* nonConstNode = const_cast(node); std::map::iterator it = m_DataNodeToPlanarFigureData.find(nonConstNode); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; // remove observers data.m_Figure->RemoveObserver( data.m_EndPlacementObserverTag ); data.m_Figure->RemoveObserver( data.m_SelectObserverTag ); data.m_Figure->RemoveObserver( data.m_StartInteractionObserverTag ); data.m_Figure->RemoveObserver( data.m_EndInteractionObserverTag ); m_DataNodeToPlanarFigureData.erase( it ); } } void QmitkFiberfoxView::NodeAdded( const mitk::DataNode* node ) { // add observer for selection in renderwindow mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); bool isPositionMarker (false); node->GetBoolProperty("isContourMarker", isPositionMarker); if( figure && !isPositionMarker ) { MITK_DEBUG << "figure added. will add interactor if needed."; mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetInteractor()); mitk::DataNode* nonConstNode = const_cast( node ); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", nonConstNode); } else { // just to be sure that the interactor is not added twice mitk::GlobalInteraction::GetInstance()->RemoveInteractor(figureInteractor); } MITK_DEBUG << "adding interactor to globalinteraction"; mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); MITK_DEBUG << "will now add observers for planarfigure"; QmitkPlanarFigureData data; data.m_Figure = figure; // // add observer for event when figure has been placed typedef itk::SimpleMemberCommand< QmitkFiberfoxView > SimpleCommandType; // SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); // initializationCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureInitialized ); // data.m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); // add observer for event when figure is picked (selected) typedef itk::MemberCommand< QmitkFiberfoxView > MemberCommandType; MemberCommandType::Pointer selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureSelected ); data.m_SelectObserverTag = figure->AddObserver( mitk::SelectPlanarFigureEvent(), selectCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer startInteractionCommand = SimpleCommandType::New(); startInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::DisableCrosshairNavigation); data.m_StartInteractionObserverTag = figure->AddObserver( mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); m_DataNodeToPlanarFigureData[nonConstNode] = data; } } void QmitkFiberfoxView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) { mitk::TNodePredicateDataType::Pointer isPf = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allPfs = this->GetDataStorage()->GetSubset( isPf ); for ( mitk::DataStorage::SetOfObjects::const_iterator it = allPfs->begin(); it!=allPfs->end(); ++it) { mitk::DataNode* node = *it; if( node->GetData() == object ) { node->SetSelected(true); m_SelectedFiducial = node; } else node->SetSelected(false); } UpdateGui(); this->RequestRenderWindowUpdate(); } void QmitkFiberfoxView::SetFocus() { m_Controls->m_CircleButton->setFocus(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h index 63ff823723..472cec2de2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h @@ -1,136 +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 #include #include #include "ui_QmitkFiberfoxViewControls.h" #include #include #include #include #include /*! \brief View for fiber based diffusion software phantoms (Fiberfox). \sa QmitkFunctionality \ingroup Functionalities */ // Forward Qt class declarations using namespace std; class QmitkFiberfoxView : 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 string VIEW_ID; QmitkFiberfoxView(); virtual ~QmitkFiberfoxView(); virtual void CreateQtPartControl(QWidget *parent); void SetFocus(); typedef itk::Image ItkUcharImgType; typedef itk::Vector GradientType; typedef vector GradientListType; template vector > MakeGradientList() ; protected slots: void OnDrawROI(); ///< adds new ROI, handles interactors etc. void OnAddBundle(); ///< adds new fiber bundle to datastorage void OnFlipButton(); ///< negate one coordinate of the fiber waypoints in the selcted planar figure. needed in case of unresolvable twists void GenerateFibers(); ///< generate fibers from the selected ROIs void GenerateImage(); ///< generate artificial image from the selected fiber bundle void JoinBundles(); ///< merges selcted fiber bundles into one void CopyBundles(); ///< add copy of the selected bundle to the datamanager void ApplyTransform(); ///< rotate and shift selected bundles void AlignOnGrid(); ///< shift selected fiducials to nearest voxel center - void FiberModelFrameVisibility(int index);///< only show parameters of selected fiber model type - void NonFiberModelFrameVisibility(int index);///< only show parameters of selected non-fiber model type + void Comp1ModelFrameVisibility(int index);///< only show parameters of selected fiber model type + void Comp2ModelFrameVisibility(int index);///< only show parameters of selected non-fiber model type + void Comp3ModelFrameVisibility(int index);///< only show parameters of selected non-fiber model type + void Comp4ModelFrameVisibility(int index);///< only show parameters of selected non-fiber model type void ShowAdvancedOptions(int state); /** update fibers if any parameter changes */ void OnFiberDensityChanged(int value); void OnFiberSamplingChanged(int value); void OnTensionChanged(double value); void OnContinuityChanged(double value); void OnBiasChanged(double value); void OnVarianceChanged(double value); void OnDistributionChanged(int value); void OnAddGibbsRinging(int value); void OnConstantRadius(int value); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList&); GradientListType GenerateHalfShell(int NPoints); ///< generate vectors distributed over the halfsphere Ui::QmitkFiberfoxViewControls* m_Controls; void UpdateGui(); ///< enable/disbale buttons etc. according to current datamanager selection void PlanarFigureSelected( itk::Object* object, const itk::EventObject& ); void EnableCrosshairNavigation(); ///< enable crosshair navigation if planar figure interaction ends void DisableCrosshairNavigation(); ///< disable crosshair navigation if planar figure interaction starts void NodeAdded( const mitk::DataNode* node ); ///< add observers void NodeRemoved(const mitk::DataNode* node); ///< remove observers /** structure to keep track of planar figures and observers */ struct QmitkPlanarFigureData { QmitkPlanarFigureData() : m_Figure(0) , m_EndPlacementObserverTag(0) , m_SelectObserverTag(0) , m_StartInteractionObserverTag(0) , m_EndInteractionObserverTag(0) , m_Flipped(0) { } mitk::PlanarFigure* m_Figure; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; unsigned int m_Flipped; }; std::map m_DataNodeToPlanarFigureData; ///< map each planar figure uniquely to a QmitkPlanarFigureData mitk::Image::Pointer m_TissueMask; ///< mask defining which regions of the image should contain signal and which are containing only noise mitk::DataNode::Pointer m_SelectedFiducial; ///< selected planar ellipse mitk::DataNode::Pointer m_SelectedImage; - mitk::DataNode::Pointer m_SelectedBundle; mitk::DataNode::Pointer m_SelectedDWI; vector< mitk::DataNode::Pointer > m_SelectedBundles; vector< mitk::DataNode::Pointer > m_SelectedBundles2; vector< mitk::DataNode::Pointer > m_SelectedFiducials; vector< mitk::DataNode::Pointer > m_SelectedImages; }; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui index a172316b28..f45819d6b4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui @@ -1,2064 +1,2020 @@ QmitkFiberfoxViewControls 0 0 493 - 1206 + 1438 Form 0 Fiber Definition Qt::Vertical 20 40 color: rgb(255, 0, 0); Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. Qt::AutoText Qt::AlignJustify|Qt::AlignVCenter true Fiducial Options All fiducials are treated as circles with the same radius as the first fiducial. Use Constant Fiducial Radius false false Align selected fiducials with voxel grid. Shifts selected fiducials to nearest voxel center. Align With Grid Operations false Copy Bundles false Transform Selection QFrame::NoFrame QFrame::Raised 0 Y false Rotation angle (in degree) around x-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Axis: false Rotation angle (in degree) around y-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Translation: false Translation (in mm) in direction of the z-axis. -1000.000000000000000 1000.000000000000000 0.100000000000000 Translation (in mm) in direction of the y-axis. -1000.000000000000000 1000.000000000000000 0.100000000000000 X false Rotation: false Z false Rotation angle (in degree) around z-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Translation (in mm) in direction of the x-axis. -1000.000000000000000 1000.000000000000000 0.100000000000000 Scaling: false Scaling factor for selected fiber bundle along the x-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the y-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the z-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 false Join Bundles If checked, the fiducials belonging to the modified bundle are also modified. Include Fiducials true Fiber Options QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 Tension: false Fiber Sampling: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Fiber sampling points (per cm) 1 100 1 10 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Bias: false Continuity: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 QFrame::NoFrame QFrame::Raised 0 6 #Fibers: false Specify number of fibers to generate for the selected bundle. 1 1000000 100 100 false Generate Fibers QFrame::NoFrame QFrame::Raised 0 Select fiber distribution inside of the fiducials. Uniform Gaussian Fiber Distribution: false Variance of the gaussian 3 0.001000000000000 10.000000000000000 0.010000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 Disable to only generate fibers if "Generate Fibers" button is pressed. Real Time Fibers true Disable to only generate fibers if "Generate Fibers" button is pressed. Advanced Options false QFrame::NoFrame QFrame::Raised 0 false 30 30 Draw elliptical fiducial. :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true false 30 30 Flip fiber waypoints of selcted fiducial around one axis. :/QmitkDiffusionImaging/refresh.xpm:/QmitkDiffusionImaging/refresh.xpm 32 32 false true Qt::Horizontal 40 20 Signal Generation + + + + Intra-axonal Compartment + + + + + + Select signal model for intra-axonal compartment. + + + + Stick Model + + + + + Zeppelin Model + + + + + Tensor Model + + + + + + + + + + + + + + + + Data Fiber Bundle: false <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true Tissue Mask: false <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> true - + - Noise and Artifacts + Extra-axonal Compartments - - - - - true - - - QFrame::NoFrame - - - QFrame::Raised - - - - 6 - - - 0 - - - - - - - - - - - - - - k-Space Undersampling: - - - false - - - - - - - Image is upsampled using this factor, afterwards fourier transformed, cropped to the original size and then inverse fourier transformed. - - - 1 - - - - 2 - - - - - 4 - - - - - 8 - - - - - 16 - - - - - 32 - - - - - 64 - - - - - 128 - - - - - 256 - - - - - - - - - - - true - - - QFrame::NoFrame - - - QFrame::Raised + + + + + Select signal model for extra-axonal compartment. - - - QFormLayout::AllNonFixedFieldsGrow - - - 0 + + + Ball Model - - 0 + + + + Astrosticks Model - - 0 + + + + Dot Model - + - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - - - Variance: - - - - - - - Variance of Rician noise model. - - - 4 - - - 0.000000000000000 - - - 100000.000000000000000 - - - 0.001000000000000 - - - 25.000000000000000 - - - - - + + - - - - Add Gibbs Ringing - - - false - - + + - - - - - - - true - - - Start DWI generation from selected fiebr bundle. If no fiber bundle is selected, a grayscale image containing a simple gradient is generated. - - - Generate Image - - - - - - - Intra-axonal Compartment - - - false - - - false - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - - - Determins anisotropy of kernel tensor (zeppelin-model). - - - 0.010000000000000 - - - 1.000000000000000 - - - 0.100000000000000 - - - 0.700000000000000 - - - - - - - Fractional Anisotropy: - - - - - + + - - + + + + + - Select signal model for intra-axonal compartment. + Select signal model for extra-axonal compartment. - Zeppelin Model + -- - Stick Model + Ball Model + + + + + Astrosticks Model + + + + + Dot Model - - - - QFrame::NoFrame - - - QFrame::Raised + + + + Qt::Horizontal - - - 0 - - - - - - - - - - - - - - T2 relaxation: - - - false - - - - - - - T2 of intra axonal compartment (in milliseconds). - - - 1 - - - 10000 - - - 1 - - - 90 - - - - - - + + + + + QFrame::NoFrame QFrame::Raised - + 0 - + - Diffusivity parameter of the stick-model. - - - 4 - - - 0.000100000000000 + Weighting factor between the two extra-axonal compartments. 1.000000000000000 - 0.000500000000000 + 0.100000000000000 - 0.005000000000000 + 0.300000000000000 - + - Diffusivity: + Compartment Fraction: + + + + + + + true + + + Start DWI generation from selected fiebr bundle. If no fiber bundle is selected, a grayscale image containing a simple gradient is generated. + + + Generate Image + + + Image Settings - + QFrame::NoFrame QFrame::Raised 0 6 - - - - Fiber Radius: - - - - - - - Output k-Space Image - - - false - - - - - - - Treat voxel content as fiber-only if at least one fiber is present. - - - Enforce Pure Fiber Voxels - - - false - - - - - - - Repetitions: - - - - - - - Number of signal averages. Increase to reduce noise. - - - 1 - - - 100 - - - 1 - - - 1 - - - - T2* relaxation: + <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> false - - - - Scaling factor for signal. - - - 0 - - - 10000 - - - 1 - - - 200 - - - - - - - Large values shrink (towards nearest neighbour interpolation), small values strech interpolation function (towards linear interpolation). - - - 1 - - - 10000 + + + + Output k-Space Image - - 10 + + false - - + + - Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation. + Large values shrink (towards nearest neighbour interpolation), small values strech interpolation function (towards linear interpolation). - 0 + 1 - 1000 + 10000 - 0 + 10 - - + + T2* relaxation time (in milliseconds). - - 1 - - 10000 + 100.000000000000000 - 1 + 0.100000000000000 - 50 + 1.000000000000000 - - + + + + Treat voxel content as fiber-only if at least one fiber is present. + - Interpolation Shrink: + Enforce Pure Fiber Voxels + + + false TE in milliseconds 1 10000 1 100 - - - - - - - - - - + + + + Fiber Radius: + + + + - Signal Scale: + Interpolation Shrink: - - false + + + + + + Repetitions: - Echo time TE: + <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> false - Line readout time: + Line Readout Time: false - - + + - T2* relaxation time (in milliseconds). + Number of signal averages. Increase to reduce noise. + + + 1 - 100.000000000000000 + 100 - 0.100000000000000 + 1 - 1.000000000000000 - - - - - - - - - - color: rgb(255, 0, 0); - - - Using mask image geometry! - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 6 - - - - - Gradient Directions: + 1 - - + + - Number of gradient directions distributed over the half sphere. + Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds). - 0 + 1 10000 1 - 30 + 50 - - + + - + Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation. - - + + 0 - - + + 1000 - - b-Value: + + 0 - - false + + + + + + Signal Scale: - + - b-value in mm/s² + TE in milliseconds - 0 + 1 10000 - 100 + 1 - 1000 + 125 + + + + color: rgb(255, 0, 0); + + + Using geometry of selected image! + + + + + + + color: rgb(255, 0, 0); + + + Using gradients of selected DWI! + + + QFrame::NoFrame QFrame::Raised 0 3 0.100000000000000 50.000000000000000 0.100000000000000 - 2.500000000000000 + 2.000000000000000 Image Spacing: 3 0.100000000000000 50.000000000000000 0.100000000000000 - 2.500000000000000 + 2.000000000000000 3 0.100000000000000 50.000000000000000 0.100000000000000 - 2.500000000000000 + 2.000000000000000 Image Dimensions: Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 - 32 + 11 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 - - 100 + + 1000 + + + 1 + + + 11 + + + + + + + Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. + + + 1 + + + 1000 + + + 1 + + + 3 + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 6 + + + + + Gradient Directions: + + + + + + + Number of gradient directions distributed over the half sphere. + + + 0 + + + 10000 + + + 1 + + + 30 + + + + + + + + + + + + + - - 1 + + b-Value: - - 32 + + false - - + + - Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. + b-value in mm/s² - 1 + 0 - 100 + 10000 - 1 + 100 - 5 + 1000 - - - - color: rgb(255, 0, 0); - - - Using gradients of selected DWI! - - - - + Advanced Options - + Qt::Vertical 20 40 - - + + - Extra-axonal Compartment + Noise and Artifacts - - - - - Select signal model for extra-axonal compartment. + + + + + true - - - Ball Model - - - - - - QFrame::NoFrame QFrame::Raised - + + + 6 + 0 - - - - Diffusivity parameter of the ball-model. - - - 4 - - - 0.000100000000000 - - - 1.000000000000000 - - - 0.000500000000000 - - - 0.001000000000000 - - - - - - Diffusivity: - - - - - + - T2 relaxation: + k-Space Undersampling: false - - + + + + Image is upsampled using this factor, afterwards fourier transformed, cropped to the original size and then inverse fourier transformed. + + + 0 + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + + + 32 + + + + + 64 + + + + + 128 + + + + + 256 + + + + + + + + + + + true + + + QFrame::NoFrame + + + QFrame::Raised + + + + QFormLayout::AllNonFixedFieldsGrow + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + + + Variance: + + + + + - T2 of extra axonal compartment (in milliseconds). + Variance of Rician noise model. + + + 4 - 1 + 0.000000000000000 - 10000 + 100000.000000000000000 - 1 + 0.001000000000000 - 100 + 25.000000000000000 + + + + Add Gibbs Ringing + + + false + + + + + + + + + + Inter-axonal Compartment + + + + + + + + + + + + Select signal model for intra-axonal compartment. + + + + -- + + + + + Stick Model + + + + + Zeppelin Model + + + + + Tensor Model + + + + + + + + + + QmitkTensorModelParametersWidget + QWidget +
QmitkTensorModelParametersWidget.h
+ 1 +
+ + QmitkStickModelParametersWidget + QWidget +
QmitkStickModelParametersWidget.h
+ 1 +
+ + QmitkZeppelinModelParametersWidget + QWidget +
QmitkZeppelinModelParametersWidget.h
+ 1 +
+ + QmitkBallModelParametersWidget + QWidget +
QmitkBallModelParametersWidget.h
+ 1 +
+ + QmitkAstrosticksModelParametersWidget + QWidget +
QmitkAstrosticksModelParametersWidget.h
+ 1 +
+ + QmitkDotModelParametersWidget + QWidget +
QmitkDotModelParametersWidget.h
+ 1 +
+
tabWidget m_CircleButton m_FlipButton m_RealTimeFibers - m_AdvancedOptionsBox m_DistributionBox + m_AdvancedOptionsBox m_VarianceBox m_FiberDensityBox m_FiberSamplingBox m_TensionBox m_ContinuityBox m_BiasBox m_GenerateFibersButton m_ConstantRadiusBox m_AlignOnGrid m_XrotBox m_YrotBox m_ZrotBox m_XtransBox m_YtransBox m_ZtransBox m_XscaleBox m_YscaleBox m_ZscaleBox m_TransformBundlesButton m_CopyBundlesButton m_JoinBundlesButton m_IncludeFiducials m_GenerateImageButton m_SizeX m_SizeY m_SizeZ m_SpacingX m_SpacingY m_SpacingZ m_NumGradientsBox m_BvalueBox + m_AdvancedOptionsBox_2 m_RepetitionsBox - m_SignalScaleBox m_TEbox m_LineReadoutTimeBox m_T2starBox m_FiberRadius m_InterpolationShrink m_EnforcePureFiberVoxelsBox m_KspaceImageBox - m_AdvancedOptionsBox_2 - m_FiberCompartmentModelBox - m_TensorFaBox - m_StickDiffusivityBox - m_FiberT2Box - m_NonFiberCompartmentModelBox - m_BallD - m_NonFiberT2Box + m_Compartment1Box + m_Compartment2Box + m_Compartment3Box + m_Compartment4Box + m_Comp4FractionBox m_NoiseLevel - m_KspaceUndersamplingBox m_AddGibbsRinging + m_KspaceUndersamplingBox
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingView.cpp index 82facef8ba..90abcfacc0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingView.cpp @@ -1,757 +1,758 @@ /*=================================================================== 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 "QmitkGibbsTrackingView.h" #include // Qt #include #include #include // MITK #include #include #include #include #include // ITK #include #include #include // MISC #include QmitkTrackingWorker::QmitkTrackingWorker(QmitkGibbsTrackingView* view) : m_View(view) { } void QmitkTrackingWorker::run() { m_View->m_GlobalTracker = QmitkGibbsTrackingView::GibbsTrackingFilterType::New(); m_View->m_GlobalTracker->SetQBallImage(m_View->m_ItkQBallImage); m_View->m_GlobalTracker->SetTensorImage(m_View->m_ItkTensorImage); m_View->m_GlobalTracker->SetMaskImage(m_View->m_MaskImage); m_View->m_GlobalTracker->SetStartTemperature((float)m_View->m_Controls->m_StartTempSlider->value()/100); m_View->m_GlobalTracker->SetEndTemperature((float)m_View->m_Controls->m_EndTempSlider->value()/10000); m_View->m_GlobalTracker->SetIterations(m_View->m_Iterations); m_View->m_GlobalTracker->SetParticleWeight((float)m_View->m_Controls->m_ParticleWeightSlider->value()/10000); m_View->m_GlobalTracker->SetParticleWidth((float)(m_View->m_Controls->m_ParticleWidthSlider->value())/10); m_View->m_GlobalTracker->SetParticleLength((float)(m_View->m_Controls->m_ParticleLengthSlider->value())/10); m_View->m_GlobalTracker->SetInexBalance((float)m_View->m_Controls->m_InExBalanceSlider->value()/10); m_View->m_GlobalTracker->SetMinFiberLength(m_View->m_Controls->m_FiberLengthSlider->value()); m_View->m_GlobalTracker->SetCurvatureThreshold(cos((float)m_View->m_Controls->m_CurvatureThresholdSlider->value()*M_PI/180)); m_View->m_GlobalTracker->SetRandomSeed(m_View->m_Controls->m_RandomSeedSlider->value()); try{ m_View->m_GlobalTracker->Update(); } catch( mitk::Exception e ) { MITK_ERROR << "Internal error occured: " << e.what() << "\nAborting"; } m_View->m_TrackingThread.quit(); } const std::string QmitkGibbsTrackingView::VIEW_ID = "org.mitk.views.gibbstracking"; QmitkGibbsTrackingView::QmitkGibbsTrackingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_ThreadIsRunning(false) , m_GlobalTracker(NULL) , m_QBallImage(NULL) , m_MaskImage(NULL) , m_ImageNode(NULL) , m_ItkQBallImage(NULL) , m_ItkTensorImage(NULL) , m_FiberBundleNode(NULL) , m_MaskImageNode(NULL) , m_TrackingWorker(this) , m_Iterations(10000000) , m_LastStep(0) { m_TrackingWorker.moveToThread(&m_TrackingThread); connect(&m_TrackingThread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_TrackingThread, SIGNAL(started()), &m_TrackingWorker, SLOT(run())); connect(&m_TrackingThread, SIGNAL(finished()), this, SLOT(AfterThread())); connect(&m_TrackingThread, SIGNAL(terminated()), this, SLOT(AfterThread())); m_TrackingTimer = new QTimer(this); } QmitkGibbsTrackingView::~QmitkGibbsTrackingView() { delete m_TrackingTimer; } // update tracking status and generate fiber bundle void QmitkGibbsTrackingView::TimerUpdate() { int currentStep = m_GlobalTracker->GetCurrentStep(); mitk::ProgressBar::GetInstance()->Progress(currentStep-m_LastStep); UpdateTrackingStatus(); GenerateFiberBundle(); m_LastStep = currentStep; } // tell global tractography filter to stop after current step void QmitkGibbsTrackingView::StopGibbsTracking() { if (m_GlobalTracker.IsNull()) return; //mitk::ProgressBar::GetInstance()->Progress(m_GlobalTracker->GetSteps()-m_LastStep+1); m_GlobalTracker->SetAbortTracking(true); m_Controls->m_TrackingStop->setEnabled(false); m_Controls->m_TrackingStop->setText("Stopping Tractography ..."); } // update gui elements and generate fiber bundle after tracking is finished void QmitkGibbsTrackingView::AfterThread() { m_ThreadIsRunning = false; m_TrackingTimer->stop(); mitk::ProgressBar::GetInstance()->Progress(m_GlobalTracker->GetSteps()-m_LastStep+1); UpdateGUI(); if( !m_GlobalTracker->GetIsInValidState() ) { QMessageBox::critical( NULL, "Gibbs Tracking", "An internal error occured. Tracking aborted.\n Please check the log for details." ); m_FiberBundleNode = NULL; return; } UpdateTrackingStatus(); if(m_Controls->m_ParticleWeightSlider->value()==0) { m_Controls->m_ParticleWeightLabel->setText(QString::number(m_GlobalTracker->GetParticleWeight())); m_Controls->m_ParticleWeightSlider->setValue(m_GlobalTracker->GetParticleWeight()*10000); } if(m_Controls->m_ParticleWidthSlider->value()==0) { m_Controls->m_ParticleWidthLabel->setText(QString::number(m_GlobalTracker->GetParticleWidth())); m_Controls->m_ParticleWidthSlider->setValue(m_GlobalTracker->GetParticleWidth()*10); } if(m_Controls->m_ParticleLengthSlider->value()==0) { m_Controls->m_ParticleLengthLabel->setText(QString::number(m_GlobalTracker->GetParticleLength())); m_Controls->m_ParticleLengthSlider->setValue(m_GlobalTracker->GetParticleLength()*10); } GenerateFiberBundle(); m_FiberBundleNode = 0; m_GlobalTracker = 0; // images not needed anymore ( relevant only for computation ) // we need to release them to remove the memory access block created through CastToItk<> calls this->m_ItkQBallImage = 0; this->m_ItkTensorImage = 0; } // start tracking timer and update gui elements before tracking is started void QmitkGibbsTrackingView::BeforeThread() { m_ThreadIsRunning = true; m_TrackingTime = QTime::currentTime(); m_ElapsedTime = 0; m_TrackingTimer->start(1000); m_LastStep = 0; UpdateGUI(); } // setup gui elements and signal/slot connections void QmitkGibbsTrackingView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkGibbsTrackingViewControls; m_Controls->setupUi( parent ); AdvancedSettings(); connect( m_TrackingTimer, SIGNAL(timeout()), this, SLOT(TimerUpdate()) ); connect( m_Controls->m_TrackingStop, SIGNAL(clicked()), this, SLOT(StopGibbsTracking()) ); connect( m_Controls->m_TrackingStart, SIGNAL(clicked()), this, SLOT(StartGibbsTracking()) ); connect( m_Controls->m_AdvancedSettingsCheckbox, SIGNAL(clicked()), this, SLOT(AdvancedSettings()) ); connect( m_Controls->m_SaveTrackingParameters, SIGNAL(clicked()), this, SLOT(SaveTrackingParameters()) ); connect( m_Controls->m_LoadTrackingParameters, SIGNAL(clicked()), this, SLOT(LoadTrackingParameters()) ); connect( m_Controls->m_IterationsSlider, SIGNAL(valueChanged(int)), this, SLOT(SetIterations(int)) ); connect( m_Controls->m_ParticleWidthSlider, SIGNAL(valueChanged(int)), this, SLOT(SetParticleWidth(int)) ); connect( m_Controls->m_ParticleLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(SetParticleLength(int)) ); connect( m_Controls->m_InExBalanceSlider, SIGNAL(valueChanged(int)), this, SLOT(SetInExBalance(int)) ); connect( m_Controls->m_FiberLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(SetFiberLength(int)) ); connect( m_Controls->m_ParticleWeightSlider, SIGNAL(valueChanged(int)), this, SLOT(SetParticleWeight(int)) ); connect( m_Controls->m_StartTempSlider, SIGNAL(valueChanged(int)), this, SLOT(SetStartTemp(int)) ); connect( m_Controls->m_EndTempSlider, SIGNAL(valueChanged(int)), this, SLOT(SetEndTemp(int)) ); connect( m_Controls->m_CurvatureThresholdSlider, SIGNAL(valueChanged(int)), this, SLOT(SetCurvatureThreshold(int)) ); connect( m_Controls->m_RandomSeedSlider, SIGNAL(valueChanged(int)), this, SLOT(SetRandomSeed(int)) ); connect( m_Controls->m_OutputFileButton, SIGNAL(clicked()), this, SLOT(SetOutputFile()) ); } } void QmitkGibbsTrackingView::SetInExBalance(int value) { m_Controls->m_InExBalanceLabel->setText(QString::number((float)value/10)); } void QmitkGibbsTrackingView::SetFiberLength(int value) { m_Controls->m_FiberLengthLabel->setText(QString::number(value)+"mm"); } void QmitkGibbsTrackingView::SetRandomSeed(int value) { if (value>=0) m_Controls->m_RandomSeedLabel->setText(QString::number(value)); else m_Controls->m_RandomSeedLabel->setText("auto"); } void QmitkGibbsTrackingView::SetParticleWeight(int value) { if (value>0) m_Controls->m_ParticleWeightLabel->setText(QString::number((float)value/10000)); else m_Controls->m_ParticleWeightLabel->setText("auto"); } void QmitkGibbsTrackingView::SetStartTemp(int value) { m_Controls->m_StartTempLabel->setText(QString::number((float)value/100)); } void QmitkGibbsTrackingView::SetEndTemp(int value) { m_Controls->m_EndTempLabel->setText(QString::number((float)value/10000)); } void QmitkGibbsTrackingView::SetParticleWidth(int value) { if (value>0) m_Controls->m_ParticleWidthLabel->setText(QString::number((float)value/10)+" mm"); else m_Controls->m_ParticleWidthLabel->setText("auto"); } void QmitkGibbsTrackingView::SetParticleLength(int value) { if (value>0) m_Controls->m_ParticleLengthLabel->setText(QString::number((float)value/10)+" mm"); else m_Controls->m_ParticleLengthLabel->setText("auto"); } void QmitkGibbsTrackingView::SetCurvatureThreshold(int value) { m_Controls->m_CurvatureThresholdLabel->setText(QString::number(value)+"°"); } void QmitkGibbsTrackingView::SetIterations(int value) { switch(value) { case 0: m_Controls->m_IterationsLabel->setText("Iterations: 1x10^4"); m_Iterations = 10000; break; case 1: m_Controls->m_IterationsLabel->setText("Iterations: 5x10^4"); m_Iterations = 50000; break; case 2: m_Controls->m_IterationsLabel->setText("Iterations: 1x10^5"); m_Iterations = 100000; break; case 3: m_Controls->m_IterationsLabel->setText("Iterations: 5x10^5"); m_Iterations = 500000; break; case 4: m_Controls->m_IterationsLabel->setText("Iterations: 1x10^6"); m_Iterations = 1000000; break; case 5: m_Controls->m_IterationsLabel->setText("Iterations: 5x10^6"); m_Iterations = 5000000; break; case 6: m_Controls->m_IterationsLabel->setText("Iterations: 1x10^7"); m_Iterations = 10000000; break; case 7: m_Controls->m_IterationsLabel->setText("Iterations: 5x10^7"); m_Iterations = 50000000; break; case 8: m_Controls->m_IterationsLabel->setText("Iterations: 1x10^8"); m_Iterations = 100000000; break; case 9: m_Controls->m_IterationsLabel->setText("Iterations: 5x10^8"); m_Iterations = 500000000; break; } } void QmitkGibbsTrackingView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkGibbsTrackingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } // called if datamanager selection changes void QmitkGibbsTrackingView::OnSelectionChanged( std::vector nodes ) { if (m_ThreadIsRunning) return; m_ImageNode = NULL; m_MaskImageNode = NULL; // iterate all selected objects for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if( node.IsNotNull() && dynamic_cast(node->GetData()) ) m_ImageNode = node; else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) m_ImageNode = node; else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) m_MaskImageNode = node; } } UpdateGUI(); } // update gui elements displaying trackings status void QmitkGibbsTrackingView::UpdateTrackingStatus() { if (m_GlobalTracker.IsNull()) return; m_ElapsedTime += m_TrackingTime.elapsed()/1000; m_TrackingTime.restart(); unsigned long hours = m_ElapsedTime/3600; unsigned long minutes = (m_ElapsedTime%3600)/60; unsigned long seconds = m_ElapsedTime%60; m_Controls->m_ProposalAcceptance->setText(QString::number(m_GlobalTracker->GetProposalAcceptance()*100)+"%"); m_Controls->m_TrackingTimeLabel->setText( QString::number(hours)+QString("h ")+QString::number(minutes)+QString("m ")+QString::number(seconds)+QString("s") ); m_Controls->m_NumConnectionsLabel->setText( QString::number(m_GlobalTracker->GetNumConnections()) ); m_Controls->m_NumParticlesLabel->setText( QString::number(m_GlobalTracker->GetNumParticles()) ); m_Controls->m_CurrentStepLabel->setText( QString::number(100*(float)(m_GlobalTracker->GetCurrentStep()-1)/m_GlobalTracker->GetSteps())+"%" ); m_Controls->m_AcceptedFibersLabel->setText( QString::number(m_GlobalTracker->GetNumAcceptedFibers()) ); } // update gui elements (enable/disable elements and set tooltips) void QmitkGibbsTrackingView::UpdateGUI() { if (m_ImageNode.IsNotNull()) { m_Controls->m_QballImageLabel->setText(m_ImageNode->GetName().c_str()); m_Controls->m_DataFrame->setTitle("Input Data"); } else { m_Controls->m_QballImageLabel->setText("mandatory"); m_Controls->m_DataFrame->setTitle("Please Select Input Data"); } if (m_MaskImageNode.IsNotNull()) m_Controls->m_MaskImageLabel->setText(m_MaskImageNode->GetName().c_str()); else m_Controls->m_MaskImageLabel->setText("optional"); if (!m_ThreadIsRunning && m_ImageNode.IsNotNull()) { m_Controls->m_TrackingStop->setEnabled(false); m_Controls->m_TrackingStart->setEnabled(true); m_Controls->m_LoadTrackingParameters->setEnabled(true); m_Controls->m_IterationsSlider->setEnabled(true); m_Controls->m_AdvancedFrame->setEnabled(true); m_Controls->m_TrackingStop->setText("Stop Tractography"); m_Controls->m_TrackingStart->setToolTip("Start tractography. No further change of parameters possible."); m_Controls->m_TrackingStop->setToolTip(""); } else if (!m_ThreadIsRunning) { m_Controls->m_TrackingStop->setEnabled(false); m_Controls->m_TrackingStart->setEnabled(false); m_Controls->m_LoadTrackingParameters->setEnabled(true); m_Controls->m_IterationsSlider->setEnabled(true); m_Controls->m_AdvancedFrame->setEnabled(true); m_Controls->m_TrackingStop->setText("Stop Tractography"); m_Controls->m_TrackingStart->setToolTip("No Q-Ball image selected."); m_Controls->m_TrackingStop->setToolTip(""); } else { m_Controls->m_TrackingStop->setEnabled(true); m_Controls->m_TrackingStart->setEnabled(false); m_Controls->m_LoadTrackingParameters->setEnabled(false); m_Controls->m_IterationsSlider->setEnabled(false); m_Controls->m_AdvancedFrame->setEnabled(false); m_Controls->m_AdvancedFrame->setVisible(false); m_Controls->m_AdvancedSettingsCheckbox->setChecked(false); m_Controls->m_TrackingStart->setToolTip("Tracking in progress."); m_Controls->m_TrackingStop->setToolTip("Stop tracking and display results."); } } // show/hide advanced settings frame void QmitkGibbsTrackingView::AdvancedSettings() { m_Controls->m_AdvancedFrame->setVisible(m_Controls->m_AdvancedSettingsCheckbox->isChecked()); } // set mask image data node void QmitkGibbsTrackingView::SetMask() { std::vector nodes = GetDataManagerSelection(); if (nodes.empty()) { m_MaskImageNode = NULL; m_Controls->m_MaskImageLabel->setText("-"); return; } for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if (node.IsNotNull() && dynamic_cast(node->GetData())) { m_MaskImageNode = node; m_Controls->m_MaskImageLabel->setText(node->GetName().c_str()); return; } } } // check for mask and qbi and start tracking thread void QmitkGibbsTrackingView::StartGibbsTracking() { if(m_ThreadIsRunning) { MITK_WARN("QmitkGibbsTrackingView")<<"Thread already running!"; return; } m_GlobalTracker = NULL; if (m_ImageNode.IsNull()) { QMessageBox::information( NULL, "Warning", "Please load and select a qball image before starting image processing."); return; } if (dynamic_cast(m_ImageNode->GetData())) m_QBallImage = dynamic_cast(m_ImageNode->GetData()); else if (dynamic_cast(m_ImageNode->GetData())) m_TensorImage = dynamic_cast(m_ImageNode->GetData()); if (m_QBallImage.IsNull() && m_TensorImage.IsNull()) return; // cast qbi to itk m_ItkTensorImage = NULL; m_ItkQBallImage = NULL; m_MaskImage = NULL; if (m_QBallImage.IsNotNull()) { m_ItkQBallImage = ItkQBallImgType::New(); mitk::CastToItkImage(m_QBallImage, m_ItkQBallImage); } else { m_ItkTensorImage = ItkTensorImage::New(); mitk::CastToItkImage(m_TensorImage, m_ItkTensorImage); } // mask image found? // catch exceptions thrown by the itkAccess macros try{ if(m_MaskImageNode.IsNotNull()) { if (dynamic_cast(m_MaskImageNode->GetData())) mitk::CastToItkImage(dynamic_cast(m_MaskImageNode->GetData()), m_MaskImage); } } catch(...){}; unsigned int steps = m_Iterations/10000; if (steps<10) steps = 10; m_LastStep = 1; mitk::ProgressBar::GetInstance()->AddStepsToDo(steps); // start worker thread m_TrackingThread.start(QThread::LowestPriority); } // generate mitkFiberBundle from tracking filter output void QmitkGibbsTrackingView::GenerateFiberBundle() { if (m_GlobalTracker.IsNull() || (!(m_Controls->m_VisualizationCheckbox->isChecked() || m_Controls->m_VisualizeOnceButton->isChecked()) && m_ThreadIsRunning)) return; if (m_Controls->m_VisualizeOnceButton->isChecked()) m_Controls->m_VisualizeOnceButton->setChecked(false); vtkSmartPointer fiberBundle = m_GlobalTracker->GetFiberBundle(); if ( m_GlobalTracker->GetNumAcceptedFibers()==0 ) return; m_FiberBundle = mitk::FiberBundleX::New(fiberBundle); if (m_FiberBundleNode.IsNotNull()){ GetDefaultDataStorage()->Remove(m_FiberBundleNode); m_FiberBundleNode = 0; } m_FiberBundleNode = mitk::DataNode::New(); m_FiberBundleNode->SetData(m_FiberBundle); - QString name(m_ImageNode->GetName().c_str()); + QString name("FiberBundle_"); + name += m_ImageNode->GetName().c_str(); name += "_Gibbs"; m_FiberBundleNode->SetName(name.toStdString()); m_FiberBundleNode->SetVisibility(true); if (!m_OutputFileName.isEmpty()) { QString filename = m_OutputFileName; mitk::FiberBundleXWriter::Pointer writer = mitk::FiberBundleXWriter::New(); writer->SetFileName(filename.toStdString()); writer->SetInputFiberBundleX(m_FiberBundle.GetPointer()); try { writer->Update(); QMessageBox::information(NULL, "Fiber bundle saved to", filename); } catch (itk::ExceptionObject &ex) { QMessageBox::information(NULL, "Fiber bundle could not be saved", QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription())); if(m_ImageNode.IsNull()) GetDataStorage()->Add(m_FiberBundleNode); else GetDataStorage()->Add(m_FiberBundleNode, m_ImageNode); } } else { if(m_ImageNode.IsNull()) GetDataStorage()->Add(m_FiberBundleNode); else GetDataStorage()->Add(m_FiberBundleNode, m_ImageNode); } } void QmitkGibbsTrackingView::SetOutputFile() { // SELECT FOLDER DIALOG m_OutputFileName = QFileDialog::getSaveFileName(0, tr("Set file name"), QDir::currentPath()+"/FiberBundle.fib", tr("Fiber Bundle (*.fib)") ); if (m_OutputFileName.isEmpty()) m_Controls->m_OutputFileLabel->setText("N/A"); else m_Controls->m_OutputFileLabel->setText(m_OutputFileName); } // save current tracking paramters as xml file (.gtp) void QmitkGibbsTrackingView::SaveTrackingParameters() { TiXmlDocument documentXML; TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement("global_tracking_parameter_file"); mainXML->SetAttribute("file_version", "0.1"); documentXML.LinkEndChild(mainXML); TiXmlElement* paramXML = new TiXmlElement("parameter_set"); paramXML->SetAttribute("iterations", QString::number(m_Iterations).toStdString()); paramXML->SetAttribute("particle_length", QString::number((float)m_Controls->m_ParticleLengthSlider->value()/10).toStdString()); paramXML->SetAttribute("particle_width", QString::number((float)m_Controls->m_ParticleWidthSlider->value()/10).toStdString()); paramXML->SetAttribute("particle_weight", QString::number((float)m_Controls->m_ParticleWeightSlider->value()/10000).toStdString()); paramXML->SetAttribute("temp_start", QString::number((float)m_Controls->m_StartTempSlider->value()/100).toStdString()); paramXML->SetAttribute("temp_end", QString::number((float)m_Controls->m_EndTempSlider->value()/10000).toStdString()); paramXML->SetAttribute("inexbalance", QString::number((float)m_Controls->m_InExBalanceSlider->value()/10).toStdString()); paramXML->SetAttribute("fiber_length", QString::number(m_Controls->m_FiberLengthSlider->value()).toStdString()); paramXML->SetAttribute("curvature_threshold", QString::number(m_Controls->m_CurvatureThresholdSlider->value()).toStdString()); mainXML->LinkEndChild(paramXML); QString filename = QFileDialog::getSaveFileName( 0, tr("Save Parameters"), QDir::currentPath()+"/param.gtp", tr("Global Tracking Parameters (*.gtp)") ); if(filename.isEmpty() || filename.isNull()) return; if(!filename.endsWith(".gtp")) filename += ".gtp"; documentXML.SaveFile( filename.toStdString() ); } void QmitkGibbsTrackingView::UpdateIteraionsGUI(unsigned long iterations) { switch(iterations) { case 10000: m_Controls->m_IterationsSlider->setValue(0); m_Controls->m_IterationsLabel->setText("Iterations: 10^4"); break; case 50000: m_Controls->m_IterationsSlider->setValue(1); m_Controls->m_IterationsLabel->setText("Iterations: 5x10^4"); break; case 100000: m_Controls->m_IterationsSlider->setValue(2); m_Controls->m_IterationsLabel->setText("Iterations: 10^5"); break; case 500000: m_Controls->m_IterationsSlider->setValue(3); m_Controls->m_IterationsLabel->setText("Iterations: 5x10^5"); break; case 1000000: m_Controls->m_IterationsSlider->setValue(4); m_Controls->m_IterationsLabel->setText("Iterations: 10^6"); break; case 5000000: m_Controls->m_IterationsSlider->setValue(5); m_Controls->m_IterationsLabel->setText("Iterations: 5x10^6"); break; case 10000000: m_Controls->m_IterationsSlider->setValue(6); m_Controls->m_IterationsLabel->setText("Iterations: 10^7"); break; case 50000000: m_Controls->m_IterationsSlider->setValue(7); m_Controls->m_IterationsLabel->setText("Iterations: 5x10^7"); break; case 100000000: m_Controls->m_IterationsSlider->setValue(8); m_Controls->m_IterationsLabel->setText("Iterations: 10^8"); break; case 500000000: m_Controls->m_IterationsSlider->setValue(9); m_Controls->m_IterationsLabel->setText("Iterations: 5x10^8"); break; case 1000000000: m_Controls->m_IterationsSlider->setValue(10); m_Controls->m_IterationsLabel->setText("Iterations: 10^9"); break; case 5000000000: m_Controls->m_IterationsSlider->setValue(11); m_Controls->m_IterationsLabel->setText("Iterations: 5x10^9"); break; } } // load current tracking paramters from xml file (.gtp) void QmitkGibbsTrackingView::LoadTrackingParameters() { QString filename = QFileDialog::getOpenFileName(0, tr("Load Parameters"), QDir::currentPath(), tr("Global Tracking Parameters (*.gtp)") ); if(filename.isEmpty() || filename.isNull()) return; TiXmlDocument doc( filename.toStdString() ); doc.LoadFile(); TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); pElem = hDoc.FirstChildElement().Element(); hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement("parameter_set").Element(); QString iterations(pElem->Attribute("iterations")); m_Iterations = iterations.toULong(); UpdateIteraionsGUI(m_Iterations); QString particleLength(pElem->Attribute("particle_length")); float pLength = particleLength.toFloat(); QString particleWidth(pElem->Attribute("particle_width")); float pWidth = particleWidth.toFloat(); if (pLength==0) m_Controls->m_ParticleLengthLabel->setText("auto"); else m_Controls->m_ParticleLengthLabel->setText(particleLength+" mm"); if (pWidth==0) m_Controls->m_ParticleWidthLabel->setText("auto"); else m_Controls->m_ParticleWidthLabel->setText(particleWidth+" mm"); m_Controls->m_ParticleWidthSlider->setValue(pWidth*10); m_Controls->m_ParticleLengthSlider->setValue(pLength*10); QString partWeight(pElem->Attribute("particle_weight")); m_Controls->m_ParticleWeightSlider->setValue(partWeight.toFloat()*10000); m_Controls->m_ParticleWeightLabel->setText(partWeight); QString startTemp(pElem->Attribute("temp_start")); m_Controls->m_StartTempSlider->setValue(startTemp.toFloat()*100); m_Controls->m_StartTempLabel->setText(startTemp); QString endTemp(pElem->Attribute("temp_end")); m_Controls->m_EndTempSlider->setValue(endTemp.toFloat()*10000); m_Controls->m_EndTempLabel->setText(endTemp); QString inExBalance(pElem->Attribute("inexbalance")); m_Controls->m_InExBalanceSlider->setValue(inExBalance.toFloat()*10); m_Controls->m_InExBalanceLabel->setText(inExBalance); QString fiberLength(pElem->Attribute("fiber_length")); m_Controls->m_FiberLengthSlider->setValue(fiberLength.toInt()); m_Controls->m_FiberLengthLabel->setText(fiberLength+"mm"); QString curvThres(pElem->Attribute("curvature_threshold")); m_Controls->m_CurvatureThresholdSlider->setValue(curvThres.toInt()); m_Controls->m_CurvatureThresholdLabel->setText(curvThres+"°"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.cpp index dbf50eec80..2f26f69ef9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.cpp @@ -1,751 +1,751 @@ /*=================================================================== 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. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include #include // Blueberry #include #include // Qmitk #include "QmitkOdfMaximaExtractionView.h" // MITK #include #include #include #include #include #include // ITK #include #include #include #include #include #include #include const std::string QmitkOdfMaximaExtractionView::VIEW_ID = "org.mitk.views.odfmaximaextractionview"; using namespace mitk; QmitkOdfMaximaExtractionView::QmitkOdfMaximaExtractionView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) { } // Destructor QmitkOdfMaximaExtractionView::~QmitkOdfMaximaExtractionView() { } void QmitkOdfMaximaExtractionView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkOdfMaximaExtractionViewControls; m_Controls->setupUi( parent ); connect((QObject*) m_Controls->m_StartTensor, SIGNAL(clicked()), (QObject*) this, SLOT(StartTensor())); connect((QObject*) m_Controls->m_StartFiniteDiff, SIGNAL(clicked()), (QObject*) this, SLOT(StartFiniteDiff())); connect((QObject*) m_Controls->m_GenerateImageButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateImage())); connect((QObject*) m_Controls->m_ImportPeaks, SIGNAL(clicked()), (QObject*) this, SLOT(ConvertPeaks())); connect((QObject*) m_Controls->m_ImportShCoeffs, SIGNAL(clicked()), (QObject*) this, SLOT(ConvertShCoeffs())); } } void QmitkOdfMaximaExtractionView::UpdateGui() { m_Controls->m_GenerateImageButton->setEnabled(false); m_Controls->m_StartFiniteDiff->setEnabled(false); m_Controls->m_StartTensor->setEnabled(false); m_Controls->m_CoeffImageFrame->setEnabled(false); if (!m_ImageNodes.empty() || !m_TensorImageNodes.empty()) { m_Controls->m_InputData->setTitle("Input Data"); if (!m_TensorImageNodes.empty()) { m_Controls->m_DwiFibLabel->setText(m_TensorImageNodes.front()->GetName().c_str()); m_Controls->m_StartTensor->setEnabled(true); } else { m_Controls->m_DwiFibLabel->setText(m_ImageNodes.front()->GetName().c_str()); m_Controls->m_StartFiniteDiff->setEnabled(true); m_Controls->m_GenerateImageButton->setEnabled(true); m_Controls->m_CoeffImageFrame->setEnabled(true); m_Controls->m_ShOrderBox->setEnabled(true); m_Controls->m_MaxNumPeaksBox->setEnabled(true); m_Controls->m_PeakThresholdBox->setEnabled(true); m_Controls->m_AbsoluteThresholdBox->setEnabled(true); } } else m_Controls->m_DwiFibLabel->setText("mandatory"); if (m_ImageNodes.empty()) { m_Controls->m_ImportPeaks->setEnabled(false); m_Controls->m_ImportShCoeffs->setEnabled(false); } else { m_Controls->m_ImportPeaks->setEnabled(true); m_Controls->m_ImportShCoeffs->setEnabled(true); } if (!m_BinaryImageNodes.empty()) { m_Controls->m_MaskLabel->setText(m_BinaryImageNodes.front()->GetName().c_str()); } else { m_Controls->m_MaskLabel->setText("optional"); } } template void QmitkOdfMaximaExtractionView::TemplatedConvertShCoeffs(mitk::Image* mitkImg) { typedef itk::ShCoefficientImageImporter< float, shOrder > FilterType; typedef mitk::ImageToItk< itk::Image< float, 4 > > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImg); caster->Update(); typename FilterType::Pointer filter = FilterType::New(); switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: filter->SetToolkit(FilterType::FSL); break; case 1: filter->SetToolkit(FilterType::MRTRIX); break; default: filter->SetToolkit(FilterType::FSL); } filter->SetInputImage(caster->GetOutput()); filter->GenerateData(); typename FilterType::QballImageType::Pointer itkQbi = filter->GetQballImage(); typename FilterType::CoefficientImageType::Pointer itkCi = filter->GetCoefficientImage(); { mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkCi.GetPointer() ); img->SetVolume( itkCi->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); node->SetName("_ShCoefficientImage"); GetDataStorage()->Add(node); } { mitk::QBallImage::Pointer img = mitk::QBallImage::New(); img->InitializeByItk( itkQbi.GetPointer() ); img->SetVolume( itkQbi->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); node->SetName("_QballImage"); GetDataStorage()->Add(node); } } void QmitkOdfMaximaExtractionView::ConvertShCoeffs() { if (m_ImageNodes.empty()) return; mitk::Image::Pointer mitkImg = dynamic_cast(m_ImageNodes.at(0)->GetData()); if (mitkImg->GetDimension()!=4) { MITK_INFO << "wrong image type (need 4 dimensions)"; return; } int nrCoeffs = mitkImg->GetLargestPossibleRegion().GetSize()[3]; // solve bx² + cx + d = 0 = shOrder² + 2*shOrder + 2-2*neededCoeffs; int c=3, d=2-2*nrCoeffs; double D = c*c-4*d; int shOrder; if (D>0) { shOrder = (-c+sqrt(D))/2.0; if (shOrder<0) shOrder = (-c-sqrt(D))/2.0; } else if (D==0) shOrder = -c/2.0; MITK_INFO << "using SH-order " << shOrder; switch (shOrder) { case 4: TemplatedConvertShCoeffs<4>(mitkImg); break; case 6: TemplatedConvertShCoeffs<6>(mitkImg); break; case 8: TemplatedConvertShCoeffs<8>(mitkImg); break; case 10: TemplatedConvertShCoeffs<10>(mitkImg); break; case 12: TemplatedConvertShCoeffs<12>(mitkImg); break; default: MITK_INFO << "SH-order " << shOrder << " not supported"; } } void QmitkOdfMaximaExtractionView::ConvertPeaks() { if (m_ImageNodes.empty()) return; switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: { typedef itk::Image< float, 4 > ItkImageType; typedef itk::FslPeakImageConverter< float > FilterType; FilterType::Pointer filter = FilterType::New(); FilterType::InputType::Pointer inputVec = FilterType::InputType::New(); mitk::Geometry3D::Pointer geom; for (int i=0; i(m_ImageNodes.at(i)->GetData()); geom = mitkImg->GetGeometry(); typedef mitk::ImageToItk< FilterType::InputImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImg); caster->Update(); FilterType::InputImageType::Pointer itkImg = caster->GetOutput(); inputVec->InsertElement(inputVec->Size(), itkImg); } filter->SetInputImages(inputVec); filter->GenerateData(); mitk::Vector3D outImageSpacing = geom->GetSpacing(); float maxSpacing = 1; if(outImageSpacing[0]>outImageSpacing[1] && outImageSpacing[0]>outImageSpacing[2]) maxSpacing = outImageSpacing[0]; else if (outImageSpacing[1] > outImageSpacing[2]) maxSpacing = outImageSpacing[1]; else maxSpacing = outImageSpacing[2]; mitk::FiberBundleX::Pointer directions = filter->GetOutputFiberBundle(); - directions->SetGeometry(geom); + // directions->SetGeometry(geom); DataNode::Pointer node = DataNode::New(); node->SetData(directions); node->SetName("_VectorField"); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(maxSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node); typedef FilterType::DirectionImageContainerType DirectionImageContainerType; DirectionImageContainerType::Pointer container = filter->GetDirectionImageContainer(); for (int i=0; iSize(); i++) { ItkDirectionImage3DType::Pointer itkImg = container->GetElement(i); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_ImageNodes.at(i)->GetName().c_str()); name += "_Direction"; name += QString::number(i+1); node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node); } break; } case 1: { typedef itk::Image< float, 4 > ItkImageType; typedef itk::MrtrixPeakImageConverter< float > FilterType; FilterType::Pointer filter = FilterType::New(); // cast to itk mitk::Image::Pointer mitkImg = dynamic_cast(m_ImageNodes.at(0)->GetData()); mitk::Geometry3D::Pointer geom = mitkImg->GetGeometry(); typedef mitk::ImageToItk< FilterType::InputImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImg); caster->Update(); FilterType::InputImageType::Pointer itkImg = caster->GetOutput(); filter->SetInputImage(itkImg); filter->GenerateData(); mitk::Vector3D outImageSpacing = geom->GetSpacing(); float maxSpacing = 1; if(outImageSpacing[0]>outImageSpacing[1] && outImageSpacing[0]>outImageSpacing[2]) maxSpacing = outImageSpacing[0]; else if (outImageSpacing[1] > outImageSpacing[2]) maxSpacing = outImageSpacing[1]; else maxSpacing = outImageSpacing[2]; mitk::FiberBundleX::Pointer directions = filter->GetOutputFiberBundle(); - directions->SetGeometry(geom); + //directions->SetGeometry(geom); DataNode::Pointer node = DataNode::New(); node->SetData(directions); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_VectorField"; node->SetName(name.toStdString().c_str()); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(maxSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node); typedef FilterType::DirectionImageContainerType DirectionImageContainerType; DirectionImageContainerType::Pointer container = filter->GetDirectionImageContainer(); for (int i=0; iSize(); i++) { ItkDirectionImage3DType::Pointer itkImg = container->GetElement(i); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_Direction"; name += QString::number(i+1); node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node); } break; } } } void QmitkOdfMaximaExtractionView::GenerateImage() { if (!m_ImageNodes.empty()) GenerateDataFromDwi(); } void QmitkOdfMaximaExtractionView::StartTensor() { if (m_TensorImageNodes.empty()) return; typedef itk::DiffusionTensorPrincipalDirectionImageFilter< float, float > MaximaExtractionFilterType; MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); mitk::Geometry3D::Pointer geometry; try{ TensorImage::Pointer img = dynamic_cast(m_TensorImageNodes.at(0)->GetData()); ItkTensorImage::Pointer itkImage = ItkTensorImage::New(); CastToItkImage(img, itkImage); filter->SetInput(itkImage); geometry = img->GetGeometry(); } catch(itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); throw e; } if (!m_BinaryImageNodes.empty()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_BinaryImageNodes.at(0)->GetData()); CastToItkImage(mitkMaskImg, itkMaskImage); filter->SetMaskImage(itkMaskImage); } if (m_Controls->m_NormalizationBox->currentIndex()==0) filter->SetNormalizeVectors(false); filter->Update(); if (m_Controls->m_OutputDirectionImagesBox->isChecked()) { MaximaExtractionFilterType::OutputImageType::Pointer itkImg = filter->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_TensorImageNodes.at(0)->GetName().c_str()); name += "_PrincipalDirection"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node); } if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); mitk::Image::Pointer image2 = mitk::Image::New(); image2->InitializeByItk( numDirImage.GetPointer() ); image2->SetVolume( numDirImage->GetBufferPointer() ); DataNode::Pointer node2 = DataNode::New(); node2->SetData(image2); QString name(m_TensorImageNodes.at(0)->GetName().c_str()); name += "_NumDirections"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2); } if (m_Controls->m_OutputVectorFieldBox->isChecked()) { mitk::Vector3D outImageSpacing = geometry->GetSpacing(); float minSpacing = 1; if(outImageSpacing[0]GetOutputFiberBundle(); - directions->SetGeometry(geometry); + // directions->SetGeometry(geometry); DataNode::Pointer node = DataNode::New(); node->SetData(directions); QString name(m_TensorImageNodes.at(0)->GetName().c_str()); name += "_VectorField"; node->SetName(name.toStdString().c_str()); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node); } } template void QmitkOdfMaximaExtractionView::StartMaximaExtraction() { typedef itk::FiniteDiffOdfMaximaExtractionFilter< float, shOrder, 20242 > MaximaExtractionFilterType; typename MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: filter->SetToolkit(MaximaExtractionFilterType::FSL); break; case 1: filter->SetToolkit(MaximaExtractionFilterType::MRTRIX); break; default: filter->SetToolkit(MaximaExtractionFilterType::FSL); } mitk::Geometry3D::Pointer geometry; try{ Image::Pointer img = dynamic_cast(m_ImageNodes.at(0)->GetData()); typedef ImageToItk< typename MaximaExtractionFilterType::CoefficientImageType > CasterType; typename CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); filter->SetInput(caster->GetOutput()); geometry = img->GetGeometry(); } catch(itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); throw; } filter->SetAngularThreshold(cos((float)m_Controls->m_AngularThreshold->value()*M_PI/180)); filter->SetClusteringThreshold(cos((float)m_Controls->m_ClusteringAngleBox->value()*M_PI/180)); filter->SetMaxNumPeaks(m_Controls->m_MaxNumPeaksBox->value()); filter->SetPeakThreshold(m_Controls->m_PeakThresholdBox->value()); filter->SetAbsolutePeakThreshold(m_Controls->m_AbsoluteThresholdBox->value()); if (!m_BinaryImageNodes.empty()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_BinaryImageNodes.at(0)->GetData()); CastToItkImage(mitkMaskImg, itkMaskImage); filter->SetMaskImage(itkMaskImage); } switch (m_Controls->m_NormalizationBox->currentIndex()) { case 0: filter->SetNormalizationMethod(MaximaExtractionFilterType::NO_NORM); break; case 1: filter->SetNormalizationMethod(MaximaExtractionFilterType::MAX_VEC_NORM); break; case 2: filter->SetNormalizationMethod(MaximaExtractionFilterType::SINGLE_VEC_NORM); break; } filter->Update(); if (m_Controls->m_OutputDirectionImagesBox->isChecked()) { typedef typename MaximaExtractionFilterType::ItkDirectionImageContainer ItkDirectionImageContainer; typename ItkDirectionImageContainer::Pointer container = filter->GetDirectionImageContainer(); for (int i=0; iSize(); i++) { typename MaximaExtractionFilterType::ItkDirectionImage::Pointer itkImg = container->GetElement(i); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_Direction"; name += QString::number(i+1); node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node); } } if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); mitk::Image::Pointer image2 = mitk::Image::New(); image2->InitializeByItk( numDirImage.GetPointer() ); image2->SetVolume( numDirImage->GetBufferPointer() ); DataNode::Pointer node2 = DataNode::New(); node2->SetData(image2); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_NumDirections"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2); } if (m_Controls->m_OutputVectorFieldBox->isChecked()) { mitk::Vector3D outImageSpacing = geometry->GetSpacing(); float minSpacing = 1; if(outImageSpacing[0]GetOutputFiberBundle(); - directions->SetGeometry(geometry); + // directions->SetGeometry(geometry); DataNode::Pointer node = DataNode::New(); node->SetData(directions); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_VectorField"; node->SetName(name.toStdString().c_str()); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node); } } void QmitkOdfMaximaExtractionView::StartFiniteDiff() { if (m_ImageNodes.empty()) return; switch (m_Controls->m_ShOrderBox->currentIndex()) { case 0: StartMaximaExtraction<2>(); break; case 1: StartMaximaExtraction<4>(); break; case 2: StartMaximaExtraction<6>(); break; case 3: StartMaximaExtraction<8>(); break; case 4: StartMaximaExtraction<10>(); break; case 5: StartMaximaExtraction<12>(); break; } } void QmitkOdfMaximaExtractionView::GenerateDataFromDwi() { typedef itk::OdfMaximaExtractionFilter< float > MaximaExtractionFilterType; MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); mitk::Geometry3D::Pointer geometry; if (!m_ImageNodes.empty()) { try{ Image::Pointer img = dynamic_cast(m_ImageNodes.at(0)->GetData()); typedef ImageToItk< MaximaExtractionFilterType::CoefficientImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); filter->SetShCoeffImage(caster->GetOutput()); geometry = img->GetGeometry(); } catch(itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); return; } } else return; filter->SetMaxNumPeaks(m_Controls->m_MaxNumPeaksBox->value()); filter->SetPeakThreshold(m_Controls->m_PeakThresholdBox->value()); if (!m_BinaryImageNodes.empty()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_BinaryImageNodes.at(0)->GetData()); CastToItkImage(mitkMaskImg, itkMaskImage); filter->SetMaskImage(itkMaskImage); } switch (m_Controls->m_NormalizationBox->currentIndex()) { case 0: filter->SetNormalizationMethod(MaximaExtractionFilterType::NO_NORM); break; case 1: filter->SetNormalizationMethod(MaximaExtractionFilterType::MAX_VEC_NORM); break; case 2: filter->SetNormalizationMethod(MaximaExtractionFilterType::SINGLE_VEC_NORM); break; } filter->GenerateData(); ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); if (m_Controls->m_OutputDirectionImagesBox->isChecked()) { typedef MaximaExtractionFilterType::ItkDirectionImageContainer ItkDirectionImageContainer; ItkDirectionImageContainer::Pointer container = filter->GetDirectionImageContainer(); for (int i=0; iSize(); i++) { MaximaExtractionFilterType::ItkDirectionImage::Pointer itkImg = container->GetElement(i); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_Direction"; name += QString::number(i+1); node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node); } } if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { mitk::Image::Pointer image2 = mitk::Image::New(); image2->InitializeByItk( numDirImage.GetPointer() ); image2->SetVolume( numDirImage->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(image2); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_NumDirections"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node); } if (m_Controls->m_OutputVectorFieldBox->isChecked()) { mitk::Vector3D outImageSpacing = geometry->GetSpacing(); float minSpacing = 1; if(outImageSpacing[0]GetOutputFiberBundle(); - directions->SetGeometry(geometry); + // directions->SetGeometry(geometry); DataNode::Pointer node = DataNode::New(); node->SetData(directions); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_VectorField"; node->SetName(name.toStdString().c_str()); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node); } } void QmitkOdfMaximaExtractionView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkOdfMaximaExtractionView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkOdfMaximaExtractionView::OnSelectionChanged( std::vector nodes ) { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_DwiFibLabel->setText("mandatory"); m_Controls->m_MaskLabel->setText("optional"); m_BinaryImageNodes.clear(); m_ImageNodes.clear(); m_TensorImageNodes.clear(); // iterate all selected objects, adjust warning visibility for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_TensorImageNodes.push_back(node); } else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) m_BinaryImageNodes.push_back(node); else m_ImageNodes.push_back(node); } } UpdateGui(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionView.cpp index 6fb6019aa4..961a581783 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionView.cpp @@ -1,1067 +1,1061 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //#define MBILOG_ENABLE_DEBUG #include "QmitkQBallReconstructionView.h" #include "mitkDiffusionImagingConfigure.h" // qt includes #include // itk includes #include "itkTimeProbe.h" // mitk includes #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkNodePredicateDataType.h" #include "QmitkDataStorageComboBox.h" #include "QmitkStdMultiWidget.h" #include "itkDiffusionQballReconstructionImageFilter.h" #include "itkAnalyticalDiffusionQballReconstructionImageFilter.h" #include "itkDiffusionMultiShellQballReconstructionImageFilter.h" #include "itkVectorContainer.h" #include "mitkQBallImage.h" #include "mitkProperties.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunction.h" #include "mitkTransferFunctionProperty.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include "berryIStructuredSelection.h" #include "berryIWorkbenchWindow.h" #include "berryISelectionService.h" #include const std::string QmitkQBallReconstructionView::VIEW_ID = "org.mitk.views.qballreconstruction"; typedef float TTensorPixelType; const int QmitkQBallReconstructionView::nrconvkernels = 252; struct QbrShellSelection { QmitkQBallReconstructionView* m_View; mitk::DataNode * m_Node; std::string m_NodeName; std::vector m_CheckBoxes; QLabel * m_Label; mitk::DiffusionImage * m_Image; typedef mitk::DiffusionImage::BValueMap BValueMap; QbrShellSelection(QmitkQBallReconstructionView* view, mitk::DataNode * node) : m_View(view), m_Node(node), m_NodeName(node->GetName()) { m_Image = dynamic_cast * > (node->GetData()); if(!m_Image){MITK_INFO << "QmitkQBallReconstructionView::QbrShellSelection : fail to initialize DiffusionImage "; return;} GenerateCheckboxes(); } void GenerateCheckboxes() { BValueMap origMap = m_Image->GetB_ValueMap(); BValueMap::iterator itStart = origMap.begin(); itStart++; BValueMap::iterator itEnd = origMap.end(); m_Label = new QLabel(m_NodeName.c_str()); m_Label->setVisible(true); m_View->m_Controls->m_QBallSelectionBox->layout()->addWidget(m_Label); for(BValueMap::iterator it = itStart ; it!= itEnd; it++) { QCheckBox * box = new QCheckBox(QString::number(it->first)); m_View->m_Controls->m_QBallSelectionBox->layout()->addWidget(box); box->setChecked(true); box->setCheckable(true); // box->setVisible(true); m_CheckBoxes.push_back(box); } } void SetVisible(bool vis) { foreach(QCheckBox * box, m_CheckBoxes) { box->setVisible(vis); } } BValueMap GetBValueSelctionMap() { BValueMap inputMap = m_Image->GetB_ValueMap(); BValueMap outputMap; double val = 0; if(inputMap.find(0) == inputMap.end()){ MITK_INFO << "QbrShellSelection: return empty BValueMap from GUI Selection"; return outputMap; }else{ outputMap[val] = inputMap[val]; MITK_INFO << val; } foreach(QCheckBox * box, m_CheckBoxes) { if(box->isChecked()){ val = box->text().toDouble(); outputMap[val] = inputMap[val]; MITK_INFO << val; } } return outputMap; } ~QbrShellSelection() { m_View->m_Controls->m_QBallSelectionBox->layout()->removeWidget(m_Label); delete m_Label; for(std::vector::iterator it = m_CheckBoxes.begin() ; it!= m_CheckBoxes.end(); it++) { m_View->m_Controls->m_QBallSelectionBox->layout()->removeWidget((*it)); delete (*it); } m_CheckBoxes.clear(); } }; using namespace berry; struct QbrSelListener : ISelectionListener { berryObjectMacro(QbrSelListener); QbrSelListener(QmitkQBallReconstructionView* view) { m_View = view; } void DoSelectionChanged(ISelection::ConstPointer selection) { // save current selection in member variable m_View->m_CurrentSelection = selection.Cast(); // do something with the selected items if(m_View->m_CurrentSelection) { bool foundDwiVolume = false; m_View->m_Controls->m_DiffusionImageLabel->setText("mandatory"); m_View->m_Controls->m_InputData->setTitle("Please Select Input Data"); QString selected_images = ""; mitk::DataStorage::SetOfObjects::Pointer set = mitk::DataStorage::SetOfObjects::New(); int at = 0; // iterate selection for (IStructuredSelection::iterator i = m_View->m_CurrentSelection->Begin(); i != m_View->m_CurrentSelection->End(); ++i) { // extract datatree node if (mitk::DataNodeObject::Pointer nodeObj = i->Cast()) { mitk::DataNode::Pointer node = nodeObj->GetDataNode(); mitk::DiffusionImage* diffusionImage; // only look at interesting types if(diffusionImage = dynamic_cast * >(node->GetData())) { foundDwiVolume = true; selected_images += QString(node->GetName().c_str()); if(i + 1 != m_View->m_CurrentSelection->End()) selected_images += "\n"; set->InsertElement(at++, node); } } } m_View->GenerateShellSelectionUI(set); m_View->m_Controls->m_DiffusionImageLabel->setText(selected_images); m_View->m_Controls->m_ButtonStandard->setEnabled(foundDwiVolume); if (foundDwiVolume) m_View->m_Controls->m_InputData->setTitle("Input Data"); else m_View->m_Controls->m_DiffusionImageLabel->setText("mandatory"); } } void SelectionChanged(IWorkbenchPart::Pointer part, ISelection::ConstPointer selection) { // check, if selection comes from datamanager if (part) { QString partname(part->GetPartName().c_str()); if(partname.compare("Datamanager")==0) { // apply selection DoSelectionChanged(selection); } } } QmitkQBallReconstructionView* m_View; }; // --------------- QmitkQBallReconstructionView----------------- // QmitkQBallReconstructionView::QmitkQBallReconstructionView() : QmitkFunctionality(), m_Controls(NULL), m_MultiWidget(NULL) { } QmitkQBallReconstructionView::QmitkQBallReconstructionView(const QmitkQBallReconstructionView& other) { Q_UNUSED(other); throw std::runtime_error("Copy constructor not implemented"); } QmitkQBallReconstructionView::~QmitkQBallReconstructionView() { this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->RemovePostSelectionListener(/*"org.mitk.views.datamanager",*/ m_SelListener); } void QmitkQBallReconstructionView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkQBallReconstructionViewControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_DiffusionImageLabel->setText("mandatory"); QStringList items; items << "2" << "4" << "6" << "8" << "10" << "12"; m_Controls->m_QBallReconstructionMaxLLevelComboBox->addItems(items); m_Controls->m_QBallReconstructionMaxLLevelComboBox->setCurrentIndex(1); MethodChoosen(m_Controls->m_QBallReconstructionMethodComboBox->currentIndex()); #ifndef DIFFUSION_IMAGING_EXTENDED m_Controls->m_QBallReconstructionMethodComboBox->removeItem(3); #endif AdvancedCheckboxClicked(); } m_SelListener = berry::ISelectionListener::Pointer(new QbrSelListener(this)); this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->AddPostSelectionListener(/*"org.mitk.views.datamanager",*/ m_SelListener); berry::ISelection::ConstPointer sel( this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.datamanager")); m_CurrentSelection = sel.Cast(); m_SelListener.Cast()->DoSelectionChanged(sel); } void QmitkQBallReconstructionView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkQBallReconstructionView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkQBallReconstructionView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_ButtonStandard), SIGNAL(clicked()), this, SLOT(ReconstructStandard()) ); connect( (QObject*)(m_Controls->m_AdvancedCheckbox), SIGNAL(clicked()), this, SLOT(AdvancedCheckboxClicked()) ); connect( (QObject*)(m_Controls->m_QBallReconstructionMethodComboBox), SIGNAL(currentIndexChanged(int)), this, SLOT(MethodChoosen(int)) ); } } void QmitkQBallReconstructionView::OnSelectionChanged( std::vector nodes ) { } void QmitkQBallReconstructionView::Activated() { QmitkFunctionality::Activated(); berry::ISelection::ConstPointer sel( this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.datamanager")); m_CurrentSelection = sel.Cast(); m_SelListener.Cast()->DoSelectionChanged(sel); } void QmitkQBallReconstructionView::Deactivated() { QmitkFunctionality::Deactivated(); } void QmitkQBallReconstructionView::ReconstructStandard() { int index = m_Controls->m_QBallReconstructionMethodComboBox->currentIndex(); #ifndef DIFFUSION_IMAGING_EXTENDED if(index>=3) { index = index + 1; } #endif switch(index) { case 0: { // Numerical Reconstruct(0,0); break; } case 1: { // Standard Reconstruct(1,0); break; } case 2: { // Solid Angle Reconstruct(1,6); break; } case 3: { // Constrained Solid Angle Reconstruct(1,7); break; } case 4: { // ADC Reconstruct(1,4); break; } case 5: { // Raw Signal Reconstruct(1,5); break; } case 6: { // Q-Ball reconstruction Reconstruct(2,0); break; } } } void QmitkQBallReconstructionView::MethodChoosen(int method) { #ifndef DIFFUSION_IMAGING_EXTENDED if(method>=3) { method = method + 1; } #endif m_Controls->m_QBallSelectionBox->setHidden(true); m_Controls->m_OutputCoeffsImage->setHidden(true); - m_Controls->m_UseWeights->setHidden(true); if (method==0) m_Controls->m_ShFrame->setVisible(false); else m_Controls->m_ShFrame->setVisible(true); switch(method) { case 0: m_Controls->m_Description->setText("Numerical recon. (Tuch 2004)"); break; case 1: m_Controls->m_Description->setText("Spherical harmonics recon. (Descoteaux 2007)"); m_Controls->m_OutputCoeffsImage->setHidden(false); break; case 2: m_Controls->m_Description->setText("SH recon. with solid angle consideration (Aganj 2009)"); m_Controls->m_OutputCoeffsImage->setHidden(false); break; case 3: m_Controls->m_Description->setText("SH solid angle with non-neg. constraint (Goh 2009)"); break; case 4: m_Controls->m_Description->setText("SH recon. of the plain ADC-profiles"); break; case 5: m_Controls->m_Description->setText("SH recon. of the raw diffusion signal"); break; case 6: m_Controls->m_Description->setText("SH recon. of the multi shell diffusion signal (Aganj 2010)"); m_Controls->m_QBallSelectionBox->setHidden(false); m_Controls->m_OutputCoeffsImage->setHidden(false); - m_Controls->m_UseWeights->setHidden(false); break; } } void QmitkQBallReconstructionView::AdvancedCheckboxClicked() { bool check = m_Controls->m_AdvancedCheckbox->isChecked(); m_Controls->m_QBallReconstructionMaxLLevelTextLabel_2->setVisible(check); m_Controls->m_QBallReconstructionMaxLLevelComboBox->setVisible(check); m_Controls->m_QBallReconstructionLambdaTextLabel_2->setVisible(check); m_Controls->m_QBallReconstructionLambdaLineEdit->setVisible(check); m_Controls->m_QBallReconstructionThresholdLabel_2->setVisible(check); m_Controls->m_QBallReconstructionThreasholdEdit->setVisible(check); m_Controls->label_2->setVisible(check); m_Controls->frame_2->setVisible(check); } void QmitkQBallReconstructionView::Reconstruct(int method, int normalization) { if (m_CurrentSelection) { mitk::DataStorage::SetOfObjects::Pointer set = mitk::DataStorage::SetOfObjects::New(); int at = 0; for (IStructuredSelection::iterator i = m_CurrentSelection->Begin(); i != m_CurrentSelection->End(); ++i) { if (mitk::DataNodeObject::Pointer nodeObj = i->Cast()) { mitk::DataNode::Pointer node = nodeObj->GetDataNode(); if(QString("DiffusionImage").compare(node->GetData()->GetNameOfClass())==0) { set->InsertElement(at++, node); } } } if(method == 0) { NumericalQBallReconstruction(set, normalization); } else { #if BOOST_VERSION / 100000 > 0 #if BOOST_VERSION / 100 % 1000 > 34 if(method == 1) { AnalyticalQBallReconstruction(set, normalization); } if(method == 2) { MultiQBallReconstruction(set); } #else std::cout << "ERROR: Boost 1.35 minimum required" << std::endl; QMessageBox::warning(NULL,"ERROR","Boost 1.35 minimum required"); #endif #else std::cout << "ERROR: Boost 1.35 minimum required" << std::endl; QMessageBox::warning(NULL,"ERROR","Boost 1.35 minimum required"); #endif } } } void QmitkQBallReconstructionView::NumericalQBallReconstruction (mitk::DataStorage::SetOfObjects::Pointer inImages, int normalization) { try { itk::TimeProbe clock; int nrFiles = inImages->size(); if (!nrFiles) return; QString status; mitk::ProgressBar::GetInstance()->AddStepsToDo(nrFiles); mitk::DataStorage::SetOfObjects::const_iterator itemiter( inImages->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( inImages->end() ); std::vector nodes; while ( itemiter != itemiterend ) // for all items { mitk::DiffusionImage* vols = static_cast*>( (*itemiter)->GetData()); std::string nodename; (*itemiter)->GetStringProperty("name", nodename); ++itemiter; // QBALL RECONSTRUCTION clock.Start(); MITK_INFO << "QBall reconstruction "; mitk::StatusBar::GetInstance()->DisplayText(status.sprintf( "QBall reconstruction for %s", nodename.c_str()).toAscii()); typedef itk::DiffusionQballReconstructionImageFilter QballReconstructionImageFilterType; QballReconstructionImageFilterType::Pointer filter = QballReconstructionImageFilterType::New(); filter->SetGradientImage( vols->GetDirections(), vols->GetVectorImage() ); filter->SetBValue(vols->GetB_Value()); filter->SetThreshold( m_Controls->m_QBallReconstructionThreasholdEdit->value() ); switch(normalization) { case 0: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_STANDARD); break; } case 1: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_B_ZERO_B_VALUE); break; } case 2: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_B_ZERO); break; } case 3: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_NONE); break; } default: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_STANDARD); } } filter->Update(); clock.Stop(); MITK_DEBUG << "took " << clock.GetMeanTime() << "s." ; // ODFs TO DATATREE mitk::QBallImage::Pointer image = mitk::QBallImage::New(); image->InitializeByItk( filter->GetOutput() ); //image->SetImportVolume( filter->GetOutput()->GetBufferPointer(), 0, 0, mitk::Image::ImportMemoryManagementType::ManageMemory ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); QString newname; newname = newname.append(nodename.c_str()); newname = newname.append("_QN%1").arg(normalization); SetDefaultNodeProperties(node, newname.toStdString()); nodes.push_back(node); mitk::ProgressBar::GetInstance()->Progress(); } std::vector::iterator nodeIt; for(nodeIt = nodes.begin(); nodeIt != nodes.end(); ++nodeIt) GetDefaultDataStorage()->Add(*nodeIt); mitk::StatusBar::GetInstance()->DisplayText(status.sprintf("Finished Processing %d Files", nrFiles).toAscii()); m_MultiWidget->RequestUpdate(); } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; QMessageBox::information(0, "Reconstruction not possible:", ex.GetDescription()); return ; } } void QmitkQBallReconstructionView::AnalyticalQBallReconstruction( mitk::DataStorage::SetOfObjects::Pointer inImages, int normalization) { try { itk::TimeProbe clock; int nrFiles = inImages->size(); if (!nrFiles) return; std::vector lambdas; float minLambda = m_Controls->m_QBallReconstructionLambdaLineEdit->value(); lambdas.push_back(minLambda); int nLambdas = lambdas.size(); QString status; mitk::ProgressBar::GetInstance()->AddStepsToDo(nrFiles*nLambdas); mitk::DataStorage::SetOfObjects::const_iterator itemiter( inImages->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( inImages->end() ); std::vector* nodes = new std::vector(); while ( itemiter != itemiterend ) // for all items { mitk::DiffusionImage* vols = static_cast*>( (*itemiter)->GetData()); std::string nodename; (*itemiter)->GetStringProperty("name",nodename); itemiter++; // QBALL RECONSTRUCTION clock.Start(); MITK_INFO << "QBall reconstruction "; mitk::StatusBar::GetInstance()->DisplayText(status.sprintf( "QBall reconstruction for %s", nodename.c_str()).toAscii()); for(int i=0; im_QBallReconstructionMaxLLevelComboBox->currentIndex()) { case 0: { TemplatedAnalyticalQBallReconstruction<2>(vols, currentLambda, nodename, nodes, normalization); break; } case 1: { TemplatedAnalyticalQBallReconstruction<4>(vols, currentLambda, nodename, nodes, normalization); break; } case 2: { TemplatedAnalyticalQBallReconstruction<6>(vols, currentLambda, nodename, nodes, normalization); break; } case 3: { TemplatedAnalyticalQBallReconstruction<8>(vols, currentLambda, nodename, nodes, normalization); break; } case 4: { TemplatedAnalyticalQBallReconstruction<10>(vols, currentLambda, nodename, nodes, normalization); break; } case 5: { TemplatedAnalyticalQBallReconstruction<12>(vols, currentLambda, nodename, nodes, normalization); break; } } clock.Stop(); MITK_DEBUG << "took " << clock.GetMeanTime() << "s." ; mitk::ProgressBar::GetInstance()->Progress(); } } std::vector::iterator nodeIt; for(nodeIt = nodes->begin(); nodeIt != nodes->end(); ++nodeIt) GetDefaultDataStorage()->Add(*nodeIt); m_MultiWidget->RequestUpdate(); mitk::StatusBar::GetInstance()->DisplayText(status.sprintf("Finished Processing %d Files", nrFiles).toAscii()); } catch (itk::ExceptionObject &ex) { MITK_INFO << ex; QMessageBox::information(0, "Reconstruction not possible:", ex.GetDescription()); return; } } template void QmitkQBallReconstructionView::TemplatedAnalyticalQBallReconstruction( mitk::DiffusionImage* vols, float lambda, std::string nodename, std::vector* nodes, int normalization) { typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); filter->SetGradientImage( vols->GetDirections(), vols->GetVectorImage() ); filter->SetBValue(vols->GetB_Value()); filter->SetThreshold( m_Controls->m_QBallReconstructionThreasholdEdit->value() ); filter->SetLambda(lambda); switch(normalization) { case 0: { filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); break; } case 1: { filter->SetNormalizationMethod(FilterType::QBAR_B_ZERO_B_VALUE); break; } case 2: { filter->SetNormalizationMethod(FilterType::QBAR_B_ZERO); break; } case 3: { filter->SetNormalizationMethod(FilterType::QBAR_NONE); break; } case 4: { filter->SetNormalizationMethod(FilterType::QBAR_ADC_ONLY); break; } case 5: { filter->SetNormalizationMethod(FilterType::QBAR_RAW_SIGNAL); break; } case 6: { filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); break; } case 7: { filter->SetNormalizationMethod(FilterType::QBAR_NONNEG_SOLID_ANGLE); break; } default: { filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); } } filter->Update(); // ODFs TO DATATREE mitk::QBallImage::Pointer image = mitk::QBallImage::New(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); QString newname; newname = newname.append(nodename.c_str()); newname = newname.append("_QA%1").arg(normalization); SetDefaultNodeProperties(node, newname.toStdString()); nodes->push_back(node); if(m_Controls->m_OutputCoeffsImage->isChecked()) { mitk::Image::Pointer coeffsImage = mitk::Image::New(); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); mitk::DataNode::Pointer coeffsNode=mitk::DataNode::New(); coeffsNode->SetData( coeffsImage ); coeffsNode->SetProperty( "name", mitk::StringProperty::New( QString(nodename.c_str()).append("_coeffs").toStdString()) ); nodes->push_back(coeffsNode); } } void QmitkQBallReconstructionView::MultiQBallReconstruction( mitk::DataStorage::SetOfObjects::Pointer inImages) { try { itk::TimeProbe clock; int nrFiles = inImages->size(); if (!nrFiles) return; std::vector lambdas; float minLambda = m_Controls->m_QBallReconstructionLambdaLineEdit->value(); lambdas.push_back(minLambda); int nLambdas = lambdas.size(); QString status; mitk::ProgressBar::GetInstance()->AddStepsToDo(nrFiles*nLambdas); mitk::DataStorage::SetOfObjects::const_iterator itemiter( inImages->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( inImages->end() ); std::vector* nodes = new std::vector(); while ( itemiter != itemiterend ) // for all items { mitk::DiffusionImage* vols = static_cast*>( (*itemiter)->GetData()); const mitk::DataNode * nodePointer = (*itemiter).GetPointer(); std::string nodename; (*itemiter)->GetStringProperty("name",nodename); itemiter++; // QBALL RECONSTRUCTION clock.Start(); MITK_INFO << "QBall reconstruction "; mitk::StatusBar::GetInstance()->DisplayText(status.sprintf( "QBall reconstruction for %s", nodename.c_str()).toAscii()); for(int i=0; im_QBallReconstructionMaxLLevelComboBox->currentIndex()) { case 0: { TemplatedMultiQBallReconstruction<2>(vols, currentLambda, nodePointer, nodes); break; } case 1: { TemplatedMultiQBallReconstruction<4>(vols, currentLambda, nodePointer, nodes); break; } case 2: { TemplatedMultiQBallReconstruction<6>(vols, currentLambda, nodePointer, nodes); break; } case 3: { TemplatedMultiQBallReconstruction<8>(vols, currentLambda, nodePointer, nodes); break; } case 4: { TemplatedMultiQBallReconstruction<10>(vols, currentLambda, nodePointer, nodes); break; } case 5: { TemplatedMultiQBallReconstruction<12>(vols, currentLambda, nodePointer, nodes); break; } } clock.Stop(); MITK_DEBUG << "took " << clock.GetMeanTime() << "s." ; mitk::ProgressBar::GetInstance()->Progress(); } } std::vector::iterator nodeIt; for(nodeIt = nodes->begin(); nodeIt != nodes->end(); ++nodeIt) GetDefaultDataStorage()->Add(*nodeIt); m_MultiWidget->RequestUpdate(); mitk::StatusBar::GetInstance()->DisplayText(status.sprintf("Finished Processing %d Files", nrFiles).toAscii()); } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; QMessageBox::information(0, "Reconstruction not possible:", ex.GetDescription()); return ; } } template void QmitkQBallReconstructionView::TemplatedMultiQBallReconstruction( mitk::DiffusionImage* vols, float lambda, const mitk::DataNode * dataNodePointer, std::vector* nodes) { typedef itk::DiffusionMultiShellQballReconstructionImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); std::string nodename; dataNodePointer->GetStringProperty("name",nodename); filter->SetBValueMap(m_ShellSelectorMap[dataNodePointer]->GetBValueSelctionMap()); filter->SetGradientImage( vols->GetDirections(), vols->GetVectorImage(), vols->GetB_Value() ); - - //filter->SetBValue(vols->GetB_Value()); - filter->SetUseWeights( m_Controls->m_UseWeights->isChecked()); - filter->SetThreshold( m_Controls->m_QBallReconstructionThreasholdEdit->value() ); filter->SetLambda(lambda); filter->Update(); // ODFs TO DATATREE mitk::QBallImage::Pointer image = mitk::QBallImage::New(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); QString newname; newname = newname.append(nodename.c_str()); newname = newname.append("_QAMultiShell"); SetDefaultNodeProperties(node, newname.toStdString()); nodes->push_back(node); if(m_Controls->m_OutputCoeffsImage->isChecked()) { mitk::Image::Pointer coeffsImage = mitk::Image::New(); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); mitk::DataNode::Pointer coeffsNode=mitk::DataNode::New(); coeffsNode->SetData( coeffsImage ); coeffsNode->SetProperty( "name", mitk::StringProperty::New( QString(nodename.c_str()).append("_coeffs").toStdString()) ); nodes->push_back(coeffsNode); } } void QmitkQBallReconstructionView::SetDefaultNodeProperties(mitk::DataNode::Pointer node, std::string name) { node->SetProperty( "ShowMaxNumber", mitk::IntProperty::New( 500 ) ); node->SetProperty( "Scaling", mitk::FloatProperty::New( 1.0 ) ); node->SetProperty( "Normalization", mitk::OdfNormalizationMethodProperty::New()); node->SetProperty( "ScaleBy", mitk::OdfScaleByProperty::New()); node->SetProperty( "IndexParam1", mitk::FloatProperty::New(2)); node->SetProperty( "IndexParam2", mitk::FloatProperty::New(1)); node->SetProperty( "visible", mitk::BoolProperty::New( true ) ); node->SetProperty( "VisibleOdfs", mitk::BoolProperty::New( false ) ); node->SetProperty ("layer", mitk::IntProperty::New(100)); node->SetProperty( "DoRefresh", mitk::BoolProperty::New( true ) ); //node->SetProperty( "opacity", mitk::FloatProperty::New(1.0f) ); node->SetProperty( "name", mitk::StringProperty::New(name) ); } //node->SetProperty( "volumerendering", mitk::BoolProperty::New( false ) ); //node->SetProperty( "use color", mitk::BoolProperty::New( true ) ); //node->SetProperty( "texture interpolation", mitk::BoolProperty::New( true ) ); //node->SetProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ); //node->SetProperty( "layer", mitk::IntProperty::New(0)); //node->SetProperty( "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ); //node->SetOpacity(1.0f); //node->SetColor(1.0,1.0,1.0); //node->SetVisibility(true); //node->SetProperty( "IsQBallVolume", mitk::BoolProperty::New( true ) ); //mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); //mitk::LevelWindow levelwindow; //// levelwindow.SetAuto( image ); //levWinProp->SetLevelWindow( levelwindow ); //node->GetPropertyList()->SetPropertx( "levelwindow", levWinProp ); //// add a default rainbow lookup table for color mapping //if(!node->GetProperty("LookupTable")) //{ // mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); // vtkLookupTable* vtkLut = mitkLut->GetVtkLookupTable(); // vtkLut->SetHueRange(0.6667, 0.0); // vtkLut->SetTableRange(0.0, 20.0); // vtkLut->Build(); // mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); // mitkLutProp->SetLookupTable(mitkLut); // node->SetProperty( "LookupTable", mitkLutProp ); //} //if(!node->GetProperty("binary")) // node->SetProperty( "binary", mitk::BoolProperty::New( false ) ); //// add a default transfer function //mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); //node->SetProperty ( "TransferFunction", mitk::TransferFunctionProperty::New ( tf.GetPointer() ) ); //// set foldername as string property //mitk::StringProperty::Pointer nameProp = mitk::StringProperty::New( name ); //node->SetProperty( "name", nameProp ); void QmitkQBallReconstructionView::GenerateShellSelectionUI(mitk::DataStorage::SetOfObjects::Pointer set) { std::map tempMap; const mitk::DataStorage::SetOfObjects::iterator setEnd( set->end() ); mitk::DataStorage::SetOfObjects::iterator NodeIt( set->begin() ); while(NodeIt != setEnd) { if(m_ShellSelectorMap.find( (*NodeIt).GetPointer() ) != m_ShellSelectorMap.end()) { tempMap[(*NodeIt).GetPointer()] = m_ShellSelectorMap[(*NodeIt).GetPointer()]; m_ShellSelectorMap.erase((*NodeIt).GetPointer()); }else { tempMap[(*NodeIt).GetPointer()] = new QbrShellSelection(this, (*NodeIt) ); tempMap[(*NodeIt).GetPointer()]->SetVisible(true); } NodeIt++; } for(std::map::iterator it = m_ShellSelectorMap.begin(); it != m_ShellSelectorMap.end();it ++) { delete it->second; } m_ShellSelectorMap.clear(); m_ShellSelectorMap = tempMap; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionViewControls.ui index 16f500cf6e..a8afb2c9a2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionViewControls.ui @@ -1,332 +1,349 @@ QmitkQBallReconstructionViewControls 0 0 372 844 0 0 true QmitkQBallReconstructionViewControls Please Select Input Data Input for Q-Ball reconstruction. Raw DWI: Input for Q-Ball reconstruction. <font color='red'>mandatory</font> true Parameters Advanced Settings QFrame::StyledPanel QFrame::Raised QFrame::NoFrame QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 true B0 Threshold false QFrame::NoFrame QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 QFrame::NoFrame QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 true Regularization Parameter Lambda: false true Maximum l-Level: false true -1 true Spherical Harmonics: 3 1.000000000000000 0.001000000000000 0.006000000000000 Output SH-Coefficient Image - - - - <html><head/><body><p>Only for a dataset with 3 Shells and an arethmetic progression (e.g. b1=1000, b2=2000, b3=3000 ).</p><p>Weightings will be applied on the interpolated directions.</p></body></html> - - - Use Shell Weights - - - 2 Numerical Standard Solid Angle Constraint Solid Angle ADC-Profile only Raw Signal only Multi-Shell TextLabel false Start Reconstruction true Qt::LeftToRight false Multi-Shell Reconstruction Qt::Vertical 20 0 diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStochasticFiberTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStochasticFiberTrackingView.cpp index 9ae4d9e13c..5c1838d2e6 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStochasticFiberTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStochasticFiberTrackingView.cpp @@ -1,287 +1,288 @@ /*=================================================================== 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 // Qmitk #include "QmitkStochasticFiberTrackingView.h" #include "QmitkStdMultiWidget.h" // Qt #include // MITK #include #include // VTK #include #include #include #include #include #include const std::string QmitkStochasticFiberTrackingView::VIEW_ID = "org.mitk.views.stochasticfibertracking"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkStochasticFiberTrackingView::QmitkStochasticFiberTrackingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_DiffusionImage( NULL ) , m_SeedRoi( NULL ) { } // Destructor QmitkStochasticFiberTrackingView::~QmitkStochasticFiberTrackingView() { } void QmitkStochasticFiberTrackingView::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkStochasticFiberTrackingViewControls; m_Controls->setupUi( parent ); connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); connect( m_Controls->m_SeedsPerVoxelSlider, SIGNAL(valueChanged(int)), this, SLOT(OnSeedsPerVoxelChanged(int)) ); connect( m_Controls->m_MaxCacheSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnMaxCacheSizeChanged(int)) ); connect( m_Controls->m_MaxTractLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(OnMaxTractLengthChanged(int)) ); } } void QmitkStochasticFiberTrackingView::OnSeedsPerVoxelChanged(int value) { m_Controls->m_SeedsPerVoxelLabel->setText(QString("Seeds per Voxel: ")+QString::number(value)); } void QmitkStochasticFiberTrackingView::OnMaxTractLengthChanged(int value) { m_Controls->m_MaxTractLengthLabel->setText(QString("Max. Tract Length: ")+QString::number(value)); } void QmitkStochasticFiberTrackingView::OnMaxCacheSizeChanged(int value) { m_Controls->m_MaxCacheSizeLabel->setText(QString("Max. Cache Size: ")+QString::number(value)+"GB"); } void QmitkStochasticFiberTrackingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkStochasticFiberTrackingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkStochasticFiberTrackingView::OnSelectionChanged( std::vector nodes ) { m_DiffusionImageNode = NULL; m_DiffusionImage = NULL; m_SeedRoi = NULL; m_Controls->m_DiffusionImageLabel->setText("mandatory"); m_Controls->m_RoiImageLabel->setText("mandatory"); for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { if( dynamic_cast*>(node->GetData()) ) { m_DiffusionImageNode = node; m_DiffusionImage = dynamic_cast*>(node->GetData()); m_Controls->m_DiffusionImageLabel->setText(node->GetName().c_str()); } else { bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) { m_SeedRoi = dynamic_cast(node->GetData()); m_Controls->m_RoiImageLabel->setText(node->GetName().c_str()); } } } } if(m_DiffusionImage.IsNotNull() && m_SeedRoi.IsNotNull()) { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->commandLinkButton->setEnabled(true); } else { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->commandLinkButton->setEnabled(false); } } void QmitkStochasticFiberTrackingView::DoFiberTracking() { typedef itk::VectorImage< short int, 3 > DWIVectorImageType; typedef itk::Image< float, 3 > FloatImageType; typedef itk::Image< unsigned int, 3 > CImageType; typedef itk::StochasticTractographyFilter< DWIVectorImageType, FloatImageType, CImageType > TrackingFilterType; typedef itk::DTITubeSpatialObject<3> DTITubeType; typedef itk::DTITubeSpatialObjectPoint<3> DTITubePointType; typedef itk::SceneSpatialObject<3> SceneSpatialObjectType; /* get Gradients/Direction of dwi */ itk::VectorContainer< unsigned int, vnl_vector_fixed >::Pointer Pdir = m_DiffusionImage->GetDirections(); /* bValueContainer, Container includes b-values according to corresponding gradient-direction*/ TrackingFilterType::bValueContainerType::Pointer vecCont = TrackingFilterType::bValueContainerType::New(); /* for each gradient set b-Value; for 0-gradient set b-value eq. 0 */ for ( int i=0; i<(int)Pdir->size(); ++i) { vnl_vector_fixed valsGrad = Pdir->at(i); if (valsGrad.get(0) == 0 && valsGrad.get(1) == 0 && valsGrad.get(2) == 0) { //set 0-Gradient to bValue 0 vecCont->InsertElement(i,0); }else{ vecCont->InsertElement(i,m_DiffusionImage->GetB_Value()); } } /* define measurement frame (identity-matrix 3x3) */ TrackingFilterType::MeasurementFrameType measurement_frame = m_DiffusionImage->GetMeasurementFrame(); /* generate white matterImage (dummy?)*/ FloatImageType::Pointer wmImage = FloatImageType::New(); wmImage->SetSpacing( m_DiffusionImage->GetVectorImage()->GetSpacing() ); wmImage->SetOrigin( m_DiffusionImage->GetVectorImage()->GetOrigin() ); wmImage->SetDirection( m_DiffusionImage->GetVectorImage()->GetDirection() ); wmImage->SetLargestPossibleRegion( m_DiffusionImage->GetVectorImage()->GetLargestPossibleRegion() ); wmImage->SetBufferedRegion( wmImage->GetLargestPossibleRegion() ); wmImage->SetRequestedRegion( wmImage->GetLargestPossibleRegion() ); wmImage->Allocate(); itk::ImageRegionIterator ot(wmImage, wmImage->GetLargestPossibleRegion() ); while (!ot.IsAtEnd()) { ot.Set(1); ++ot; } /* init TractographyFilter */ TrackingFilterType::Pointer trackingFilter = TrackingFilterType::New(); trackingFilter->SetInput(m_DiffusionImage->GetVectorImage().GetPointer()); trackingFilter->SetbValues(vecCont); trackingFilter->SetGradients(Pdir); trackingFilter->SetMeasurementFrame(measurement_frame); trackingFilter->SetWhiteMatterProbabilityImageInput(wmImage); trackingFilter->SetTotalTracts(m_Controls->m_SeedsPerVoxelSlider->value()); trackingFilter->SetMaxLikelihoodCacheSize(m_Controls->m_MaxCacheSizeSlider->value()*1000); trackingFilter->SetMaxTractLength(m_Controls->m_MaxTractLengthSlider->value()); //itk::Image< char, 3 > mitk::ImageToItk< itk::Image< unsigned char, 3 > >::Pointer binaryImageToItk1 = mitk::ImageToItk< itk::Image< unsigned char, 3 > >::New(); binaryImageToItk1->SetInput( m_SeedRoi ); binaryImageToItk1->Update(); vtkSmartPointer vPoints = vtkSmartPointer::New(); vtkSmartPointer vCellArray = vtkSmartPointer::New(); itk::ImageRegionConstIterator< BinaryImageType > it(binaryImageToItk1->GetOutput(), binaryImageToItk1->GetOutput()->GetRequestedRegion()); it.Begin(); mitk::Geometry3D* geom = m_DiffusionImage->GetGeometry(); while(!it.IsAtEnd()) { itk::ImageConstIterator::PixelType tmpPxValue = it.Get(); if(tmpPxValue != 0){ mitk::Point3D point; itk::ImageRegionConstIterator< BinaryImageType >::IndexType seedIdx = it.GetIndex(); trackingFilter->SetSeedIndex(seedIdx); trackingFilter->Update(); /* get results from Filter */ /* write each single tract into member container */ TrackingFilterType::TractContainerType::Pointer container_tmp = trackingFilter->GetOutputTractContainer(); TrackingFilterType::TractContainerType::Iterator elIt = container_tmp->Begin(); TrackingFilterType::TractContainerType::Iterator end = container_tmp->End(); bool addTract = true; while( elIt != end ){ TrackingFilterType::TractContainerType::Element tract = elIt.Value(); TrackingFilterType::TractContainerType::Element::ObjectType::VertexListType::ConstPointer vertexlist = tract->GetVertexList(); vtkSmartPointer vPolyLine = vtkSmartPointer::New(); for( int j=0; j<(int)vertexlist->Size(); j++) { TrackingFilterType::TractContainerType::Element::ObjectType::VertexListType::Element vertex = vertexlist->GetElement(j); mitk::Point3D index; index[0] = (float)vertex[0]; index[1] = (float)vertex[1]; index[2] = (float)vertex[2]; if (geom->IsIndexInside(index)) { geom->IndexToWorld(index, point); vtkIdType id = vPoints->InsertNextPoint(point.GetDataPointer()); vPolyLine->GetPointIds()->InsertNextId(id); } else { addTract = false; break; } } if (addTract) vCellArray->InsertNextCell(vPolyLine); ++elIt; } } ++it; } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(vPoints); fiberPolyData->SetLines(vCellArray); mitk::FiberBundleX::Pointer fib = mitk::FiberBundleX::New(fiberPolyData); mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(fib); - QString name(m_DiffusionImageNode->GetName().c_str()); - name += "_FiberBundle"; + QString name("FiberBundle_"); + name += m_DiffusionImageNode->GetName().c_str(); + name += "_Probabilistic"; fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); - GetDataStorage()->Add(fbNode); + GetDataStorage()->Add(fbNode, m_DiffusionImageNode); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp index b654509cc7..712d2e7423 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp @@ -1,245 +1,245 @@ /*=================================================================== 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 // Qmitk #include "QmitkStreamlineTrackingView.h" #include "QmitkStdMultiWidget.h" // Qt #include // MITK #include #include #include // VTK #include #include #include #include #include #include const std::string QmitkStreamlineTrackingView::VIEW_ID = "org.mitk.views.streamlinetracking"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkStreamlineTrackingView::QmitkStreamlineTrackingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_TensorImage( NULL ) , m_SeedRoi( NULL ) { } // Destructor QmitkStreamlineTrackingView::~QmitkStreamlineTrackingView() { } void QmitkStreamlineTrackingView::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkStreamlineTrackingViewControls; m_Controls->setupUi( parent ); connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); connect( m_Controls->m_SeedsPerVoxelSlider, SIGNAL(valueChanged(int)), this, SLOT(OnSeedsPerVoxelChanged(int)) ); connect( m_Controls->m_MinTractLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(OnMinTractLengthChanged(int)) ); connect( m_Controls->m_FaThresholdSlider, SIGNAL(valueChanged(int)), this, SLOT(OnFaThresholdChanged(int)) ); connect( m_Controls->m_AngularThresholdSlider, SIGNAL(valueChanged(int)), this, SLOT(OnAngularThresholdChanged(int)) ); connect( m_Controls->m_StepsizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnStepsizeChanged(int)) ); connect( m_Controls->m_fSlider, SIGNAL(valueChanged(int)), this, SLOT(OnfChanged(int)) ); connect( m_Controls->m_gSlider, SIGNAL(valueChanged(int)), this, SLOT(OngChanged(int)) ); } } void QmitkStreamlineTrackingView::OnfChanged(int value) { m_Controls->m_fLabel->setText(QString("f: ")+QString::number((float)value/100)); } void QmitkStreamlineTrackingView::OngChanged(int value) { m_Controls->m_gLabel->setText(QString("g: ")+QString::number((float)value/100)); } void QmitkStreamlineTrackingView::OnAngularThresholdChanged(int value) { if (value<0) m_Controls->m_AngularThresholdLabel->setText(QString("Min. Curvature Radius: auto")); else m_Controls->m_AngularThresholdLabel->setText(QString("Min. Curvature Radius: ")+QString::number((float)value/10)+QString("mm")); } void QmitkStreamlineTrackingView::OnSeedsPerVoxelChanged(int value) { m_Controls->m_SeedsPerVoxelLabel->setText(QString("Seeds per Voxel: ")+QString::number(value)); } void QmitkStreamlineTrackingView::OnMinTractLengthChanged(int value) { m_Controls->m_MinTractLengthLabel->setText(QString("Min. Tract Length: ")+QString::number(value)+QString("mm")); } void QmitkStreamlineTrackingView::OnFaThresholdChanged(int value) { m_Controls->m_FaThresholdLabel->setText(QString("FA Threshold: ")+QString::number((float)value/100)); } void QmitkStreamlineTrackingView::OnStepsizeChanged(int value) { if (value==0) m_Controls->m_StepsizeLabel->setText(QString("Stepsize: auto")); else m_Controls->m_StepsizeLabel->setText(QString("Stepsize: ")+QString::number((float)value/10)+QString("mm")); } void QmitkStreamlineTrackingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkStreamlineTrackingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkStreamlineTrackingView::OnSelectionChanged( std::vector nodes ) { m_TensorImageNode = NULL; m_TensorImage = NULL; m_SeedRoi = NULL; m_MaskImage = NULL; m_Controls->m_TensorImageLabel->setText("mandatory"); m_Controls->m_RoiImageLabel->setText("optional"); m_Controls->m_MaskImageLabel->setText("optional"); for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { if( dynamic_cast(node->GetData()) ) { m_TensorImageNode = node; m_TensorImage = dynamic_cast(node->GetData()); m_Controls->m_TensorImageLabel->setText(node->GetName().c_str()); } else { bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary && m_SeedRoi.IsNull()) { m_SeedRoi = dynamic_cast(node->GetData()); m_Controls->m_RoiImageLabel->setText(node->GetName().c_str()); } else if (isBinary) { m_MaskImage = dynamic_cast(node->GetData()); m_Controls->m_MaskImageLabel->setText(node->GetName().c_str()); } } } } if(m_TensorImageNode.IsNotNull()) { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->commandLinkButton->setEnabled(true); } else { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->commandLinkButton->setEnabled(false); } } void QmitkStreamlineTrackingView::DoFiberTracking() { if (m_TensorImage.IsNull()) return; typedef itk::Image< itk::DiffusionTensor3D, 3> TensorImageType; typedef mitk::ImageToItk CastType; typedef mitk::ImageToItk CastType2; CastType::Pointer caster = CastType::New(); caster->SetInput(m_TensorImage); caster->Update(); TensorImageType::Pointer image = caster->GetOutput(); typedef itk::StreamlineTrackingFilter< float > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput(image); filter->SetSeedsPerVoxel(m_Controls->m_SeedsPerVoxelSlider->value()); filter->SetFaThreshold((float)m_Controls->m_FaThresholdSlider->value()/100); filter->SetMinCurvatureRadius((float)m_Controls->m_AngularThresholdSlider->value()/10); filter->SetStepSize((float)m_Controls->m_StepsizeSlider->value()/10); filter->SetF((float)m_Controls->m_fSlider->value()/100); filter->SetG((float)m_Controls->m_gSlider->value()/100); filter->SetInterpolate(m_Controls->m_InterpolationBox->isChecked()); filter->SetMinTractLength(m_Controls->m_MinTractLengthSlider->value()); - //filter->SetNumberOfThreads(1); if (m_SeedRoi.IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(m_SeedRoi, mask); filter->SetSeedImage(mask); } if (m_MaskImage.IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(m_MaskImage, mask); filter->SetMaskImage(mask); } filter->Update(); vtkSmartPointer fiberBundle = filter->GetFiberPolyData(); if ( fiberBundle->GetNumberOfLines()==0 ) return; mitk::FiberBundleX::Pointer fib = mitk::FiberBundleX::New(fiberBundle); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(fib); - QString name(m_TensorImageNode->GetName().c_str()); + QString name("FiberBundle_"); + name += m_TensorImageNode->GetName().c_str(); name += "_Streamline"; node->SetName(name.toStdString()); node->SetVisibility(true); - GetDataStorage()->Add(node); + GetDataStorage()->Add(node, m_TensorImageNode); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp index e2ebf77c96..0198ad45d3 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp @@ -1,83 +1,83 @@ /*=================================================================== 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 "mitkPluginActivator.h" #include #include "src/internal/QmitkDiffusionImagingPublicPerspective.h" #include "src/internal/QmitkQBallReconstructionView.h" #include "src/internal/QmitkPreprocessingView.h" #include "src/internal/QmitkDiffusionDicomImportView.h" #include "src/internal/QmitkDiffusionQuantificationView.h" #include "src/internal/QmitkTensorReconstructionView.h" #include "src/internal/QmitkControlVisualizationPropertiesView.h" #include "src/internal/QmitkODFDetailsView.h" #include "src/internal/QmitkGibbsTrackingView.h" #include "src/internal/QmitkStochasticFiberTrackingView.h" #include "src/internal/QmitkFiberProcessingView.h" #include "src/internal/QmitkFiberBundleDeveloperView.h" #include "src/internal/QmitkPartialVolumeAnalysisView.h" #include "src/internal/QmitkIVIMView.h" #include "src/internal/QmitkTractbasedSpatialStatisticsView.h" #include "src/internal/QmitkTbssSkeletonizationView.h" #include "src/internal/QmitkStreamlineTrackingView.h" #include "src/internal/Connectomics/QmitkConnectomicsDataView.h" #include "src/internal/Connectomics/QmitkConnectomicsNetworkOperationsView.h" #include "src/internal/Connectomics/QmitkConnectomicsStatisticsView.h" -#include "src/internal/QmitkDwiSoftwarePhantomView.h" #include "src/internal/QmitkOdfMaximaExtractionView.h" #include "src/internal/QmitkFiberfoxView.h" +#include "src/internal/QmitkFiberExtractionView.h" namespace mitk { void PluginActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionImagingPublicPerspective, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkQBallReconstructionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkPreprocessingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionDicomImport, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionQuantificationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTensorReconstructionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkControlVisualizationPropertiesView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkODFDetailsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkGibbsTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkStochasticFiberTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberProcessingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberBundleDeveloperView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkPartialVolumeAnalysisView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkIVIMView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTractbasedSpatialStatisticsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTbssSkeletonizationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConnectomicsDataView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConnectomicsNetworkOperationsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConnectomicsStatisticsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkStreamlineTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkOdfMaximaExtractionView, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkDwiSoftwarePhantomView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberfoxView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberExtractionView, context) } void PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) } } Q_EXPORT_PLUGIN2(org_mitk_gui_qt_diffusionimaging, mitk::PluginActivator) diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimagingapp/files.cmake index e4e0d32f05..05beffb8a1 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/files.cmake @@ -1,94 +1,95 @@ set(SRC_CPP_FILES QmitkDiffusionImagingAppApplication.cpp QmitkDiffusionImagingAppWorkbenchAdvisor.cpp ) set(INTERNAL_CPP_FILES QmitkDiffusionApplicationPlugin.cpp QmitkDiffusionImagingAppIntroPart.cpp Perspectives/QmitkDiffusionImagingAppPerspective.cpp Perspectives/QmitkWelcomePerspective.cpp Perspectives/QmitkDIAppConnectomicsPerspective.cpp Perspectives/QmitkDIAppDicomImportPerspective.cpp Perspectives/QmitkDIAppFiberTractographyPerspective.cpp Perspectives/QmitkDIAppIVIMPerspective.cpp Perspectives/QmitkDIAppPreprocessingReconstructionPerspective.cpp Perspectives/QmitkDIAppQuantificationPerspective.cpp Perspectives/QmitkDIAppTBSSPerspective.cpp Perspectives/QmitkDIAppUtilityPerspective.cpp Perspectives/QmitkDIAppImageProcessingPerspective.cpp Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp Perspectives/QmitkDIAppRegistrationPerspective.cpp Perspectives/QmitkDIAppVisualizationPerspective.cpp ) set(UI_FILES src/internal/QmitkWelcomeScreenViewControls.ui ) set(MOC_H_FILES src/internal/QmitkDiffusionImagingAppIntroPart.h src/internal/QmitkDiffusionApplicationPlugin.h src/QmitkDiffusionImagingAppApplication.h src/internal/Perspectives/QmitkDiffusionImagingAppPerspective.h src/internal/Perspectives/QmitkWelcomePerspective.h src/internal/Perspectives/QmitkDIAppConnectomicsPerspective.h src/internal/Perspectives/QmitkDIAppDicomImportPerspective.h src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.h src/internal/Perspectives/QmitkDIAppIVIMPerspective.h src/internal/Perspectives/QmitkDIAppPreprocessingReconstructionPerspective.h src/internal/Perspectives/QmitkDIAppQuantificationPerspective.h src/internal/Perspectives/QmitkDIAppTBSSPerspective.h src/internal/Perspectives/QmitkDIAppUtilityPerspective.h src/internal/Perspectives/QmitkDIAppImageProcessingPerspective.h src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.h src/internal/Perspectives/QmitkDIAppRegistrationPerspective.h src/internal/Perspectives/QmitkDIAppVisualizationPerspective.h ) set(CACHED_RESOURCE_FILES # 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 plugin.xml resources/icon_dicom.xpm resources/diffusionimaging.png resources/preprocessing.png resources/Measurement_48.png resources/volvis.png resources/perspectives/diffusionimaging.png resources/perspectives/icon_home.png resources/perspectives/connectomics.png resources/perspectives/dicomimport.png resources/perspectives/tractography.png resources/perspectives/ivim.png resources/perspectives/preprocessingreconstruction.png resources/perspectives/quantification.png resources/perspectives/tbss.png resources/perspectives/utilities.png resources/perspectives/imageProcessing.png resources/perspectives/registration.png resources/perspectives/phantomData2.png resources/perspectives/eye.png resources/perspectives/registration.xpm resources/perspectives/chart.png resources/perspectives/preprocessing.png + resources/perspectives/syntheticdata.png ) set(QRC_FILES # uncomment the following line if you want to use Qt resources resources/welcome/QmitkWelcomeScreenView.qrc resources/org_mitk_gui_qt_diffusionimagingapp.qrc ) # 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.diffusionimagingapp/plugin.xml b/Plugins/org.mitk.gui.qt.diffusionimagingapp/plugin.xml index 7d773de29a..61d7c39bad 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/plugin.xml +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/plugin.xml @@ -1,93 +1,93 @@ + icon="resources/perspectives/syntheticdata.png"/> diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/perspectives/syntheticdata.png b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/perspectives/syntheticdata.png new file mode 100644 index 0000000000..ae592d88bb Binary files /dev/null and b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/perspectives/syntheticdata.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/QmitkWelcomeScreenView.qrc b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/QmitkWelcomeScreenView.qrc index c55deeb5a5..79affa1245 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/QmitkWelcomeScreenView.qrc +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/QmitkWelcomeScreenView.qrc @@ -1,36 +1,36 @@ style.css function.js pics/background.jpg pics/popup_bttn_close.png pics/experimental.png pics/button_mitka.png pics/button_mitk.png mitkdiffusionimagingappwelcomeview.html pics/01adicomimport.png pics/01dicomimport.png pics/02apreprocessingreconstruction.png pics/02preprocessingreconstruction.png pics/03aquantification.png pics/03quantification.png pics/04atractography.png pics/04tractography.png pics/05atbss.png pics/05tbss.png pics/06aconnectomics.png pics/06connectomics.png pics/07aivim.png pics/07ivim.png pics/08avolumevisualization.png pics/08volumevisualization.png - pics/10asoftwarephantoms.png - pics/10softwarephantoms.png pics/11asegmentation.png pics/11segmentation.png pics/12aregistration.png pics/12registration.png pics/13autilities.png pics/13utilities.png + pics/10softwarephantoms.png + pics/10asoftwarephantoms.png diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/function.js b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/function.js index d36c31c125..37c853c483 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/function.js +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/function.js @@ -1,323 +1,323 @@ // If you want to create a new button you have to add some data (strings) to the following five arrays. // Make sure that you add your data at the same position in each array. // The buttons will be generated in order to the array's index. e.g. data at array's index '0' will generate the first button. // enter the name of your module here var moduleNames = new Array("Dicom Import", "IVIM", "Preprocessing", "Quantification", "Tractography", "Connectomics", - "Synthetic Images", + "Synthetic Data", "Registration", "Image Processing", "Visualization", "Utilities", "MITK Downloads & News"); // add the MITK-link to your module var moduleLinks = new Array("mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.dicomimport?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.ivim?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.preprocessingreconstruction?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.quantification?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.tractography?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.connectomics?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.syntheticdata?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.registration?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.imageprocessing?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.visualization?clear=false", "mitk://mitk.perspectives/org.mitk.diffusionimagingapp.perspectives.utility?clear=false", "http://www.mitk.org"); // add the filename of your icon for the module. Place the picture in subdirectory "pics". // The picture's width should be 136 pixel; the height 123 pixel. var picFilenames = new Array("01dicomimport.png", "07ivim.png", "02preprocessingreconstruction.png", "03quantification.png", "04tractography.png", "06connectomics.png", "10softwarephantoms.png", "12registration.png", "11segmentation.png", "08volumevisualization.png", "13utilities.png", "button_mitk.png"); // if you want to create an animated icon, add the name of your animated gif (placed in subdirectory "pics"). Otherwise enter an empty string "". // The animation's width should be 136 pixel; the height 123 pixel. var aniFilenames = new Array("01adicomimport.png", "07aivim.png", "02apreprocessingreconstruction.png", "03aquantification.png", "04atractography.png", "06aconnectomics.png", "10asoftwarephantoms.png", "12aregistration.png", "11asegmentation.png", "08avolumevisualization.png", "13autilities.png", "button_mitka.png"); // if your module is not stable, you can mark it as experimental. // just set true for experimental or false for stable. var experimental = new Array(false, false, false, false, false, false, - true, + false, true, false, false, false, false); // add the description for your module. The description is displayed in a PopUp-window. var moduleDescriptions = new Array("'Dicom Import' supports direct import of Siemens diffusion weighted DICOM files.", "'IVIM' stands for Intravoxel Incoherent Motion. The technique allows for the estimation of tissue perfusion on basis of diffusion measurements. Several models are supported by this module. Interactive exploration of the data is supported.", "'Preprocessing & Reconstruction' lets you estimate diffusion tensors or q-balls using different reconstruction methods and calculates scalar indices (FA, GFA, ...). It also includes an ODF Peak Extraction view and preprocessing steps like gradient avaraging or reduction and baseline image extraction.", "'Quantification' allows partial volume analysis and the evaluation and exploration of Tract Based Spatial Statistic datasets (it does NOT reimplement the TBSS methods available in FSL). The Partial Volume Analysis view provides a very robust method for semi-automatic ROI analysis. It uses EM clustering to probabilistically segment fiber vs. non-fiber vs. partial volume.", "'Tractography' implements several fiber tractography algorithms (global, probabilistic and streamline). The fiber bundle operations view allows for extraction, join, and substraction of bundles. It also generates a variety of images from given fiber tracts and gives detailed information about the fiberbundle itself.", "'Connectomics' aims at building graphs (nodes and edges) from a global tractogram and applying graph theory for data analysis. fMRI-data might be incorporated in future.", - "'Synthetic Images' provides tools to generate DWI software phantoms.", + "'Synthetic Data' contains the Fiberfox software phantom tool as well as instruments like tract density image or fiber envelope generation.", "'Registration' provides views for rigid and point based image registration (only non-diffusion!).", "'Image Processing' provides tools for image segmentation and diffusion unrelated image processing.", "'Visualization' provides easy to use and fast volume rendering of images, means to capture high resolution screenshots as well as movies of the 3D sceen.", "'Utilities' provides the property list view to modify the properties of the selected data node as well as a logging view for debugging purposes.", "Open the MITK website in an external browser."); var bttns = new Array(); var d = document, da = d.all; // holds id of current mouseover-HTML-element var currentTarget; // get the id of current mouseover-HTML-element d.onmouseover = function(o){ var e = da ? event.srcElement : o.target; currentTarget = e.id; } // build-function called by onload-event in HTML-document function createButtons(){ for (i=0; i < moduleNames.length; i++){ bttns[i] = new Button(moduleNames[i],moduleLinks[i], picFilenames[i], aniFilenames[i],moduleDescriptions[i]); bttns[i].createButton(); } for (i=0; i < moduleNames.length; i++){ if(experimental[i]){ setExperimental(i); } } createClearFloat(); } // Class Button function Button(moduleName, moduleLink, picFilename, aniFilename, moduleDescr){ // Properties this.bttnID = "bttn" + moduleName; this.modName = moduleName; this.modLink = moduleLink; this.picPath = "pics/" + picFilename; this.aniPath = "pics/" + aniFilename; this.modDescr = moduleDescr; // Methods this.createButton = function(){ // get DIV-wrapper for Button and append it to HTML-document bttnWrapper = this.createWrapper(); document.getElementById("bttnField").appendChild(bttnWrapper); // get link-element for picture and append it to DIV-wrapper bttnPicLink = this.createPicLink(); bttnWrapper.appendChild(bttnPicLink); // set HTML attributes for button-element bttn = document.createElement("img"); bttn.src = this.picPath; bttn.id = this.bttnID; bttn.className = "modBttn"; bttn.height = 123; bttn.width = 136; bttn.onmouseover = function(){startAni(this.id);}; bttn.onmouseout = function(){stopAni(this.id);}; // append button to link-element bttnPicLink.appendChild(bttn); // create text-link and add it to DIV-wrapper bttnTxtLink = document.createElement("a"); bttnTxtLink.href = this.modLink; bttnTxtLink.className = "txtLink"; bttnTxtLink.appendChild(document.createTextNode(this.modName)); bttnWrapper.appendChild(bttnTxtLink); // create pop-up link for module description bttnPopUpLink = document.createElement("a"); modName = this.modName; modDescr = this.modDescr; bttnPopUpLink.onclick = function(){showPopUpWindow();}; bttnPopUpLink.className = "popUpLink"; bttnPopUpLink.id = "popup" + this.modName; bttnPopUpLink.appendChild(document.createTextNode("more info >>")); bttnWrapper.appendChild(document.createElement("br")); bttnWrapper.appendChild(bttnPopUpLink); return bttn; } this.createWrapper = function(){ bttnWrapper = document.createElement("div"); bttnWrapper.id = "wrapper" + this.modName; bttnWrapper.className = "bttnWrap"; return bttnWrapper; } this.createPicLink = function(){ picLink = document.createElement("a"); picLink.href = this.modLink; picLink.id = "link" + this.modName; return picLink; } } function showPopUpWindow(){ // modules position in array? modulePos = getPos(currentTarget,"popup"); // get reference to anchor-element in HTML-document popUpAnchor = document.getElementById("popupAnchor"); // check if a popUp is open if(popUpAnchor.hasChildNodes()){ // if a popUp is open, remove it! popUpAnchor.removeChild(document.getElementById("popup")); } // create new container for popUp container = document.createElement("div"); container.id = "popup"; container.align = "right"; // append popUp-container to HTML-document popUpAnchor.appendChild(container); // create close-button and append it to popUp-container bttnClose = document.createElement("img"); bttnClose.src = "pics/popup_bttn_close.png"; bttnClose.id = "bttnClose"; bttnClose.onclick = function(){closeInfoWindow();}; container.appendChild(bttnClose); // create container for content-elements contHeadline = document.createElement("div"); contHeadline.id = "contHeadline"; contDescription = document.createElement("div"); contDescription.id = "contDescription"; contModLink = document.createElement("div"); contModLink.id = "contModLink"; // append content-container to popUp-container container.appendChild(contHeadline); container.appendChild(contDescription); container.appendChild(contModLink); // create text-elements with content headline = document.createTextNode(moduleNames[modulePos] + " "); description = document.createTextNode(moduleDescriptions[modulePos]); moduleLink = document.createElement("a"); moduleLink.href = moduleLinks[modulePos] ; moduleLink.className = 'moduleLink'; moduleLinkTxt = document.createTextNode("Click here to open '" + moduleNames[modulePos].toLowerCase() + "'"); moduleLink.appendChild(moduleLinkTxt); // append text-elements to their container contHeadline.appendChild(headline); contDescription.appendChild(description); contModLink.appendChild(moduleLink); } function getPos(id,prefix){ if(prefix == "popup"){ targetID = id.slice(5); }else{ if(prefix == "bttn"){ targetID = id.slice(4); } } for(i=0; i < moduleNames.length; i++ ){ if(moduleNames[i] == targetID){ return i; } } } function setExperimental(modPos){ linkID = "link" + moduleNames[modPos]; expPic = document.createElement("img"); expPic.src = "pics/experimental.png"; expPic.className = "expPic"; //alert(bttns[modPos].bttnID); expPic.onmouseover = function(){startAni(bttns[modPos].bttnID);changeToHover(bttns[modPos].bttnID);}; expPic.onmouseout = function(){stopAni(bttns[modPos].bttnID);changeToNormal(bttns[modPos].bttnID);}; document.getElementById(linkID).appendChild(expPic); } function changeToHover(targetId){ bttn = document.getElementById(targetId); bttn.className = "modBttnHover"; } function changeToNormal(targetId){ bttn = document.getElementById(targetId); bttn.className = "modBttn"; } // function to close PopUp-window function closeInfoWindow(){ popUpAnchor = document.getElementById("popupAnchor"); popUpAnchor.removeChild(document.getElementById("popup")); } function createClearFloat(){ cf = document.createElement("div"); cf.className = "clearfloat"; document.getElementById("bttnField").appendChild(cf); } startAni = function(targetId){ modulePos = getPos(targetId,"bttn"); if(aniFilenames[modulePos] != ''){ bttn = document.getElementById(targetId); bttn.src = "pics/" + aniFilenames[modulePos]; } } stopAni = function(targetId){ modulePos = getPos(targetId,"bttn"); bttn = document.getElementById(targetId); bttn.src = "pics/" + picFilenames[modulePos]; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/mitkdiffusionimagingappwelcomeview.html b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/mitkdiffusionimagingappwelcomeview.html index 6e03435910..d050141429 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/mitkdiffusionimagingappwelcomeview.html +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/mitkdiffusionimagingappwelcomeview.html @@ -1,37 +1,37 @@ MITK Diffusion Imaging App

Welcome to MITK Diffusion!

-
- This application includes all diffusion imaging modules that were developed at the German Cancer Research Center (DKFZ). The software is developed on the basis of the well established, free open source software toolkit MITK. It is designed to perform tasks like fiber tracking, quantification, group analysis, connectomics, or other image post processing tasks. For more information, please also visit our website www.mitk.org. +
+ This application includes all diffusion imaging modules that were developed at the German Cancer Research Center (DKFZ). The software is developed on the basis of the well established, free open source software toolkit MITK. It is designed to perform tasks like fiber tracking, quantification, group analysis, connectomics, synthetic data generation or other image processing tasks. For more information, please also visit our website www.mitk.org or have a look at the help perspective.

Instructions:

diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/pics/10asoftwarephantoms.png b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/pics/10asoftwarephantoms.png index 52c36e2fbd..c5947dd44b 100644 Binary files a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/pics/10asoftwarephantoms.png and b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/pics/10asoftwarephantoms.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/pics/10softwarephantoms.png b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/pics/10softwarephantoms.png index 32345fccfe..d4f3d6bc01 100644 Binary files a/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/pics/10softwarephantoms.png and b/Plugins/org.mitk.gui.qt.diffusionimagingapp/resources/welcome/pics/10softwarephantoms.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp index 68a7c17e9b..c53e45079f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp @@ -1,64 +1,68 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkDIAppFiberTractographyPerspective.h" #include "berryIViewLayout.h" void QmitkDIAppFiberTractographyPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { std::string editorArea = layout->GetEditorArea(); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mitk.diffusionimaginginternal.leftcontrols2", berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); berry::IFolderLayout::Pointer bottomleft = layout->CreateFolder("org.mitk.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.5f, "org.mitk.diffusionimaginginternal.leftcontrols2"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .6f, "org.mitk.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // add the views ///////////////////////////////////////////// left->AddView("org.mitk.views.gibbstracking"); berry::IViewLayout::Pointer lo = layout->GetViewLayout("org.mitk.views.gibbstracking"); lo->SetCloseable(false); left->AddView("org.mitk.views.stochasticfibertracking"); lo = layout->GetViewLayout("org.mitk.views.stochasticfibertracking"); lo->SetCloseable(false); left->AddView("org.mitk.views.streamlinetracking"); lo = layout->GetViewLayout("org.mitk.views.streamlinetracking"); lo->SetCloseable(false); + bottomleft->AddView("org.mitk.views.fiberextraction"); + berry::IViewLayout::Pointer lo2 = layout->GetViewLayout("org.mitk.views.fiberextraction"); + lo2->SetCloseable(false); + bottomleft->AddView("org.mitk.views.fiberprocessing"); - berry::IViewLayout::Pointer lo2 = layout->GetViewLayout("org.mitk.views.fiberprocessing"); + lo2 = layout->GetViewLayout("org.mitk.views.fiberprocessing"); lo2->SetCloseable(false); bottomleft->AddView("org.mitk.views.segmentation"); lo2 = layout->GetViewLayout("org.mitk.views.segmentation"); lo2->SetCloseable(false); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp index bf149736ee..67e3e08eac 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp @@ -1,56 +1,56 @@ /*=================================================================== 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 "QmitkDIAppSyntheticDataGenerationPerspective.h" #include "berryIViewLayout.h" void QmitkDIAppSyntheticDataGenerationPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// std::string editorArea = layout->GetEditorArea(); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .4f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.fiberfoxview"); berry::IViewLayout::Pointer lo = layout->GetViewLayout("org.mitk.views.fiberfoxview"); lo->SetCloseable(false); - left->AddView("org.mitk.views.dwisoftwarephantomview"); - lo = layout->GetViewLayout("org.mitk.views.dwisoftwarephantomview"); + left->AddView("org.mitk.views.fiberprocessing"); + lo = layout->GetViewLayout("org.mitk.views.fiberprocessing"); lo->SetCloseable(false); left->AddView("org.mitk.views.segmentation"); lo = layout->GetViewLayout("org.mitk.views.segmentation"); lo->SetCloseable(false); } diff --git a/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkModuleView.cpp b/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkModuleView.cpp index b1c24b69bf..05fbff3d5f 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkModuleView.cpp +++ b/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkModuleView.cpp @@ -1,99 +1,100 @@ /*=================================================================== 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 "QmitkModuleView.h" #include #include #include #include #include #include QmitkModuleView::QmitkModuleView() : tableView(0) { } void QmitkModuleView::SetFocus() { //tableView->setFocus(); } void QmitkModuleView::CreateQtPartControl(QWidget *parent) { QHBoxLayout* layout = new QHBoxLayout(); layout->setMargin(0); parent->setLayout(layout); tableView = new QTableView(parent); QmitkModuleTableModel* tableModel = new QmitkModuleTableModel(tableView); QSortFilterProxyModel* sortProxyModel = new QSortFilterProxyModel(tableView); sortProxyModel->setSourceModel(tableModel); sortProxyModel->setDynamicSortFilter(true); tableView->setModel(sortProxyModel); tableView->verticalHeader()->hide(); tableView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->setSelectionMode(QAbstractItemView::ExtendedSelection); tableView->setTextElideMode(Qt::ElideMiddle); tableView->setSortingEnabled(true); tableView->sortByColumn(0, Qt::AscendingOrder); + // Fixed size for "Id" column tableView->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents); + // Fixed size for "Version" column tableView->horizontalHeader()->setResizeMode(2, QHeaderView::ResizeToContents); - tableView->horizontalHeader()->setResizeMode(5, QHeaderView::ResizeToContents); tableView->horizontalHeader()->setStretchLastSection(true); tableView->horizontalHeader()->setCascadingSectionResizes(true); layout->addWidget(tableView); if (viewState) { berry::IMemento::Pointer tableHeaderState = viewState->GetChild("tableHeader"); if (tableHeaderState) { std::string key; tableHeaderState->GetString("qsettings-key", key); if (!key.empty()) { QSettings settings; QByteArray ba = settings.value(QString::fromStdString(key)).toByteArray(); tableView->horizontalHeader()->restoreState(ba); } } } } void QmitkModuleView::Init(berry::IViewSite::Pointer site, berry::IMemento::Pointer memento) { berry::QtViewPart::Init(site, memento); viewState = memento; } void QmitkModuleView::SaveState(berry::IMemento::Pointer memento) { QString key = "QmitkModuleView_tableHeader"; QByteArray ba = tableView->horizontalHeader()->saveState(); QSettings settings; settings.setValue(key, ba); berry::IMemento::Pointer tableHeaderState = memento->CreateChild("tableHeader"); tableHeaderState->PutString("qsettings-key", key.toStdString()); } diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp index 5ad4f50784..83c1d09fae 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp @@ -1,432 +1,454 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "QmitkImageCropper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkUndoController.h" #include "mitkBoundingObjectCutter.h" #include "mitkImageAccessByItk.h" #include "mitkITKImageImport.h" #include "mitkIDataStorageService.h" #include "mitkNodePredicateDataType.h" #include //to be moved to mitkInteractionConst.h by StateMachineEditor const mitk::OperationType QmitkImageCropper::OP_EXCHANGE = 717; // constructors for operation classes QmitkImageCropper::opExchangeNodes::opExchangeNodes( mitk::OperationType type, mitk::DataNode* node, mitk::BaseData* oldData, mitk::BaseData* newData ) :mitk::Operation(type),m_Node(node),m_OldData(oldData),m_NewData(newData), m_NodeDeletedObserverTag(0), m_OldDataDeletedObserverTag(0), m_NewDataDeletedObserverTag(0) { // listen to the node the image is hold itk::MemberCommand::Pointer nodeDeletedCommand = itk::MemberCommand::New(); nodeDeletedCommand->SetCallbackFunction(this, &opExchangeNodes::NodeDeleted); m_NodeDeletedObserverTag = m_Node->AddObserver(itk::DeleteEvent(), nodeDeletedCommand); m_OldDataDeletedObserverTag = m_OldData->AddObserver(itk::DeleteEvent(), nodeDeletedCommand); m_NewDataDeletedObserverTag = m_NewData->AddObserver(itk::DeleteEvent(), nodeDeletedCommand); } // destructor for operation class QmitkImageCropper::opExchangeNodes::~opExchangeNodes() { if (m_Node != NULL) { m_Node->RemoveObserver(m_NodeDeletedObserverTag); m_Node=NULL; } if (m_OldData.IsNotNull()) { m_OldData->RemoveObserver(m_OldDataDeletedObserverTag); m_OldData=NULL; } if (m_NewData.IsNotNull()) { m_NewData->RemoveObserver(m_NewDataDeletedObserverTag); m_NewData=NULL; } } void QmitkImageCropper::opExchangeNodes::NodeDeleted(const itk::Object * /*caller*/, const itk::EventObject &/*event*/) { m_Node = NULL; m_OldData = NULL; m_NewData = NULL; } QmitkImageCropper::QmitkImageCropper(QObject *parent) : m_Controls(NULL), m_ParentWidget(0) { m_Interface = new mitk::ImageCropperEventInterface; m_Interface->SetImageCropper( this ); } QmitkImageCropper::~QmitkImageCropper() { //delete smart pointer objects m_CroppingObjectNode = NULL; m_CroppingObject = NULL; m_Interface->Delete(); } void QmitkImageCropper::CreateQtPartControl(QWidget* parent) { if (!m_Controls) { m_ParentWidget = parent; // build ui elements m_Controls = new Ui::QmitkImageCropperControls; m_Controls->setupUi(parent); // setup ui elements m_Controls->groupInfo->hide(); m_Controls->m_SurroundingSlider->hide(); m_Controls->m_SurroundingSpin->hide(); m_Controls->m_BoxButton->setEnabled(true); - + m_Controls->warningLabel->setVisible(false); // create ui element connections this->CreateConnections(); } } void QmitkImageCropper::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_CropButton, SIGNAL(clicked()), this, SLOT(CropImage())); // click on the crop button connect( m_Controls->m_BoxButton, SIGNAL(clicked()), this, SLOT(CreateNewBoundingObject()) ); connect( m_Controls->m_EnableSurroundingCheckBox, SIGNAL(toggled(bool)), this, SLOT(SurroundingCheck(bool)) ); connect( m_Controls->chkInformation, SIGNAL(toggled(bool)), this, SLOT(ChkInformationToggled(bool)) ); } } void QmitkImageCropper::Activated() { QmitkFunctionality::Activated(); // just call the inherited function } void QmitkImageCropper::Deactivated() { RemoveBoundingObjectFromNode(); QmitkFunctionality::Deactivated(); // just call the inherited function mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } /*! When called with an opExchangeNodes, it changes the content of a node from one data set to another */ void QmitkImageCropper::ExecuteOperation (mitk::Operation *operation) { if (!operation) return; switch (operation->GetOperationType()) { case OP_EXCHANGE: { //RemoveBoundingObjectFromNode(); opExchangeNodes* op = static_cast(operation); op->GetNode()->SetData(op->GetNewData()); mitk::RenderingManager::GetInstance()->InitializeViews(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } default:; } } void QmitkImageCropper::CreateNewBoundingObject() { // attach the cuboid to the image and update the views if (this->IsVisible()) { if (m_ImageNode.IsNotNull()) { m_ImageToCrop = dynamic_cast(m_ImageNode->GetData()); if(m_ImageToCrop.IsNotNull()) { if (this->GetDefaultDataStorage()->GetNamedDerivedNode("CroppingObject", m_ImageNode)) { //Remove m_Cropping this->RemoveBoundingObjectFromNode(); } bool fitCroppingObject = false; if(m_CroppingObject.IsNull()) { CreateBoundingObject(); fitCroppingObject = true; } if (m_CroppingObject.IsNull()) return; AddBoundingObjectToNode( m_ImageNode, fitCroppingObject ); m_ImageNode->SetVisibility(true); mitk::RenderingManager::GetInstance()->InitializeViews(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_Controls->m_BoxButton->setText("Reset bounding box!"); m_Controls->m_CropButton->setEnabled(true); } } else QMessageBox::information(NULL, "Image cropping functionality", "Load an image first!"); } } void QmitkImageCropper::SurroundingCheck(bool value) { if(value) { if(m_ImageNode.IsNotNull()) { mitk::DataNode *imageNode = m_ImageNode.GetPointer(); if (imageNode) { mitk::BaseData* data = imageNode->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast( data ); if (image) { float min = 10000.0; float max = -10000.0; min = image->GetScalarValueMin(); max = image->GetScalarValueMax(); m_Controls->m_SurroundingSlider->setRange((int)min,(int)max); m_Controls->m_SurroundingSpin->setRange((int)min,(int)max); } } } m_Controls->m_SurroundingSlider->show(); m_Controls->m_SurroundingSpin->show(); } else m_Controls->m_EnableSurroundingCheckBox->setChecked(false); } else { m_Controls->m_SurroundingSlider->hide(); m_Controls->m_SurroundingSpin->hide(); } } void QmitkImageCropper::CropImage() { // test, if image is selected if (m_ImageToCrop.IsNull()) return; // test, if bounding box is visible if (m_CroppingObjectNode.IsNull()) { QMessageBox::information(NULL, "Image cropping functionality", "Generate a new bounding object first!"); return; } // image and bounding object ok mitk::BoundingObjectCutter::Pointer cutter = mitk::BoundingObjectCutter::New(); cutter->SetBoundingObject( m_CroppingObject ); cutter->SetInput( m_ImageToCrop ); cutter->AutoOutsideValueOff(); if (m_Controls->m_EnableSurroundingCheckBox->isChecked()) { cutter->SetOutsideValue(m_Controls->m_SurroundingSpin->value()); } // do the actual cutting try { cutter->Update(); //cutter->UpdateLargestPossibleRegion(); } catch(itk::ExceptionObject&) { QMessageBox::warning ( NULL, tr("Cropping not possible"), tr("Sorry, the bounding box has to be completely inside the image.\n\n" "The possibility to drag it larger than the image is a bug and has to be fixed."), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton ); return; } // cutting successful mitk::Image::Pointer resultImage = cutter->GetOutput(); resultImage->DisconnectPipeline(); RemoveBoundingObjectFromNode(); { opExchangeNodes* doOp = new opExchangeNodes(OP_EXCHANGE, m_ImageNode.GetPointer(), m_ImageNode->GetData(), resultImage); opExchangeNodes* undoOp = new opExchangeNodes(OP_EXCHANGE, m_ImageNode.GetPointer(), resultImage, m_ImageNode->GetData()); // TODO: MITK doesn't recognize that a new event happens in the next line, // because nothing happens in the render window. // As a result the undo action will happen together with the last action // recognized by MITK. mitk::OperationEvent* operationEvent = new mitk::OperationEvent( m_Interface, doOp, undoOp, "Crop image"); mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent( operationEvent ); // tell the undo controller about the action ExecuteOperation(doOp); // execute action } m_Controls->m_BoxButton->setEnabled(true); m_Controls->m_CropButton->setEnabled(false); } void QmitkImageCropper::CreateBoundingObject() { QStringList items; items << tr("Cuboid") << tr("Ellipsoid") << tr("Cylinder") << tr("Cone"); bool ok; QString item = QInputDialog::getItem(m_Parent, tr("Select Bounding Object"), tr("Type of Bounding Object:"), items, 0, false, &ok); if (!ok) return; if (item == "Ellipsoid") m_CroppingObject = mitk::Ellipsoid::New(); else if(item == "Cylinder") m_CroppingObject = mitk::Cylinder::New(); else if (item == "Cone") m_CroppingObject = mitk::Cone::New(); else if (item == "Cuboid") m_CroppingObject = mitk::Cuboid::New(); else return; m_CroppingObjectNode = mitk::DataNode::New(); m_CroppingObjectNode->SetData( m_CroppingObject ); m_CroppingObjectNode->SetProperty( "name", mitk::StringProperty::New( "CroppingObject" ) ); m_CroppingObjectNode->SetProperty( "color", mitk::ColorProperty::New(1.0, 1.0, 0.0) ); m_CroppingObjectNode->SetProperty( "opacity", mitk::FloatProperty::New(0.4) ); m_CroppingObjectNode->SetProperty( "layer", mitk::IntProperty::New(99) ); // arbitrary, copied from segmentation functionality m_CroppingObjectNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_AffineInteractor = mitk::AffineInteractor::New("AffineInteractions ctrl-drag", m_CroppingObjectNode); } void QmitkImageCropper::OnSelectionChanged(std::vector nodes) { this->RemoveBoundingObjectFromNode(); if (nodes.size() != 1 || dynamic_cast(nodes[0]->GetData()) == 0) { m_ParentWidget->setEnabled(false); + m_Controls->warningLabel->setVisible(false); return; } m_ImageNode = nodes[0]; m_ParentWidget->setEnabled(true); + // do not accept datanodes with dimension of less than three + mitk::Image* m_ImageToCrop = dynamic_cast(nodes[0]->GetData()); + if (m_ImageToCrop == NULL) + { + return; + } + unsigned int dim = m_ImageToCrop->GetDimension(); + if (dim < 3) + { + m_Controls->warningLabel->setVisible(true); + m_ParentWidget->setEnabled(false); + } + else + { + m_Controls->warningLabel->setVisible(false); + } } void QmitkImageCropper::AddBoundingObjectToNode(mitk::DataNode* node, bool fit) { m_ImageToCrop = dynamic_cast(node->GetData()); - + unsigned int dim = m_ImageToCrop->GetDimension(); + if (dim < 3) + { + MITK_WARN << "Image Cropper does not support 1D/2D Objects. Aborting operation"; + return; + } if(!this->GetDefaultDataStorage()->Exists(m_CroppingObjectNode)) { this->GetDefaultDataStorage()->Add(m_CroppingObjectNode, node); if (fit) { m_CroppingObject->FitGeometry(m_ImageToCrop->GetTimeSlicedGeometry()); } mitk::GlobalInteraction::GetInstance()->AddInteractor( m_AffineInteractor ); } m_CroppingObjectNode->SetVisibility(true); } void QmitkImageCropper::RemoveBoundingObjectFromNode() { if (m_CroppingObjectNode.IsNotNull()) { if(this->GetDefaultDataStorage()->Exists(m_CroppingObjectNode)) { this->GetDefaultDataStorage()->Remove(m_CroppingObjectNode); mitk::GlobalInteraction::GetInstance()->RemoveInteractor(m_AffineInteractor); m_CroppingObject = NULL; } m_Controls->m_BoxButton->setText("New bounding box!"); } } void QmitkImageCropper::ChkInformationToggled( bool on ) { if (on) m_Controls->groupInfo->show(); else m_Controls->groupInfo->hide(); } void QmitkImageCropper::StdMultiWidgetAvailable( QmitkStdMultiWidget& stdMultiWidget ) { m_MultiWidget = &stdMultiWidget; } void QmitkImageCropper::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkImageCropper::NodeRemoved(const mitk::DataNode *node) { std::string name = node->GetName(); if (strcmp(name.c_str(), "CroppingObject")==0) { m_Controls->m_CropButton->setEnabled(false); m_Controls->m_BoxButton->setEnabled(true); } } diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperControls.ui b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperControls.ui index 5c308c06fe..eec64dacb6 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperControls.ui +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperControls.ui @@ -1,381 +1,426 @@ QmitkImageCropperControls 0 0 - 365 + 422 651 0 0 BoundingObjectImageCropper + + + + true + + + + + + + + 170 + 0 + 0 + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 170 + 0 + 0 + + + + + + + + The image cropper cannot handle 2D images + + + false 0 0 crop the selected image Crop false 0 0 crop the selected image New bounding box! -2000 2000 -1000 0 0 Set border voxel value false -2000 2000 -1000 Qt::Horizontal 0 0 Show usage information 24 0 0 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The yellow box around the selected image can be changed in size and orientation. You can use it to mark an interesing region of the image and then use the &quot;Crop&quot; button to cut off parts of the image that are outside the box.<br />The original image will not be modified, it will only be hidden.</p></body></html> Qt::AlignVCenter true 0 0 :/imagecropper/btn_ctrl.xpm false false 0 0 :/imagecropper/mouse_left.xpm false false Move the box false 0 0 :/imagecropper/btn_ctrl.xpm false false 0 0 :/imagecropper/mouse_middle.xpm false false Rotate the box false 0 0 :/imagecropper/btn_ctrl.xpm false false 0 0 :/imagecropper/mouse_right.xpm false false Resize the box false Qt::Vertical QSizePolicy::Expanding 20 200 QmitkDataStorageComboBox.h - - m_SurroundingSpin valueChanged(int) m_SurroundingSlider setValue(int) 20 20 20 20 m_SurroundingSlider valueChanged(int) m_SurroundingSpin setValue(int) 20 20 20 20 diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox index f3a1131c37..545034b0b3 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox @@ -1,44 +1,54 @@ /** \page org_mitk_views_imagestatistics The Image Statistics View \image html ImageStatistic_48.png "Icon of the View" \section QmitkImageStatisticsUserManualSummary Summary This view provides an easy interface to quickly compute some features of a whole image or a region of interest. This document will tell you how to use this view, but it is assumed that you already know how to use MITK in general. Please see \ref QmitkImageStatisticsUserManualDetails for more detailed information on usage and supported filters. If you encounter problems using the view, please have a look at the \ref QmitkImageStatisticsUserManualTrouble page. \section QmitkImageStatisticsUserManualDetails Details Manual sections: -- \ref QmitkImageStatisticsUserManualOverview +- \ref QmitkImageStatisticsUserManualOverview - \ref QmitkImageStatisticsUserManualUsage - \ref QmitkImageStatisticsUserManualTrouble \section QmitkImageStatisticsUserManualOverview Overview This view provides an easy interface to quickly compute some features of a whole image or a region of interest. \image html Screenshot1.png "The interface" \section QmitkImageStatisticsUserManualUsage Usage -After selection of an image or a binary mask of an image in the datamanader, the Image Statistics view shows some statistical information. If a mask is selected, the name of the mask and the name of the image, to which the mask is applied, are shown at the top. +After selection of an image or a binary mask of an image in the datamanager, the Image Statistics view shows some statistical information. If a mask is selected, the name of the mask and the name of the image, to which the mask is applied, are shown at the top. -Below it is the statistics window which displays the calculated statistical features (such as mean, standard deviation...) and the histogram. +Check "Ignore zero-valued voxels" to hide voxels with grayvalue zero. -At the bottom of the view are two buttons. They copy their respective data in csv format to the clipboard. +Below it is the statistics window which displays the calculated statistical features (such as mean, standard deviation...). + +Beneath the statistics window is the histogram window, which shows the histogram of the current selection. + +At top of the histogram window are two radiobuttons. Toggle one of them to either show the histogram as a barchart or as a lineplot. + +Use mousewheel to zoom in and out the histogram. With the left mouse button the histogram is pannable in zoomed state. + +If the histogram is displayed as a barchart a tooltip is available by hovering over one of the bins. A tooltip is also available, if an intesity profile is created for a path element as mask. + +At the bottom of each view is one button. They copy their respective data in csv format to the clipboard. \section QmitkImageStatisticsUserManualTrouble Troubleshooting No known problems. All other problems.
Please report to the MITK mailing list. See http://www.mitk.org/wiki/Mailinglist on how to do this. */ diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/Screenshot1.png b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/Screenshot1.png index f3a9347f68..47b4835b84 100644 Binary files a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/Screenshot1.png and b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/Screenshot1.png differ diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp index 59ce4f08d3..e909931fa7 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp @@ -1,178 +1,180 @@ /*=================================================================== 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 "QmitkImageStatisticsCalculationThread.h" //QT headers #include #include QmitkImageStatisticsCalculationThread::QmitkImageStatisticsCalculationThread():QThread(), m_StatisticsImage(NULL), m_BinaryMask(NULL), m_PlanarFigureMask(NULL), m_TimeStep(0), m_IgnoreZeros(false), m_CalculationSuccessful(false), m_StatisticChanged(false) { } QmitkImageStatisticsCalculationThread::~QmitkImageStatisticsCalculationThread() { } void QmitkImageStatisticsCalculationThread::Initialize( mitk::Image::Pointer image, mitk::Image::Pointer binaryImage, mitk::PlanarFigure::Pointer planarFig ) { // reset old values if( this->m_StatisticsImage.IsNotNull() ) this->m_StatisticsImage = 0; if( this->m_BinaryMask.IsNotNull() ) this->m_BinaryMask = 0; if( this->m_PlanarFigureMask.IsNotNull()) this->m_PlanarFigureMask = 0; // set new values if passed in if(image.IsNotNull()) this->m_StatisticsImage = image->Clone(); if(binaryImage.IsNotNull()) this->m_BinaryMask = binaryImage->Clone(); if(planarFig.IsNotNull()) this->m_PlanarFigureMask = dynamic_cast(planarFig.GetPointer()); // once clone methods for planar figures are implemented, copy the data here! } void QmitkImageStatisticsCalculationThread::SetTimeStep( int times ) { this->m_TimeStep = times; } int QmitkImageStatisticsCalculationThread::GetTimeStep() { return this->m_TimeStep; } mitk::ImageStatisticsCalculator::Statistics QmitkImageStatisticsCalculationThread::GetStatisticsData() { return this->m_StatisticsStruct; } mitk::Image::Pointer QmitkImageStatisticsCalculationThread::GetStatisticsImage() { return this->m_StatisticsImage; } void QmitkImageStatisticsCalculationThread::SetIgnoreZeroValueVoxel(bool _arg) { this->m_IgnoreZeros = _arg; } bool QmitkImageStatisticsCalculationThread::GetIgnoreZeroValueVoxel() { return this->m_IgnoreZeros; } std::string QmitkImageStatisticsCalculationThread::GetLastErrorMessage() { return m_message; } QmitkImageStatisticsCalculationThread::HistogramType::Pointer QmitkImageStatisticsCalculationThread::GetTimeStepHistogram() { return this->m_TimeStepHistogram; } bool QmitkImageStatisticsCalculationThread::GetStatisticsChangedFlag() { return m_StatisticChanged; } bool QmitkImageStatisticsCalculationThread::GetStatisticsUpdateSuccessFlag() { return m_CalculationSuccessful; } void QmitkImageStatisticsCalculationThread::run() { bool statisticCalculationSuccessful = true; mitk::ImageStatisticsCalculator::Pointer calculator = mitk::ImageStatisticsCalculator::New(); if(this->m_StatisticsImage.IsNotNull()) { calculator->SetImage(m_StatisticsImage); calculator->SetMaskingModeToNone(); } else { statisticCalculationSuccessful = false; } // Bug 13416 : The ImageStatistics::SetImageMask() method can throw exceptions, i.e. when the dimensionality // of the masked and input image differ, we need to catch them and mark the calculation as failed // the same holds for the ::SetPlanarFigure() try { if(this->m_BinaryMask.IsNotNull()) { calculator->SetImageMask(m_BinaryMask); calculator->SetMaskingModeToImage(); } if(this->m_PlanarFigureMask.IsNotNull()) { calculator->SetPlanarFigure(m_PlanarFigureMask); calculator->SetMaskingModeToPlanarFigure(); } } catch( const itk::ExceptionObject& e) { MITK_ERROR << "ITK Exception:" << e.what(); statisticCalculationSuccessful = false; } bool statisticChanged = false; calculator->SetDoIgnorePixelValue(this->m_IgnoreZeros); calculator->SetIgnorePixelValue(0); try { statisticChanged = calculator->ComputeStatistics(m_TimeStep); } catch ( mitk::Exception& e) { m_message = e.GetDescription(); statisticCalculationSuccessful = false; } catch ( const std::runtime_error &e ) { + m_message = "Exception Occurred. See log for details."; MITK_ERROR<< "Runtime Exception: " << e.what(); statisticCalculationSuccessful = false; } catch ( const std::exception &e ) { + m_message = "Exception Occurred. See log for details."; MITK_ERROR<< "Standard Exception: " << e.what(); statisticCalculationSuccessful = false; } this->m_StatisticChanged = statisticChanged; this->m_CalculationSuccessful = statisticCalculationSuccessful; if(statisticCalculationSuccessful) { this->m_StatisticsStruct = calculator->GetStatistics(m_TimeStep); if(this->m_TimeStepHistogram.IsNotNull()) { this->m_TimeStepHistogram = NULL; } this->m_TimeStepHistogram = (HistogramType*) calculator->GetHistogram(m_TimeStep); } } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp index f4b23ce932..4a7f2d3d74 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp @@ -1,696 +1,722 @@ /*=================================================================== 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 "QmitkImageStatisticsView.h" // Qt includes #include // berry includes #include // mitk includes #include "mitkNodePredicateDataType.h" #include "mitkPlanarFigureInteractor.h" // itk includes #include "itksys/SystemTools.hxx" #include #include const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics"; QmitkImageStatisticsView::QmitkImageStatisticsView(QObject* /*parent*/, const char* /*name*/) : m_Controls( NULL ), m_TimeStepperAdapter( NULL ), m_SelectedImage( NULL ), m_SelectedImageMask( NULL ), m_SelectedPlanarFigure( NULL ), m_ImageObserverTag( -1 ), m_ImageMaskObserverTag( -1 ), m_PlanarFigureObserverTag( -1 ), m_CurrentStatisticsValid( false ), m_StatisticsUpdatePending( false ), m_DataNodeSelectionChanged ( false ), m_Visible(false) { this->m_CalculationThread = new QmitkImageStatisticsCalculationThread; } QmitkImageStatisticsView::~QmitkImageStatisticsView() { if ( m_SelectedImage != NULL ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask != NULL ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure != NULL ) m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } delete this->m_CalculationThread; } void QmitkImageStatisticsView::CreateQtPartControl(QWidget *parent) { if (m_Controls == NULL) { m_Controls = new Ui::QmitkImageStatisticsViewControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); m_Controls->m_LineProfileWidget->SetPathModeToPlanarFigure(); } } void QmitkImageStatisticsView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(this->m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardHistogramButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_ButtonCopyStatisticsToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardStatisticsButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_IgnoreZerosCheckbox), SIGNAL(clicked()),(QObject*) this, SLOT(OnIgnoreZerosCheckboxClicked()) ); connect( (QObject*) this->m_CalculationThread, SIGNAL(finished()),this, SLOT( OnThreadedStatisticsCalculationEnds()),Qt::QueuedConnection); connect( (QObject*) this, SIGNAL(StatisticsUpdate()),this, SLOT( RequestStatisticsUpdate()), Qt::QueuedConnection); - connect( (QObject*) this->m_Controls->m_StatisticsTable, SIGNAL(cellDoubleClicked(int,int)),this, SLOT( JumpToCoordinates(int,int)) ); + connect( (QObject*) (this->m_Controls->m_barRadioButton), SIGNAL(clicked()), (QObject*) (this->m_Controls->m_JSHistogram), SLOT(OnBarRadioButtonSelected())); + connect( (QObject*) (this->m_Controls->m_lineRadioButton), SIGNAL(clicked()), (QObject*) (this->m_Controls->m_JSHistogram), SLOT(OnLineRadioButtonSelected())); } } void QmitkImageStatisticsView::JumpToCoordinates(int row ,int col) { mitk::Point3D world; if (row==4) world = m_WorldMin; else if (row==3) world = m_WorldMax; else return; mitk::IRenderWindowPart* part = this->GetRenderWindowPart(); if (part) { part->GetRenderWindow("axial")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetRenderWindow("sagittal")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetRenderWindow("coronal")->GetSliceNavigationController()->SelectSliceByPoint(world); } } void QmitkImageStatisticsView::OnIgnoreZerosCheckboxClicked() { emit StatisticsUpdate(); } void QmitkImageStatisticsView::OnClipboardHistogramButtonClicked() { if ( m_CurrentStatisticsValid ) { typedef mitk::ImageStatisticsCalculator::HistogramType HistogramType; const HistogramType *histogram = this->m_CalculationThread->GetTimeStepHistogram().GetPointer(); QString clipboard( "Measurement \t Frequency\n" ); for ( HistogramType::ConstIterator it = histogram->Begin(); it != histogram->End(); ++it ) { clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( it.GetMeasurementVector()[0], 0, 'f', 2 ) .arg( it.GetFrequency() ); } QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { QApplication::clipboard()->clear(); } } void QmitkImageStatisticsView::OnClipboardStatisticsButtonClicked() { if ( this->m_CurrentStatisticsValid ) { const mitk::ImageStatisticsCalculator::Statistics &statistics = this->m_CalculationThread->GetStatisticsData(); // Copy statistics to clipboard ("%Ln" will use the default locale for // number formatting) QString clipboard( "Mean \t StdDev \t RMS \t Max \t Min \t N \t V (mm³)\n" ); clipboard = clipboard.append( "%L1 \t %L2 \t %L3 \t %L4 \t %L5 \t %L6 \t %L7" ) .arg( statistics.Mean, 0, 'f', 10 ) .arg( statistics.Sigma, 0, 'f', 10 ) .arg( statistics.RMS, 0, 'f', 10 ) .arg( statistics.Max, 0, 'f', 10 ) .arg( statistics.Min, 0, 'f', 10 ) .arg( statistics.N ) .arg( m_Controls->m_StatisticsTable->item( 0, 6 )->text() ); QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { QApplication::clipboard()->clear(); } } void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, const QList &selectedNodes ) { if (this->m_Visible) { this->SelectionChanged( selectedNodes ); } else { this->m_DataNodeSelectionChanged = true; } } void QmitkImageStatisticsView::SelectionChanged(const QList &selectedNodes) { if( this->m_StatisticsUpdatePending ) { this->m_DataNodeSelectionChanged = true; return; // not ready for new data now! } if (selectedNodes.size() == this->m_SelectedDataNodes.size()) { int i = 0; for (; i < selectedNodes.size(); ++i) { if (selectedNodes.at(i) != this->m_SelectedDataNodes.at(i)) { break; } } // node selection did not change if (i == selectedNodes.size()) return; } this->ReinitData(); + if (!selectedNodes.size()) + { + m_Controls->m_JSHistogram->ClearHistogram(); + m_Controls->m_lineRadioButton->setEnabled(true); + m_Controls->m_barRadioButton->setEnabled(true); + m_Controls->m_InfoLabel->setText(QString("")); + } if(selectedNodes.size() == 1 || selectedNodes.size() == 2) { + bool isBinary = false; + selectedNodes.value(0)->GetBoolProperty("binary",isBinary); + if(isBinary) + { + m_Controls->m_JSHistogram->ClearHistogram(); + m_Controls->m_lineRadioButton->setEnabled(true); + m_Controls->m_barRadioButton->setEnabled(true); + m_Controls->m_InfoLabel->setText(QString("")); + } for (int i= 0; i< selectedNodes.size(); ++i) { this->m_SelectedDataNodes.push_back(selectedNodes.at(i)); } this->m_DataNodeSelectionChanged = false; this->m_Controls->m_ErrorMessageLabel->setText( "" ); this->m_Controls->m_ErrorMessageLabel->hide(); emit StatisticsUpdate(); } else { this->m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::ReinitData() { while( this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if(this->m_SelectedImage != NULL) { this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag); this->m_SelectedImage = NULL; } if(this->m_SelectedImageMask != NULL) { this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag); this->m_SelectedImageMask = NULL; } if(this->m_SelectedPlanarFigure != NULL) { this->m_SelectedPlanarFigure->RemoveObserver( this->m_PlanarFigureObserverTag); this->m_SelectedPlanarFigure = NULL; } this->m_SelectedDataNodes.clear(); this->m_StatisticsUpdatePending = false; m_Controls->m_ErrorMessageLabel->setText( "" ); m_Controls->m_ErrorMessageLabel->hide(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_Controls->m_LineProfileWidget->ClearItemModel(); } void QmitkImageStatisticsView::OnThreadedStatisticsCalculationEnds() { std::stringstream message; message << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->hide(); this->WriteStatisticsToGUI(); } void QmitkImageStatisticsView::UpdateStatistics() { mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); if ( renderPart == NULL ) { this->m_StatisticsUpdatePending = false; return; } m_WorldMin.Fill(-1); m_WorldMax.Fill(-1); // classify selected nodes mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); std::string maskName = std::string(); std::string maskType = std::string(); unsigned int maskDimension = 0; // reset data from last run ITKCommandType::Pointer changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::SelectedDataModified ); mitk::DataNode::Pointer planarFigureNode; for( int i= 0 ; i < this->m_SelectedDataNodes.size(); ++i) { mitk::PlanarFigure::Pointer planarFig = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); if( imagePredicate->CheckNode(this->m_SelectedDataNodes.at(i)) ) { bool isMask = false; this->m_SelectedDataNodes.at(i)->GetPropertyValue("binary", isMask); if( this->m_SelectedImageMask == NULL && isMask) { this->m_SelectedImageMask = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageMaskObserverTag = this->m_SelectedImageMask->AddObserver(itk::ModifiedEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; } else if( !isMask ) { if(this->m_SelectedImage == NULL) { this->m_SelectedImage = static_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } } } else if (planarFig.IsNotNull()) { if(this->m_SelectedPlanarFigure == NULL) { this->m_SelectedPlanarFigure = planarFig; this->m_PlanarFigureObserverTag = this->m_SelectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = this->m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; planarFigureNode = m_SelectedDataNodes.at(i); } } else { std::stringstream message; message << "" << "Invalid data node type!" << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); } } if(maskName == "") { maskName = "None"; maskType = ""; maskDimension = 0; } if (m_SelectedPlanarFigure != NULL && m_SelectedImage == NULL) { mitk::DataStorage::SetOfObjects::ConstPointer parentSet = this->GetDataStorage()->GetSources(planarFigureNode); for (int i=0; iSize(); i++) { mitk::DataNode::Pointer node = parentSet->ElementAt(i); if( imagePredicate->CheckNode(node) ) { bool isMask = false; node->GetPropertyValue("binary", isMask); if( !isMask ) { if(this->m_SelectedImage == NULL) { this->m_SelectedImage = static_cast(node->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } } } } } unsigned int timeStep = renderPart->GetTimeNavigationController()->GetTime()->GetPos(); if ( m_SelectedImage != NULL && m_SelectedImage->IsInitialized()) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { std::stringstream message; message << "Multi-component images not supported."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_Controls->m_LineProfileWidget->ClearItemModel(); + m_Controls->m_JSHistogram->ClearHistogram(); m_CurrentStatisticsValid = false; this->m_StatisticsUpdatePending = false; + m_Controls->m_lineRadioButton->setEnabled(true); + m_Controls->m_barRadioButton->setEnabled(true); + m_Controls->m_InfoLabel->setText(QString("")); return; } std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); // check time step validity if(m_SelectedImage->GetDimension() <= 3 && timeStep > m_SelectedImage->GetDimension(3)-1) { timeStep = m_SelectedImage->GetDimension(3)-1; } //// initialize thread and trigger it this->m_CalculationThread->SetIgnoreZeroValueVoxel( m_Controls->m_IgnoreZerosCheckbox->isChecked() ); this->m_CalculationThread->Initialize( m_SelectedImage, m_SelectedImageMask, m_SelectedPlanarFigure ); this->m_CalculationThread->SetTimeStep( timeStep ); std::stringstream message; message << "Calculating statistics..."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); try { // Compute statistics this->m_CalculationThread->start(); } catch ( const mitk::Exception& e) { std::stringstream message; message << "" << e.GetDescription() << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::runtime_error &e ) { // In case of exception, print error message on GUI std::stringstream message; message << "" << e.what() << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); // In case of exception, print error message on GUI std::stringstream message; message << "Error! Unequal Dimensions of Image and Segmentation. No recompute possible "; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } } else { this->m_StatisticsUpdatePending = false; } } void QmitkImageStatisticsView::SelectedDataModified() { if( !m_StatisticsUpdatePending ) { emit StatisticsUpdate(); } } void QmitkImageStatisticsView::NodeRemoved(const mitk::DataNode *node) { while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if (node->GetData() == m_SelectedImage) { m_SelectedImage = NULL; } } void QmitkImageStatisticsView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { if(this->m_DataNodeSelectionChanged) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->m_StatisticsUpdatePending = true; this->UpdateStatistics(); } } if (this->GetRenderWindowPart()) this->GetRenderWindowPart()->RequestUpdate(); } void QmitkImageStatisticsView::WriteStatisticsToGUI() { + m_Controls->m_lineRadioButton->setEnabled(true); + m_Controls->m_barRadioButton->setEnabled(true); + m_Controls->m_InfoLabel->setText(QString("")); + if(m_DataNodeSelectionChanged) { this->m_StatisticsUpdatePending = false; this->RequestStatisticsUpdate(); return; // stop visualization of results and calculate statistics of new selection } if ( this->m_CalculationThread->GetStatisticsUpdateSuccessFlag()) { if ( this->m_CalculationThread->GetStatisticsChangedFlag() ) { // Do not show any error messages m_Controls->m_ErrorMessageLabel->hide(); m_CurrentStatisticsValid = true; } + if (m_Controls->m_barRadioButton->isChecked()) + { + m_Controls->m_JSHistogram->OnBarRadioButtonSelected(); + } m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); - m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); - m_Controls->m_HistogramWidget->SetHistogram( this->m_CalculationThread->GetTimeStepHistogram().GetPointer() ); - m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); - //int timeStep = this->m_CalculationThread->GetTimeStep(); + m_Controls->m_JSHistogram->ComputeHistogram( this->m_CalculationThread->GetTimeStepHistogram().GetPointer() ); this->FillStatisticsTableView( this->m_CalculationThread->GetStatisticsData(), this->m_CalculationThread->GetStatisticsImage()); } else { m_Controls->m_SelectedMaskLabel->setText( "None" ); m_Controls->m_ErrorMessageLabel->setText( m_CalculationThread->GetLastErrorMessage().c_str() ); m_Controls->m_ErrorMessageLabel->show(); // Clear statistics and histogram this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_Controls->m_LineProfileWidget->ClearItemModel(); + //m_Controls->m_JSHistogram->clearHistogram(); m_CurrentStatisticsValid = false; + // If a (non-closed) PlanarFigure is selected, display a line profile widget if ( m_SelectedPlanarFigure != NULL ) { // check whether PlanarFigure is initialized const mitk::Geometry2D *planarFigureGeometry2D = m_SelectedPlanarFigure->GetGeometry2D(); if ( planarFigureGeometry2D == NULL ) { // Clear statistics, histogram, and GUI this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_Controls->m_LineProfileWidget->ClearItemModel(); + m_Controls->m_JSHistogram->ClearHistogram(); m_CurrentStatisticsValid = false; m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_SelectedMaskLabel->setText( "None" ); this->m_StatisticsUpdatePending = false; + m_Controls->m_lineRadioButton->setEnabled(true); + m_Controls->m_barRadioButton->setEnabled(true); + m_Controls->m_InfoLabel->setText(QString("")); return; } - // TODO: enable line profile widget - m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); - m_Controls->m_LineProfileWidget->SetImage( this->m_CalculationThread->GetStatisticsImage() ); - m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); - m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); + unsigned int timeStep = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); + m_Controls->m_JSHistogram->SetImage(this->m_CalculationThread->GetStatisticsImage()); + m_Controls->m_JSHistogram->SetPlanarFigure(m_SelectedPlanarFigure); + m_Controls->m_JSHistogram->ComputeIntensityProfile(timeStep); + m_Controls->m_lineRadioButton->setEnabled(false); + m_Controls->m_barRadioButton->setEnabled(false); + std::stringstream message; + message << "Only linegraph available for an intesityprofile!"; + m_Controls->m_InfoLabel->setText(message.str().c_str()); } } this->m_StatisticsUpdatePending = false; } void QmitkImageStatisticsView::ComputeIntensityProfile( mitk::PlanarLine* line ) { double sampling = 300; QmitkVtkHistogramWidget::HistogramType::Pointer histogram = QmitkVtkHistogramWidget::HistogramType::New(); itk::Size<1> siz; siz[0] = sampling; itk::FixedArray lower, higher; lower.Fill(0); mitk::Point3D begin = line->GetWorldControlPoint(0); mitk::Point3D end = line->GetWorldControlPoint(1); itk::Vector direction = (end - begin); higher.Fill(direction.GetNorm()); histogram->Initialize(siz, lower, higher); for(int i = 0; i < sampling; i++) { double d = m_SelectedImage->GetPixelValueByWorldCoordinate(begin + double(i)/sampling * direction); histogram->SetFrequency(i,d); } - m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); - m_Controls->m_HistogramWidget->SetHistogram( histogram ); - m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); + m_Controls->m_JSHistogram->ComputeHistogram( histogram ); } void QmitkImageStatisticsView::FillStatisticsTableView( const mitk::ImageStatisticsCalculator::Statistics &s, const mitk::Image *image ) { if (s.MaxIndex.size()==3) { mitk::Point3D index; index[0] = s.MaxIndex[0]; index[1] = s.MaxIndex[1]; index[2] = s.MaxIndex[2]; m_SelectedImage->GetGeometry()->IndexToWorld(index, m_WorldMax); index[0] = s.MinIndex[0]; index[1] = s.MinIndex[1]; index[2] = s.MinIndex[2]; m_SelectedImage->GetGeometry()->IndexToWorld(index, m_WorldMin); } int decimals = 2; mitk::PixelType doublePix = mitk::MakeScalarPixelType< double >(); mitk::PixelType floatPix = mitk::MakeScalarPixelType< float >(); if (image->GetPixelType()==doublePix || image->GetPixelType()==floatPix) decimals = 5; this->m_Controls->m_StatisticsTable->setItem( 0, 0, new QTableWidgetItem( QString("%1").arg(s.Mean, 0, 'f', decimals) ) ); this->m_Controls->m_StatisticsTable->setItem( 0, 1, new QTableWidgetItem( QString("%1").arg(s.Sigma, 0, 'f', decimals) ) ); this->m_Controls->m_StatisticsTable->setItem( 0, 2, new QTableWidgetItem( QString("%1").arg(s.RMS, 0, 'f', decimals) ) ); QString max; max.append(QString("%1").arg(s.Max, 0, 'f', decimals)); max += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 0, 3, new QTableWidgetItem( max ) ); QString min; min.append(QString("%1").arg(s.Min, 0, 'f', decimals)); min += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 0, 4, new QTableWidgetItem( min ) ); this->m_Controls->m_StatisticsTable->setItem( 0, 5, new QTableWidgetItem( QString("%1").arg(s.N) ) ); const mitk::Geometry3D *geometry = image->GetGeometry(); if ( geometry != NULL ) { const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); double volume = spacing[0] * spacing[1] * spacing[2] * (double) s.N; this->m_Controls->m_StatisticsTable->setItem( 0, 6, new QTableWidgetItem( QString("%1").arg(volume, 0, 'f', decimals) ) ); } else { this->m_Controls->m_StatisticsTable->setItem( 0, 6, new QTableWidgetItem( "NA" ) ); } } void QmitkImageStatisticsView::InvalidateStatisticsTableView() { for ( unsigned int i = 0; i < 7; ++i ) { this->m_Controls->m_StatisticsTable->setItem( 0, i, new QTableWidgetItem( "NA" ) ); } } void QmitkImageStatisticsView::Activated() { } void QmitkImageStatisticsView::Deactivated() { } void QmitkImageStatisticsView::Visible() { m_Visible = true; if (m_DataNodeSelectionChanged) { if (this->IsCurrentSelectionValid()) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->SelectionChanged(this->GetDataManagerSelection()); } m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::Hidden() { m_Visible = false; } void QmitkImageStatisticsView::SetFocus() { } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui index 0fde924582..711c668e07 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui @@ -1,342 +1,477 @@ QmitkImageStatisticsViewControls true 0 0 465 800 Form - + 0 0 Mask: None 2 Qt::Horizontal 40 20 color: rgb(255, 0, 0); Error Message Qt::AutoText Ignore zero-valued voxels Statistics - 0 + 9 - 0 + 9 - 0 + 9 - + 0 0 100 175 16777215 170 Qt::ScrollBarAlwaysOff Qt::ScrollBarAsNeeded true true true Qt::DotLine true false false 80 true 80 false true true false 25 25 false false Mean StdDev RMS Max Min N V (mm³) Component 1 0 0 Copy to Clipboard Qt::Horizontal 40 20 150 160 Histogram false - - + + 0 - + + + + 0 + 0 + + + + + + + 0 + 0 + + + - + 0 0 Copy to Clipboard Qt::Horizontal 40 20 + + + + + 0 + 0 + + + + + 0 + 50 + + + + + 16777215 + 16777215 + + + + Plot + + + + + 0 + 20 + 411 + 31 + + + + + QLayout::SetDefaultConstraint + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 10 + 0 + + + + + + + + + 0 + 0 + + + + + + + Use barchart + + + true + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Use linegraph + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + - + Qt::Vertical 20 40 QmitkVtkHistogramWidget QWidget
QmitkVtkHistogramWidget.h
1
QmitkVtkLineProfileWidget QWidget
QmitkVtkLineProfileWidget.h
1
+ + QmitkHistogramJSWidget + QWidget +
QmitkHistogramJSWidget.h
+ 1 +
diff --git a/Plugins/org.mitk.gui.qt.python.console/CMakeLists.txt b/Plugins/org.mitk.gui.qt.python.console/CMakeLists.txt deleted file mode 100644 index 59aab2aaa5..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# The project name must correspond to the directory name of your plug-in -# and must not contain periods. -if(MITK_USE_Python) - project(org_mitk_gui_qt_python_console) - - set(SWIG_PYTHON_WRAPPER _mitkCorePython SwigRuntimePython) - - MACRO_CREATE_MITK_CTK_PLUGIN( - EXPORT_DIRECTIVE CONSOLE_EXPORT - EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDENCIES QmitkExt CTK - ) - - include_directories("${MITK_WRAPPING_SOURCE_DIR}/CSwig" "${MITK_WRAPPING_BINARY_DIR}/CSwig/Core") - - target_link_libraries(org_mitk_gui_qt_python_console ${SWIG_PYTHON_WRAPPER}) - -else() - message("MITK Python Console needs Python. Enable MITK_USE_PYTHON") -endif() \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.python.console/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.python.console/documentation/doxygen/modules.dox deleted file mode 100644 index d846545dc4..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/documentation/doxygen/modules.dox +++ /dev/null @@ -1,16 +0,0 @@ -/** - \defgroup org_mitk_gui_qt_python_console org.mitk.gui.qt.python.console - \ingroup MITKPlugins - - \brief Describe your plugin here. - -*/ - -/** - \defgroup org_mitk_gui_qt_python_console_internal Internal - \ingroup org_mitk_gui_qt_python_console - - \brief This subcategory includes the internal classes of the org.mitk.gui.qt.python.console 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.python.console/files.cmake b/Plugins/org.mitk.gui.qt.python.console/files.cmake deleted file mode 100644 index 281f9b4b20..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/files.cmake +++ /dev/null @@ -1,61 +0,0 @@ -set(SRC_CPP_FILES - -) - -set(INTERNAL_CPP_FILES - mitkPluginActivator.cpp - QmitkPythonConsoleView.cpp - QmitkPythonEditor.cpp - QmitkPythonScriptEditor.cpp - QmitkPythonVariableStack.cpp - QmitkPythonCommandHistory.cpp - QmitkPythonScriptEditorHighlighter.cpp - QmitkPythonCommandHistoryTreeWidget.cpp - QmitkPythonVariableStackTreeWidget.cpp - QmitkPythonTextEditor.cpp - QmitkCTKPythonShell.cpp - QmitkPythonMediator.cpp - QmitkPythonPerspective.cpp - QmitkPythonSnippets.cpp -) - -set(UI_FILES - src/internal/QmitkPythonConsoleViewControls.ui - src/internal/QmitkPythonEditor.ui - src/internal/QmitkPythonVariableStack.ui - src/internal/QmitkPythonSnippets.ui -) - -set(MOC_H_FILES - src/internal/mitkPluginActivator.h - src/internal/QmitkPythonCommandHistory.h - src/internal/QmitkPythonCommandHistoryTreeWidget.h - src/internal/QmitkPythonConsoleView.h - src/internal/QmitkPythonEditor.h - src/internal/QmitkPythonPerspective.h - src/internal/QmitkPythonScriptEditor.h - src/internal/QmitkPythonScriptEditorHighlighter.h - src/internal/QmitkPythonTextEditor.h - src/internal/QmitkPythonVariableStack.h - src/internal/QmitkPythonSnippets.h - src/internal/QmitkPythonVariableStackTreeWidget.h - src/internal/QmitkCTKPythonShell.h -) - -set(CACHED_RESOURCE_FILES - resources/py.png - plugin.xml -) - -set(QRC_FILES - resources/QmitkPythonConsoleView.qrc -) - -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.python.console/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.python.console/manifest_headers.cmake deleted file mode 100644 index b03312206e..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/manifest_headers.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(Plugin-Name "MITK Python Console") -set(Plugin-Version "0.9") -set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") -set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.common.legacy) \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.python.console/mitkPythonPath.h.in b/Plugins/org.mitk.gui.qt.python.console/mitkPythonPath.h.in deleted file mode 100644 index 32f0dc836c..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/mitkPythonPath.h.in +++ /dev/null @@ -1,9 +0,0 @@ -#define MITK_PYTHONPATH_MITK_LIBRARY_DIRS "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@" - -#define MITK_PYTHONPATH_ITK_LIBRARY_DIRS "@ITK_LIBRARY_DIRS@" -#define MITK_PYTHONPATH_WRAP_ITK_DIR "@ITK_LIBRARY_DIRS@" - -#define MITK_PYTHONPATH_VTK_LIBRARY_DIRS "@VTK_LIBRARY_DIRS@" -#define MITK_PYTHONPATH_VTK_PYTHON_WRAPPING_DIR "@VTK_DIR@/Wrapping/Python" - -#define MITK_PYTHONPATH_OPEN_CV_LIBRARY_DIRS "@OpenCV_DIR@/lib" diff --git a/Plugins/org.mitk.gui.qt.python.console/plugin.xml b/Plugins/org.mitk.gui.qt.python.console/plugin.xml deleted file mode 100644 index 4a611a1ba6..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/plugin.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Plugins/org.mitk.gui.qt.python.console/resources/QmitkPythonConsoleView.qrc b/Plugins/org.mitk.gui.qt.python.console/resources/QmitkPythonConsoleView.qrc deleted file mode 100644 index 2d23172ff1..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/resources/QmitkPythonConsoleView.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - py.png - - diff --git a/Plugins/org.mitk.gui.qt.python.console/resources/icon.xpm b/Plugins/org.mitk.gui.qt.python.console/resources/icon.xpm deleted file mode 100644 index 9057c20bc6..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/resources/icon.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static const char * icon_xpm[] = { -"16 16 2 1", -" c #FF0000", -". c #000000", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" "}; diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkCTKPythonShell.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkCTKPythonShell.cpp deleted file mode 100644 index cd4c6b80c8..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkCTKPythonShell.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/*=================================================================== - -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 "QmitkCTKPythonShell.h" - -#include "mitkNodePredicateDataType.h" - -#include "QmitkDataStorageComboBox.h" -#include "QmitkStdMultiWidget.h" - -#include "mitkDataStorageEditorInput.h" - -// berry Includes -#include -#include -#include - -#include -#include -#include -#include - -#include - - -QmitkCTKPythonShell::QmitkCTKPythonShell(ctkAbstractPythonManager* pythonManager, QWidget* _parent) -{ - this->initialize( pythonManager ); - m_PythonManager = pythonManager; - - QmitkPythonMediator::getInstance()->registerPasteCommandClient( this ); -} - -QmitkCTKPythonShell::~QmitkCTKPythonShell() -{ - QmitkPythonMediator::getInstance()->unregisterPasteCommandClient( this ); -} - -void QmitkCTKPythonShell::dragEnterEvent(QDragEnterEvent *event) -{ - event->accept(); -} -void QmitkCTKPythonShell::paste(const QString& command) -{ - m_PythonManager->executeString( command ); -} - -void QmitkCTKPythonShell::dropEvent(QDropEvent *event) -{ - QList urls = event->mimeData()->urls(); - for(int i = 0; i < urls.size(); i++) - { - m_PythonManager->executeString(urls[i].toString()); - } -} - -bool QmitkCTKPythonShell::canInsertFromMimeData( const QMimeData *source ) const -{ - return true; -} - -void QmitkCTKPythonShell::executeCommand(const QString& command) -{ - emit this->executeCommandSignal(command); - ctkPythonConsole::executeCommand(command); - QmitkPythonMediator::getInstance()->update(); -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkCTKPythonShell.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkCTKPythonShell.h deleted file mode 100644 index 88a4b12216..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkCTKPythonShell.h +++ /dev/null @@ -1,64 +0,0 @@ -/*=================================================================== - -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 _QMITKCTKPYTHONSHELL_H -#define _QMITKCTKPYTHONSHELL_H - -#include -#include -#include "QmitkPythonMediator.h" - -#include -#include -#include - - -/*! - * \ingroup org_mitk_gui_qt_imagenavigator_internal - * - * \brief QmitkPythonVariableStack - * - * Document your class here. - * - * \sa QmitkFunctionality - */ -class QmitkCTKPythonShell : public ctkPythonConsole, public QmitkPythonPasteClient -{ - Q_OBJECT -public: - QmitkCTKPythonShell(ctkAbstractPythonManager* pythonManager, QWidget* _parent = 0); - ~QmitkCTKPythonShell(); - - virtual void paste(const QString& command); - - -protected: - virtual void dragEnterEvent(QDragEnterEvent *event); - virtual void dropEvent(QDropEvent *event); - virtual bool canInsertFromMimeData( const QMimeData *source ) const; - virtual void executeCommand(const QString& command); - -signals: - void executeCommandSignal(const QString&); -private: - ctkAbstractPythonManager* m_PythonManager; -}; - - - - -#endif // _QmitkPythonVariableStack_H_INCLUDED - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistory.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistory.cpp deleted file mode 100644 index c2990e7c94..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistory.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/*=================================================================== - -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 - -// Qmitk -#include "QmitkPythonCommandHistory.h" -#include "QmitkPythonConsoleView.h" -#include "QmitkStdMultiWidget.h" - -// Qt -#include - - - -#include "mitkCoreObjectFactory.h" -#include -#include -#include -#include -#include - -#include "berryFileEditorInput.h" -#include - -const std::string QmitkPythonCommandHistory::VIEW_ID = "org.mitk.views.pythoncommandhistory"; - -QmitkPythonCommandHistory::QmitkPythonCommandHistory() -: QmitkFunctionality() -//, m_Controls( 0 ) -, m_MultiWidget( NULL ) -{ -} - -QmitkPythonCommandHistory::~QmitkPythonCommandHistory() -{ - QmitkPythonMediator::getInstance()->unregisterClient(this); -} - - -void QmitkPythonCommandHistory::CreateQtPartControl( QWidget *parent ) -{ - QGridLayout *gridLayout; - - - if (parent->objectName().isEmpty()) - parent->setObjectName(QString::fromUtf8("parent")); - parent->resize(790, 773); - parent->setMinimumSize(QSize(0, 0)); - gridLayout = new QGridLayout(parent); - gridLayout->setObjectName(QString::fromUtf8("gridLayout")); - m_treeWidget = new QmitkPythonCommandHistoryTreeWidget(parent); - QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem(); - treeWidgetItem->setText(0, QString::fromUtf8("Command")); - treeWidgetItem->setFlags(Qt::ItemIsEditable); - m_treeWidget->setHeaderItem(treeWidgetItem); - m_treeWidget->setObjectName(QString::fromUtf8("treeWidget")); - m_treeWidget->setColumnCount(1); - m_treeWidget->setDragEnabled(true); - m_treeWidget->setDragDropMode(QAbstractItemView::DragOnly); - m_treeWidget->setAcceptDrops(false); - m_treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); - - gridLayout->addWidget(m_treeWidget, 0, 0, 1, 1); - parent->setWindowTitle(QApplication::translate("QmitkPythonConsoleViewControls", "QmitkTemplate", 0, QApplication::UnicodeUTF8)); - - QMetaObject::connectSlotsByName(parent); - QmitkPythonMediator::getInstance()->setClient(this); -} - - -void QmitkPythonCommandHistory::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) -{ - m_MultiWidget = &stdMultiWidget; -} - - -void QmitkPythonCommandHistory::StdMultiWidgetNotAvailable() -{ - m_MultiWidget = NULL; -} - -void QmitkPythonCommandHistory::AddCommand(const QString& command) -{ - m_commandHistory.push_back(QStringList() << command); - m_treeWidget->clear(); - for(int i = 0; i < m_commandHistory.size(); i++) - { - if( m_commandHistory[i].value(0).compare("") != 0 ) - m_treeWidget->addTopLevelItem(new QTreeWidgetItem(m_commandHistory[i])); - } -} - -void QmitkPythonCommandHistory::SetCommandHistory(std::vector history) -{ - m_commandHistory = history; - m_treeWidget->clear(); - for(int i = 0; i < m_commandHistory.size(); i++) - { - if( m_commandHistory[i].value(0).compare("") != 0 ) - m_treeWidget->addTopLevelItem(new QTreeWidgetItem(m_commandHistory[i])); - } -} - -void QmitkPythonCommandHistory::update() -{ - SetCommandHistory(QmitkPythonMediator::getInstance()->GetCommandHistory()); -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistory.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistory.h deleted file mode 100644 index f8c1d7e146..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistory.h +++ /dev/null @@ -1,79 +0,0 @@ -/*=================================================================== - -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 QmitkPythonCommandHistory_h -#define QmitkPythonCommandHistory_h - -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "QmitkPythonCommandHistoryTreeWidget.h" -#include "QmitkPythonMediator.h" - - -class QmitkPythonCommandHistory : public QmitkFunctionality, public QmitkPythonClient -{ - // 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; - - QmitkPythonCommandHistory(); - QmitkPythonCommandHistory(const QmitkPythonCommandHistory& other) - { - Q_UNUSED(other) - throw std::runtime_error("Copy constructor not implemented"); - } - virtual ~QmitkPythonCommandHistory(); - - virtual void CreateQtPartControl(QWidget *parent); - - virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); - virtual void StdMultiWidgetNotAvailable(); - void SetCommandHistory(std::vector); - virtual void update(); - - public slots: - void AddCommand(const QString&); - - protected slots: - - - private: - QmitkStdMultiWidget* m_MultiWidget; - std::vector m_commandHistory; - QmitkPythonCommandHistoryTreeWidget *m_treeWidget; - QmitkPythonMediator *m_PythonMediator; -}; - -#endif // _QMITKPYTHONCONSOLEVIEW_H_INCLUDED - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistoryTreeWidget.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistoryTreeWidget.cpp deleted file mode 100755 index 62605360d3..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistoryTreeWidget.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonCommandHistoryTreeWidget.h" - -#include -#include -#include -#include -#include - - -QmitkPythonCommandHistoryTreeWidget::QmitkPythonCommandHistoryTreeWidget(QWidget *parent) -:QTreeWidget(parent) -{ -} - -QmitkPythonCommandHistoryTreeWidget::~QmitkPythonCommandHistoryTreeWidget() -{ -} - -void QmitkPythonCommandHistoryTreeWidget::mouseMoveEvent(QMouseEvent *event) -{ - // if not left button - return - if (!(event->buttons() & Qt::LeftButton)) return; - - // if no item selected, return (else it would crash) - if (selectedItems().isEmpty()) return; - - QDrag *drag = new QDrag(this); - QMimeData *mimeData = new QMimeData; - - //QList list; - QList listItems = selectedItems(); - - for(int i = 0; i < listItems.size(); i++) - { - //list.append(QUrl(listItems[i]->text(0))); - mimeData->setText(listItems[i]->text(0)); - } - //mimeData->setUrls(list); - drag->setMimeData(mimeData); - - // start drag - drag->start(Qt::CopyAction | Qt::MoveAction); -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistoryTreeWidget.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistoryTreeWidget.h deleted file mode 100755 index 4fb45b2c93..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonCommandHistoryTreeWidget.h +++ /dev/null @@ -1,42 +0,0 @@ -/*=================================================================== - -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 QMITKPYTHONCOMMANDHISTORYTREEWIDGET_H_ -#define QMITKPYTHONCOMMANDHISTORYTREEWIDGET_H_ - -#include - -class QmitkPythonCommandHistoryTreeWidget : public QTreeWidget -{ - // 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: - QmitkPythonCommandHistoryTreeWidget(QWidget *parent = 0); - virtual ~QmitkPythonCommandHistoryTreeWidget(); - -signals: - -protected slots: - -protected: - virtual void mouseMoveEvent(QMouseEvent *event); - -private: -}; - -#endif diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleView.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleView.cpp deleted file mode 100644 index 44033d205b..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleView.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/*=================================================================== - -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 - -// Qmitk -#include "QmitkPythonConsoleView.h" -#include "QmitkStdMultiWidget.h" - -// Qt -#include -#include - -#include "mitkCoreObjectFactory.h" -#include -#include -#include -#include -#include -#include -//#include - -#include "berryFileEditorInput.h" -#include - -#include "QmitkPythonVariableStack.h" -#include "QmitkPythonCommandHistory.h" -#include "mitkPythonPath.h" - - -const std::string QmitkPythonConsoleView::VIEW_ID = "org.mitk.views.pythonconsole"; - -QmitkPythonConsoleView::QmitkPythonConsoleView() -: QmitkFunctionality() -//, m_Controls( 0 ) -, m_MultiWidget( NULL ) -,m_ctkPythonManager( NULL ) -,m_ctkPythonShell( NULL ) -{ - // TODO: take it to the activator -// std::cout << "running PYTHON PATH COMMANDS" << std::endl; - - QmitkPythonMediator::getInstance()->runSimpleString("import sys"); - - std::string cmd ( "sys.path.append('" MITK_PYTHONPATH_MITK_LIBRARY_DIRS "');" ); - QmitkPythonMediator::getInstance()->runSimpleString(cmd.c_str()); - - cmd = "sys.path.append('" MITK_PYTHONPATH_ITK_LIBRARY_DIRS "');"; - QmitkPythonMediator::getInstance()->runSimpleString(cmd.c_str()); - - cmd = "sys.path.append('" MITK_PYTHONPATH_WRAP_ITK_DIR "');"; - QmitkPythonMediator::getInstance()->runSimpleString(cmd.c_str()); - - cmd = "sys.path.append('" MITK_PYTHONPATH_VTK_LIBRARY_DIRS "');"; - QmitkPythonMediator::getInstance()->runSimpleString(cmd.c_str()); - - cmd = "sys.path.append('" MITK_PYTHONPATH_VTK_PYTHON_WRAPPING_DIR "');"; - QmitkPythonMediator::getInstance()->runSimpleString(cmd.c_str()); - - if( strcmp("", MITK_PYTHONPATH_OPEN_CV_LIBRARY_DIRS) != 0 ) - { -// std::cout << "setting opencv PYTHON PATH" << std::endl; - cmd = "sys.path.append('" MITK_PYTHONPATH_OPEN_CV_LIBRARY_DIRS "');"; - QmitkPythonMediator::getInstance()->runSimpleString(cmd.c_str()); - } -} - -QmitkPythonConsoleView::~QmitkPythonConsoleView() -{ - QmitkPythonMediator::getInstance()->unregisterClient(this); -} - - -void QmitkPythonConsoleView::CreateQtPartControl( QWidget *parent ) -{ - QGridLayout *gridLayout; - if (parent->objectName().isEmpty()) - parent->setObjectName(QString::fromUtf8("parent")); - parent->resize(790, 774); - parent->setMinimumSize(QSize(0, 0)); - gridLayout = new QGridLayout(parent); - gridLayout->setObjectName(QString::fromUtf8("gridLayout")); - m_ctkPythonManager = new ctkAbstractPythonManager(parent); - m_ctkPythonShell = new QmitkCTKPythonShell(m_ctkPythonManager, parent); - m_ctkPythonShell->setObjectName(QString::fromUtf8("m_ctkPythonShell")); - m_ctkPythonShell->setMinimumSize(QSize(120, 100)); - m_ctkPythonShell->setMaximumSize(QSize(2000, 2000)); - gridLayout->addWidget(m_ctkPythonShell, 0, 0, 1, 1); - m_ButtonOpenEditor = new QPushButton(parent); - m_ButtonOpenEditor->setObjectName(QString::fromUtf8("m_ButtonOpenEditor")); - gridLayout->addWidget(m_ButtonOpenEditor, 1, 0, 1, 1); - parent->setWindowTitle(QApplication::translate("parent", "QmitkTemplate", 0, QApplication::UnicodeUTF8)); - m_ButtonOpenEditor->setText(QApplication::translate("parent", "Open Editor", 0, QApplication::UnicodeUTF8)); - QMetaObject::connectSlotsByName(parent); - mitk::DataStorage::Pointer dataStorage = this->GetDefaultDataStorage(); - - m_ctkPythonManager->executeString("import mitk"); - QmitkPythonMediator::getInstance()->setClient(this); - QmitkPythonMediator::getInstance()->update(); - - connect( m_ctkPythonShell, SIGNAL(executeCommandSignal(const QString&)), - this, SLOT(SetCommandHistory(const QString&))); - connect( m_ButtonOpenEditor, SIGNAL(clicked()), this, SLOT(OpenEditor()) ); -} - - -void QmitkPythonConsoleView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) -{ - m_MultiWidget = &stdMultiWidget; -} - - -void QmitkPythonConsoleView::StdMultiWidgetNotAvailable() -{ - m_MultiWidget = NULL; -} - - -void QmitkPythonConsoleView::OnSelectionChanged( std::vector nodes ) -{ - for( std::vector::iterator it = nodes.begin(); - it != nodes.end(); - ++it ) - { - mitk::DataNode::Pointer node = *it; - - if( node.IsNotNull() && dynamic_cast(node->GetData()) ) - { - return; - } - } -} - -void QmitkPythonConsoleView::NodeAdded(const mitk::DataNode* node) -{ -} - -void QmitkPythonConsoleView::OpenEditor() -{ - berry::FileEditorInput::Pointer editorInput; - editorInput = new berry::FileEditorInput(""); - m_PythonEditor = this->GetSite()->GetPage()->OpenEditor(editorInput, QmitkPythonEditor::EDITOR_ID, true, berry::IWorkbenchPage::MATCH_NONE).Cast(); - -} - -void QmitkPythonConsoleView::SetCommandHistory(const QString& command) -{ - QmitkPythonMediator::getInstance()->SetCommandHistory(command); -// QmitkPythonMediator::getInstance()->update(); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkPythonConsoleView::update() -{ - //QmitkPythonMediator::runSimpleString("\r\n"); -} - -QmitkPythonMediator *QmitkPythonConsoleView::getPythonMediator() -{ - return m_PythonMediator; -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleView.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleView.h deleted file mode 100644 index 59b337c4cb..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleView.h +++ /dev/null @@ -1,97 +0,0 @@ -/*=================================================================== - -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 QmitkPythonConsoleView_h -#define QmitkPythonConsoleView_h - -#include - -#include -#include "QmitkPythonEditor.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -//#include "ctkPythonShell.h" -#include "QmitkCTKPythonShell.h" -#include "ctkAbstractPythonManager.h" -#include "QmitkPythonMediator.h" - - - -/*! - \brief QmitkPythonConsoleView - - \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. - - \sa QmitkFunctionality - \ingroup Functionalities -*/ - - -class QmitkPythonConsoleView : public QmitkFunctionality, public QmitkPythonClient -{ - // 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; - - QmitkPythonConsoleView(); - QmitkPythonConsoleView(const QmitkPythonConsoleView& other) - { - Q_UNUSED(other) - throw std::runtime_error("Copy constructor not implemented"); - } - virtual ~QmitkPythonConsoleView(); - - virtual void CreateQtPartControl(QWidget *parent); - - virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); - virtual void StdMultiWidgetNotAvailable(); - virtual void NodeAdded(const mitk::DataNode* node); - virtual void update(); - QmitkPythonMediator *getPythonMediator(); - - protected slots: - void OpenEditor(); - void SetCommandHistory(const QString&); - - protected: - virtual void OnSelectionChanged( std::vector nodes ); - QmitkStdMultiWidget* m_MultiWidget; - - berry::SmartPointer m_PythonEditor; - private: - FILE * m_scriptFile; - QmitkCTKPythonShell *m_ctkPythonShell; - ctkAbstractPythonManager *m_ctkPythonManager; - QPushButton *m_ButtonOpenEditor; - QmitkPythonMediator *m_PythonMediator; -}; - -#endif // _QMITKPYTHONCONSOLEVIEW_H_INCLUDED - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleViewControls.ui b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleViewControls.ui deleted file mode 100644 index 0bf83d1d3d..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonConsoleViewControls.ui +++ /dev/null @@ -1,58 +0,0 @@ - - - QmitkPythonConsoleViewControls - - - - 0 - 0 - 790 - 774 - - - - - 0 - 0 - - - - QmitkTemplate - - - - - - - 120 - 100 - - - - - 1000 - 1000 - - - - - - - - Open Editor - - - - - - - - ctkPythonShell - QWidget -
ctkPythonShell.h
- 1 -
-
- - -
diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.cpp deleted file mode 100644 index 29f1126980..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonEditor.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "berryFileEditorInput.h" - -const std::string QmitkPythonEditor::EDITOR_ID = "org.mitk.editors.pythoneditor"; - -QmitkPythonEditor::QmitkPythonEditor() -{ - -} - -QmitkPythonEditor::~QmitkPythonEditor() -{ -} - -void QmitkPythonEditor::CreateQtPartControl(QWidget* parent) -{ - m_PythonScriptEditor = new QmitkPythonScriptEditor(parent); - - if (parent->objectName().isEmpty()) - parent->setObjectName(QString::fromUtf8("parent")); - parent->resize(790, 773); - parent->setMinimumSize(QSize(0, 0)); - QGridLayout *gridLayout = new QGridLayout(parent); - gridLayout->setObjectName(QString::fromUtf8("gridLayout")); - gridLayout->addWidget(m_PythonScriptEditor, 0, 0, 1, 3); - - QMetaObject::connectSlotsByName(parent); -} - -void QmitkPythonEditor::Init(berry::IEditorSite::Pointer site, berry::IEditorInput::Pointer input) -{ - if (input.Cast().IsNull()) - throw berry::PartInitException("Invalid Input: Must be FileEditorInput"); - - this->SetSite(site); - this->SetInput(input); -} - -void QmitkPythonEditor::SetFocus() -{ -} - -berry::IPartListener::Events::Types QmitkPythonEditor::GetPartEventTypes() const -{ - return Events::CLOSED | Events::HIDDEN | Events::VISIBLE; -} - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.h deleted file mode 100644 index da49644f58..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.h +++ /dev/null @@ -1,69 +0,0 @@ -/*=================================================================== - -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 QMITKPYTHONEDITOR_H_ -#define QMITKPYTHONEDITOR_H_ - -#include -#include - -#include - -#include "mitkQtCommonDll.h" - -#include -#include -#include -#include "QmitkPythonScriptEditor.h" - -class QmitkPythonEditor : public berry::QtEditorPart, virtual public berry::IPartListener -{ - - Q_OBJECT - -public: - berryObjectMacro(QmitkPythonEditor); - - static const std::string EDITOR_ID; - - QmitkPythonEditor(); - QmitkPythonEditor(const QmitkPythonEditor& other) - { - Q_UNUSED(other) - throw std::runtime_error("Copy constructor not implemented"); - } - ~QmitkPythonEditor(); - - void Init(berry::IEditorSite::Pointer site, berry::IEditorInput::Pointer input); - - void SetFocus(); - - void DoSave() {} - void DoSaveAs() {} - bool IsDirty() const { return false; } - bool IsSaveAsAllowed() const { return false; } - -protected: - - void CreateQtPartControl(QWidget* parent); - - Events::Types GetPartEventTypes() const; - -private: - QmitkPythonScriptEditor *m_PythonScriptEditor; -}; - -#endif diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.ui b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.ui deleted file mode 100644 index bd7aa02b68..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonEditor.ui +++ /dev/null @@ -1,51 +0,0 @@ - - - QmitkPythonConsoleViewControls - - - - 0 - 0 - 790 - 773 - - - - - 0 - 0 - - - - QmitkTemplate - - - - - - - - - Load Script - - - - - - - Save Script - - - - - - - Run Script - - - - - - - - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonMediator.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonMediator.cpp deleted file mode 100755 index be79ea40a2..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonMediator.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonMediator.h" -#include - -QmitkPythonMediator::QmitkPythonMediator() -{ -} - -QmitkPythonMediator::~QmitkPythonMediator() -{ -} - -void QmitkPythonMediator::Initialize() -{ - if(!Py_IsInitialized()) - Py_Initialize(); -} - -void QmitkPythonMediator::Finalize() -{ - if(m_clients.size() == 0) - Py_Finalize(); -} - -QmitkPythonMediator *QmitkPythonMediator::getInstance() -{ - static QmitkPythonMediator m_mediatorInstance; - return &m_mediatorInstance; -} - -void QmitkPythonMediator::paste(const QString& pasteCommand) -{ - std::set::iterator it - = m_PasteClients.begin(); - - while( it!= m_PasteClients.end()) - { - (*it)->paste( pasteCommand ); - ++it; - } -} - -void QmitkPythonMediator::runSimpleString(const char* str) -{ - if(!Py_IsInitialized()){ - Py_Initialize(); - } - PyRun_SimpleString(str); -} - -std::vector QmitkPythonMediator::getAttributeList() -{ - PyObject* dict = PyImport_GetModuleDict(); - PyObject* object = PyDict_GetItemString(dict, "__main__"); - PyObject* dirMain = PyObject_Dir(object); - PyObject* tempObject; - std::vector variableStack; - - if(dirMain){ - QString attr, attrValue, attrType; - variableStack.clear(); - for(int i = 0; iob_type->tp_name; - if(PyUnicode_Check(tempObject) || PyString_Check(tempObject)) - attrValue = PyString_AsString(tempObject); - else - attrValue = ""; - variableStack.push_back(QStringList() << attr << attrValue << attrType); - } - } - return variableStack; -} - -PyObject * QmitkPythonMediator::getPyObject(PyObject * object) -{ - PyObject* dict = PyImport_GetModuleDict(); - PyObject* main = PyDict_GetItemString(dict, "__main__"); - return PyObject_GetAttr(main, object); -} - -PyObject * QmitkPythonMediator::getPyObjectString(QString * objectName) -{ - PyObject* dict = PyImport_GetModuleDict(); - PyObject* main = PyDict_GetItemString(dict, "__main__"); - return PyObject_GetAttrString(main, objectName->toLocal8Bit().data()); -} - -void QmitkPythonMediator::registerPasteCommandClient(QmitkPythonPasteClient * client ) -{ - m_PasteClients.insert( client ); -} - -void QmitkPythonMediator::unregisterPasteCommandClient(QmitkPythonPasteClient * client) -{ - m_PasteClients.erase( client ); -} - -void QmitkPythonMediator::setClient(QmitkPythonClient * client) -{ - m_clients.insert(client); -} - -void QmitkPythonMediator::unregisterClient(QmitkPythonClient * client) -{ - m_clients.erase( client ); -} - -void QmitkPythonMediator::update() -{ - if(Py_IsInitialized) - { - std::set::iterator it - = m_clients.begin(); - - while( it!= m_clients.end()) - { - (*it)->update(); - ++it; - } - } -} - -void QmitkPythonMediator::SetCommandHistory(const QString& command) -{ - m_commandHistory.push_back(QStringList() << command); -} - -std::vector QmitkPythonMediator::GetCommandHistory() -{ - return m_commandHistory; -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonMediator.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonMediator.h deleted file mode 100755 index 845f052245..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonMediator.h +++ /dev/null @@ -1,74 +0,0 @@ -/*=================================================================== - -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 QmitkPythonMediator_h -#define QmitkPythonMediator_h - -#include -#include -#include -#include -#include -#include "mitkCommon.h" - -class QmitkPythonClient -{ - public: - virtual ~QmitkPythonClient(){}; - virtual void update() = 0; -}; - -class QmitkPythonPasteClient -{ - public: - virtual ~QmitkPythonPasteClient(){}; - virtual void paste(const QString&) = 0; -}; - -class QmitkPythonMediator -{ - public: - void update(); - - static void runSimpleString(const char*); - static std::vector getAttributeList(); - static PyObject * getPyObject(PyObject * object); - static PyObject * getPyObjectString(QString * objectName); - static QmitkPythonMediator *getInstance(); - - void setClient(QmitkPythonClient *); - void unregisterClient(QmitkPythonClient *); - void registerPasteCommandClient(QmitkPythonPasteClient *); - void unregisterPasteCommandClient(QmitkPythonPasteClient *); - void paste(const QString& pasteCommand); - std::vector GetCommandHistory(); - void SetCommandHistory(const QString&); - void Initialize(); - void Finalize(); - - protected: - QmitkPythonMediator(); - virtual ~QmitkPythonMediator(); - - private: - std::set m_clients; - std::set m_PasteClients; - std::vector m_commandHistory; - std::vector m_variableStack; -}; - -#endif // _QMITKPYTHONCONSOLEVIEW_H_INCLUDED - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonPerspective.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonPerspective.cpp deleted file mode 100644 index f4bd8e2867..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonPerspective.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonPerspective.h" -#include "berryIViewLayout.h" - - -void QmitkPythonPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) -{ - std::string editorArea = layout->GetEditorArea(); - - layout->AddView("org.mitk.views.datamanager", - berry::IPageLayout::LEFT, 0.3f, editorArea); - layout->AddView("org.mitk.views.pythoncommandhistory", - berry::IPageLayout::TOP, 0.3f, "org.mitk.views.datamanager"); - - berry::IViewLayout::Pointer lo = layout->GetViewLayout("org.mitk.views.datamanager"); - lo->SetCloseable(false); - - berry::IFolderLayout::Pointer leftbottomFolder = layout->CreateFolder("leftbottom", berry::IPageLayout::BOTTOM, 0.7f, "org.mitk.views.datamanager"); - leftbottomFolder->AddView("org.mitk.views.pythonvariablestack"); - leftbottomFolder->AddView("org.mitk.views.pythonsnippets"); - leftbottomFolder->AddView("org.mitk.views.imagenavigator"); - - berry::IFolderLayout::Pointer bottomFolder = layout->CreateFolder("bottom", berry::IPageLayout::BOTTOM, 0.7f, editorArea); - bottomFolder->AddView("org.mitk.views.pythonconsole"); - bottomFolder->AddView("org.mitk.views.propertylistview"); - bottomFolder->AddView("org.blueberry.views.logview"); -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditor.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditor.cpp deleted file mode 100644 index a208d47db3..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditor.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonScriptEditor.h" -//#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "berryFileEditorInput.h" -#include -#include - -#include "QmitkPythonConsoleView.h" -#include "QmitkPythonVariableStack.h" -#include "QmitkPythonScriptEditorHighlighter.h" - -#include "QmitkPythonMediator.h" - -const std::string QmitkPythonScriptEditor::EDITOR_ID = "org.mitk.editors.pythonscripteditor"; - -QmitkPythonScriptEditor::QmitkPythonScriptEditor(QWidget *parent) -:QWidget(parent) -{ - QGridLayout *gridLayout; - QPushButton *buttonLoadScript; - QPushButton *buttonSaveScript; - QPushButton *buttonRunScript; - - if (parent->objectName().isEmpty()) - parent->setObjectName(QString::fromUtf8("parent")); - parent->resize(790, 773); - parent->setMinimumSize(QSize(0, 0)); - gridLayout = new QGridLayout(parent); - gridLayout->setObjectName(QString::fromUtf8("gridLayout")); - m_TextEditor = new QTextEdit(parent); - m_TextEditor->setObjectName(QString::fromUtf8("m_TextEditor")); - m_TextEditor->viewport()->setAcceptDrops(true); - - QmitkPythonScriptEditorHighlighter *highlighter = new QmitkPythonScriptEditorHighlighter(m_TextEditor->document()); - - gridLayout->addWidget(m_TextEditor, 0, 0, 1, 3); - - buttonLoadScript = new QPushButton(parent); - buttonLoadScript->setObjectName(QString::fromUtf8("buttonLoadScript")); - - gridLayout->addWidget(buttonLoadScript, 1, 0, 1, 1); - - buttonSaveScript = new QPushButton(parent); - buttonSaveScript->setObjectName(QString::fromUtf8("buttonSaveScript")); - - gridLayout->addWidget(buttonSaveScript, 1, 1, 1, 1); - - buttonRunScript = new QPushButton(parent); - buttonRunScript->setObjectName(QString::fromUtf8("buttonRunScript")); - - gridLayout->addWidget(buttonRunScript, 1, 2, 1, 1); - parent->setWindowTitle(QApplication::translate("parent", "QmitkTemplate", 0, QApplication::UnicodeUTF8)); - buttonLoadScript->setText(QApplication::translate("parent", "Load Script", 0, QApplication::UnicodeUTF8)); - buttonSaveScript->setText(QApplication::translate("parent", "Save Script", 0, QApplication::UnicodeUTF8)); - buttonRunScript->setText(QApplication::translate("parent", "Run Script", 0, QApplication::UnicodeUTF8)); - - QMetaObject::connectSlotsByName(parent); - - connect(buttonLoadScript, SIGNAL(clicked()), this, SLOT(OpenScript())); - connect(buttonSaveScript, SIGNAL(clicked()), this, SLOT(SaveScript())); - connect(buttonRunScript, SIGNAL(clicked()), this, SLOT(RunScript())); - QmitkPythonMediator::getInstance()->Initialize(); - QmitkPythonMediator::getInstance()->registerPasteCommandClient( this ); -} - -QmitkPythonScriptEditor::~QmitkPythonScriptEditor() -{ - QmitkPythonMediator::getInstance()->unregisterPasteCommandClient( this ); - QmitkPythonMediator::getInstance()->Finalize(); -} - -void QmitkPythonScriptEditor::paste(const QString& command) -{ - if( this->isVisible() ) - m_TextEditor->append(command); -} -void QmitkPythonScriptEditor::LoadScript(const char* filename){ - std::istream* fileStream = new std::ifstream(filename); - char line[255]; - QString qline; - m_TextEditor->setText(""); - m_scriptFile = fopen(filename, "r"); - if(fileStream) - { - while(!fileStream->eof()) - { - fileStream->getline(line,255); - qline = line; - m_TextEditor->append(qline); - } - } - else - { - } -} - -void QmitkPythonScriptEditor::SaveScript(){ - QString fileName = QFileDialog::getSaveFileName(this,tr("Save File"),"",tr("*.py")); - if(fileName.compare("") != 0) - { - ofstream myfile; - myfile.open(fileName.toLocal8Bit().data()); - myfile << m_TextEditor->toPlainText().toLocal8Bit().data(); - myfile.close(); - } -} - -void QmitkPythonScriptEditor::OpenScript(){ - QString fileName = QFileDialog::getOpenFileName(NULL,mitk::CoreObjectFactory::GetInstance()->GetFileExtensions(),"",tr("*.py")); - if(fileName.compare("") != 0) - LoadScript(fileName.toStdString().c_str()); -} - -void QmitkPythonScriptEditor::RunScript(){ - QmitkPythonMediator::runSimpleString(m_TextEditor->toPlainText().toLocal8Bit().data()); - QmitkPythonMediator::getInstance()->update(); -} - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditor.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditor.h deleted file mode 100644 index 7ba84380ab..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonScriptEditor.h +++ /dev/null @@ -1,69 +0,0 @@ -/*=================================================================== - -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 QMITKPYTHONSCRIPTEDITOR_H_ -#define QMITKPYTHONSCRIPTEDITOR_H_ - -#include -#include - -#include "QmitkPythonTextEditor.h" -//#include - -#include "mitkQtCommonDll.h" - -#include -#include -#include -#include - -#include -#include "QmitkPythonMediator.h" - -class QmitkPythonScriptEditor : public QWidget, public QmitkPythonPasteClient //, berry::QtEditorPart -{ - // 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: - berryObjectMacro(QmitkPythonScriptEditor); - - static const std::string EDITOR_ID; - - QmitkPythonScriptEditor(QWidget *parent = 0); - virtual void paste(const QString& command); - ~QmitkPythonScriptEditor(); - -signals: - void RanScript(); - -protected slots: - /// \brief Called when the user clicks the GUI button - void LoadScript(const char *); - void SaveScript(); - void OpenScript(); - void RunScript(); - -protected: - -private: - QTextEdit* m_TextEditor; - FILE *m_scriptFile; - QmitkPythonMediator *m_PythonMediator; -}; - -#endif diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.cpp deleted file mode 100644 index 7ead0eb97c..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonSnippets.h" - -#include "mitkNodePredicateDataType.h" - -#include "QmitkDataStorageComboBox.h" -#include "QmitkStdMultiWidget.h" -#include "QmitkPythonConsoleView.h" - -#include "mitkDataStorageEditorInput.h" - -// berry Includes -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "QmitkPythonMediator.h" -#include "QmitkPythonScriptEditorHighlighter.h" - -const std::string QmitkPythonSnippets::VIEW_ID = "org.mitk.views.pythonsnippets"; - -std::map QmitkPythonSnippets::CreateDefaultSnippets() -{ - std::map defaultSnippets; - - defaultSnippets["itk image processing"] = - "import itk\n" - "import mitkCast\n\n" - "print 'using ITK ' + itk.Version.GetITKVersion()\n" - "itkImage = mitkCast.node2itk( Pic3D, itk.Image.US3 )\n" - "kernel = itk.strel( 3, 3 )\n" - "filter = itk.GrayscaleDilateImageFilter[itkImage,itkImage,kernel].New( itkImage, Kernel=kernel )\n" - "filter.Update()\n" - "Pic3DFiltered = mitkCast.itk2node( filter.GetOutput(), 'Pic3DFiltered' )\n"; - - defaultSnippets["itk batch image processing"] = - "import itk\n" - "import mitkCast\n\n" - "print 'using ITK ' + itk.Version.GetITKVersion()\n" - "itkImage = mitkcast.node2itk( Pic3D, itk.Image.US3 )\n" - "for s in range(5):\n" - "kernel = itk.strel( 3, s+1 )\n" - "filter = itk.GrayscaleDilateImageFilter[itkImage,itkImage,kernel].New( itkImage, Kernel=kernel )\n" - "filter.Update()\n" - "exec( \"newnode_\" + str(s+1) + \" = mitkcast.itk2node( filter.GetOutput(), 'demo_\" + str(s+1) + \"')\" )\n"; - - defaultSnippets["Import itk and vtk"] = - "import itk, vtk"; - - return defaultSnippets; -} - -const std::map QmitkPythonSnippets::DEFAULT_SNIPPETS - = QmitkPythonSnippets::CreateDefaultSnippets(); - -QmitkPythonSnippets::QmitkPythonSnippets() -: m_MultiWidget(NULL) -, m_Controls(0) -{ -} - -QmitkPythonSnippets::~QmitkPythonSnippets() -{ - berry::IPreferencesService::Pointer _PreferencesService = - berry::Platform::GetServiceRegistry().GetServiceById( - berry::IPreferencesService::ID); - berry::IPreferences::Pointer node = _PreferencesService->GetSystemPreferences()->Node(VIEW_ID); - std::map::iterator it - = m_Snippets.begin(); - - node->Clear(); - while( it != m_Snippets.end() ) - { - QString snippet = QString::fromStdString(it->second); - snippet = snippet.replace("\n", "
"); -// std::cout << "adding " << it->first << ": " << snippet.toStdString() << std::endl; - node->Put( it->first, snippet.toStdString() ); - ++it; - } - node->Flush(); -} - -void QmitkPythonSnippets::CreateQtPartControl(QWidget *parent) -{ - if( !m_Controls ) - { - m_Controls = new Ui::QmitkPythonSnippets; - m_Controls->setupUi( parent ); - QmitkPythonScriptEditorHighlighter *highlighter = - new QmitkPythonScriptEditorHighlighter(m_Controls->Content->document()); - } - - // get all snippets - berry::IPreferencesService::Pointer _PreferencesService = - berry::Platform::GetServiceRegistry().GetServiceById( - berry::IPreferencesService::ID); - - // insert default snippets if there were no prefs before - if( !_PreferencesService->GetSystemPreferences()->NodeExists(VIEW_ID) ) - { - m_Snippets = DEFAULT_SNIPPETS; - } - else - { - berry::IPreferences::Pointer node = _PreferencesService->GetSystemPreferences()->Node(VIEW_ID); - std::vector keys = node->Keys(); - std::string snippet; - for( size_t i = 0; i < keys.size(); ++i) - { -// std::cout << "inserting " << keys.at(i) << std::endl; - snippet = node->Get( keys.at(i), "" ); - QString qsnippet = QString::fromStdString(snippet); - qsnippet = qsnippet.replace("
", "\n"); -// std::cout << "inserting " << keys.at(i) << ": " << qsnippet.toStdString() << std::endl; - m_Snippets[keys.at(i)] = qsnippet.toStdString(); - } - } - - this->Update(); - - connect( m_Controls->Name, SIGNAL(currentIndexChanged(int)), this, SLOT(on_Name_currentIndexChanged(int)) ); - connect( m_Controls->AddNewSnippet, SIGNAL(clicked()), this, SLOT(on_AddNewSnippet_clicked()) ); - connect( m_Controls->RemoveSnippet, SIGNAL(clicked()), this, SLOT(on_RemoveSnippet_clicked()) ); - connect( m_Controls->PasteNow, SIGNAL(clicked()), this, SLOT(on_PasteNow_clicked()) ); - connect( m_Controls->Content, SIGNAL(textChanged()), this, SLOT(on_Content_textChanged()) ); - connect( m_Controls->RenameSnippet, SIGNAL(clicked()), - this, SLOT(on_RenameSnippet_clicked()) ); - connect( m_Controls->RestoreDefaultSnippets, SIGNAL(clicked()), - this, SLOT(on_RestoreDefaultSnippets_clicked()) ); -} - -void QmitkPythonSnippets::SetFocus () -{ - -} - -int QmitkPythonSnippets::GetSizeFlags(bool width) -{ - if(!width) - { - return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; - } - else - { - return 0; - } -} - -int QmitkPythonSnippets::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) -{ - if(width==false) - { - return 160; - } - else - { - return preferredResult; - } -} - -void QmitkPythonSnippets::on_Name_currentIndexChanged(int i) -{ -// std::cout << "on_Name_currentIndexChanged" << std::endl; - if( m_Controls->Name->count() == 0 ) - return; - QString name = m_Controls->Name->currentText(); - m_Controls->Content->setText( QString::fromStdString(m_Snippets[name.toStdString()]) ); -} - -void QmitkPythonSnippets::CreateUniqueName( QString& name ) -{ - QString basename = name; - size_t i = 2; - while( m_Snippets.find(name.toStdString()) != m_Snippets.end() ) - { - name = basename + QString("_%1").arg(i); - ++i; - } -} - -void QmitkPythonSnippets::on_RestoreDefaultSnippets_clicked() -{ - QString question = QString("Really restore default Snippets?"); - int remove = QMessageBox::question( QApplication::topLevelWidgets().at(0), - QString("Confirm restoring"), - question, - QMessageBox::Yes | QMessageBox::No, - QMessageBox::No ); - if( remove == QMessageBox::Yes || remove == QMessageBox::Ok ) - { - std::map::const_iterator it - = DEFAULT_SNIPPETS.begin(); - while( it != DEFAULT_SNIPPETS.end() ) - { - m_Snippets[it->first] = it->second; - ++it; - } - this->Update(); - } - -} - -void QmitkPythonSnippets::on_AddNewSnippet_clicked() -{ - QString name = "newSnippet"; - CreateUniqueName(name); - m_Snippets[name.toStdString()] = ""; - m_NameToSelect = name; - this->Update(); -} - -void QmitkPythonSnippets::on_RemoveSnippet_clicked() -{ - if( m_Controls->Name->count() == 0 ) - return; - QString name = m_Controls->Name->currentText(); - QString question = QString("Really remove Snippet %1?").arg(name); - int remove = QMessageBox::question( QApplication::topLevelWidgets().at(0), - QString("Confirm removal"), - question, - QMessageBox::Yes | QMessageBox::No, - QMessageBox::No ); - if( remove == QMessageBox::Yes || remove == QMessageBox::Ok ) - { - std::map::iterator it - = m_Snippets.find( name.toStdString() ); - if( it!= m_Snippets.end() ) - { -// std::cout << "removing " << it->first << std::endl; - m_Snippets.erase(it); - } - this->Update(); - } -} - -void QmitkPythonSnippets::on_PasteNow_clicked() -{ - if( m_Controls->Name->count() == 0 ) - return; - - QString name = m_Controls->Name->currentText(); - QString snippet = QString::fromStdString(m_Snippets[name.toStdString()]); - QmitkPythonMediator::getInstance()->paste( snippet ); - QmitkPythonMediator::getInstance()->update(); -} - -void QmitkPythonSnippets::on_Content_textChanged() -{ - if( m_Controls->Name->count() == 0 ) - return; - - std::string name = (m_Controls->Name->currentText()).toStdString(); - std::string snippet = m_Controls->Content->toPlainText().toStdString(); - - if( m_Snippets.find(name) != m_Snippets.end() ) - m_Snippets[name] = snippet; -} - -void QmitkPythonSnippets::on_RenameSnippet_clicked() -{ -// std::cout << "on_Name_editTextChanged" << std::endl; - if( m_Controls->Name->count() == 0 ) - return; - - QString newName; - bool repeat = false; - do - { - newName = QInputDialog::getText( QApplication::topLevelWidgets().at(0), - "Name the Snippet", "Name:", QLineEdit::Normal, - m_NameToSelect, &repeat ); - - if( newName != m_Controls->Name->currentText() ) - { - repeat = m_Snippets.find(newName.toStdString()) != m_Snippets.end() - || newName.isEmpty(); - if( repeat ) - QMessageBox::information( QApplication::topLevelWidgets().at(0) - , QString("Invalid Name"), - "Invalid name. Please enter another one"); - } - else - repeat = false; - } - while( repeat ); - - - // name changed - if( newName != m_Controls->Name->currentText() ) - { - std::map::iterator it - = m_Snippets.find( m_NameToSelect.toStdString() ); - std::string snippet = it->second; - m_Snippets.erase(it); - m_Snippets[newName.toStdString()] = snippet; - m_NameToSelect = newName; - this->Update(); - } -} - -void QmitkPythonSnippets::Update() -{ - if( m_NameToSelect.isEmpty() ) - { - QString name = m_Controls->Name->currentText(); - m_NameToSelect = name; - } - - m_Controls->Name->clear(); - std::map::iterator it - = m_Snippets.begin(); - - while( it != m_Snippets.end() ) - { - m_Controls->Name->addItem( QString::fromStdString( it->first ) ); - ++it; - } - - // reselect previous or last one if there are elements or nothing if there are no snippets - std::string current = m_NameToSelect.toStdString(); - int index = -1; - if( m_Snippets.find(current) != m_Snippets.end() ) - { - index = m_Controls->Name->findText( m_NameToSelect ); - } - else if( m_Snippets.size() > 0 ) - { - index = m_Controls->Name->count()-1; - } - - if( index >= 0 ) - { - m_Controls->Name->setCurrentIndex(index); - current = m_Controls->Name->itemText( index ).toStdString(); - m_Controls->Content->setPlainText( QString::fromStdString(m_Snippets[current]) ); - } - - // clear the current name - m_NameToSelect.clear(); -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.h deleted file mode 100644 index ed58674c8a..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.h +++ /dev/null @@ -1,98 +0,0 @@ -/*=================================================================== - -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 _QmitkPythonSnippets_H -#define _QmitkPythonSnippets_H - -#include -#include "berryISizeProvider.h" - -#include -#include -#include -#include "QmitkStepperAdapter.h" -#include "ui_QmitkPythonSnippets.h" - -#include - -#include "berryISizeProvider.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -/*! - * \ingroup org_mitk_gui_qt_imagenavigator_internal - * - * \brief QmitkPythonSnippets - * - * Document your class here. - * - * \sa QmitkFunctionality - */ -class QmitkPythonSnippets : public QObject, public berry::QtViewPart, public berry::ISizeProvider -{ - - // this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) - Q_OBJECT - - public: - - static const std::string VIEW_ID; - static std::map CreateDefaultSnippets(); - static const std::map DEFAULT_SNIPPETS; - - QmitkPythonSnippets(); - virtual ~QmitkPythonSnippets(); - - virtual void CreateQtPartControl(QWidget *parent); - - QmitkStdMultiWidget* GetActiveStdMultiWidget(); - - void SetFocus(); - - virtual int GetSizeFlags(bool width); - virtual int ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult); - -protected slots: - void on_Name_currentIndexChanged(int i); - void on_RenameSnippet_clicked(); - void on_AddNewSnippet_clicked(); - void on_RemoveSnippet_clicked(); - void on_PasteNow_clicked(); - void on_RestoreDefaultSnippets_clicked(); - void on_Content_textChanged(); - -protected: - void Update(); - void CreateUniqueName( QString& name ); - QmitkStdMultiWidget* m_MultiWidget; - QTableWidget *m_tableWidget; - Ui::QmitkPythonSnippets* m_Controls; - std::map m_Snippets; - QString m_NameToSelect; -}; - - - - -#endif // _QmitkPythonSnippets_H_INCLUDED - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.ui b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.ui deleted file mode 100644 index cfd1ee1d46..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonSnippets.ui +++ /dev/null @@ -1,89 +0,0 @@ - - - QmitkPythonSnippets - - - - 0 - 0 - 613 - 436 - - - - - 0 - 0 - - - - true - - - QmitkTemplate - - - - - - Name: - - - - - - - true - - - - - - - Content: - - - - - - - Paste Now! - - - - - - - Add new Snippet - - - - - - - Remove Snippet - - - - - - - Rename Snippet - - - - - - - Restore default Snippets - - - - - - - - - - - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonTextEditor.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonTextEditor.cpp deleted file mode 100755 index 7559841ba1..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonTextEditor.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonTextEditor.h" - -#include -#include -#include - - -QmitkPythonTextEditor::QmitkPythonTextEditor(QWidget *parent) -:QTextEdit(parent) -{ - QmitkPythonMediator::getInstance()->registerPasteCommandClient( this ); -} - -QmitkPythonTextEditor::~QmitkPythonTextEditor() -{ - QmitkPythonMediator::getInstance()->unregisterPasteCommandClient( this ); -} - -void QmitkPythonTextEditor::dragEnterEvent(QDragEnterEvent *event) -{ - event->accept(); -} - -void QmitkPythonTextEditor::paste(const QString& command) -{ - this->insertPlainText(command + "\n"); -} -void QmitkPythonTextEditor::dropEvent(QDropEvent *event) -{ - //QDropEvent drop(event->pos(),Qt::MoveAction, event->mimeData(), event->mouseButtons(), Qt::ShiftModifier, event->type()); - //QTextEdit::dropEvent(&drop); - QList urls = event->mimeData()->urls(); - for(int i = 0; i < urls.size(); i++) - { - this->insertPlainText(urls[i].toString().append("\n")); - } - -} - -bool QmitkPythonTextEditor::canInsertFromMimeData( const QMimeData *source ) const -{ - return true; -} - -/* -void QmitkPythonTextEditor::insertFromMimeData( const QMimeData *source ) -{ - if (source->hasImage()) - { - QImage image = qvariant_cast(source->imageData()); - QTextCursor cursor = this->textCursor(); - QTextDocument *document = this->document(); - document->addResource(QTextDocument::ImageResource, QUrl("image"), image); - cursor.insertImage("image"); - } -}*/ diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.cpp deleted file mode 100644 index 7f60c7a7f1..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonVariableStack.h" - -#include "mitkNodePredicateDataType.h" - -#include "QmitkDataStorageComboBox.h" -#include "QmitkStdMultiWidget.h" -#include "QmitkPythonConsoleView.h" - -#include "mitkDataStorageEditorInput.h" - -// berry Includes -#include -#include -#include -#include - -#include -#include -#include -#include "QmitkPythonMediator.h" - -const std::string QmitkPythonVariableStack::VIEW_ID = "org.mitk.views.pythonvariablestack"; - -QmitkPythonVariableStack::QmitkPythonVariableStack() -: m_MultiWidget(NULL) -, m_Controls(0) -{ -} - -QmitkPythonVariableStack::~QmitkPythonVariableStack() -{ - QmitkPythonMediator::getInstance()->unregisterClient(m_treeModel); -} - -void QmitkPythonVariableStack::CreateQtPartControl(QWidget *parent) -{ - if( !m_Controls ) - { - m_Controls = new Ui::QmitkPythonConsoleViewControls; - m_Controls->setupUi( parent ); - } - m_treeModel = new QmitkPythonVariableStackTreeWidget(); - m_Controls->tableView->setSelectionBehavior( QAbstractItemView::SelectRows ); - m_Controls->tableView->setAlternatingRowColors(true); - m_Controls->tableView->setDragEnabled(true); - m_Controls->tableView->setDropIndicatorShown(true); - m_Controls->tableView->setAcceptDrops(true); - m_Controls->tableView->setModel( m_treeModel); - QmitkPythonMediator::getInstance()->setClient(m_treeModel); - //QmitkPythonMediator::getInstance()->update(); - // add the multiwidget to the dings - mitk::BaseRenderer* renderer = mitk::BaseRenderer::GetInstance( - this->GetActiveStdMultiWidget()->GetRenderWindow4()->GetVtkRenderWindow() ); - mitk::RendererAccess::Set3DRenderer( renderer->GetVtkRenderer() ); - m_treeModel->update(); -} - -QmitkPythonVariableStackTreeWidget* QmitkPythonVariableStack::getModel() -{ - return m_treeModel; -} - -void QmitkPythonVariableStack::SetFocus () -{ - -} - -QmitkStdMultiWidget* QmitkPythonVariableStack::GetActiveStdMultiWidget() -{ - QmitkStdMultiWidget* activeStdMultiWidget = 0; - berry::IEditorPart::Pointer editor = - this->GetSite()->GetPage()->GetActiveEditor(); - - if (editor.Cast().IsNotNull()) - { - activeStdMultiWidget = editor.Cast()->GetStdMultiWidget(); - } - else - { - mitk::DataStorageEditorInput::Pointer editorInput; - editorInput = new mitk::DataStorageEditorInput(); - berry::IEditorPart::Pointer editor = this->GetSite()->GetPage()->OpenEditor(editorInput, QmitkStdMultiWidgetEditor::EDITOR_ID, false); - activeStdMultiWidget = editor.Cast()->GetStdMultiWidget(); - } - - return activeStdMultiWidget; -} - -int QmitkPythonVariableStack::GetSizeFlags(bool width) -{ - if(!width) - { - return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; - } - else - { - return 0; - } -} - -int QmitkPythonVariableStack::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) -{ - if(width==false) - { - return 160; - } - else - { - return preferredResult; - } -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.h b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.h deleted file mode 100644 index 12780f77ec..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.h +++ /dev/null @@ -1,99 +0,0 @@ -/*=================================================================== - -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 _QMITKPYTHONVARIABLESTACK_H -#define _QMITKPYTHONVARIABLESTACK_H - -#include -#include "berryISizeProvider.h" - -#include -#include -#include -#include "QmitkStepperAdapter.h" -#include "ui_QmitkPythonVariableStack.h" -#include "QmitkPythonVariableStackTreeWidget.h" - -#include - -#include "berryISizeProvider.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -/*! - * \ingroup org_mitk_gui_qt_imagenavigator_internal - * - * \brief QmitkPythonVariableStack - * - * Document your class here. - * - * \sa QmitkFunctionality - */ -class QmitkPythonVariableStack : public berry::QtViewPart, public berry::ISizeProvider -{ - - // this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) - Q_OBJECT - - public: - - static const std::string VIEW_ID; - - QmitkPythonVariableStack(); - QmitkPythonVariableStack(const QmitkPythonVariableStack& other) - { - Q_UNUSED(other) - throw std::runtime_error("Copy constructor not implemented"); - } - virtual ~QmitkPythonVariableStack(); - - virtual void CreateQtPartControl(QWidget *parent); - - QmitkStdMultiWidget* GetActiveStdMultiWidget(); - - void SetFocus(); - - virtual int GetSizeFlags(bool width); - virtual int ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult); - QmitkPythonVariableStackTreeWidget* getModel(); - - -public slots: - -protected slots: - -protected: - QmitkStdMultiWidget* m_MultiWidget; - QTableWidget *m_tableWidget; - Ui::QmitkPythonConsoleViewControls* m_Controls; - QmitkPythonVariableStackTreeWidget* m_treeModel; - -private: - -}; - - - - -#endif // _QmitkPythonVariableStack_H_INCLUDED - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.ui b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.ui deleted file mode 100644 index ea730be5e8..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStack.ui +++ /dev/null @@ -1,58 +0,0 @@ - - - QmitkPythonConsoleViewControls - - - - 0 - 0 - 790 - 773 - - - - - 0 - 0 - - - - true - - - QmitkTemplate - - - - - - true - - - true - - - QAbstractItemView::DragDrop - - - true - - - false - - - true - - - false - - - false - - - - - - - - diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStackTreeWidget.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStackTreeWidget.cpp deleted file mode 100755 index b5a29eb0a5..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/QmitkPythonVariableStackTreeWidget.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/*=================================================================== - -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 "QmitkPythonVariableStackTreeWidget.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "QmitkPythonMediator.h" -#include "QmitkCustomVariants.h" -#include "QmitkNodeDescriptor.h" -#include "QmitkNodeDescriptorManager.h" -#include "mitkDataStorage.h" -#include "mitkDataNode.h" - -QmitkPythonVariableStackTreeWidget::QmitkPythonVariableStackTreeWidget(QWidget* parent) - :QAbstractTableModel(parent) -{ -} - -QmitkPythonVariableStackTreeWidget::~QmitkPythonVariableStackTreeWidget() -{ -} - -bool QmitkPythonVariableStackTreeWidget::dropMimeData ( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent ) -{ - // Early exit, returning true, but not actually doing anything (ignoring data). - if (action == Qt::IgnoreAction) - return true; - - // Note, we are returning true if we handled it, and false otherwise - bool returnValue = false; - - if(data->hasFormat("application/x-mitk-datanodes")) - { - returnValue = true; - - QString arg = QString(data->data("application/x-mitk-datanodes").data()); - QStringList listOfDataNodeAddressPointers = arg.split(","); - - QStringList::iterator slIter; - for (slIter = listOfDataNodeAddressPointers.begin(); - slIter != listOfDataNodeAddressPointers.end(); - slIter++) - { - long val = (*slIter).toLong(); - mitk::DataNode* node = static_cast((void*)val); - - itk::SmartPointer * resultptr; - resultptr = new itk::SmartPointer((itk::SmartPointer &)node); - - if(resultptr) - { - int i = 0; - while(swig_types_initial[i] != 0) - { - if(swig_types_initial[i] == _swigt__p_itk__SmartPointerTmitk__DataNode_t) - SWIGTYPE_p_itk__SmartPointerTmitk__DataNode_t = SWIG_TypeRegister(swig_types_initial[i]); - i++; - } - - PyObject * resultObj = SWIG_NewPointerObj((void*)(resultptr), SWIGTYPE_p_itk__SmartPointerTmitk__DataNode_t, 1); - PyObject* dict = PyImport_GetModuleDict(); - PyObject* object = PyDict_GetItemString(dict, "__main__"); - - if(object){ - Py_INCREF(object); - PyModule_AddObject(object, node->GetName().c_str(), resultObj); - } - setVariableStack(QmitkPythonMediator::getAttributeList()); - } - } - - } - return returnValue; -} - -QVariant QmitkPythonVariableStackTreeWidget::headerData(int section, Qt::Orientation orientation, - int role) const -{ - QVariant headerData; - - // show only horizontal header - if ( role == Qt::DisplayRole ) - { - if( orientation == Qt::Horizontal ) - { - // first column: "Attribute" - if(section == 0) - headerData = "Attribute"; - else if(section == 1) - headerData = "Value"; - else if(section == 2) - headerData = "Type"; - } - } - - return headerData; -} - -Qt::ItemFlags QmitkPythonVariableStackTreeWidget::flags(const QModelIndex &index) const -{ - Qt::ItemFlags flags = QAbstractItemModel::flags(index); - - if(index.isValid()) - return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | flags; - else - return Qt::ItemIsDropEnabled | flags; -} - -int QmitkPythonVariableStackTreeWidget::rowCount(const QModelIndex &) const -{ - return m_variableStack.size(); -} - -int QmitkPythonVariableStackTreeWidget::columnCount(const QModelIndex &) const -{ - return 3; -} - -QVariant QmitkPythonVariableStackTreeWidget::data(const QModelIndex &index, int role) const -{ - if (index.isValid() && !m_variableStack.empty()) - { - if(role == Qt::DisplayRole) - { - QStringList item = m_variableStack.at(index.row()); - if(index.column() == 0) - return item[0]; - if(index.column() == 1) - return item[1]; - if(index.column() == 2) - return item[2]; - } - } - return QVariant(); -} - -void QmitkPythonVariableStackTreeWidget::clear() -{ - m_variableStack.clear(); - QAbstractTableModel::reset(); -} - -void QmitkPythonVariableStackTreeWidget::setVariableStack(std::vector varStack) -{ - m_variableStack = varStack; - QAbstractTableModel::reset(); -} - -std::vector QmitkPythonVariableStackTreeWidget::getVariableStack() -{ - return m_variableStack; -} - -QMimeData * QmitkPythonVariableStackTreeWidget::mimeData(const QModelIndexList & indexes) const -{ - - QMimeData * ret = new QMimeData; - - QString dataNodeAddresses(""); - - for (int indexesCounter = 0; indexesCounter < indexes.size(); indexesCounter++) - { - QString name = m_variableStack[indexes.at(indexesCounter).row()][0]; - QString type = m_variableStack[indexes.at(indexesCounter).row()][2]; - - if(type != "DataNode_PointerPtr") - return NULL; - - mitk::DataNode* node; - itk::SmartPointer *arg; - - PyObject * obj = QmitkPythonMediator::getPyObjectString(&name); - int i = 0; - while(swig_types_initial[i] != 0) - { - if(swig_types_initial[i] == _swigt__p_itk__SmartPointerTmitk__DataNode_t) - SWIGTYPE_p_itk__SmartPointerTmitk__DataNode_t = SWIG_TypeRegister(swig_types_initial[i]); - i++; - } - if ((SWIG_ConvertPtr(obj,(void **)(&arg),SWIGTYPE_p_itk__SmartPointerTmitk__DataNode_t, - SWIG_POINTER_EXCEPTION | 0)) == -1) return NULL; - - if(arg == NULL){ - return NULL; - } - try { - node = (mitk::DataNode *)((itk::SmartPointer const *)arg)->GetPointer(); - } - catch(std::exception &_e) { - { - std::cout << "Not a DataNode" << std::endl; - } - } - - long a = reinterpret_cast(node); - - if (dataNodeAddresses.size() != 0) - { - QTextStream(&dataNodeAddresses) << ","; - } - QTextStream(&dataNodeAddresses) << a; - - ret->setData("application/x-mitk-datanodes", QByteArray(dataNodeAddresses.toAscii())); - } - - return ret; -} - -QStringList QmitkPythonVariableStackTreeWidget::mimeTypes() const -{ - QStringList types; - types << "application/x-mitk-datanodes"; - types << "application/x-qabstractitemmodeldatalist"; - return types; -} - -Qt::DropActions QmitkPythonVariableStackTreeWidget::supportedDropActions() const -{ - return Qt::CopyAction | Qt::MoveAction; -} - -Qt::DropActions QmitkPythonVariableStackTreeWidget::supportedDragActions() const -{ - return Qt::CopyAction | Qt::MoveAction; -} - -void QmitkPythonVariableStackTreeWidget::update() -{ -// std::cout << "QmitkPythonVariableStackTreeWidget::update()" << std::endl; - setVariableStack(QmitkPythonMediator::getAttributeList()); -} diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.cpp deleted file mode 100644 index 9eeb4d6855..0000000000 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/*=================================================================== - -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 "mitkPluginActivator.h" - -#include "QmitkPythonConsoleView.h" -#include "QmitkPythonVariableStack.h" -#include "QmitkPythonCommandHistory.h" -#include "QmitkPythonEditor.h" -#include "QmitkPythonSnippets.h" -#include "QmitkPythonPerspective.h" - -#include - -namespace mitk { - - void PluginActivator::start(ctkPluginContext* context) - { - BERRY_REGISTER_EXTENSION_CLASS(QmitkPythonConsoleView, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkPythonVariableStack, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkPythonCommandHistory, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkPythonEditor, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkPythonSnippets, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkPythonPerspective, context) - } - - void PluginActivator::stop(ctkPluginContext* context) - { - Q_UNUSED(context) - } - -} - -Q_EXPORT_PLUGIN2(org_mitk_gui_qt_imagenavigator, mitk::PluginActivator) diff --git a/Plugins/org.mitk.gui.qt.python/CMakeLists.txt b/Plugins/org.mitk.gui.qt.python/CMakeLists.txt new file mode 100644 index 0000000000..352805d7d5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/CMakeLists.txt @@ -0,0 +1,6 @@ +project(org_mitk_gui_qt_python) + +MACRO_CREATE_MITK_CTK_PLUGIN( + EXPORT_DIRECTIVE org_mitk_gui_qt_python_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDENCIES QmitkExt mitkPython) \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.python/documentation/UserManual/org.mitk.gui.qt.python.dox b/Plugins/org.mitk.gui.qt.python/documentation/UserManual/org.mitk.gui.qt.python.dox new file mode 100644 index 0000000000..d1ab3c52fe --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/documentation/UserManual/org.mitk.gui.qt.python.dox @@ -0,0 +1,10 @@ +/** +\page org_mitk_gui_qt_python The Python Plugin + +Available sections: + - \ref org_mitk_gui_qt_pythonOverview + +\section org_mitk_gui_qt_pythonOverview Overview +The Python view provides the graphical front end to run Python code through the mitkPython module. Furthermore the ITK/VTK/OpenCV Python wrapping can be used. + +*/ diff --git a/Plugins/org.mitk.gui.qt.python/files.cmake b/Plugins/org.mitk.gui.qt.python/files.cmake new file mode 100644 index 0000000000..d2d693e932 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/files.cmake @@ -0,0 +1,31 @@ +set(SRC_CPP_FILES +) + +set(INTERNAL_CPP_FILES + mitkPluginActivator.cpp + QmitkPythonView.cpp +) + +set(MOC_H_FILES + src/internal/QmitkPythonView.h + src/internal/mitkPluginActivator.h +) + +set(CPP_FILES ) + +set(CACHED_RESOURCE_FILES + plugin.xml + resources/Python.png +) + +set(QRC_FILES + resources/Python.qrc +) + +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.python/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.python/manifest_headers.cmake new file mode 100644 index 0000000000..a083a5b4a6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MITK Python") +set(Plugin-Version "1.0.0") +set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.python/plugin.xml b/Plugins/org.mitk.gui.qt.python/plugin.xml new file mode 100644 index 0000000000..c69d1a6080 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/plugin.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.python.console/resources/py.png b/Plugins/org.mitk.gui.qt.python/resources/Python.png similarity index 100% rename from Plugins/org.mitk.gui.qt.python.console/resources/py.png rename to Plugins/org.mitk.gui.qt.python/resources/Python.png diff --git a/Plugins/org.mitk.gui.qt.python/resources/Python.qrc b/Plugins/org.mitk.gui.qt.python/resources/Python.qrc new file mode 100644 index 0000000000..5b36d01dbf --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/resources/Python.qrc @@ -0,0 +1,5 @@ + + + Python.png + + diff --git a/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp b/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp new file mode 100644 index 0000000000..32b6a104bc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp @@ -0,0 +1,98 @@ +/*=================================================================== + +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 "QmitkPythonView.h" +#include +#include +#include "mitkPluginActivator.h" +#include +#include +#include + +const std::string QmitkPythonView::VIEW_ID = "org.mitk.views.python"; + +struct QmitkPythonViewData +{ + // widget + QmitkPythonVariableStackTableView* m_PythonVariableStackTableView; + QmitkPythonSnippets* m_PythonSnippets; + + QmitkCtkPythonShell* m_PythonShell; + QmitkPythonTextEditor* m_TextEditor; +}; + +QmitkPythonView::QmitkPythonView() + : d( new QmitkPythonViewData ) +{ + d->m_PythonVariableStackTableView = 0; + d->m_PythonShell = 0; +} + +QmitkPythonView::~QmitkPythonView() +{ + delete d; +} + +void QmitkPythonView::CreateQtPartControl(QWidget* parent) +{ + d->m_PythonVariableStackTableView = new QmitkPythonVariableStackTableView; + d->m_PythonVariableStackTableView->SetDataStorage(this->GetDataStorage()); + d->m_PythonVariableStackTableView->horizontalHeader()->setResizeMode(QHeaderView::Interactive); + + QString snippetsFilePath = mitk::PluginActivator::m_XmlFilePath; + MITK_DEBUG("QmitkPythonView") << "got snippetsFilePath " << snippetsFilePath.toStdString(); + + d->m_PythonSnippets = new QmitkPythonSnippets(snippetsFilePath); + + MITK_DEBUG("QmitkPythonView") << "initializing varStackSnippetsTab"; + QTabWidget* varStackSnippetsTab = new QTabWidget; + varStackSnippetsTab->addTab( d->m_PythonVariableStackTableView, "Variable Stack" ); + varStackSnippetsTab->addTab( d->m_PythonSnippets, "Snippets" ); + varStackSnippetsTab->setTabPosition( QTabWidget::South ); + + MITK_DEBUG("QmitkPythonView") << "initializing m_PythonShell"; + d->m_PythonShell = new QmitkCtkPythonShell; + + MITK_DEBUG("QmitkPythonView") << "initializing m_TextEditor"; + d->m_TextEditor = new QmitkPythonTextEditor; + + MITK_DEBUG("QmitkPythonView") << "initializing tabWidgetConsoleEditor"; + QTabWidget* tabWidgetConsoleEditor = new QTabWidget; + tabWidgetConsoleEditor->addTab( d->m_PythonShell, "Console" ); + tabWidgetConsoleEditor->addTab( d->m_TextEditor, "Text Editor" ); + tabWidgetConsoleEditor->setTabPosition( QTabWidget::South ); + + QList sizes; + sizes << 1 << 3; + QSplitter* splitter = new QSplitter; + splitter->addWidget(varStackSnippetsTab); + splitter->addWidget(tabWidgetConsoleEditor); + splitter->setStretchFactor ( 0, 1 ); + splitter->setStretchFactor ( 1, 3 ); + + QGridLayout* layout = new QGridLayout; + layout->addWidget( splitter, 0, 0 ); + parent->setLayout(layout); + + MITK_DEBUG("QmitkPythonView") << "creating connections for m_PythonSnippets"; + connect( d->m_PythonSnippets, SIGNAL(PasteCommandRequested(QString)), d->m_PythonShell, SLOT(Paste(QString)) ); + connect( d->m_PythonSnippets, SIGNAL(PasteCommandRequested(QString)), d->m_TextEditor, SLOT(Paste(QString)) ); +} + +void QmitkPythonView::SetFocus() +{ + d->m_PythonShell->setFocus(); +} diff --git a/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.h b/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.h new file mode 100644 index 0000000000..41b4bee47a --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.h @@ -0,0 +1,64 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkPythonView_H_ +#define QmitkPythonView_H_ + +/// Qmitk +#include + +/// +/// d pointer forward declaration +/// +struct QmitkPythonViewData; + +/// +/// \brief New python view (CONSOLE) +/// +class QmitkPythonView : public QmitkAbstractView +{ + Q_OBJECT + +public: + + static const std::string VIEW_ID; // = "org.mitk.extapp.defaultperspective" + /// + /// \brief Standard ctor. + /// + QmitkPythonView(); + + /// + /// \brief Standard dtor. + /// + virtual ~QmitkPythonView(); + +protected: + + /// + /// \brief Create the view here. + /// + virtual void CreateQtPartControl(QWidget* parent); + + /// + /// focus on load image + /// + void SetFocus(); + +private: + QmitkPythonViewData* d; +}; + +#endif /*QmitkPythonView_H_*/ diff --git a/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.cpp new file mode 100644 index 0000000000..e59a8e8108 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.cpp @@ -0,0 +1,38 @@ +/*=================================================================== + +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 "mitkPluginActivator.h" +#include +#include "QmitkPythonView.h" + +namespace mitk +{ + QString PluginActivator::m_XmlFilePath; + + void PluginActivator::start(ctkPluginContext* context) + { + m_XmlFilePath = context->getDataFile("PythonSnippets.xml").absoluteFilePath(); + + BERRY_REGISTER_EXTENSION_CLASS(QmitkPythonView, context) + } + + void PluginActivator::stop(ctkPluginContext* context) + { + Q_UNUSED(context) + } + +} + +Q_EXPORT_PLUGIN2(org_mitk_gui_qt_python, mitk::PluginActivator) diff --git a/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.h similarity index 71% rename from Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h rename to Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.h index b96fd0fb6e..9a32e11e62 100644 --- a/Plugins/org.mitk.gui.qt.python.console/src/internal/mitkPluginActivator.h +++ b/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.h @@ -1,40 +1,39 @@ /*=================================================================== 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 MITKPLUGINACTIVATOR_H #define MITKPLUGINACTIVATOR_H #include #include - namespace mitk { - class MITK_LOCAL PluginActivator : - public QObject, public ctkPluginActivator - { - Q_OBJECT - Q_INTERFACES(ctkPluginActivator) - - public: +class MITK_LOCAL PluginActivator : + public QObject, public ctkPluginActivator +{ + Q_OBJECT + Q_INTERFACES(ctkPluginActivator) - void start(ctkPluginContext* context); - void stop(ctkPluginContext* context); +public: + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); - }; // PluginActivator + static QString m_XmlFilePath; +}; // PluginActivator } #endif // MITKPLUGINACTIVATOR_H diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkDeformableClippingPlaneView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkDeformableClippingPlaneView.cpp index 8765b086ba..dc0f7341de 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkDeformableClippingPlaneView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkDeformableClippingPlaneView.cpp @@ -1,549 +1,552 @@ /*=================================================================== 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 "QmitkDeformableClippingPlaneView.h" #include "mitkClippingPlaneDeformationTool.h" #include "mitkClippingPlaneRotationTool.h" #include "mitkClippingPlaneTranslationTool.h" #include "mitkHeightFieldSurfaceClipImageFilter.h" #include "mitkImageToSurfaceFilter.h" #include "mitkInteractionConst.h" #include "mitkLabeledImageLookupTable.h" #include "mitkLabeledImageVolumeCalculator.h" #include "mitkLevelWindowProperty.h" #include "mitkLookupTableProperty.h" #include "mitkPlane.h" +#include "mitkRenderingModeProperty.h" #include "mitkRotationOperation.h" #include "mitkSurfaceVtkMapper3D.h" #include "mitkVtkRepresentationProperty.h" #include "vtkFloatArray.h" #include "vtkPointData.h" #include "vtkProperty.h" const std::string QmitkDeformableClippingPlaneView::VIEW_ID = "org.mitk.views.deformableclippingplane"; QmitkDeformableClippingPlaneView::QmitkDeformableClippingPlaneView() : QmitkFunctionality() , m_MultiWidget(NULL) , m_ToolManager(NULL) { //Current fix for bug 10707. Waiting for a solution of bug 10834. itk::Object::Pointer o; o = mitk::ClippingPlaneRotationTool::New(); o = mitk::ClippingPlaneDeformationTool::New(); o = mitk::ClippingPlaneTranslationTool::New(); } QmitkDeformableClippingPlaneView::~QmitkDeformableClippingPlaneView() { } void QmitkDeformableClippingPlaneView::CreateQtPartControl(QWidget *parent) { // create GUI widgets m_Controls.setupUi(parent); this->CreateConnections(); } void QmitkDeformableClippingPlaneView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkDeformableClippingPlaneView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkDeformableClippingPlaneView::CreateConnections() { m_ToolManager = m_Controls.interactionToolSelectionBox->GetToolManager(); m_ToolManager->SetDataStorage(*(this->GetDefaultDataStorage())); assert(m_ToolManager); mitk::NodePredicateProperty::Pointer clipPredicate = mitk::NodePredicateProperty::New("clippingPlane",mitk::BoolProperty::New(true)); //set only clipping planes in the list of the selector m_Controls.clippingPlaneSelector->SetDataStorage(this->GetDefaultDataStorage()); m_Controls.clippingPlaneSelector->SetPredicate(clipPredicate); //Shows and set the tool buttons m_Controls.interactionToolSelectionBox->SetGenerateAccelerators(true); m_Controls.interactionToolSelectionBox->SetDisplayedToolGroups("ClippingTool"); m_Controls.interactionToolSelectionBox->SetLayoutColumns(3); m_Controls.interactionToolSelectionBox->SetEnabledMode(QmitkToolSelectionBox::EnabledWithWorkingData); //No working data set, yet m_Controls.volumeGroupBox->setEnabled(false); m_Controls.noSelectedImageLabel->show(); m_Controls.planesWarningLabel->hide(); connect (m_Controls.createNewPlanePushButton, SIGNAL(clicked()), this, SLOT(OnCreateNewClippingPlane())); connect (m_Controls.updateVolumePushButton, SIGNAL(clicked()), this, SLOT(OnCalculateClippingVolume())); connect (m_Controls.clippingPlaneSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnComboBoxSelectionChanged(const mitk::DataNode*))); } void QmitkDeformableClippingPlaneView::Activated() { QmitkFunctionality::Activated(); } void QmitkDeformableClippingPlaneView::Deactivated() { QmitkFunctionality::Deactivated(); } void QmitkDeformableClippingPlaneView::OnComboBoxSelectionChanged( const mitk::DataNode* node ) { mitk::DataNode* selectedNode = const_cast(node); if( selectedNode != NULL ) { //remember the active tool int toolID = m_ToolManager->GetActiveToolID(); m_ToolManager->SetWorkingData(selectedNode); //reset Tool m_ToolManager->ActivateTool(-1); //set tool again with new working data (calls activated() in Tool) m_ToolManager->ActivateTool(toolID); } this->UpdateView(); } void QmitkDeformableClippingPlaneView::OnSelectionChanged(mitk::DataNode* node) { std::vector nodes; nodes.push_back(node); this->OnSelectionChanged(nodes); } void QmitkDeformableClippingPlaneView::OnSelectionChanged(std::vector nodes) { bool isClippingPlane(false); for(unsigned int i = 0; i < nodes.size(); ++i) { if(nodes.at(i)->GetBoolProperty("clippingPlane", isClippingPlane)) m_Controls.clippingPlaneSelector->setCurrentIndex( m_Controls.clippingPlaneSelector->Find(nodes.at(i)) ); else { if(dynamic_cast (nodes.at(i)->GetData())&& nodes.at(i)) { if(m_ToolManager->GetReferenceData(0)!= NULL && nodes.at(i)->GetData()==m_ToolManager->GetReferenceData(0)->GetData()) return; m_ToolManager->SetReferenceData(nodes.at(i)); } } } this->UpdateView(); } void::QmitkDeformableClippingPlaneView::NodeChanged(const mitk::DataNode* /*node*/) { this->UpdateView(); } void QmitkDeformableClippingPlaneView::NodeRemoved(const mitk::DataNode* node) { bool isClippingPlane(false); if (node->GetBoolProperty("clippingPlane", isClippingPlane)) { if(this->GetAllClippingPlanes()->Size()<=1) { m_ToolManager->SetWorkingData(NULL); this->UpdateView(); } else { if (GetAllClippingPlanes()->front()!= node) this->OnSelectionChanged(GetAllClippingPlanes()->front()); else this->OnSelectionChanged(GetAllClippingPlanes()->ElementAt(1)); } } else { if(m_ToolManager->GetReferenceData(0)!= NULL) { if(node->GetData() == m_ToolManager->GetReferenceData(0)->GetData()) { m_ToolManager->SetReferenceData(NULL); m_Controls.volumeList->clear(); } this->UpdateView(); } } } void QmitkDeformableClippingPlaneView::UpdateView() { if (m_ToolManager->GetReferenceData(0)!= NULL) { m_Controls.noSelectedImageLabel->hide(); m_Controls.selectedImageLabel->setText(QString::fromUtf8(m_ToolManager->GetReferenceData(0)->GetName().c_str())); if (m_ToolManager->GetWorkingData(0)!= NULL) { bool isSegmentation(false); m_ToolManager->GetReferenceData(0)->GetBoolProperty("binary", isSegmentation); m_Controls.volumeGroupBox->setEnabled(isSegmentation); //clear list --> than search for all shown clipping plans (max 7 planes) m_Controls.selectedVolumePlanesLabel->setText(""); m_Controls.planesWarningLabel->hide(); int volumePlanes=0; mitk::DataStorage::SetOfObjects::ConstPointer allClippingPlanes = this->GetAllClippingPlanes(); for (mitk::DataStorage::SetOfObjects::ConstIterator itPlanes = allClippingPlanes->Begin(); itPlanes != allClippingPlanes->End(); itPlanes++) { bool isVisible(false); itPlanes.Value()->GetBoolProperty("visible",isVisible); if (isVisible) { if (volumePlanes<7) { volumePlanes ++; m_Controls.selectedVolumePlanesLabel->setText(m_Controls.selectedVolumePlanesLabel->text().append(QString::fromStdString(itPlanes.Value()->GetName()+"\n"))); } else { m_Controls.planesWarningLabel->show(); return; } } } } else { m_Controls.volumeGroupBox->setEnabled(false); m_Controls.selectedVolumePlanesLabel->setText(""); m_Controls.volumeList->clear(); } } else { m_Controls.volumeGroupBox->setEnabled(false); m_Controls.noSelectedImageLabel->show(); m_Controls.selectedImageLabel->setText(""); m_Controls.selectedVolumePlanesLabel->setText(""); m_Controls.planesWarningLabel->hide(); } } void QmitkDeformableClippingPlaneView::OnCreateNewClippingPlane() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); mitk::Image::Pointer referenceImage = mitk::Image::New(); //the new clipping plane mitk::Plane::Pointer plane = mitk::Plane::New(); double imageDiagonal = 200; if (referenceNode != NULL) { referenceImage = dynamic_cast (referenceNode->GetData()); if (referenceImage.IsNotNull()) { // check if user wants a surface model if(m_Controls.surfaceModelCheckBox->isChecked()) { //Check if there is a surface node from the image. If not, create one bool createSurfaceFromImage(true); mitk::TNodePredicateDataType::Pointer isSurface = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer childNodes = m_ToolManager->GetDataStorage()->GetDerivations(referenceNode,isSurface, true); for (mitk::DataStorage::SetOfObjects::ConstIterator itChildNodes = childNodes->Begin(); itChildNodes != childNodes->End(); itChildNodes++) { if (itChildNodes.Value().IsNotNull()) createSurfaceFromImage=false; } if(createSurfaceFromImage) { //Lsg 2: Surface for the 3D-perspective mitk::ImageToSurfaceFilter::Pointer surfaceFilter = mitk::ImageToSurfaceFilter::New(); surfaceFilter->SetInput(referenceImage); surfaceFilter->SetThreshold(1); surfaceFilter->SetSmooth(true); //Downsampling surfaceFilter->SetDecimate(mitk::ImageToSurfaceFilter::DecimatePro); mitk::DataNode::Pointer surfaceNode = mitk::DataNode::New(); surfaceNode->SetData(surfaceFilter->GetOutput()); surfaceNode->SetProperty("color", referenceNode->GetProperty("color")); surfaceNode->SetOpacity(0.5); surfaceNode->SetName(referenceNode->GetName()); m_ToolManager->GetDataStorage()->Add(surfaceNode, referenceNode); } } //If an image is selected trim the plane to this. imageDiagonal = referenceImage->GetGeometry()->GetDiagonalLength(); plane->SetOrigin( referenceImage->GetGeometry()->GetCenter()); // Rotate plane mitk::Vector3D rotationAxis; mitk::FillVector3D(rotationAxis, 0.0, 1.0, 0.0); mitk::RotationOperation op(mitk::OpROTATE, referenceImage->GetGeometry()->GetCenter(), rotationAxis, 90.0); plane->GetGeometry()->ExecuteOperation(&op); } } //set some properties for the clipping plane plane->SetExtent(imageDiagonal * 0.9, imageDiagonal * 0.9); plane->SetResolution(64, 64); // Set scalars (for colorization of plane) vtkFloatArray *scalars = vtkFloatArray::New(); scalars->SetName("Distance"); scalars->SetNumberOfComponents(1); for ( unsigned int i = 0; i < plane->GetVtkPolyData(0)->GetNumberOfPoints(); ++i) { scalars->InsertNextValue(-1.0); } plane->GetVtkPolyData(0)->GetPointData()->SetScalars(scalars); plane->GetVtkPolyData(0)->GetPointData()->Update(); mitk::DataNode::Pointer planeNode = mitk::DataNode::New(); planeNode->SetData(plane); std::stringstream planeName; planeName << "ClippingPlane "; planeName << this->GetAllClippingPlanes()->Size() + 1; planeNode->SetName(planeName.str()); planeNode->AddProperty("clippingPlane",mitk::BoolProperty::New(true)); // Make plane pickable planeNode->SetBoolProperty("pickable", true); mitk::SurfaceVtkMapper3D::SetDefaultProperties(planeNode); // Don't include plane in bounding box! planeNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); // Set lookup table for plane surface visualization vtkLookupTable *lookupTable = vtkLookupTable::New(); lookupTable->SetHueRange(0.6, 0.0); lookupTable->SetSaturationRange(1.0, 1.0); lookupTable->SetValueRange(1.0, 1.0); lookupTable->SetTableRange(-1.0, 1.0); lookupTable->Build(); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetVtkLookupTable(lookupTable); mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut); planeNode->SetProperty("LookupTable", prop); planeNode->SetBoolProperty("scalar visibility", true); planeNode->SetBoolProperty("color mode", true); planeNode->SetFloatProperty("ScalarsRangeMinimum", -1.0); planeNode->SetFloatProperty("ScalarsRangeMaximum", 1.0); // Configure material so that only scalar colors are shown planeNode->SetColor(0.0f,0.0f,0.0f); planeNode->SetOpacity(1.0f); planeNode->SetFloatProperty("material.wireframeLineWidth",2.0f); //Set view of plane to wireframe planeNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); //Set the plane as working data for the tools and selected it this->OnSelectionChanged (planeNode); //Add the plane to data storage this->GetDataStorage()->Add(planeNode); //Change the index of the selector to the new generated node m_Controls.clippingPlaneSelector->setCurrentIndex( m_Controls.clippingPlaneSelector->Find(planeNode) ); // set crosshair invisible mitk::DataNode* dataNode; dataNode = this->m_MultiWidget->GetWidgetPlane1(); if(dataNode) dataNode->SetVisibility(false); dataNode = this->m_MultiWidget->GetWidgetPlane2(); if(dataNode) dataNode->SetVisibility(false); dataNode = this->m_MultiWidget->GetWidgetPlane3(); if(dataNode) dataNode->SetVisibility(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDeformableClippingPlaneView::OnCalculateClippingVolume() { mitk::DataNode::Pointer imageNode = m_ToolManager->GetReferenceData(0); bool isSegmentation(false); imageNode->GetBoolProperty("binary", isSegmentation); if(imageNode.IsNull() || !isSegmentation) { MITK_ERROR << "No segmentation selected! Can't calculate volume"; return; } std::vector clippingPlanes; mitk::DataStorage::SetOfObjects::ConstPointer allClippingPlanes = this->GetAllClippingPlanes(); for (mitk::DataStorage::SetOfObjects::ConstIterator itPlanes = allClippingPlanes->Begin(); itPlanes != allClippingPlanes->End(); itPlanes++) { bool isVisible(false); itPlanes.Value()->GetBoolProperty("visible",isVisible); mitk::Surface* plane = dynamic_cast(itPlanes.Value()->GetData()); if (isVisible && plane) clippingPlanes.push_back(plane); } if (clippingPlanes.empty()) { MITK_ERROR << "No clipping plane selected! Can't calculate volume"; return; } //deactivate Tools m_ToolManager->ActivateTool(-1); //Clear the list of volumes, before calculating the new values m_Controls.volumeList->clear(); imageNode->SetBoolProperty("visible", false); //set some properties for clipping the image-->Output: labled Image mitk::HeightFieldSurfaceClipImageFilter::Pointer surfaceClipFilter = mitk::HeightFieldSurfaceClipImageFilter::New(); surfaceClipFilter->SetInput(dynamic_cast (imageNode->GetData())); surfaceClipFilter->SetClippingModeToMultiPlaneValue(); surfaceClipFilter->SetClippingSurfaces(clippingPlanes); surfaceClipFilter->Update(); //delete the old clipped image node mitk::DataStorage::SetOfObjects::ConstPointer oldClippedNode = this->GetDataStorage()->GetSubset(mitk::NodePredicateProperty::New("name", mitk::StringProperty::New("Clipped Image"))); if (oldClippedNode.IsNotNull()) this->GetDataStorage()->Remove(oldClippedNode); //add the new clipped image node mitk::DataNode::Pointer clippedNode = mitk::DataNode::New(); mitk::Image::Pointer clippedImage = surfaceClipFilter->GetOutput(); clippedImage->DisconnectPipeline(); clippedNode->SetData(clippedImage); //clippedNode->SetProperty("helper object", mitk::BoolProperty::New(true)); clippedNode->SetName("Clipped Image"); clippedNode->SetColor(1.0,1.0,1.0); // color property will not be used, labeled image lookuptable will be used instead clippedNode->SetProperty ("use color", mitk::BoolProperty::New(false)); clippedNode->SetOpacity(0.4); this->GetDataStorage()->Add(clippedNode); mitk::LabeledImageVolumeCalculator::Pointer volumeCalculator = mitk::LabeledImageVolumeCalculator::New(); volumeCalculator->SetImage(clippedImage); volumeCalculator->Calculate(); std::vector volumes = volumeCalculator->GetVolumes(); mitk::LabeledImageLookupTable::Pointer lut = mitk::LabeledImageLookupTable::New(); int lablesWithVolume=0; for(unsigned int i = 1; i < volumes.size(); ++i) { if(volumes.at(i)!=0) { lablesWithVolume++; mitk::Color color (GetLabelColor(lablesWithVolume)); lut->SetColorForLabel(i,color.GetRed(), color.GetGreen(), color.GetBlue(), 1.0); QColor qcolor; qcolor.setRgbF(color.GetRed(), color.GetGreen(), color.GetBlue(), 0.7); //output volume as string "x.xx ml" std::stringstream stream; stream<< std::fixed << std::setprecision(2)<setText(QString::fromStdString(stream.str())); item->setBackgroundColor(qcolor); m_Controls.volumeList->addItem(item); } } + //set the rendering mode to use the lookup table and level window + clippedNode->SetProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR)); mitk::LookupTableProperty::Pointer lutProp = mitk::LookupTableProperty::New(lut.GetPointer()); clippedNode->SetProperty("LookupTable", lutProp); // it is absolutely important, to use the LevelWindow settings provided by // the LUT generator, otherwise, it is not guaranteed, that colors show // up correctly. clippedNode->SetProperty("levelwindow", mitk::LevelWindowProperty::New(lut->GetLevelWindow())); } mitk::DataStorage::SetOfObjects::ConstPointer QmitkDeformableClippingPlaneView::GetAllClippingPlanes() { mitk::NodePredicateProperty::Pointer clipPredicate= mitk::NodePredicateProperty::New("clippingPlane",mitk::BoolProperty::New(true)); mitk::DataStorage::SetOfObjects::ConstPointer allPlanes = m_ToolManager->GetDataStorage()->GetSubset(clipPredicate); return allPlanes; } mitk::Color QmitkDeformableClippingPlaneView::GetLabelColor(int label) { float red, green, blue; switch ( label % 6 ) { case 0: {red = 1.0; green = 0.0; blue = 0.0; break;} case 1: {red = 0.0; green = 1.0; blue = 0.0; break;} case 2: {red = 0.0; green = 0.0; blue = 1.0;break;} case 3: {red = 1.0; green = 1.0; blue = 0.0;break;} case 4: {red = 1.0; green = 0.0; blue = 1.0;break;} case 5: {red = 0.0; green = 1.0; blue = 1.0;break;} default: {red = 0.0; green = 0.0; blue = 0.0;} } float tmp[3] = { red, green, blue }; double factor; int outerCycleNr = label / 6; int cycleSize = pow(2.0,(int)(log((double)(outerCycleNr))/log( 2.0 ))); if (cycleSize==0) cycleSize = 1; int insideCycleCounter = outerCycleNr % cycleSize; if ( outerCycleNr == 0) factor = 255; else factor = ( 256 / ( 2 * cycleSize ) ) + ( insideCycleCounter * ( 256 / cycleSize ) ); tmp[0]= tmp[0]/256*factor; tmp[1]= tmp[1]/256*factor; tmp[2]= tmp[2]/256*factor; return mitk::Color(tmp); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.cpp index 1d34b0b5db..afeeab8217 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.cpp @@ -1,234 +1,198 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkOtsuAction.h" // MITK #include #include #include #include #include #include +#include #include #include // ITK #include // Qt #include #include #include #include #include #include using namespace berry; using namespace mitk; using namespace std; QmitkOtsuAction::QmitkOtsuAction() : m_OtsuSegmentationDialog(NULL) { } QmitkOtsuAction::~QmitkOtsuAction() { } void QmitkOtsuAction::Run(const QList &selectedNodes) { this->m_DataNode = selectedNodes[0]; //this->m_selectedNodes = selectedNodes; m_OtsuSegmentationDialog = new QDialog(QApplication::activeWindow(),Qt::WindowTitleHint | Qt::WindowSystemMenuHint); QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 0); QHBoxLayout* spinBoxLayout = new QHBoxLayout; QHBoxLayout* buttonLayout = new QHBoxLayout; m_OtsuSpinBox = new QSpinBox; m_OtsuSpinBox->setRange(2, 32); m_OtsuSpinBox->setValue(2); m_OtsuPushButton = new QPushButton("OK"); QPushButton* CancelButton = new QPushButton("Cancel"); connect(m_OtsuPushButton, SIGNAL(clicked()), this, SLOT(OtsuSegmentationDone())); connect(CancelButton, SIGNAL(clicked()), m_OtsuSegmentationDialog, SLOT(reject())); QLabel* numberOfThresholdsLabel = new QLabel("Select number of Regions of Interest:"); numberOfThresholdsLabel->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); layout->addWidget(numberOfThresholdsLabel); layout->addLayout(spinBoxLayout); spinBoxLayout->addSpacing(50); spinBoxLayout->addWidget(m_OtsuSpinBox); spinBoxLayout->addSpacing(50); layout->addLayout(buttonLayout); buttonLayout->addWidget(m_OtsuPushButton); buttonLayout->addWidget(CancelButton); m_OtsuSegmentationDialog->setLayout(layout); m_OtsuSegmentationDialog->setFixedSize(300, 80); m_OtsuSegmentationDialog->open(); } void QmitkOtsuAction::OtsuSegmentationDone() { - - /* - if (result == QDialog::Rejected) - m_ThresholdingToolManager->ActivateTool(-1);*/ - this->PerformOtsuSegmentation(); m_OtsuSegmentationDialog->deleteLater(); m_OtsuSegmentationDialog = NULL; - //m_ThresholdingToolManager->SetReferenceData(NULL); - //m_ThresholdingToolManager->SetWorkingData(NULL); - RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkOtsuAction::SetDataStorage(DataStorage *dataStorage) { m_DataStorage = dataStorage; } void QmitkOtsuAction::SetFunctionality(QtViewPart* /*functionality*/) { } void QmitkOtsuAction::PerformOtsuSegmentation() { this->m_OtsuSegmentationDialog->setCursor(Qt::WaitCursor); int numberOfThresholds = this->m_OtsuSpinBox->value() - 1; int proceed; QMessageBox* messageBox = new QMessageBox(QMessageBox::Question, NULL, "The otsu segmentation computation may take several minutes depending on the number of Regions you selected. Proceed anyway?", QMessageBox::Ok | QMessageBox::Cancel); if (numberOfThresholds >= 5) { proceed = messageBox->exec(); if (proceed != QMessageBox::Ok) return; } mitk::Image::Pointer mitkImage = 0; mitkImage = dynamic_cast( this->m_DataNode->GetData() ); try { // get selected mitk image const unsigned short dim = 3; typedef short InputPixelType; typedef unsigned char OutputPixelType; typedef itk::Image< InputPixelType, dim > InputImageType; typedef itk::Image< OutputPixelType, dim > OutputImageType; - //typedef itk::OtsuThresholdImageFilter< InputImageType, OutputImageType > FilterType; typedef itk::OtsuMultipleThresholdsImageFilter< InputImageType, OutputImageType > FilterType; - //typedef itk::MultiplyImageFilter< OutputImageType, OutputImageType, OutputImageType> MultiplyFilterType; - //typedef itk::RandomImageSource< OutputImageType> RandomImageSourceType; - //typedef itk::ImageRegionIterator< OutputImageType > ImageIteratorType; - FilterType::Pointer filter = FilterType::New(); - //MultiplyFilterType::Pointer multiplyImageFilter = MultiplyFilterType::New(); - //RandomImageSourceType::Pointer randomImageSource = RandomImageSourceType::New(); filter->SetNumberOfThresholds(numberOfThresholds); - //filter->SetLabelOffset(0); - /* - filter->SetOutsideValue( 1 ); - filter->SetInsideValue( 0 );*/ InputImageType::Pointer itkImage; mitk::CastToItkImage(mitkImage, itkImage); filter->SetInput( itkImage ); -// filter->UpdateOutputInformation(); - - //multiplyImageFilter->SetInput1(filter->GetOutput()); - //OutputImageType::Pointer constantImage = OutputImageType::New(); - //constantImage->SetLargestPossibleRegion(filter->GetOutput()->GetLargestPossibleRegion()); - //constantImage->SetBufferedRegion(filter->GetOutput()->GetLargestPossibleRegion()); - //constantImage->Allocate(); - //ImageIteratorType it(constantImage, constantImage->GetLargestPossibleRegion()); - //while (!it.IsAtEnd()) - //{ - // it.Set(1); - // ++it; - //} - - ////randomImageSource->SetSize(filter->GetOutput()->GetLargestPossibleRegion().GetSize()); - ////multiplyImageFilter->SetInput2(randomImageSource->GetOutput()); - //multiplyImageFilter->SetInput2(constantImage); filter->Update(); - //multiplyImageFilter->Update(); mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); std::string nameOfResultImage = this->m_DataNode->GetName(); nameOfResultImage.append("Otsu"); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); resultNode->SetProperty("binary", mitk::BoolProperty::New(false) ); - resultNode->SetProperty("use color", mitk::BoolProperty::New(false) ); + + mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); + renderingMode->SetValue( mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR ); + resultNode->SetProperty("Image Rendering.Mode", renderingMode); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut); - //resultNode->GetProperty(prop, "LookupTable"); - vtkLookupTable *lookupTable = vtkLookupTable::New(); lookupTable->SetHueRange(1.0, 0.0); lookupTable->SetSaturationRange(1.0, 1.0); lookupTable->SetValueRange(1.0, 1.0); lookupTable->SetTableRange(-1.0, 1.0); lookupTable->Build(); lut->SetVtkLookupTable(lookupTable); prop->SetLookupTable(lut); resultNode->SetProperty("LookupTable",prop); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; - levelwindow.SetRangeMinMax(0, numberOfThresholds); + levelwindow.SetRangeMinMax(0, numberOfThresholds + 1); levWinProp->SetLevelWindow( levelwindow ); resultNode->SetProperty( "levelwindow", levWinProp ); - //resultNode->SetData( mitk::ImportItkImage ( filter->GetOutput() ) ); resultNode->SetData( mitk::ImportItkImage ( filter->GetOutput() ) ); this->m_DataStorage->Add(resultNode, this->m_DataNode); this->m_OtsuSegmentationDialog->setCursor(Qt::ArrowCursor); } catch( std::exception& err ) { MITK_ERROR(this->GetClassName()) << err.what(); } } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp index e9dcc42f5c..5a696f73a5 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp @@ -1,128 +1,214 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include //Mitk -#include "mitkDataNode.h" +#include +#include +#include // Qmitk #include "UltrasoundSupport.h" #include // Qt #include // Ultrasound #include "mitkUSDevice.h" const std::string UltrasoundSupport::VIEW_ID = "org.mitk.views.ultrasoundsupport"; void UltrasoundSupport::SetFocus() { m_Controls.m_AddDevice->setFocus(); } void UltrasoundSupport::CreateQtPartControl( QWidget *parent ) { m_Timer = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); connect( m_Controls.m_AddDevice, SIGNAL(clicked()), this, SLOT(OnClickedAddNewDevice()) ); // Change Widget Visibilities connect( m_Controls.m_AddDevice, SIGNAL(clicked()), this->m_Controls.m_NewVideoDeviceWidget, SLOT(CreateNewDevice()) ); // Init NewDeviceWidget connect( m_Controls.m_NewVideoDeviceWidget, SIGNAL(Finished()), this, SLOT(OnNewDeviceWidgetDone()) ); // After NewDeviceWidget finished editing connect( m_Controls.m_BtnView, SIGNAL(clicked()), this, SLOT(OnClickedViewDevice()) ); connect( m_Timer, SIGNAL(timeout()), this, SLOT(DisplayImage())); + connect( m_Controls.crop_left, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged()) ); + connect( m_Controls.crop_right, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged()) ); + connect( m_Controls.crop_top, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged()) ); + connect( m_Controls.crop_bot, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged()) ); + + //connect (m_Controls.m_ActiveVideoDevices, SIGNAL()) // Initializations m_Controls.m_NewVideoDeviceWidget->setVisible(false); - std::string filter = "(&(" + mitk::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(IsActive=true))"; - m_Controls.m_ActiveVideoDevices->Initialize(mitk::USImageMetadata::PROP_DEV_MODEL ,filter); + std::string filter = "(&(" + mitk::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::US_PROPKEY_ISACTIVE + "=true))"; + m_Controls.m_ActiveVideoDevices->Initialize(mitk::USDevice::US_PROPKEY_LABEL ,filter); + + //UI initializations + m_Controls.crop_left->setEnabled(false); + m_Controls.crop_right->setEnabled(false); + m_Controls.crop_bot->setEnabled(false); + m_Controls.crop_top->setEnabled(false); m_Node = mitk::DataNode::New(); m_Node->SetName("US Image Stream"); this->GetDataStorage()->Add(m_Node); } void UltrasoundSupport::OnClickedAddNewDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_AddDevice->setVisible(false); m_Controls.m_Headline->setText("Add New Device:"); } void UltrasoundSupport::DisplayImage() { - // m_Device->UpdateOutputData(0); - // mitk::USImage::Pointer image = m_Device->GetOutput(); - m_Device->UpdateOutputData(0); m_Node->SetData(m_Device->GetOutput()); this->RequestRenderWindowUpdate(); m_FrameCounter ++; if (m_FrameCounter == 10) { int nMilliseconds = m_Clock.restart(); - float fps = 10000.0f / (nMilliseconds ); + int fps = 10000.0f / (nMilliseconds ); m_Controls.m_FramerateLabel->setText("Current Framerate: "+ QString::number(fps) +" FPS"); m_FrameCounter = 0; } } +void UltrasoundSupport::OnCropAreaChanged() +{ +if (m_Device->GetDeviceClass()=="org.mitk.modules.us.USVideoDevice") + { + mitk::USVideoDevice::Pointer currentVideoDevice = dynamic_cast(m_Device.GetPointer()); + + mitk::USDevice::USImageCropArea newArea; + newArea.cropLeft = m_Controls.crop_left->value(); + newArea.cropTop = m_Controls.crop_top->value(); + newArea.cropRight = m_Controls.crop_right->value(); + newArea.cropBottom = m_Controls.crop_bot->value(); + + //check enabled: if not we are in the initializing step and don't need to do anything + //otherwise: update crop area + if (m_Controls.crop_right->isEnabled()) + currentVideoDevice->SetCropArea(newArea); + + GlobalReinit(); + } +else + { + MITK_WARN << "No USVideoDevice: Cannot Crop!"; + } +} + void UltrasoundSupport::OnClickedViewDevice() { m_FrameCounter = 0; + // We use the activity state of the timer to determine whether we are currently viewing images if ( ! m_Timer->isActive() ) // Activate Imaging { + //get device & set data node m_Device = m_Controls.m_ActiveVideoDevices->GetSelectedService(); if (m_Device.IsNull()){ m_Timer->stop(); return; } - //m_Device->UpdateOutputData(0); m_Device->Update(); m_Node->SetData(m_Device->GetOutput()); + + //start timer int interval = (1000 / m_Controls.m_FrameRate->value()); m_Timer->setInterval(interval); m_Timer->start(); + + //reinit view + GlobalReinit(); + + //change UI elements m_Controls.m_BtnView->setText("Stop Viewing"); + m_Controls.m_FrameRate->setEnabled(false); + m_Controls.crop_left->setValue(m_Device->GetCropArea().cropLeft); + m_Controls.crop_right->setValue(m_Device->GetCropArea().cropRight); + m_Controls.crop_bot->setValue(m_Device->GetCropArea().cropBottom); + m_Controls.crop_top->setValue(m_Device->GetCropArea().cropTop); + m_Controls.crop_left->setEnabled(true); + m_Controls.crop_right->setEnabled(true); + m_Controls.crop_bot->setEnabled(true); + m_Controls.crop_top->setEnabled(true); } - else - { //deactivate imaging - m_Controls.m_BtnView->setText("Start Viewing"); + else //deactivate imaging + { + //stop timer & release data m_Timer->stop(); m_Node->ReleaseData(); this->RequestRenderWindowUpdate(); + + //change UI elements + m_Controls.m_BtnView->setText("Start Viewing"); + m_Controls.m_FrameRate->setEnabled(true); + m_Controls.crop_left->setEnabled(false); + m_Controls.crop_right->setEnabled(false); + m_Controls.crop_bot->setEnabled(false); + m_Controls.crop_top->setEnabled(false); } } void UltrasoundSupport::OnNewDeviceWidgetDone() { m_Controls.m_NewVideoDeviceWidget->setVisible(false); m_Controls.m_DeviceManagerWidget->setVisible(true); m_Controls.m_AddDevice->setVisible(true); m_Controls.m_Headline->setText("Connected Devices:"); +} + +void UltrasoundSupport::GlobalReinit() +{ + // get all nodes that have not set "includeInBoundingBox" to false + mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); + mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); + + // calculate bounding geometry of these nodes + mitk::TimeSlicedGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs, "visible"); + + // initialize the views to the bounding geometry + mitk::RenderingManager::GetInstance()->InitializeViews(bounds); +} + +UltrasoundSupport::UltrasoundSupport() +{ +m_DevicePersistence = mitk::USDevicePersistence::New(); +m_DevicePersistence->RestoreLastDevices(); +} + +UltrasoundSupport::~UltrasoundSupport() +{ +m_DevicePersistence->StoreCurrentDevices(); +m_Controls.m_DeviceManagerWidget->DisconnectAllDevices(); } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h index bf8a990af0..0bc0766b9d 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h @@ -1,97 +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. ===================================================================*/ #ifndef UltrasoundSupport_h #define UltrasoundSupport_h #include #include +#include #include "ui_UltrasoundSupportControls.h" #include /*! \brief UltrasoundSupport This plugin provides functionality to manage Ultrasound devices, create video devices and to view device images. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class UltrasoundSupport : 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: virtual void SetFocus(); static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent); - signals: + UltrasoundSupport(); + virtual ~UltrasoundSupport(); public slots: /* * \brief This is called when the newDeviceWidget is closed */ void OnNewDeviceWidgetDone(); protected slots: void OnClickedAddNewDevice(); void OnClickedViewDevice(); + void OnCropAreaChanged(); + /* * \brief This is the main imaging loop that is called regularily during the imaging process */ void DisplayImage(); protected: + + int m_FrameCounter; /* * \brief This timer triggers periodic updates to the pipeline */ QTimer *m_Timer; QTime m_Clock; /* * \brief The device that is currently used to aquire images */ mitk::USDevice::Pointer m_Device; /* * \brief The node that we feed images into */ mitk::DataNode::Pointer m_Node; mitk::Image::Pointer m_Image; Ui::UltrasoundSupportControls m_Controls; + /** @brief reinits the view globally. */ + void GlobalReinit(); + + mitk::USDevicePersistence::Pointer m_DevicePersistence; + }; #endif // UltrasoundSupport_h diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupportControls.ui b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupportControls.ui index 9e89ec192d..03a2baab20 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupportControls.ui +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupportControls.ui @@ -1,193 +1,450 @@ UltrasoundSupportControls 0 0 - 467 + 410 461 0 0 QmitkTemplate 0 Device Management 12 75 true - Connected Devices: + Ultrasound Devices: - - - New Device - - + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 120 + 0 + + + + New Device + + + + Qt::Vertical 20 40 US Imaging - + 12 75 true Active Ultrasound Devices: 0 0 - - - Start Viewing + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 120 + 0 + + + + Start Viewing + + + + + + + + + Qt::Vertical - + + + 20 + 40 + + + - - - Current Framerate: 0 FPS + + + Qt::Horizontal - - - - 75 - true - - + - Framerate Limit: + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Crop Ultrasound Image:</span></p></body></html> - - - 1 - - - 50 - - - 30 + + + + + + + Top + + + + + + + + + 999 + + + 5 + + + + + + + mm + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Bottom + + + + + + + + + 999 + + + 5 + + + + + + + mm + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Right + + + + + + + + + 999 + + + 5 + + + + + + + mm + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Left + + + + + + + + + 999 + + + 5 + + + + + + + mm + + + + + + + + + + + + + Qt::Horizontal - + - (Restart viewing to make changes effective) + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Framrate Settings:</span></p></body></html> - - - Qt::Vertical - - - - 20 - 40 - + + + Current Framerate: 0 FPS - + + + + + + + + Framerate Limit: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 1 + + + 50 + + + 30 + + + + QmitkUSDeviceManagerWidget QWidget
QmitkUSDeviceManagerWidget.h
1
QmitkUSNewVideoDeviceWidget QWidget
QmitkUSNewVideoDeviceWidget.h
1
QmitkServiceListWidget QWidget
QmitkServiceListWidget.h
1
diff --git a/SuperBuild.cmake b/SuperBuild.cmake index a23d2bce16..d886c417bd 100644 --- a/SuperBuild.cmake +++ b/SuperBuild.cmake @@ -1,308 +1,353 @@ #----------------------------------------------------------------------------- # Convenient macro allowing to download a file #----------------------------------------------------------------------------- macro(downloadFile url dest) file(DOWNLOAD ${url} ${dest} STATUS status) list(GET status 0 error_code) list(GET status 1 error_msg) if(error_code) message(FATAL_ERROR "error: Failed to download ${url} - ${error_msg}") endif() endmacro() #----------------------------------------------------------------------------- # MITK Prerequisites #----------------------------------------------------------------------------- if(UNIX AND NOT APPLE) include(mitkFunctionCheckPackageHeader) # Check for libxt-dev mitkFunctionCheckPackageHeader(StringDefs.h libxt-dev /usr/include/X11/) # Check for libtiff4-dev mitkFunctionCheckPackageHeader(tiff.h libtiff4-dev) # Check for libwrap0-dev mitkFunctionCheckPackageHeader(tcpd.h libwrap0-dev) endif() #----------------------------------------------------------------------------- # ExternalProjects #----------------------------------------------------------------------------- set(external_projects VTK GDCM CableSwig ITK Boost DCMTK CTK OpenCV SOFA MITKData ) - set(MITK_USE_CableSwig ${MITK_USE_Python}) set(MITK_USE_GDCM 1) set(MITK_USE_ITK 1) set(MITK_USE_VTK 1) foreach(proj VTK GDCM CableSwig ITK DCMTK CTK OpenCV SOFA) 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() if(BUILD_TESTING) set(EXTERNAL_MITK_DATA_DIR "${MITK_DATA_DIR}" CACHE PATH "Path to the MITK data directory") mark_as_advanced(EXTERNAL_MITK_DATA_DIR) if(EXTERNAL_MITK_DATA_DIR) set(MITK_DATA_DIR ${EXTERNAL_MITK_DATA_DIR}) endif() endif() # Look for git early on, if needed if((BUILD_TESTING AND NOT EXTERNAL_MITK_DATA_DIR) OR (MITK_USE_CTK AND NOT EXTERNAL_CTK_DIR)) find_package(Git REQUIRED) endif() #----------------------------------------------------------------------------- # External project settings #----------------------------------------------------------------------------- include(ExternalProject) set(ep_base "${CMAKE_BINARY_DIR}/CMakeExternals") set_property(DIRECTORY PROPERTY EP_BASE ${ep_base}) set(ep_install_dir ${ep_base}/Install) #set(ep_build_dir ${ep_base}/Build) set(ep_source_dir ${ep_base}/Source) #set(ep_parallelism_level) set(ep_build_shared_libs ON) set(ep_build_testing OFF) if(NOT MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL) set(MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL http://mitk.org/download/thirdparty) endif() # Compute -G arg for configuring external projects with the same CMake generator: if(CMAKE_EXTRA_GENERATOR) set(gen "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}") else() set(gen "${CMAKE_GENERATOR}") endif() # Use this value where semi-colons are needed in ep_add args: set(sep "^^") ## -if(MSVC90 OR MSVC10) - set(ep_common_C_FLAGS "${CMAKE_C_FLAGS} /bigobj /MP") - set(ep_common_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /MP") -else() - set(ep_common_C_FLAGS "${CMAKE_C_FLAGS} -DLINUX_EXTRA") - set(ep_common_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLINUX_EXTRA") +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} -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=${ep_common_C_FLAGS} - -DCMAKE_CXX_FLAGS:STRING=${ep_common_CXX_FLAGS} + -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} ) # 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_Boost MITK_USE_SYSTEM_Boost MITK_USE_BLUEBERRY MITK_USE_CTK MITK_USE_DCMTK MITK_DCMTK_BUILD_SHARED_LIBS MITK_USE_OpenCV MITK_USE_SOFA MITK_USE_Python MITK_USE_OpenCL ) #----------------------------------------------------------------------------- # 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 ${VTK_DEPENDS} ${ITK_DEPENDS} # Optionnal dependencies ${Boost_DEPENDS} ${CTK_DEPENDS} ${DCMTK_DEPENDS} ${OpenCV_DEPENDS} ${SOFA_DEPENDS} ${MITK-Data_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() set(proj MITK-Configure) ExternalProject_Add(${proj} LIST_SEPARATOR ^^ DOWNLOAD_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_CACHE_ARGS - ${ep_common_args} - ${mitk_superbuild_boolean_args} - ${mitk_optional_cache_args} - -DMITK_USE_SUPERBUILD:BOOL=OFF + # --------------- 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 -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_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_DIMENSIONS:STRING=${MITK_ACCESSBYITK_DIMENSIONS} + # --------------- External project dirs --------------- -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} -DMITK_KWSTYLE_EXECUTABLE:FILEPATH=${MITK_KWSTYLE_EXECUTABLE} - -DMITK_MODULES_TO_BUILD:INTERNAL=${MITK_MODULES_TO_BUILD} -DCTK_DIR:PATH=${CTK_DIR} -DDCMTK_DIR:PATH=${DCMTK_DIR} -DVTK_DIR:PATH=${VTK_DIR} # FindVTK expects VTK_DIR -DITK_DIR:PATH=${ITK_DIR} # FindITK expects ITK_DIR -DOpenCV_DIR:PATH=${OpenCV_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} - -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_DIMENSIONS:STRING=${MITK_ACCESSBYITK_DIMENSIONS} CMAKE_ARGS ${mitk_initial_cache_arg} 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 ) diff --git a/Wrapping/CMakeLists.txt b/Wrapping/CMakeLists.txt deleted file mode 100644 index a20ab40a53..0000000000 --- a/Wrapping/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -project(mitkWrap) -cmake_minimum_required(VERSION 2.6) - -include(${CMAKE_CURRENT_SOURCE_DIR}/mitkWrapSetup.cmake) - -# Find wrapping language API libraries. -if(MITK_USE_Python) - include(${CMAKE_ROOT}/Modules/FindPythonLibs.cmake) - find_program(PYTHON_EXECUTABLE - NAMES python python2.3 python2.2 python2.1 python2.0 python1.6 python1.5 - PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.2\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.1\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.0\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\1.6\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\1.5\\InstallPath] - ) - mark_as_advanced(PYTHON_EXECUTABLE) -endif(MITK_USE_Python) - -mark_as_advanced(MITK_USE_Python) -mark_as_advanced(CABLE_INDEX) -mark_as_advanced(CSWIG) -mark_as_advanced(GCCXML) - -# set a variable to determine if -# the CSwig directory should be used -set(MITK_CSWIG_DIR 0) -if(MITK_USE_Python) - set(MITK_CSWIG_DIR 1) -endif(MITK_USE_Python) - -if(MITK_CSWIG_DIR) - subdirs(CSwig) -endif(MITK_CSWIG_DIR) diff --git a/Wrapping/CSwig/CMakeLists.txt b/Wrapping/CSwig/CMakeLists.txt deleted file mode 100644 index 19eb58b447..0000000000 --- a/Wrapping/CSwig/CMakeLists.txt +++ /dev/null @@ -1,524 +0,0 @@ -if(CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") -endif(CMAKE_COMPILER_IS_GNUCXX) - -if(MITK_USE_Python) - # Python include directory. - set(MITK_INCLUDE_DIRS ${MITK_INCLUDE_DIRS} - ${PYTHON_INCLUDE_PATH}) -endif(MITK_USE_Python) - -# We have found CableSwig. Use the settings. -set(CABLE_INDEX ${CableSwig_cableidx_EXE}) -set(CSWIG ${CableSwig_cswig_EXE}) -set(GCCXML ${CableSwig_gccxml_EXE}) -set(MITK_WRAPPING_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(MITK_WRAPPING_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) - -#set(MITK_WRAP_NEEDS_DEPEND 1) -#if(${CMAKE_MAKE_PROGRAM} MATCHES make) - #set(MITK_WRAP_NEEDS_DEPEND 0) -#endif(${CMAKE_MAKE_PROGRAM} MATCHES make) -set(MITK_TOP ${MITK_SOURCE_DIR}) -set(MITK_SWIG_DEFAULT_LIB ${CableSwig_DIR}/Swig/Lib ) -set(MITK_WRAP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(MITK_WRAP_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) - -set(CSWIG_EXTRA_LINKFLAGS ) -if(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)") - set(CSWIG_EXTRA_LINKFLAGS "/IGNORE:4049") -endif(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)") - -if(CMAKE_SYSTEM MATCHES "IRIX.*") - if(CMAKE_CXX_COMPILER MATCHES "CC") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -woff 1552") - endif(CMAKE_CXX_COMPILER MATCHES "CC") -endif(CMAKE_SYSTEM MATCHES "IRIX.*") - -if(CMAKE_COMPILER_IS_GNUCXX) - string(REGEX REPLACE "-Wcast-qual" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -endif(CMAKE_COMPILER_IS_GNUCXX) - -set(IGNORE_WARNINGS -w362 -w389 -w503 -w508 -w509 -w516) -# define macros for wrapping commands -macro(GCCXML_CREATE_XML_FILE Source Bin Input Output Library) -# if the make program is not an IDE then include -# the depend file in a way that will make cmake -# re-run if it changes - set(CABLE_SWIG_DEPEND) - set(CABLE_SWIG_DEPEND_REGENERATE) - if(${CMAKE_MAKE_PROGRAM} MATCHES "make") - if(EXISTS ${Bin}/${Output}.depend) - else(EXISTS ${Bin}/${Output}.depend) - configure_file( - ${MITK_SOURCE_DIR}/Wrapping/CSwig/empty.depend.in - ${Bin}/${Output}.depend @ONLY IMMEDIATE) - endif(EXISTS ${Bin}/${Output}.depend) - include(${Bin}/${Output}.depend) - else(${CMAKE_MAKE_PROGRAM} MATCHES "make") -# for IDE generators like MS dev only include the depend files -# if they exist. This is to prevent ecessive reloading of -# workspaces after each build. This also means -# that the depends will not be correct until cmake -# is run once after the build has completed once. -# the depend files are created in the wrap tcl/python sections -# when the .xml file is parsed. - include(${Bin}/${Output}.depend OPTIONAL) - endif(${CMAKE_MAKE_PROGRAM} MATCHES "make") - - if(CABLE_SWIG_DEPEND) - # There are dependencies. Make sure all the files are present. - # If not, force the rule to re-run to update the dependencies. - foreach(f ${CABLE_SWIG_DEPEND}) - if(EXISTS ${f}) - else(EXISTS ${f}) - set(CABLE_SWIG_DEPEND_REGENERATE 1) - endif(EXISTS ${f}) - endforeach(f) - else(CABLE_SWIG_DEPEND) - # No dependencies, make the output depend on the dependency file - # itself, which should cause the rule to re-run. - set(CABLE_SWIG_DEPEND_REGENERATE 1) - endif(CABLE_SWIG_DEPEND) - if(CABLE_SWIG_DEPEND_REGENERATE) - set(CABLE_SWIG_DEPEND ${Bin}/${Output}.depend) - configure_file( - ${MITK_SOURCE_DIR}/Wrapping/CSwig/empty.depend.in - ${Bin}/${Output}.depend @ONLY IMMEDIATE) - endif(CABLE_SWIG_DEPEND_REGENERATE) - set(OutDir "Debug") - - if(WIN32) - set(OS -DWIN32) - endif(WIN32) - - add_custom_command( - COMMENT "${Output} from " - SOURCE ${Source}/${Input} - COMMAND ${GCCXML} - ARGS -fxml-start=_cable_ - -fxml=${Bin}/${Output} --gccxml-gcc-options ${SWIG_INC_FILE} - ${OS} - -DCSWIG -DCABLE_CONFIGURATION ${Source}/${Input} - TARGET ${Library} - OUTPUTS ${Bin}/${Output} - DEPENDS ${GCCXML} ${CABLE_SWIG_DEPEND}) - -endmacro(GCCXML_CREATE_XML_FILE) - - -macro(CINDEX_CREATE_IDX_FILE Bin Input Output Library) - add_custom_command( - COMMENT "${Output} from " - SOURCE ${Bin}/${Input} - COMMAND ${CABLE_INDEX} - ARGS ${Bin}/${Input} ${Bin}/${Output} - TARGET ${Library} - OUTPUTS ${Bin}/${Output} - DEPENDS ${Bin}/${Input} ${CABLE_INDEX} -) -endmacro(CINDEX_CREATE_IDX_FILE) - -set(MITK_USE_Python_NO_EXCEPTION_REGEX "(ContinuousIndex|Python)\\.xml$") - -macro(CSWIG_CREATE_PYTHON_CXX_FILE Bin MasterIdx InputIdx InputXml OutputPythonCxx Library LibraryIndexFiles) - set(CINDEX) - foreach(MIDX ${MasterIdx}) - set(CINDEX ${CINDEX} -Cindex "${MIDX}") - endforeach(MIDX) - if("${InputXml}" MATCHES "${MITK_USE_Python_NO_EXCEPTION_REGEX}") - set(MITK_SWG_FILE "") - else("${InputXml}" MATCHES "${MITK_USE_Python_NO_EXCEPTION_REGEX}") - set(MITK_SWG_FILE "-l${MITK_CSWIG_SOURCE_DIR}/mitk.swg" "-l${MITK_CSWIG_SOURCE_DIR}/mitkvtk.swg") - endif("${InputXml}" MATCHES "${MITK_USE_Python_NO_EXCEPTION_REGEX}") - string(REPLACE "_" "" LIB_PYTHON_FILES ${Library}) - - #message(STATUS "CMAKE_CFG_INTDIR: ${CMAKE_CFG_INTDIR}") - #message(STATUS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/${LIB_PYTHON_FILES}") - #make_directory(${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/${LIB_PYTHON_FILES}) - make_directory(${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${LIB_PYTHON_FILES}) - file(WRITE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${LIB_PYTHON_FILES}/__init__.py "from mitkCorePython import *") - - add_custom_command( - COMMENT "${OutputPythonCxx} from " - SOURCE ${Bin}/${InputIdx} - COMMAND ${CSWIG} - ARGS ${MITK_SWG_FILE} - -I${MITK_SWIG_DEFAULT_LIB} - -I${MITK_SWIG_DEFAULT_LIB}/python - -noruntime - -dirprot - #-keyword - ${CINDEX} ${IGNORE_WARNINGS} -depend ${Bin}/${InputXml}.depend - -outdir "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CFG_INTDIR}/${LIB_PYTHON_FILES}" - -o ${Bin}/${OutputPythonCxx} -python -c++ ${Bin}/${InputXml} - TARGET ${Library} - OUTPUTS ${Bin}/${OutputPythonCxx} - DEPENDS ${LibraryIndexFiles} ${MITK_CSWIG_SOURCE_DIR}/mitk.swg ${MITK_CSWIG_SOURCE_DIR}/mitk.swg ${Bin}/${InputXml} ${CSWIG} ) -endmacro(CSWIG_CREATE_PYTHON_CXX_FILE) - -# macro to create .xml, .idx and Python.cxx files -macro(WRAP_PYTHON_SOURCES Source Bin BaseName LibraryName MasterIdx LibraryIndexFiles) - GCCXML_CREATE_XML_FILE(${Source} ${Bin} ${BaseName}.cxx ${BaseName}.xml ${LibraryName}) - CINDEX_CREATE_IDX_FILE(${Bin} ${BaseName}.xml ${BaseName}.idx ${LibraryName}) - CSWIG_CREATE_PYTHON_CXX_FILE(${Bin} "${MasterIdx}" ${BaseName}.idx ${BaseName}.xml - ${BaseName}Python.cxx ${LibraryName} "${LibraryIndexFiles}") -endmacro(WRAP_PYTHON_SOURCES) - -# make sure required stuff is set -if(NOT EXECUTABLE_OUTPUT_PATH) - set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin CACHE INTERNAL "Single output directory for building all executables.") -endif(NOT EXECUTABLE_OUTPUT_PATH) - -set(MITK_CSWIG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) -set(MITK_CSWIG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - -if(MITK_LIBRARY_DIRS) - string(REGEX REPLACE "^/" "" MITK_INSTALL_LIBRARY_DIR "${MITK_LIBRARY_DIRS}") -endif(MITK_LIBRARY_DIRS) -if(MITK_BINARY_DIR) - string(REGEX REPLACE "^/" "" MITK_INSTALL_BIN_DIR "${MITK_BINARY_DIR}") -endif(MITK_BINARY_DIR) -set(CSWIG_MISSING_VALUES) -if(NOT CSWIG) - set(CSWIG_MISSING_VALUES "${CSWIG_MISSING_VALUES} CSWIG ") -endif(NOT CSWIG) -if(NOT CABLE_INDEX) - set(CSWIG_MISSING_VALUES "${CSWIG_MISSING_VALUES} CABLE_INDEX ") -endif(NOT CABLE_INDEX) -if(NOT GCCXML) - set(CSWIG_MISSING_VALUES "${CSWIG_MISSING_VALUES} GCCXML ") -endif(NOT GCCXML) -if(CSWIG_MISSING_VALUES) - message(SEND_ERROR "To use cswig wrapping, CSWIG, CABLE_INDEX, and GCCXML executables must be specified. If they are all in the same directory, only specifiy one of them, and then run cmake configure again and the others should be found.\nCurrently, you are missing the following:\n ${CSWIG_MISSING_VALUES}") -endif(CSWIG_MISSING_VALUES) - - -if(MITK_USE_Python) - include_directories(${PYTHON_INCLUDE_PATH} ) -endif(MITK_USE_Python) - -set(SWIG_INC - ${MITK_INCLUDE_DIRS_BUILD_TREE} - ${MITK_INCLUDE_DIRS_BUILD_TREE_CXX} - ${MITK_INCLUDE_DIRS} - ${MITK_TOP}/Wrapping/CSwig - ${MITK_TOP}/Wrapping/CSwig/Core - ) -add_definitions(-DSWIG_GLOBAL) - -include(PythonMITKModules.cmake) - -add_subdirectory(SwigRuntime) - -if(UNIX) - set(MITK_CSWIG_LIBNAME_PREFIX "lib") -else(UNIX) - set(MITK_CSWIG_LIBNAME_PREFIX "") -endif(UNIX) - -set(MITK_CSWIG_PACKAGE_DIR_BUILD "${MITK_LIBRARY_PATH}") - -#----------------------------------------------------------------------------- -# Configure python packages. -set(MITK_CSWIG_DATA_ROOT "'${MITK_DATA_ROOT}'") -set(MITK_CSWIG_TEST_ROOT "'${MITK_BINARY_DIR}/Testing'") -#if(MITK_CSWIG_CONFIGURATION_TYPES) - #foreach(config ${MITK_CSWIG_CONFIGURATION_TYPES}) - #set(ITK_CSWIG_PACKAGE_DIR "'${MITK_CSWIG_PACKAGE_DIR_BUILD}/${config}'") - #configure_file("${MITK_SOURCE_DIR}/Wrapping/CSwig/Python/mitkbase.py.in" - #"${MITK_BINARY_DIR}/Wrapping/CSwig/Python/${config}/mitkbase.py" - #@ONLY IMMEDIATE) - #endforeach(config) -#else(MITK_CSWIG_CONFIGURATION_TYPES) - #set(MITK_CSWIG_PACKAGE_DIR "'${MITK_CSWIG_PACKAGE_DIR_BUILD}'") - #configure_file("${MITK_SOURCE_DIR}/Wrapping/CSwig/Python/mitkbase.py.in" - #"${MITK_BINARY_DIR}/Wrapping/CSwig/Python/mitkbase.py" - #@ONLY IMMEDIATE) -#endif(MITK_CSWIG_CONFIGURATION_TYPES) - -# Handle out-of-source builds correctly. -# -# 1. Create a list of Python files to be installed/copied. -# 2. Copy them to ITK_BINARY_DIR if it is different from ITK_SOURCE_DIR. -# 3. Use Python's compileall to compile the copied files. -# -# *** Step 1 has to be done carefully to avoid missing out files *** -if(PYTHON_EXECUTABLE AND MITK_USE_Python) - - #file(WRITE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mitk.py "") - #configure_file(Python/mitk.py.in ${CMAKE_CURRENT_BINARY_DIR}/mitk.py) - file(COPY Python/mitkCast.py DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE) - - - set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake) - add_custom_target(mitkpython_pyc ALL echo "...") - - # Make the necessary directories. - make_directory(${MITK_BINARY_DIR}/Wrapping/CSwig/Python) - - # Now create a list of Python files. - set(MITK_PYTHON_FILES) - - # Wrapping/CSwig/Python/*.py - set(MITK_PYTHON_FILES - ${MITK_PYTHON_FILES} - mitk - ) - # Done listing files. - - # Now copy these files if necessary. - set(MITK_PYTHON_SOURCE_FILES) - set(MITK_PYTHON_OUTPUT_FILES) - #if(MITK_CSWIG_CONFIGURATION_TYPES) - #foreach(file ${MITK_PYTHON_FILES}) - #set(src "${MITK_BINARY_DIR}/Wrapping/CSwig/Python/${CMAKE_CFG_INTDIR}/${file}.py") - #set(MITK_PYTHON_SOURCE_FILES ${MITK_PYTHON_SOURCE_FILES} ${src}) - #endforeach(file) - #else(MITK_CSWIG_CONFIGURATION_TYPES) - #foreach(file ${MITK_PYTHON_FILES}) - #set(src "${MITK_BINARY_DIR}/Wrapping/CSwig/Python/${file}.py") - #set(ITK_PYTHON_SOURCE_FILES ${MITK_PYTHON_SOURCE_FILES} ${src}) - #endforeach(file) - #endif(MITK_CSWIG_CONFIGURATION_TYPES) - #if("${MITK_BINARY_DIR}" MATCHES "^${MITK_SOURCE_DIR}$") - #message("In source build -- no need to copy Python files.") - #else("${MITK_BINARY_DIR}" MATCHES "^${MITK_SOURCE_DIR}$") - #if(MITK_CSWIG_CONFIGURATION_TYPES) - #foreach(file ${MITK_PYTHON_FILES}) - #set(src "${MITK_SOURCE_DIR}/Wrapping/CSwig/Python/${file}.py") - #set(tgt "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${file}.py") - #add_custom_command(SOURCE ${src} - #COMMAND ${CMAKE_COMMAND} - #ARGS -E copy ${src} ${tgt} - #OUTPUTS ${tgt} - #TARGET copy - #COMMENT "source copy") - #endforeach(file) - #else(MITK_CSWIG_CONFIGURATION_TYPES) - #foreach(file ${MITK_PYTHON_FILES}) - #set(src "${MITK_SOURCE_DIR}/Wrapping/CSwig/Python/${file}.py") - #set(tgt "${MITK_BINARY_DIR}/Wrapping/CSwig/Python/${file}.py") - #add_custom_command(SOURCE ${src} - #COMMAND ${CMAKE_COMMAND} - #ARGS -E copy ${src} ${tgt} - #OUTPUTS ${tgt} - #TARGET mitkpython_pyc - #COMMENT "source copy") - #endforeach(file) - #endif(MITK_CSWIG_CONFIGURATION_TYPES) - #endif("${MITK_BINARY_DIR}" MATCHES "^${MITK_SOURCE_DIR}$") - - # Byte compile the Python files. - write_file(${MITK_BINARY_DIR}/Wrapping/CSwig/Python/compile_all_mitk - "import compileall\n" - "compileall.compile_dir('${MITK_BINARY_DIR}/Wrapping/CSwig/Python')\n" - "file = open('${MITK_BINARY_DIR}/Wrapping/CSwig/Python/mitk_compile_complete', 'w')\n" - "file.write('Done')\n") - - add_custom_command( - SOURCE ${MITK_BINARY_DIR}/Wrapping/CSwig/Python/compile_all_mitk - COMMAND ${PYTHON_EXECUTABLE} - ARGS ${MITK_BINARY_DIR}/Wrapping/CSwig/Python/compile_all_mitk - DEPENDS ${MITK_PYTHON_SOURCE_FILES} - OUTPUTS "${MITK_BINARY_DIR}/Wrapping/CSwig/Python/mitk_compile_complete" - TARGET mitkpython_pyc - ) - - add_custom_command( - SOURCE mitkpython_pyc - DEPENDS "${MITK_BINARY_DIR}/Wrapping/CSwig/Python/mitk_compile_complete" - TARGET mitkpython_pyc - ) - -endif(PYTHON_EXECUTABLE AND MITK_USE_Python) - -if(MITK_USE_Python) - # Install the python files created at build time. - if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" STREQUAL "2.4") - # Old-style installation. - configure_file( - "${MITK_CSWIG_SOURCE_DIR}/pythonfiles_install.cmake.in" - "${MITK_CSWIG_BINARY_DIR}/pythonfiles_install.cmake" - @ONLY IMMEDIATE) - add_custom_target(python_install) - set_target_properties(python_install PROPERTIES - POST_INSTALL_SCRIPT "${MITK_CSWIG_BINARY_DIR}/pythonfiles_install.cmake") - else("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" STREQUAL "2.4") - # Use CMake 2.6 FILES_MATCHING feature to install correctly. - if(MITK_CSWIG_CONFIGURATION_TYPES) - set(_FROMDIR ${EXECUTABLE_OUTPUT_PATH}/\${CMAKE_INSTALL_CONFIG_NAME}) - else(MITK_CSWIG_CONFIGURATION_TYPES) - set(_FROMDIR ${EXECUTABLE_OUTPUT_PATH}) - endif(MITK_CSWIG_CONFIGURATION_TYPES) - if(MITK_INSTALL_LIBRARY_DIR) - install( - DIRECTORY ${_FROMDIR}/ - DESTINATION ${MITK_INSTALL_LIBRARY_DIR} - COMPONENT "RuntimeLibraries" - FILES_MATCHING PATTERN "*.py" - ) - endif(MITK_INSTALL_LIBRARY_DIR) - endif("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" STREQUAL "2.4") - - # Install the package python files. - #foreach(file ${MITK_PYTHON_FILES}) - #if(MITK_CSWIG_CONFIGURATION_TYPES) - #install(FILES "${MITK_BINARY_DIR}/Wrapping/CSwig/Python/\${CMAKE_INSTALL_CONFIG_NAME}/${file}.py" - #DESTINATION ${MITK_INSTALL_LIBRARY_DIR}/python - #COMPONENT RuntimeLibraries) - #else(MITK_CSWIG_CONFIGURATION_TYPES) - #install(FILES "${MITK_BINARY_DIR}/Wrapping/CSwig/Python/${file}.py" - #DESTINATION ${MITK_INSTALL_LIBRARY_DIR}/python - #COMPONENT RuntimeLibraries) - #endif(MITK_CSWIG_CONFIGURATION_TYPES) - #endforeach(file) - - set(MITK_CSWIG_PACKAGE_DIR "os.path.dirname(selfpath)") - set(MITK_CSWIG_DATA_ROOT "os.path.join(os.path.dirname(selfpath),'Data')") - set(MITK_CSWIG_TEST_ROOT "''") - #configure_file("${MITK_SOURCE_DIR}/Wrapping/CSwig/Python/mitkbase.py.in" - #"${MITK_BINARY_DIR}/Wrapping/CSwig/Python/InstallOnly/mitkbase.py" - #@ONLY IMMEDIATE) - #install(FILES "${MITK_BINARY_DIR}/Wrapping/CSwig/Python/InstallOnly/mitkbase.py" - #DESTINATION ${MITK_INSTALL_LIBRARY_DIR}/python - #COMPONENT RuntimeLibraries) -endif(MITK_USE_Python) - - -macro(MITK_WRAP_LIBRARY WRAP_SOURCES LIBRARY_NAME DIRECTORY DEPEND_LIBRARY EXTRA_SOURCES MITK_LINK_LIBRARIES) - # loop over cable config files creating two lists: - # WRAP_PYTHON_SOURCES: list of generated files - foreach(Source ${WRAP_SOURCES}) - set(WRAP_PYTHON_SOURCES ${WRAP_PYTHON_SOURCES} ${Source}Python.cxx) - set(ALL_IDX_FILES ${ALL_IDX_FILES} ${MITK_WRAP_BINARY_DIR}/${DIRECTORY}/${Source}.idx ) - set(INDEX_FILE_CONTENT "${INDEX_FILE_CONTENT}${MITK_CSWIG_BINARY_DIR}/${DIRECTORY}/${Source}.idx\n") - endforeach(Source) - # add the package wrappers - set(WRAP_PYTHON_SOURCES ${WRAP_PYTHON_SOURCES} wrap_${LIBRARY_NAME}PythonPython.cxx) - if(MITK_EXTRA_PYTHON_WRAP) - foreach( extraPython ${MITK_EXTRA_PYTHON_WRAP}) - set(WRAP_PYTHON_SOURCES ${WRAP_PYTHON_SOURCES} ${extraPython}Python.cxx) - endforeach( extraPython ) - endif(MITK_EXTRA_PYTHON_WRAP) - - # set the generated sources as generated - set_source_files_properties( - ${WRAP_PYTHON_SOURCES} - GENERATED ) - set(EXTRA_LIBS ${MITK_LINK_LIBRARIES}) - if("${MITK_LINK_LIBRARIES}" MATCHES "^$") - #set(EXTRA_LIBS ${LIBRARY_NAME}) - endif("${MITK_LINK_LIBRARIES}" MATCHES "^$") - - file(APPEND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mitk.py - "from ${LIBRARY_NAME}Python import *\n") - - set(DEPENDENCIES mitkIpPic mbilog tinyxml) - set(DEPENDS ${DEPENDENCIES}) - MITK_CHECK_MODULE(_MISSING_DEP ${DEPENDENCIES}) - MITK_USE_MODULE("Mitk") - - set(ALL_INCLUDE_DIRECTORIES ${ALL_INCLUDE_DIRECTORIES} ${MITK_INCLUDE_DIRS} ${MITK_WRAP_SOURCE_DIR} ${GDCM_INCLUDE_DIRS} ) - # "D:/MITK/mitk/CoreUI/Bundles/org.mitk.gui.qt.common/src" "D:/MITK/mitk/BlueBerry/Bundles/org.blueberry.ui.qt/src" "D:/MITK/mitk/BlueBerry/Bundles/org.blueberry.ui/src" "D:/MITK/mitk/BlueBerry/Bundles/org.blueberry.core.runtime/src" "D:/MITK/mitk/CoreUI/Bundles/org.mitk.gui.common/src" "D:/MITK/mitk/BlueBerry/Bundles/org.blueberry.osgi/src" "D:/MITK/mitk/BlueBerry/Bundles/org.blueberry.osgi/src/service" "D:/MITK/mitk/Utilities/Poco/Foundation/include" "D:/binPython/BlueBerry/Bundles/org.blueberry.osgi" "D:/MITK/mitk/Utilities/Poco/Util/include" "V:/windows/x32/QT-4.6.2_VC9.0_Bin/include/QtGui" "V:/windows/x32/QT-4.6.2_VC9.0_Bin/include" - include_directories(${ALL_INCLUDE_DIRECTORIES}) - - - if(MITK_USE_Python) - if(MITK_SWIG_FILE) - set(SWIG_INC ${SWIG_INC} ${PYTHON_INCLUDE_PATH}) - set_source_files_properties(${MITK_SWIG_FILE_CXX}Python.cxx GENERATED) - set(WRAP_FILE ${MITK_SWIG_FILE_CXX}Python.cxx ) - endif(MITK_SWIG_FILE) - - add_library(_${LIBRARY_NAME}Python SHARED - ${WRAP_PYTHON_SOURCES} - ${MITK_EXTRA_PYTHON_SOURCES} - ${WRAP_FILE} - ${EXTRA_SOURCES}) - - #target_link_libraries(_${LIBRARY_NAME}Python ${DEPENDENCIES}) - - if(MITK_WRAP_NEEDS_DEPEND) - foreach(lib ${DEPEND_LIBRARY}) - add_dependencies(_${LIBRARY_NAME}Python _${lib}Python) - endforeach(lib) - endif(MITK_WRAP_NEEDS_DEPEND) - if(MITK_LIBRARY_PROPERTIES) - set_target_properties( _${LIBRARY_NAME}Python PROPERTIES PREFIX "" ${MITK_LIBRARY_PROPERTIES}) - else(MITK_LIBRARY_PROPERTIES) - set_target_properties( _${LIBRARY_NAME}Python PROPERTIES PREFIX "") - endif(MITK_LIBRARY_PROPERTIES) - - # Python extension modules on Windows must have the extension ".pyd" - # instead of ".dll" as of Python 2.5. Older python versions do support - # this suffix. - if(WIN32 AND NOT CYGWIN) - set_target_properties(_${LIBRARY_NAME}Python PROPERTIES DEBUG_POSTFIX "_d" SUFFIX ".pyd") - endif(WIN32 AND NOT CYGWIN) - - if(PYTHON_DEBUG_LIBRARY) - target_link_libraries(_${LIBRARY_NAME}Python ${DEPENDENCIES} ${EXTRA_LIBS} SwigRuntimePython debug ${PYTHON_DEBUG_LIBRARY} optimized ${PYTHON_LIBRARY}) - else(PYTHON_DEBUG_LIBRARY) - target_link_libraries(_${LIBRARY_NAME}Python ${DEPENDENCIES} ${EXTRA_LIBS} SwigRuntimePython ${PYTHON_LIBRARY}) - endif(PYTHON_DEBUG_LIBRARY) - if(MITK_INSTALL_LIBRARY_DIR) - install(TARGETS _${LIBRARY_NAME}Python - RUNTIME DESTINATION ${MITK_INSTALL_BIN_DIR} COMPONENT RuntimeLibraries - LIBRARY DESTINATION ${MITK_INSTALL_LIBRARY_DIR} COMPONENT RuntimeLibraries - ARCHIVE DESTINATION ${MITK_INSTALL_LIBRARY_DIR} COMPONENT Development) - endif(MITK_INSTALL_LIBRARY_DIR) - if(MITK_SWIG_FILE) - add_custom_command( - COMMENT "run native swig on ${MITK_SWIG_FILE}" - SOURCE ${MITK_SWIG_FILE} - COMMAND ${CSWIG} - ARGS -nocable -noruntime ${IGNORE_WARNINGS} -o ${WRAP_FILE} - -outdir "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}" - -python -c++ ${MITK_SWIG_FILE} - TARGET _${LIBRARY_NAME}Python - OUTPUTS ${WRAP_FILE} - DEPENDS ${MITK_SWIG_FILE} ${CSWIG}) - endif(MITK_SWIG_FILE) - endif(MITK_USE_Python) - - configure_file( - ${MITK_CSWIG_SOURCE_DIR}/Master.mdx.in - ${MITK_CSWIG_BINARY_DIR}/${DIRECTORY}/${LIBRARY_NAME}.mdx IMMEDIATE - ) - - set(SWIG_INC_FILE ${MITK_CSWIG_BINARY_DIR}/${DIRECTORY}/SwigInc.txt) - set(SWIG_INC_CONTENTS) - set(SWIG_INC ${ALL_INCLUDE_DIRECTORIES}) - foreach(dir ${SWIG_INC}) - set(SWIG_INC_CONTENTS "${SWIG_INC_CONTENTS}-I${dir}\n") - endforeach(dir) - configure_file(${MITK_CSWIG_SOURCE_DIR}/SwigInc.txt.in ${SWIG_INC_FILE} - @ONLY IMMEDIATE) - - foreach(Source ${WRAP_SOURCES}) - - if(MITK_USE_Python) - # python - WRAP_PYTHON_SOURCES(${MITK_CSWIG_SOURCE_DIR}/${DIRECTORY} ${MITK_CSWIG_BINARY_DIR}/${DIRECTORY} - ${Source} _${LIBRARY_NAME}Python "${MASTER_INDEX_FILES}" "${ALL_IDX_FILES}") - endif(MITK_USE_Python) - - endforeach(Source) - - - # wrap the package files for python - if(MITK_USE_Python) - # python - WRAP_PYTHON_SOURCES(${MITK_CSWIG_SOURCE_DIR}/${DIRECTORY} ${MITK_CSWIG_BINARY_DIR}/${DIRECTORY} - wrap_${LIBRARY_NAME}Python _${LIBRARY_NAME}Python "${MASTER_INDEX_FILES}" "${ALL_IDX_FILES}") - if(MITK_EXTRA_PYTHON_WRAP) - foreach( extraPython ${MITK_EXTRA_PYTHON_WRAP}) - WRAP_PYTHON_SOURCES(${MITK_CSWIG_SOURCE_DIR}/${DIRECTORY} ${MITK_CSWIG_BINARY_DIR}/${DIRECTORY} - ${extraPython} _${LIBRARY_NAME}Python "${MASTER_INDEX_FILES}" "${ALL_IDX_FILES}") - endforeach( extraPython ) - endif(MITK_EXTRA_PYTHON_WRAP) - - endif(MITK_USE_Python) - -endmacro(MITK_WRAP_LIBRARY) diff --git a/Wrapping/CSwig/Core/CMakeLists.txt b/Wrapping/CSwig/Core/CMakeLists.txt deleted file mode 100644 index 5d5225680d..0000000000 --- a/Wrapping/CSwig/Core/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# create the mitkCorePython libraries -include(wrapSources.cmake) - -set(MASTER_INDEX_FILES "${CMAKE_CURRENT_BINARY_DIR}/Mitk.mdx" -) - -set(mitkCorePythonDependencies Mitk debug vtkCommonPythonD optimized vtkCommonPython) - - -MITK_WRAP_LIBRARY("${WRAP_SOURCES_TEST}" Mitk Core - "" "" "${mitkCorePythonDependencies}") - diff --git a/Wrapping/CSwig/Core/wrapSources.cmake b/Wrapping/CSwig/Core/wrapSources.cmake deleted file mode 100644 index ccd693e9dc..0000000000 --- a/Wrapping/CSwig/Core/wrapSources.cmake +++ /dev/null @@ -1,247 +0,0 @@ -# create the mitkControllers libraries -set(WRAP_SOURCES_TEST - #Algorithms: - #wrap_itkImportMitkImageContainer //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_itkLocalVariationImageFilter //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_itkMITKScalarImageToHistogramGenerator //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_itkTotalVariationDenoisingImageFilter //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_itkTotalVariationSingleIterationImageFilter //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkBaseDataSource - wrap_mitkBaseProcess - wrap_mitkCoreObjectFactory - wrap_mitkCoreObjectFactoryBase - wrap_mitkDataNodeFactory - wrap_mitkDataNodeSource - wrap_mitkGeometry2DDataToSurfaceFilter - wrap_mitkHistogramGenerator - #wrap_mitkImageAccessByItk //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_mitkImageCast //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_mitkImageCastPart1 //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_mitkImageCastPart2 //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_mitkImageCastPart3 //Template: can be wrapped; TODO: instantiate the needed templates - #wrap_mitkImageCastPart4 //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkImageChannelSelector - wrap_mitkImageSliceSelector - wrap_mitkImageSource - wrap_mitkImageTimeSelector - wrap_mitkImageToImageFilter - wrap_mitkImageToItk - #wrap_mitkInstantiateAccessFunctions // Macros - wrap_mitkITKImageImport - wrap_mitkPointSetSource - wrap_mitkRGBToRGBACastImageFilter - wrap_mitkSubImageSelector - wrap_mitkSurfaceSource - wrap_mitkSurfaceToSurfaceFilter - wrap_mitkUIDGenerator - wrap_mitkVolumeCalculator - - #Controllers: - wrap_mitkBaseController - wrap_mitkCallbackFromGUIThread - wrap_mitkCameraController - wrap_mitkCameraRotationController - wrap_mitkFocusManager - wrap_mitkLimitedLinearUndo - wrap_mitkOperationEvent - wrap_mitkProgressBar - wrap_mitkProgressBarImplementation - wrap_mitkReferenceCountWatcher - wrap_mitkRenderingManager - wrap_mitkRenderingManagerFactory - wrap_mitkSliceNavigationController - wrap_mitkSlicesCoordinator - wrap_mitkSlicesRotator - wrap_mitkSlicesSwiveller - wrap_mitkStatusBar - wrap_mitkStatusBarImplementation - wrap_mitkStepper - #wrap_mitkTestingMacros //Macros - wrap_mitkTestManager - wrap_mitkUndoController - wrap_mitkUndoModel - wrap_mitkVerboseLimitedLinearUndo - wrap_mitkVtkInteractorCameraController - wrap_mitkVtkLayerController - - #DataManagement: - #wrap_itkVtkAbstractTransform //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkAbstractTransformGeometry - wrap_mitkAnnotationProperty - wrap_mitkApplicationCursor - wrap_mitkBaseData - wrap_mitkBaseDataTestImplementation - wrap_mitkBaseProperty - wrap_mitkClippingProperty - wrap_mitkColorProperty - #wrap_mitkCommon //Macros - wrap_mitkDataNode - wrap_mitkDataStorage - wrap_mitkDisplayGeometry - wrap_mitkEnumerationProperty - wrap_mitkGenericLookupTable - #wrap_mitkGenericProperty //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkGeometry2D - wrap_mitkGeometry2DData - wrap_mitkGeometry3D - wrap_mitkGeometryData - wrap_mitkGroupTagProperty - wrap_mitkImage - wrap_mitkImageDataItem - #wrap_mitkItkMatrixHack //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkLandmarkBasedCurvedGeometry - wrap_mitkLandmarkProjector - wrap_mitkLandmarkProjectorBasedCurvedGeometry - wrap_mitkLevelWindow - wrap_mitkLevelWindowManager - wrap_mitkLevelWindowPreset - wrap_mitkLevelWindowProperty - #wrap_mitkLine //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkLookupTable - wrap_mitkLookupTables - wrap_mitkMaterial - #wrap_mitkMatrixConvert //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkMemoryUtilities - wrap_mitkModalityProperty - wrap_mitkModeOperation - wrap_mitkNodePredicateAND - wrap_mitkNodePredicateBase - wrap_mitkNodePredicateCompositeBase - wrap_mitkNodePredicateData - wrap_mitkNodePredicateDataType - wrap_mitkNodePredicateDimension - wrap_mitkNodePredicateFirstLevel - wrap_mitkNodePredicateNOT - wrap_mitkNodePredicateOR - wrap_mitkNodePredicateProperty - wrap_mitkNodePredicateSource - wrap_mitkPlaneOrientationProperty - wrap_mitkPlaneGeometry - wrap_mitkPlaneOperation - wrap_mitkPointOperation - wrap_mitkPointSet - wrap_mitkProperties - wrap_mitkPropertyList - wrap_mitkResliceMethodProperty - wrap_mitkRotationOperation - wrap_mitkShaderProperty - wrap_mitkSlicedData - wrap_mitkSlicedGeometry3D - wrap_mitkSmartPointerProperty - wrap_mitkStandaloneDataStorage - wrap_mitkStateTransitionOperation - wrap_mitkStringProperty - wrap_mitkSurface - wrap_mitkSurfaceOperation - wrap_mitkThinPlateSplineCurvedGeometry - wrap_mitkTimeSlicedGeometry - wrap_mitkTransferFunction - wrap_mitkTransferFunctionProperty - #wrap_mitkVector //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkVtkInterpolationProperty - wrap_mitkVtkRepresentationProperty - wrap_mitkVtkResliceInterpolationProperty - wrap_mitkVtkScalarModeProperty - wrap_mitkVtkVolumeRenderingProperty - #wrap_mitkWeakPointer //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkWeakPointerProperty - - #Interactions: - wrap_mitkAction - wrap_mitkAffineInteractor - wrap_mitkCoordinateSupplier - wrap_mitkDisplayCoordinateOperation - wrap_mitkDisplayInteractor - wrap_mitkDisplayPositionEvent - wrap_mitkDisplayVectorInteractor - wrap_mitkEvent - wrap_mitkEventDescription - wrap_mitkEventMapper - wrap_mitkGlobalInteraction - wrap_mitkInteractor - wrap_mitkKeyEvent - #wrap_mitkMessage //Macros;Templates: can be wrapped; TODO: instantiate the needed templates - wrap_mitkMouseMovePointSetInteractor - wrap_mitkPointSetInteractor - wrap_mitkPositionEvent - wrap_mitkPositionTracker - wrap_mitkState - wrap_mitkStateEvent - wrap_mitkStateMachine - wrap_mitkStateMachineFactory - wrap_mitkTransition - wrap_mitkWheelEvent - - #IO: - wrap_mitkBaseDataIOFactory - wrap_mitkDicomSeriesReader - wrap_mitkFileReader - wrap_mitkFileSeriesReader - wrap_mitkFileWriter - wrap_mitkFileWriterWithInformation - wrap_mitkImageWriter - wrap_mitkImageWriterFactory - #wrap_mitkIOAdapter //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkItkImageFileIOFactory - wrap_mitkItkImageFileReader - #wrap_mitkItkPictureWrite //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkLog - wrap_mitkLookupTableProperty - wrap_mitkOperation - wrap_mitkOperationActor - wrap_mitkPicFileIOFactory - wrap_mitkPicFileReader - wrap_mitkPicFileWriter - wrap_mitkPicHelper - wrap_mitkPicVolumeTimeSeriesIOFactory - wrap_mitkPicVolumeTimeSeriesReader - wrap_mitkPixelType - wrap_mitkPointSetIOFactory - wrap_mitkPointSetReader - wrap_mitkPointSetWriter - wrap_mitkPointSetWriterFactory - #wrap_mitkRawImageFileReader // need to be modified; wrapper class tries to convert from 'std::string' to 'char *' - wrap_mitkStandardFileLocations - wrap_mitkSTLFileIOFactory - wrap_mitkSTLFileReader - #wrap_mitkSurfaceVtkWriter //Template: can be wrapped; TODO: instantiate the needed templates - wrap_mitkSurfaceVtkWriterFactory - wrap_mitkVtiFileIOFactory - wrap_mitkVtiFileReader - wrap_mitkVtkImageIOFactory - wrap_mitkVtkImageReader - wrap_mitkVtkSurfaceIOFactory - wrap_mitkVtkSurfaceReader - wrap_vtkPointSetXMLParser - - #Rendering: - #wrap_mitkBaseRenderer //leads to a crash of cswig; after bug fixed in cswig -> circular import error - wrap_mitkVtkMapper2D - wrap_mitkVtkMapper3D - wrap_mitkGeometry2DDataMapper2D - wrap_mitkGeometry2DDataVtkMapper3D - wrap_mitkGLMapper2D - wrap_mitkGradientBackground - wrap_mitkImageMapperGL2D - wrap_mitkMapper - wrap_mitkMapper2D - wrap_mitkMapper3D - wrap_mitkPointSetGLMapper2D - wrap_mitkPointSetVtkMapper3D - wrap_mitkPolyDataGLMapper2D - wrap_mitkShaderRepository - wrap_mitkSurfaceGLMapper2D - wrap_mitkSurfaceVtkMapper3D - wrap_mitkVolumeDataVtkMapper3D - wrap_mitkVtkPropRenderer - wrap_mitkVtkWidgetRendering - wrap_vtkMitkRectangleProp - wrap_vtkMitkRenderProp - wrap_vtkMitkThickSlicesFilter - wrap_mitkManufacturerLogo - - wrap_mitkCommonSuperclasses - wrap_mitkImageCaster - #wrap_qmitkFunctionality -) - diff --git a/Wrapping/CSwig/Core/wrap_MITKControllersPython.cxx b/Wrapping/CSwig/Core/wrap_MITKControllersPython.cxx deleted file mode 100644 index 66f231f1ff..0000000000 --- a/Wrapping/CSwig/Core/wrap_MITKControllersPython.cxx +++ /dev/null @@ -1,59 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkControllersPython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - "BaseController", - "CallbackFromGUIThread", - "CameraController", - "CameraRotationController", - "FocusManager", - "LimitedLinearUndo", - "OperationEvent", - "ProgressBar", - "ProgressBarImplementation", - //"ReferenceCountWatcher", - "RenderingManager", - "RenderingManagerFactory", - "SliceNavigationController", - "SlicesCoordinator", - "SlicesRotator", - "SlicesSwiveller", - "StatusBar", - "StatusBarImplementation", - "Stepper", - //"TestingMacros", - "TestManager", - "UndoController", - "UndoModel", - "VerboseLimitedLinearUndo", - "VtkInteractorCameraController", - "VtkLayerController" - }; -} -#endif diff --git a/Wrapping/CSwig/Core/wrap_itkVtkAbstractTransform.cxx b/Wrapping/CSwig/Core/wrap_itkVtkAbstractTransform.cxx deleted file mode 100644 index 3261b45d90..0000000000 --- a/Wrapping/CSwig/Core/wrap_itkVtkAbstractTransform.cxx +++ /dev/null @@ -1,32 +0,0 @@ -#include "itkVtkAbstractTransform.h" -#include "itkImage.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkAbstractTransform"; - namespace wrappers - { - typedef itk::VtkAbstractTransform::Image> VtkAbstractTransformF2; - typedef itk::VtkAbstractTransform::Image>::Pointer::SmartPointer VtkAbstractTransformF2_Pointer; - typedef itk::VtkAbstractTransform::Image> VtkAbstractTransformUC2; - typedef itk::VtkAbstractTransform::Image>::Pointer::SmartPointer VtkAbstractTransformUC2_Pointer; - typedef itk::VtkAbstractTransform::Image> VtkAbstractTransformUS2; - typedef itk::VtkAbstractTransform::Image>::Pointer::SmartPointer VtkAbstractTransformUS2_Pointer; - typedef itk::VtkAbstractTransform::Image> VtkAbstractTransformUL2; - typedef itk::VtkAbstractTransform::Image>::Pointer::SmartPointer VtkAbstractTransformUL2_Pointer; - - typedef itk::VtkAbstractTransform::Image> VtkAbstractTransformF3; - typedef itk::VtkAbstractTransform::Image>::Pointer::SmartPointer VtkAbstractTransformF3_Pointer; - typedef itk::VtkAbstractTransform::Image> VtkAbstractTransformUC3; - typedef itk::VtkAbstractTransform::Image>::Pointer::SmartPointer VtkAbstractTransformUC3_Pointer; - typedef itk::VtkAbstractTransform::Image> VtkAbstractTransformUS3; - typedef itk::VtkAbstractTransform::Image>::Pointer::SmartPointer VtkAbstractTransformUS3_Pointer; - typedef itk::VtkAbstractTransform::Image> VtkAbstractTransformUL3; - typedef itk::VtkAbstractTransform::Image>::Pointer::SmartPointer VtkAbstractTransformUL3_Pointer; - } -} - -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkAbstractTransformGeometry.cxx b/Wrapping/CSwig/Core/wrap_mitkAbstractTransformGeometry.cxx deleted file mode 100644 index 94ec0736d3..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkAbstractTransformGeometry.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkAbstractTransformGeometry.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="AbstractTransformGeometry"; - namespace wrappers - { - MITK_WRAP_OBJECT(AbstractTransformGeometry) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkAction.cxx b/Wrapping/CSwig/Core/wrap_mitkAction.cxx deleted file mode 100644 index b39ddae757..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkAction.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkAction.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Action"; - namespace wrappers - { - MITK_WRAP_OBJECT(Action) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkAffineInteractor.cxx b/Wrapping/CSwig/Core/wrap_mitkAffineInteractor.cxx deleted file mode 100644 index 54ff69d91f..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkAffineInteractor.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkAffineInteractor.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="AffineInteractor"; - namespace wrappers - { - MITK_WRAP_OBJECT(AffineInteractor) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkAlgorithmsPython.cxx b/Wrapping/CSwig/Core/wrap_mitkAlgorithmsPython.cxx deleted file mode 100644 index 72dca1eac5..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkAlgorithmsPython.cxx +++ /dev/null @@ -1,55 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkAlgorithmsPython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - //"ProcessObject", - "BaseDataSource", - "BaseProcess", - "CoreObjectFactory", - "CoreObjectFactoryBase", - "DataNodeFactory", - "DataNodeSource", - "Geometry2DDataToSurfaceFilter", - "HistogramGenerator", - "ImageChannelSelector", - "ImageSliceSelector", - "ImageSource", - "ImageTimeSelector", - "ImageToImageFilter", - "ImageToItk", - "ITKImageImport", - "PointSetSource", - "RGBToRGBACastImageFilter", - "SubImageSelector", - "SurfaceSource", - "SurfaceToSurfaceFilter", - "VolumeCalculator" - }; -} -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkAnnotationProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkAnnotationProperty.cxx deleted file mode 100644 index 4a86880aa0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkAnnotationProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkAnnotationProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="AnnotationProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(AnnotationProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkApplicationCursor.cxx b/Wrapping/CSwig/Core/wrap_mitkApplicationCursor.cxx deleted file mode 100644 index f9bb95da18..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkApplicationCursor.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkApplicationCursor.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ApplicationCursor"; - namespace wrappers - { - typedef mitk::ApplicationCursor ApplicationCursor; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseController.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseController.cxx deleted file mode 100644 index f8acbf9e2a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseController.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseController.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseController"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseController) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseData.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseData.cxx deleted file mode 100644 index c14fc349b4..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseData.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseData.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseData"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseData) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseDataIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseDataIOFactory.cxx deleted file mode 100644 index a45b4f2d69..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseDataIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseDataIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseDataIO"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseDataIO) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseDataImplementation.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseDataImplementation.cxx deleted file mode 100644 index 61c6f4fd20..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseDataImplementation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseDataImplementation.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseDataImplementation"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseDataImplementation) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseDataSource.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseDataSource.cxx deleted file mode 100644 index 010a465453..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseDataSource.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkBaseDataSource.h" -#include "mitkCSwigMacros.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseDataSource"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseDataSource) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseDataTestImplementation.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseDataTestImplementation.cxx deleted file mode 100644 index bd40939652..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseDataTestImplementation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseDataTestImplementation.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseDataTestImplementation"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseDataTestImplementation) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseProcess.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseProcess.cxx deleted file mode 100644 index 577a438ceb..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseProcess.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseProcess.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseProcess"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseProcess) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseProperty.cxx deleted file mode 100644 index d093cd335c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseRenderer.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseRenderer.cxx deleted file mode 100644 index 044d406d72..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseRenderer.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkBaseRenderer.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseRenderer"; - namespace wrappers - { - typedef mitk::BaseRenderer BaseRenderer; - typedef mitk::BaseRenderer::Pointer::SmartPointer BaseRenderer_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseVtkMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseVtkMapper2D.cxx deleted file mode 100644 index a3013e9c96..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseVtkMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseVtkMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseVtkMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseVtkMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkBaseVtkMapper3D.cxx b/Wrapping/CSwig/Core/wrap_mitkBaseVtkMapper3D.cxx deleted file mode 100644 index 31c489d5a7..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkBaseVtkMapper3D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkBaseVtkMapper3D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="BaseVtkMapper3D"; - namespace wrappers - { - MITK_WRAP_OBJECT(BaseVtkMapper3D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCallbackFromGUIThread.cxx b/Wrapping/CSwig/Core/wrap_mitkCallbackFromGUIThread.cxx deleted file mode 100644 index 3955363721..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCallbackFromGUIThread.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkCallbackFromGUIThread.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="CallbackFromGUIThread"; - namespace wrappers - { - typedef mitk::CallbackFromGUIThread CallbackFromGUIThread; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCameraController.cxx b/Wrapping/CSwig/Core/wrap_mitkCameraController.cxx deleted file mode 100644 index b04913885a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCameraController.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkCameraController.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="CameraController"; - namespace wrappers - { - MITK_WRAP_OBJECT(CameraController) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCameraRotationController.cxx b/Wrapping/CSwig/Core/wrap_mitkCameraRotationController.cxx deleted file mode 100644 index 6d2593cc82..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCameraRotationController.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkCameraRotationController.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="CameraRotationController"; - namespace wrappers - { - MITK_WRAP_OBJECT(CameraRotationController) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkClippingProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkClippingProperty.cxx deleted file mode 100644 index be61560360..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkClippingProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkClippingProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ClippingProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(ClippingProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkColorProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkColorProperty.cxx deleted file mode 100644 index e62e3de003..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkColorProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkColorProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ColorProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(ColorProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkColoredRectangleRendering.cxx b/Wrapping/CSwig/Core/wrap_mitkColoredRectangleRendering.cxx deleted file mode 100644 index 173151d9a0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkColoredRectangleRendering.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkColoredRectangleRendering.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ColoredRectangleRendering"; - namespace wrappers - { - MITK_WRAP_OBJECT(ColoredRectangleRendering) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCommon.cxx b/Wrapping/CSwig/Core/wrap_mitkCommon.cxx deleted file mode 100644 index e066e95f41..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCommon.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkCommon.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Common"; - namespace wrappers - { - typedef mitk::Common Common; - typedef mitk::Common::Pointer::SmartPointer Common_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCommonSuperclasses.cxx b/Wrapping/CSwig/Core/wrap_mitkCommonSuperclasses.cxx deleted file mode 100644 index 6396822453..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCommonSuperclasses.cxx +++ /dev/null @@ -1,39 +0,0 @@ -#include "mitkCommon.h" -#include "mitkBaseProcess.h" -#include "mitkCSwigMacros.h" -#include "mbilog.h" -#include "itkObject.h" -#include "itkDataObject.h" -#include "itkProcessObject.h" -#include "itkLightObject.h" -#include "itkObjectFactoryBase.h" -#pragma GCC visibility push(default) -#include -#pragma GCC visibility pop -#include "itkSmartPointerForwardReference.h" -#include "itkAffineTransform.h" -#include "itkMatrixOffsetTransformBase.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="CommonSuperclasses"; - namespace wrappers - { - ITK_WRAP_OBJECT(Object) - ITK_WRAP_OBJECT(DataObject) - ITK_WRAP_OBJECT(ProcessObject) - ITK_WRAP_OBJECT(LightObject) - ITK_WRAP_OBJECT(ObjectFactoryBase) - typedef itk::EndEvent::EndEvent EndEvent; - typedef mbilog::AbstractBackend::AbstractBackend AbstractBackend; - typedef itk::AffineTransform::AffineTransform AffineTransform_F3U; - typedef itk::AffineTransform::Pointer::SmartPointer AffineTransform_F3U_Pointer; - typedef itk::MatrixOffsetTransformBase::MatrixOffsetTransformBase MatrixOffsetTransformBase_F3U3U; - typedef itk::MatrixOffsetTransformBase::Pointer::SmartPointer MatrixOffsetTransformBase_F3U3U_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCoordinateSupplier.cxx b/Wrapping/CSwig/Core/wrap_mitkCoordinateSupplier.cxx deleted file mode 100644 index b07a48a3a2..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCoordinateSupplier.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkCoordinateSupplier.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="CoordinateSupplier"; - namespace wrappers - { - MITK_WRAP_OBJECT(CoordinateSupplier) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCoreObjectFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkCoreObjectFactory.cxx deleted file mode 100644 index 915ff7266f..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCoreObjectFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkCoreObjectFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="CoreObjectFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(CoreObjectFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCoreObjectFactoryBase.cxx b/Wrapping/CSwig/Core/wrap_mitkCoreObjectFactoryBase.cxx deleted file mode 100644 index 1cf535efb0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCoreObjectFactoryBase.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkCoreObjectFactoryBase.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="CoreObjectFactoryBase"; - namespace wrappers - { - MITK_WRAP_OBJECT(CoreObjectFactoryBase) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkCorePython.cxx b/Wrapping/CSwig/Core/wrap_mitkCorePython.cxx deleted file mode 100644 index d457d87d17..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkCorePython.cxx +++ /dev/null @@ -1,262 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkCorePython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - //For further information about the classes which were not wrapped, please have a look at the file wrapSources.cmake - //Algorithms: - //"ProcessObject", - "BaseDataSource", - "BaseProcess", - "CoreObjectFactory", - "CoreObjectFactoryBase", - "DataNodeFactory", - "DataNodeSource", - "Geometry2DDataToSurfaceFilter", - "HistogramGenerator", - "ImageChannelSelector", - "ImageSliceSelector", - "ImageSource", - "ImageTimeSelector", - "ImageToImageFilter", - "ImageToItk", - "ITKImageImport", - "PointSetSource", - "RGBToRGBACastImageFilter", - "SubImageSelector", - "SurfaceSource", - "SurfaceToSurfaceFilter", - "VolumeCalculator", - - //Controllers: - "BaseController", - "CallbackFromGUIThread", - "CameraController", - "CameraRotationController", - "FocusManager", - "LimitedLinearUndo", - "OperationEvent", - "ProgressBar", - "ProgressBarImplementation", - //"ReferenceCountWatcher", - "RenderingManager", - "RenderingManagerFactory", - "SliceNavigationController", - "SlicesCoordinator", - "SlicesRotator", - "SlicesSwiveller", - "StatusBar", - "StatusBarImplementation", - "Stepper", - //"TestingMacros", - "TestManager", - "UndoController", - "UndoModel", - "VerboseLimitedLinearUndo", - "VtkInteractorCameraController", - "VtkLayerController", - - - //DataManagement: - //"VtkAbstractTransform", - "AbstractTransformGeometry", - "AnnotationProperty", - "ApplicationCursor", - "BaseData", - "BaseDataTestImplementation", - "BaseProperty", - "ClippingProperty", - "ColorProperty", - //"Common", - "DataNode", - "DataStorage", - "DisplayGeometry", - "EnumerationProperty", - "GenericLookupTable", - //"GenericProperty", - "Geometry2D", - "Geometry2DData", - "Geometry3D", - "GeometryData", - "GroupTagProperty", - "Image", - "ImageDataItem", - //"ItkMatirxHack", - "LandmarkBasedCurvedGeometry", - "LandmarkProjector", - "LandmarkProjectorBasedCurvedGeometry", - "LevelWindow", - "LevelWindowManager", - "LevelWindowPreset", - "LevelWindowProperty", - //Line", - "LookupTable", - "LookupTables", - "Material", - //"MatrixConvert", - "ModalityProperty", - "NodePredicateAnd", - "NodePredicateBase", - "NodePredicateCompositeBase", - "NodePredicateData", - "NodePredicateDataType", - "NodePredicateDimension", - "NodePredicateFirstLevel", - "NodePredicateNot", - "NodePredicateOr", - "NodePredicateProperty", - "NodePredicateSource", - "PlaneOrientationProperty", - "PlaneGeometry", - "PlaneOperation", - "PointOperation", - "PointSet", - "Properties", - "PropertyList", - "ResliceMethodProperty", - "RotationOperation", - "ShaderProperty", - "SlicedData", - "SlicedGeometry3D", - "SmartPointerProperty", - "StandaloneDataStorage", - "StateTransitionOperation", - "StringProperty", - "Surface", - "ThinPlateSplineCurvedGeometry", - "TimeSlicedGeometry", - "TransferFunction", - "TransferFunctionProperty", - //"Vector", - "VtkInterpolationProperty", - "VtkRepresentationProperty", - "VtkResliceInterpolationProperty", - "VtkScalarModeProperty", - "VtkVolumeRenderingProperty", - //"WeakPointer", - "WeakPointerProperty", - - //Interactions: - "Action", - "AffineInteractor", - "CoordinateSupplier", - "DisplayCoordinateOperation", - "DisplayInteractor", - "DisplayPositionEvent", - "DisplayVectorInteractor", - "Event", - "EventDescription", - "EventMapper", - "GlobalInteraction", - "Interactor", - "KeyEvent", - //"Message", - "MouseMovePointSetInteractor", - "PointSetInteractor", - "PositionEvent", - "PositionTracker", - "State", - "StateEvent", - "StateMachine", - "StateMachineFactory", - "Transition", - "WheelEvent", - - //IO: - "BaseDataIO", - "DicomSeriesReader", - "FileReader", - "FileSeriesReader", - "FileWriter", - "FileWriterWithInformation", - "ImageWriter", - "ImageWriterFactory", - //"IOAdapter", - //"IpPicGet", - "ItkImageFileIOFactory", - "ItkImageFileReader", - "Log", - "LookupTableProperty", - "Operation", - "OperationActor", - "PicFileIOFactory", - "PicFileReader", - "PicFileWriter", - "PicHelper", - "PicVolumeTimeSeriesIOFactory", - "PicVolumeTimeSeriesReader", - "PixelType", - "PointSetIOFactory", - "PointSetReader", - "PointSetWriter", - "PointSetWriterFactory", - //"RawImageFileReader", - "StandardFileLocations", - "STLFileIOFactory", - "STLFileReader", - //"SurfaceVtkWriter", - "SurfaceVtkWriterFactory", - "VtiFileIOFactory", - "VtiFileReader", - "VtkImageIOFactory", - "VtkImageReader", - "VtkSurfaceIOFactory", - "VtkSurfaceReader", - "vtkPointSetXMLParser", - - //Rendering: - //"BaseRenderer", - "VtkMapper2D", - "VtkMapper3D", - "Geometry2DDataMapper2D", - "Geometry2DDataVtkMapper3D", - "GLMapper2D", - "GradientBackground", - "ImageMapperGL2D", - "Mapper", - "Mapper2D", - "Mapper3D", - "PointSetGLMapper2D", - "PointSetVtkMapper3D", - "PolyDataGLMapper2D", - "PolyDataGLMapper2D", - "ShaderRepository", - "SurfaceGLMapper2D", - "SurfaceVtkMapper3D", - "VtkPropRenderer", - "VtkWidgetRendering", - "vtkMitkRectangleProp", - "vtkMitkRenderProp", - "vtkMitkThickSlicesFilter", - - "CommonSuperclasses", - "ImageCaster", - //"QmitkFunctionality" - }; -} -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkDataManagementPython.cxx b/Wrapping/CSwig/Core/wrap_mitkDataManagementPython.cxx deleted file mode 100644 index 29113e4699..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDataManagementPython.cxx +++ /dev/null @@ -1,110 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkDataManagementPython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - //"VtkAbstractTransform", - "AbstractTransformGeometry", - "AnnotationProperty", - "ApplicationCursor", - "BaseData", - "BaseDataImplementation", - "BaseProperty", - "ClippingProperty", - "ColorProperty", - //"Common", - "DataNode", - "DataStorage", - "DisplayGeometry", - "EnumerationProperty", - "GenericLookupTable", - //"GenericProperty", - "Geometry2D", - "Geometry2DData", - "Geometry3D", - "GeometryData", - "GroupTagProperty", - "Image", - "ImageDataItem", - //"ItkMatirxHack", - "LandmarkBasedCurvedGeometry", - "LandmarkProjector", - "LandmarkProjectorBasedCurvedGeometry", - "LevelWindow", - "LevelWindowManager", - "LevelWindowPreset", - "LevelWindowProperty", - //Line", - "LookupTable", - //"LookupTables", - "Material", - //"MatrixConvert", - "ModalityProperty", - "NodePredicateAND", - "NodePredicateBase", - "NodePredicateCompositeBase", - "NodePredicateData", - "NodePredicateDataType", - "NodePredicateDimension", - "NodePredicateFirstLevel", - "NodePredicateNOT", - "NodePredicateOR", - "NodePredicateProperty", - "NodePredicateSource", - "PlaneDecorationProperty", - "PlaneGeometry", - "PlaneOperation", - //"PointOperation", - "PointSet", - //"Properties", - "PropertyList", - "ResliceMethodEnumProperty", - "RotationOperation", - "ShaderEnumProperty", - "SlicedData", - //"SlicedGeometry3D", - "SmartPointerProperty", - "StandaloneDataStorage", - "StateTransitionOperation", - "StringProperty", - "Surface", - "ThinPlateSplineCurvedGeometry", - "TimeSlicedGeometry", - "TransferFunction", - "TransferFunctionProperty", - //"Vector", - "VtkInterpolationProperty", - "VtkRepresentationProperty", - "VtkResliceInterpolationProperty", - "VtkScalarModeProperty", - "VtkVolumeRenderingProperty", - //"WeakPointer", - "WeakPointerProperty", - }; -} -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkDataNode.cxx b/Wrapping/CSwig/Core/wrap_mitkDataNode.cxx deleted file mode 100644 index 883747811d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDataNode.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDataNode.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DataNode"; - namespace wrappers - { - MITK_WRAP_OBJECT(DataNode); - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDataNodeFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkDataNodeFactory.cxx deleted file mode 100644 index 38e4bfa30c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDataNodeFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDataNodeFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DataNodeFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(DataNodeFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDataNodeSource.cxx b/Wrapping/CSwig/Core/wrap_mitkDataNodeSource.cxx deleted file mode 100644 index 46fe2e22e2..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDataNodeSource.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDataNodeSource.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DataNodeSource"; - namespace wrappers - { - MITK_WRAP_OBJECT(DataNodeSource) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDataStorage.cxx b/Wrapping/CSwig/Core/wrap_mitkDataStorage.cxx deleted file mode 100644 index ea8a1fad62..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDataStorage.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDataStorage.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DataStorage"; - namespace wrappers - { - MITK_WRAP_OBJECT(DataStorage) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDicomSeriesReader.cxx b/Wrapping/CSwig/Core/wrap_mitkDicomSeriesReader.cxx deleted file mode 100644 index 6bcc8151ac..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDicomSeriesReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDicomSeriesReader.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DicomSeriesReader"; - namespace wrappers - { - typedef mitk::DicomSeriesReader DicomSeriesReader; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDisplayCoordinateOperation.cxx b/Wrapping/CSwig/Core/wrap_mitkDisplayCoordinateOperation.cxx deleted file mode 100644 index 03e625d3e5..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDisplayCoordinateOperation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDisplayCoordinateOperation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DisplayCoordinateOperation"; - namespace wrappers - { - typedef mitk::DisplayCoordinateOperation DisplayCoordinateOperation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDisplayGeometry.cxx b/Wrapping/CSwig/Core/wrap_mitkDisplayGeometry.cxx deleted file mode 100644 index fe3aff5e8d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDisplayGeometry.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDisplayGeometry.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DisplayGeometry"; - namespace wrappers - { - MITK_WRAP_OBJECT(DisplayGeometry) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDisplayInteractor.cxx b/Wrapping/CSwig/Core/wrap_mitkDisplayInteractor.cxx deleted file mode 100644 index ce5140393b..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDisplayInteractor.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDisplayInteractor.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DisplayInteractor"; - namespace wrappers - { - typedef mitk::DisplayInteractor DisplayInteractor; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDisplayPositionEvent.cxx b/Wrapping/CSwig/Core/wrap_mitkDisplayPositionEvent.cxx deleted file mode 100644 index d55cc57403..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDisplayPositionEvent.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDisplayPositionEvent.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DisplayPositionEvent"; - namespace wrappers - { - typedef mitk::DisplayPositionEvent DisplayPositionEvent; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkDisplayVectorInteractor.cxx b/Wrapping/CSwig/Core/wrap_mitkDisplayVectorInteractor.cxx deleted file mode 100644 index f9965f483f..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkDisplayVectorInteractor.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkDisplayVectorInteractor.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DisplayVectorInteractor"; - namespace wrappers - { - MITK_WRAP_OBJECT(DisplayVectorInteractor) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkEnumerationProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkEnumerationProperty.cxx deleted file mode 100644 index 1ccb2058ec..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkEnumerationProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkEnumerationProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="EnumerationProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(EnumerationProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkEvent.cxx b/Wrapping/CSwig/Core/wrap_mitkEvent.cxx deleted file mode 100644 index abe321c19a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkEvent.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkEvent.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Event"; - namespace wrappers - { - typedef mitk::Event Event; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkEventDescription.cxx b/Wrapping/CSwig/Core/wrap_mitkEventDescription.cxx deleted file mode 100644 index b210d863a7..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkEventDescription.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkEventDescription.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="EventDescription"; - namespace wrappers - { - typedef mitk::EventDescription EventDescription; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkEventMapper.cxx b/Wrapping/CSwig/Core/wrap_mitkEventMapper.cxx deleted file mode 100644 index 6fcd71dcd2..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkEventMapper.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkEventMapper.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="EventMapper"; - namespace wrappers - { - typedef mitk::EventMapper EventMapper; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkFileReader.cxx b/Wrapping/CSwig/Core/wrap_mitkFileReader.cxx deleted file mode 100644 index e845705d10..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkFileReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkFileReader.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="FileReader"; - namespace wrappers - { - typedef mitk::FileReader FileReader; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkFileSeriesReader.cxx b/Wrapping/CSwig/Core/wrap_mitkFileSeriesReader.cxx deleted file mode 100644 index 8ce257f0f3..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkFileSeriesReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkFileSeriesReader.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="FileSeriesReader"; - namespace wrappers - { - typedef mitk::FileSeriesReader FileSeriesReader; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkFileWriter.cxx b/Wrapping/CSwig/Core/wrap_mitkFileWriter.cxx deleted file mode 100644 index 0378855e76..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkFileWriter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkFileWriter.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="FileWriter"; - namespace wrappers - { - MITK_WRAP_OBJECT(FileWriter) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkFileWriterWithInformation.cxx b/Wrapping/CSwig/Core/wrap_mitkFileWriterWithInformation.cxx deleted file mode 100644 index b31d5bed5b..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkFileWriterWithInformation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkFileWriterWithInformation.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="FileWriterWithInformation"; - namespace wrappers - { - MITK_WRAP_OBJECT(FileWriterWithInformation) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkFocusManager.cxx b/Wrapping/CSwig/Core/wrap_mitkFocusManager.cxx deleted file mode 100644 index a7ddbb2c51..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkFocusManager.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkFocusManager.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="FocusManager"; - namespace wrappers - { - MITK_WRAP_OBJECT(FocusManager) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGLMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkGLMapper2D.cxx deleted file mode 100644 index c00a9009f2..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGLMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGLMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="GLMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(GLMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGenericLookupTable.cxx b/Wrapping/CSwig/Core/wrap_mitkGenericLookupTable.cxx deleted file mode 100644 index 4153d04767..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGenericLookupTable.cxx +++ /dev/null @@ -1,19 +0,0 @@ -#include "mitkGenericLookupTable.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="GenericLookupTable"; - namespace wrappers - { - typedef mitk::GenericLookupTable GenericLookupTableString; - typedef mitk::GenericLookupTable GenericLookupTableFloat; - typedef mitk::GenericLookupTable GenericLookupTableInt; - typedef mitk::GenericLookupTable GenericLookupTableBool; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGenericProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkGenericProperty.cxx deleted file mode 100644 index dde722a097..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGenericProperty.cxx +++ /dev/null @@ -1,29 +0,0 @@ -#include "mitkGenericProperty.h" -#include - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="GenericProperty"; - namespace wrappers - { - typedef mitk::GenericProperty GenericPropertyPoint4D; - typedef mitk::GenericProperty::Pointer::SmartPointer GenericPropertyPoint4D_Pointer; - typedef mitk::GenericProperty GenericPropertyDouble; - typedef mitk::GenericProperty::Pointer::SmartPointer GenericPropertyDouble_Pointer; - typedef mitk::GenericProperty GenericPropertyFloat; - typedef mitk::GenericProperty::Pointer::SmartPointer GenericPropertyFloat_Pointer; - typedef mitk::GenericProperty GenericPropertyStringLookupTable; - typedef mitk::GenericProperty::Pointer::SmartPointer GenericPropertyStringLookupTable_Pointer; - typedef mitk::GenericProperty GenericPropertyPoint3I; - typedef mitk::GenericProperty::Pointer::SmartPointer GenericPropertyPoint3I_Pointer; - typedef mitk::GenericProperty GenericPropertyInt; - typedef mitk::GenericProperty::Pointer::SmartPointer GenericPropertyInt_Pointer; - typedef mitk::GenericProperty GenericPropertyVector3D; - typedef mitk::GenericProperty::Pointer::SmartPointer GenericPropertyVector3D_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGeometry2D.cxx b/Wrapping/CSwig/Core/wrap_mitkGeometry2D.cxx deleted file mode 100644 index 39c13d5ca0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGeometry2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGeometry2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Geometry2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(Geometry2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGeometry2DData.cxx b/Wrapping/CSwig/Core/wrap_mitkGeometry2DData.cxx deleted file mode 100644 index be4998731f..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGeometry2DData.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGeometry2DData.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Geometry2DData"; - namespace wrappers - { - MITK_WRAP_OBJECT(Geometry2DData) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataMapper2D.cxx deleted file mode 100644 index e59a63ca89..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGeometry2DDataMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Geometry2DDataMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(Geometry2DDataMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataToSurfaceFilter.cxx b/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataToSurfaceFilter.cxx deleted file mode 100644 index e8a0249401..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataToSurfaceFilter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGeometry2DDataToSurfaceFilter.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Geometry2DDataToSurfaceFilter"; - namespace wrappers - { - MITK_WRAP_OBJECT(Geometry2DDataToSurfaceFilter) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataVtkMapper3D.cxx b/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataVtkMapper3D.cxx deleted file mode 100644 index 0075c032ec..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGeometry2DDataVtkMapper3D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGeometry2DDataVtkMapper3D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Geometry2DDataVtkMapper3D"; - namespace wrappers - { - MITK_WRAP_OBJECT(Geometry2DDataVtkMapper3D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGeometry3D.cxx b/Wrapping/CSwig/Core/wrap_mitkGeometry3D.cxx deleted file mode 100644 index 1d3b499387..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGeometry3D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGeometry3D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Geometry3D"; - namespace wrappers - { - MITK_WRAP_OBJECT(Geometry3D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGeometryData.cxx b/Wrapping/CSwig/Core/wrap_mitkGeometryData.cxx deleted file mode 100644 index 84bf97d3af..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGeometryData.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGeometryData.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="GeometryData"; - namespace wrappers - { - MITK_WRAP_OBJECT(GeometryData) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGlobalInteraction.cxx b/Wrapping/CSwig/Core/wrap_mitkGlobalInteraction.cxx deleted file mode 100644 index 0786daa99c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGlobalInteraction.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGlobalInteraction.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="GlobalInteraction"; - namespace wrappers - { - MITK_WRAP_OBJECT(GlobalInteraction) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGradientBackground.cxx b/Wrapping/CSwig/Core/wrap_mitkGradientBackground.cxx deleted file mode 100644 index bd58f6c626..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGradientBackground.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGradientBackground.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="GradientBackground"; - namespace wrappers - { - MITK_WRAP_OBJECT(GradientBackground) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkGroupTagProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkGroupTagProperty.cxx deleted file mode 100644 index b34b949b7c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkGroupTagProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkGroupTagProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="GroupTagProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(GroupTagProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkHistogramGenerator.cxx b/Wrapping/CSwig/Core/wrap_mitkHistogramGenerator.cxx deleted file mode 100644 index b2f8669a01..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkHistogramGenerator.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkHistogramGenerator.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="HistogramGenerator"; - namespace wrappers - { - MITK_WRAP_OBJECT(HistogramGenerator) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkIOAdapter.cxx b/Wrapping/CSwig/Core/wrap_mitkIOAdapter.cxx deleted file mode 100644 index 303e21ec4b..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkIOAdapter.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkIOAdapter.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageWriterFactory"; - namespace wrappers - { - typedef mitk::ImageWriterFactory ImageWriterFactory; - typedef mitk::ImageWriterFactory::Pointer::SmartPointer ImageWriterFactory_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkIOPython.cxx b/Wrapping/CSwig/Core/wrap_mitkIOPython.cxx deleted file mode 100644 index 3ad04f3266..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkIOPython.cxx +++ /dev/null @@ -1,73 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkIOPython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - "BaseDataIO", - "DicomSeriesReader", - "FileReader", - "FileSeriesReader", - "FileWriter", - "FileWriterWithInformation", - "ImageWriter", - "ImageWriterFactory", - //"IOAdapter", - //"IpPicGet", - "ItkImageFileIOFactory", - "ItkImageFileReader", - "Log", - "LookupTableProperty", - "Operation", - "OperationActor", - "PicFileIOFactory", - "PicFileReader", - "PicFileWriter", - "PicHelper", - "PicVolumeTimeSeriesIOFactory", - "PicVolumeTimeSeriesReader", - "PixelType", - "PointSetIOFactory", - "PointSetReader", - "PointSetWriter", - "PointSetWriterFactory", - //"RawImageFileReader", - "StandardFileLocations", - "STLFileIOFactory", - "STLFileReader", - //"SurfaceVtkWriter", - "SurfaceVtkWriterFactory", - "VtiFileIOFactory", - "VtiFileReader", - "VtkImageIOFactory", - "VtkImageReader", - "VtkSurfaceIOFactory", - "VtkSurfaceReader", - "vtkPointSetXMLParser" - }; -} -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkITKImageImport.cxx b/Wrapping/CSwig/Core/wrap_mitkITKImageImport.cxx deleted file mode 100644 index db3be577ef..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkITKImageImport.cxx +++ /dev/null @@ -1,50 +0,0 @@ -#include "itkImage.h" -#include "mitkITKImageImport.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ITKImageImport"; - namespace wrappers - { - typedef mitk::ITKImageImport::Image> ITKImageImportD2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportD2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportD3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportD3_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportF2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportF2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportF3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportF3_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportUS2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportUS2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportUS3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportUS3_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportUC2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportUC2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportUC3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportUC3_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportUI2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportUI2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportUI3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportUI3_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportUL2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportUL2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportUL3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportUL3_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportSC2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportSC2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportSC3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportSC3_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportSI2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportSI2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportSI3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportSI3_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportSS2; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportSS2_Pointer; - typedef mitk::ITKImageImport::Image> ITKImageImportSS3; - typedef mitk::ITKImageImport::Image>::Pointer::SmartPointer ITKImageImportSS3_Pointer; - } -} - -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkImage.cxx b/Wrapping/CSwig/Core/wrap_mitkImage.cxx deleted file mode 100644 index 6f9910055e..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImage.cxx +++ /dev/null @@ -1,18 +0,0 @@ -#include "mitkImage.h" -#include "mitkCSwigMacros.h" -#include "vtkPythonUtil.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Image"; - namespace wrappers - { - MITK_WRAP_OBJECT(Image) - - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageAccessByItk.cxx b/Wrapping/CSwig/Core/wrap_mitkImageAccessByItk.cxx deleted file mode 100644 index c5755073f7..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageAccessByItk.cxx +++ /dev/null @@ -1,15 +0,0 @@ -#include "mitkImageAccessByItk.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetSource"; - namespace wrappers - { - typedef AccessByItk AccessByItk; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageCaster.cxx b/Wrapping/CSwig/Core/wrap_mitkImageCaster.cxx deleted file mode 100644 index e4ca38148e..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageCaster.cxx +++ /dev/null @@ -1,18 +0,0 @@ -#include "mitkImageCaster.h" -#include "mitkCSwigMacros.h" -#include "mitkImageAccessByItk.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageCaster"; - namespace wrappers - { - typedef mitk::ImageCaster ImageCaster; - typedef mitk::RendererAccess RendererAccess; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageChannelSelector.cxx b/Wrapping/CSwig/Core/wrap_mitkImageChannelSelector.cxx deleted file mode 100644 index 690b03efd2..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageChannelSelector.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageChannelSelector.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageChannelSelector"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageChannelSelector) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageDataItem.cxx b/Wrapping/CSwig/Core/wrap_mitkImageDataItem.cxx deleted file mode 100644 index 86c890d17e..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageDataItem.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageDataItem.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageDataItem"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageDataItem) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkImageMapper2D.cxx deleted file mode 100644 index b255bca7ca..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageMapperGL2D.cxx b/Wrapping/CSwig/Core/wrap_mitkImageMapperGL2D.cxx deleted file mode 100644 index 08eb7dc968..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageMapperGL2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageMapperGL2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageMapperGL2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageMapperGL2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageSliceSelector.cxx b/Wrapping/CSwig/Core/wrap_mitkImageSliceSelector.cxx deleted file mode 100644 index 014371b883..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageSliceSelector.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageSliceSelector.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageSliceSelector"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageSliceSelector) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageSource.cxx b/Wrapping/CSwig/Core/wrap_mitkImageSource.cxx deleted file mode 100644 index 379704d158..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageSource.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageSource.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageSource"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageSource) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageTimeSelector.cxx b/Wrapping/CSwig/Core/wrap_mitkImageTimeSelector.cxx deleted file mode 100644 index 85ecb2bc10..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageTimeSelector.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageTimeSelector.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageTimeSelector"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageTimeSelector) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageToImageFilter.cxx b/Wrapping/CSwig/Core/wrap_mitkImageToImageFilter.cxx deleted file mode 100644 index 25127da49d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageToImageFilter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageToImageFilter.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageToImageFilter"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageToImageFilter) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageToItk.cxx b/Wrapping/CSwig/Core/wrap_mitkImageToItk.cxx deleted file mode 100644 index f32932ba3c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageToItk.cxx +++ /dev/null @@ -1,50 +0,0 @@ -#include "itkImage.h" -#include "mitkImageToItk.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageToItk"; - namespace wrappers - { - typedef mitk::ImageToItk::Image> ImageToItkD2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkD2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkD3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkD3_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkF2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkF2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkF3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkF3_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkUS2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkUS2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkUS3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkUS3_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkUC2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkUC2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkUC3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkUC3_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkUI2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkUI2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkUI3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkUI3_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkUL2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkUL2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkUL3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkUL3_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkSC2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkSC2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkSC3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkSC3_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkSI2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkSI2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkSI3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkSI3_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkSS2; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkSS2_Pointer; - typedef mitk::ImageToItk::Image> ImageToItkSS3; - typedef mitk::ImageToItk::Image>::Pointer::SmartPointer ImageToItkSS3_Pointer; - } -} - -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkImageWriter.cxx b/Wrapping/CSwig/Core/wrap_mitkImageWriter.cxx deleted file mode 100644 index 44504151a6..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageWriter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageWriter.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageWriter"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageWriter) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkImageWriterFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkImageWriterFactory.cxx deleted file mode 100644 index f5c70385ff..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkImageWriterFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkImageWriterFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ImageWriterFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(ImageWriterFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkInteractionsPython.cxx b/Wrapping/CSwig/Core/wrap_mitkInteractionsPython.cxx deleted file mode 100644 index b0dad7498d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkInteractionsPython.cxx +++ /dev/null @@ -1,57 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkInteractionsPython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - "Action", - "AffineInteractor", - "CoordinateSupplier", - "DisplayCoordinateOperation", - "DisplayInteractor", - "DisplayPositionEvent", - "DisplayVectorInteractor", - "Event", - "EventDescription", - "EventMapper", - "GlobalInteraction", - "Interactor", - "KeyEvent", - //"Message", - "MouseMovePointSetInteractor", - "PointSetInteractor", - "PositionEvent", - "PositionTracker", - "State", - "StateEvent", - "StateMachine", - "StateMachineFactory", - "Transition", - "WheelEvent" - }; -} -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkInteractor.cxx b/Wrapping/CSwig/Core/wrap_mitkInteractor.cxx deleted file mode 100644 index 04b74191bf..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkInteractor.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkInteractor.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Interactor"; - namespace wrappers - { - MITK_WRAP_OBJECT(Interactor) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkItkImageFileIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkItkImageFileIOFactory.cxx deleted file mode 100644 index b3f15d1b02..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkItkImageFileIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkItkImageFileIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ItkImageFileIOFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(ItkImageFileIOFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkItkImageFileReader.cxx b/Wrapping/CSwig/Core/wrap_mitkItkImageFileReader.cxx deleted file mode 100644 index fb50e78f6f..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkItkImageFileReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkItkImageFileReader.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ItkImageFileReader"; - namespace wrappers - { - MITK_WRAP_OBJECT(ItkImageFileReader) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkItkPictureWrite.cxx b/Wrapping/CSwig/Core/wrap_mitkItkPictureWrite.cxx deleted file mode 100644 index 99ea4b71d0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkItkPictureWrite.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkItkPictureWrite.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ItkPictureWrite"; - namespace wrappers - { - typedef mitk::ItkPictureWrite ItkPictureWrite; - typedef mitk::ItkPictureWrite::Pointer::SmartPointer ItkPictureWrite_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkKeyEvent.cxx b/Wrapping/CSwig/Core/wrap_mitkKeyEvent.cxx deleted file mode 100644 index c7cb8097b0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkKeyEvent.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkKeyEvent.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="KeyEvent"; - namespace wrappers - { - typedef mitk::KeyEvent KeyEvent; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLandmarkBasedCurvedGeometry.cxx b/Wrapping/CSwig/Core/wrap_mitkLandmarkBasedCurvedGeometry.cxx deleted file mode 100644 index 562e6ea28b..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLandmarkBasedCurvedGeometry.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLandmarkBasedCurvedGeometry.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LandmarkBasedCurvedGeometry"; - namespace wrappers - { - MITK_WRAP_OBJECT(LandmarkBasedCurvedGeometry) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLandmarkProjector.cxx b/Wrapping/CSwig/Core/wrap_mitkLandmarkProjector.cxx deleted file mode 100644 index ef5cd11341..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLandmarkProjector.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLandmarkProjector.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LandmarkProjector"; - namespace wrappers - { - MITK_WRAP_OBJECT(LandmarkProjector) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLandmarkProjectorBasedCurvedGeometry.cxx b/Wrapping/CSwig/Core/wrap_mitkLandmarkProjectorBasedCurvedGeometry.cxx deleted file mode 100644 index 35e993b15f..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLandmarkProjectorBasedCurvedGeometry.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLandmarkProjectorBasedCurvedGeometry.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LandmarkProjectorBasedCurvedGeometry"; - namespace wrappers - { - MITK_WRAP_OBJECT(LandmarkProjectorBasedCurvedGeometry) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLevelWindow.cxx b/Wrapping/CSwig/Core/wrap_mitkLevelWindow.cxx deleted file mode 100644 index b878152cb9..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLevelWindow.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLevelWindow.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LevelWindow"; - namespace wrappers - { - typedef mitk::LevelWindow LevelWindow; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLevelWindowManager.cxx b/Wrapping/CSwig/Core/wrap_mitkLevelWindowManager.cxx deleted file mode 100644 index 79bf70e8f3..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLevelWindowManager.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLevelWindowManager.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LevelWindowManager"; - namespace wrappers - { - MITK_WRAP_OBJECT(LevelWindowManager) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLevelWindowPreset.cxx b/Wrapping/CSwig/Core/wrap_mitkLevelWindowPreset.cxx deleted file mode 100644 index 01472b8144..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLevelWindowPreset.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLevelWindowPreset.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LevelWindowPreset"; - namespace wrappers - { - typedef mitk::LevelWindowPreset LevelWindowPreset; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLevelWindowProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkLevelWindowProperty.cxx deleted file mode 100644 index 4982d5896e..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLevelWindowProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLevelWindowProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LevelWindowProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(LevelWindowProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLimitedLinearUndo.cxx b/Wrapping/CSwig/Core/wrap_mitkLimitedLinearUndo.cxx deleted file mode 100644 index 4f1e957c1d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLimitedLinearUndo.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLimitedLinearUndo.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LimitedLinearUndo"; - namespace wrappers - { - MITK_WRAP_OBJECT(LimitedLinearUndo) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLog.cxx b/Wrapping/CSwig/Core/wrap_mitkLog.cxx deleted file mode 100644 index d5d945bed0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLog.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLog.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Log"; - namespace wrappers - { - typedef mitk::LoggingBackend Log; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLogoRendering.cxx b/Wrapping/CSwig/Core/wrap_mitkLogoRendering.cxx deleted file mode 100644 index 16646bee81..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLogoRendering.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLogoRendering.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LogoRendering"; - namespace wrappers - { - MITK_WRAP_OBJECT(LogoRendering) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLookupTable.cxx b/Wrapping/CSwig/Core/wrap_mitkLookupTable.cxx deleted file mode 100644 index 0597cca06e..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLookupTable.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLookupTable.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LookupTable"; - namespace wrappers - { - MITK_WRAP_OBJECT(LookupTable) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLookupTableProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkLookupTableProperty.cxx deleted file mode 100644 index ec715a4d23..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLookupTableProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkLookupTableProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LookupTableProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(LookupTableProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkLookupTables.cxx b/Wrapping/CSwig/Core/wrap_mitkLookupTables.cxx deleted file mode 100644 index 3df32f2573..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkLookupTables.cxx +++ /dev/null @@ -1,19 +0,0 @@ -#include "mitkLookupTables.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="LookupTables"; - namespace wrappers - { - //typedef mitk::BoolLookupTable BoolLookupTable; //cswig crashes; D:\CableSwig\CableSwig\SWIG\Source\Modules\lang.cxx line 1717 symname = NULL; no check for this case - typedef mitk::FloatLookupTable FloatLookupTable; - typedef mitk::IntLookupTable IntLookupTable; - typedef mitk::StringLookupTable StringLookupTable; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkManufacturerLogo.cxx b/Wrapping/CSwig/Core/wrap_mitkManufacturerLogo.cxx deleted file mode 100644 index 60b00fde08..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkManufacturerLogo.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkManufacturerLogo.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ManufacturerLogo"; - namespace wrappers - { - MITK_WRAP_OBJECT(ManufacturerLogo) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkMapper.cxx b/Wrapping/CSwig/Core/wrap_mitkMapper.cxx deleted file mode 100644 index 009f730f09..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkMapper.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkMapper.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Mapper"; - namespace wrappers - { - MITK_WRAP_OBJECT(Mapper) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkMapper2D.cxx deleted file mode 100644 index a89d418ba4..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Mapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(Mapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkMapper3D.cxx b/Wrapping/CSwig/Core/wrap_mitkMapper3D.cxx deleted file mode 100644 index 22b9c1070d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkMapper3D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkMapper3D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Mapper3D"; - namespace wrappers - { - MITK_WRAP_OBJECT(Mapper3D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkMaterial.cxx b/Wrapping/CSwig/Core/wrap_mitkMaterial.cxx deleted file mode 100644 index 9b40b56103..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkMaterial.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkMaterial.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Material"; - namespace wrappers - { - MITK_WRAP_OBJECT(Material) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkMemoryUtilities.cxx b/Wrapping/CSwig/Core/wrap_mitkMemoryUtilities.cxx deleted file mode 100644 index 93a81738dd..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkMemoryUtilities.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkMemoryUtilities.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="MemoryUtilities"; - namespace wrappers - { - typedef mitk::MemoryUtilities MemoryUtilities; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkMessage.cxx b/Wrapping/CSwig/Core/wrap_mitkMessage.cxx deleted file mode 100644 index 5981f74c71..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkMessage.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkMessage.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Message"; - namespace wrappers - { - typedef mitk::Message Message; - typedef mitk::Message::Pointer::SmartPointer Message_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkModalityProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkModalityProperty.cxx deleted file mode 100644 index fcd4a61eb8..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkModalityProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkModalityProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ModalityProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(ModalityProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkModeOperation.cxx b/Wrapping/CSwig/Core/wrap_mitkModeOperation.cxx deleted file mode 100644 index b33d5529f9..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkModeOperation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkModeOperation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ModeOperation"; - namespace wrappers - { - typedef mitk::ModeOperation ModeOperation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkMouseMovePointSetInteractor.cxx b/Wrapping/CSwig/Core/wrap_mitkMouseMovePointSetInteractor.cxx deleted file mode 100644 index 457dd5a213..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkMouseMovePointSetInteractor.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkMouseMovePointSetInteractor.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="MouseMovePointSetInteractor"; - namespace wrappers - { - MITK_WRAP_OBJECT(MouseMovePointSetInteractor) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateAND.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateAND.cxx deleted file mode 100644 index c04aefc26d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateAND.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateAnd.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateAnd"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateAnd) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateBase.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateBase.cxx deleted file mode 100644 index 5f0b252323..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateBase.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateBase.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateBase"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateBase) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateCompositeBase.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateCompositeBase.cxx deleted file mode 100644 index bd04b49e5a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateCompositeBase.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateCompositeBase.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateCompositeBase"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateCompositeBase) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateData.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateData.cxx deleted file mode 100644 index 1b24e830c5..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateData.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateData.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateData"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateData) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateDataType.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateDataType.cxx deleted file mode 100644 index 4ae6ff55bb..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateDataType.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateDataType.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateDataType"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateDataType) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateDimension.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateDimension.cxx deleted file mode 100644 index a6ef301b81..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateDimension.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateDimension.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateDimension"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateDimension) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateFirstLevel.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateFirstLevel.cxx deleted file mode 100644 index 86676ccc1c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateFirstLevel.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateFirstLevel.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateFirstLevel"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateFirstLevel) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateNOT.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateNOT.cxx deleted file mode 100644 index ddc58f82f9..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateNOT.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateNot.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateNot"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateNot) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateOR.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateOR.cxx deleted file mode 100644 index 05f7170a3c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateOR.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateOr.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateOr"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateOr) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateProperty.cxx deleted file mode 100644 index f4b8bc4d92..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkNodePredicateSource.cxx b/Wrapping/CSwig/Core/wrap_mitkNodePredicateSource.cxx deleted file mode 100644 index b4284b7a90..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkNodePredicateSource.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkNodePredicateSource.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="NodePredicateSource"; - namespace wrappers - { - MITK_WRAP_OBJECT(NodePredicateSource) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkOperation.cxx b/Wrapping/CSwig/Core/wrap_mitkOperation.cxx deleted file mode 100644 index 834989e05c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkOperation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkOperation.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Operation"; - namespace wrappers - { - typedef mitk::Operation::Operation Operation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkOperationActor.cxx b/Wrapping/CSwig/Core/wrap_mitkOperationActor.cxx deleted file mode 100644 index 6dd84801a4..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkOperationActor.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkOperationActor.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="OperationActor"; - namespace wrappers - { - typedef mitk::OperationActor OperationActor; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkOperationEvent.cxx b/Wrapping/CSwig/Core/wrap_mitkOperationEvent.cxx deleted file mode 100644 index 01ed96d7e1..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkOperationEvent.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkOperationEvent.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="OperationEvent"; - namespace wrappers - { - typedef mitk::OperationEvent OperationEvent; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPicFileIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkPicFileIOFactory.cxx deleted file mode 100644 index 242172f0b5..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPicFileIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPicFileIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PicFileIOFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(PicFileIOFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPicFileReader.cxx b/Wrapping/CSwig/Core/wrap_mitkPicFileReader.cxx deleted file mode 100644 index 2d75de398b..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPicFileReader.cxx +++ /dev/null @@ -1,18 +0,0 @@ -#include "mitkPicFileReader.h" -#include "mitkCSwigMacros.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PicFileReader"; - namespace wrappers - { - MITK_WRAP_OBJECT(PicFileReader); - } -} - -#endif - - diff --git a/Wrapping/CSwig/Core/wrap_mitkPicFileWriter.cxx b/Wrapping/CSwig/Core/wrap_mitkPicFileWriter.cxx deleted file mode 100644 index 63a7f1fe8d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPicFileWriter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPicFileWriter.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PicFileWriter"; - namespace wrappers - { - MITK_WRAP_OBJECT(PicFileWriter) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPicHelper.cxx b/Wrapping/CSwig/Core/wrap_mitkPicHelper.cxx deleted file mode 100644 index 9b8340680d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPicHelper.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPicHelper.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PicHelper"; - namespace wrappers - { - typedef mitk::PicHelper PicHelper; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPicVolumeTimeSeriesIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkPicVolumeTimeSeriesIOFactory.cxx deleted file mode 100644 index e2a2ae8784..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPicVolumeTimeSeriesIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPicVolumeTimeSeriesIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PicVolumeTimeSeriesIOFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(PicVolumeTimeSeriesIOFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPicVolumeTimeSeriesReader.cxx b/Wrapping/CSwig/Core/wrap_mitkPicVolumeTimeSeriesReader.cxx deleted file mode 100644 index 99ae71cca8..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPicVolumeTimeSeriesReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPicVolumeTimeSeriesReader.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PicVolumeTimeSeriesReader"; - namespace wrappers - { - MITK_WRAP_OBJECT(PicVolumeTimeSeriesReader) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPixelType.cxx b/Wrapping/CSwig/Core/wrap_mitkPixelType.cxx deleted file mode 100644 index 3a7e41f641..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPixelType.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPixelType.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PixelType"; - namespace wrappers - { - typedef mitk::PixelType PixelType; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPlaneDecorationProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkPlaneDecorationProperty.cxx deleted file mode 100644 index ed013d1f3f..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPlaneDecorationProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPlaneDecorationProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PlaneDecorationProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(PlaneDecorationProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPlaneGeometry.cxx b/Wrapping/CSwig/Core/wrap_mitkPlaneGeometry.cxx deleted file mode 100644 index 9720bf9549..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPlaneGeometry.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPlaneGeometry.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PlaneGeometry"; - namespace wrappers - { - MITK_WRAP_OBJECT(PlaneGeometry) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPlaneOperation.cxx b/Wrapping/CSwig/Core/wrap_mitkPlaneOperation.cxx deleted file mode 100644 index daeb7e6232..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPlaneOperation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPlaneOperation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PlaneOperation"; - namespace wrappers - { - typedef mitk::PlaneOperation PlaneOperation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPlaneOrientationProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkPlaneOrientationProperty.cxx deleted file mode 100644 index ca5e899b35..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPlaneOrientationProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPlaneOrientationProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PlaneOrientationProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(PlaneOrientationProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointOperation.cxx b/Wrapping/CSwig/Core/wrap_mitkPointOperation.cxx deleted file mode 100644 index a5d3324e86..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointOperation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointOperation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointOperation"; - namespace wrappers - { - typedef mitk::PointOperation PointOperation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSet.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSet.cxx deleted file mode 100644 index 19d70a0a3a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSet.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSet.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSet"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSet) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetGLMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetGLMapper2D.cxx deleted file mode 100644 index f4c552b516..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetGLMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetGLMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetGLMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetGLMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetIOFactory.cxx deleted file mode 100644 index 7081890c45..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetIOFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetIOFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetInteractor.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetInteractor.cxx deleted file mode 100644 index 16b9d90fd6..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetInteractor.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetInteractor.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetInteractor"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetInteractor) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetMapper2D.cxx deleted file mode 100644 index d9c3a95b74..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetReader.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetReader.cxx deleted file mode 100644 index 2c8f8a9978..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetReader.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetReader"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetReader) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetSource.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetSource.cxx deleted file mode 100644 index 38db1ccf99..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetSource.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetSource.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetSource"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetSource) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetVtkMapper3D.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetVtkMapper3D.cxx deleted file mode 100644 index 975960a4de..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetVtkMapper3D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetVtkMapper3D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetVtkMapper3D"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetVtkMapper3D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetWriter.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetWriter.cxx deleted file mode 100644 index 0aad2ca86f..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetWriter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetWriter.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetWriter"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetWriter) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPointSetWriterFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkPointSetWriterFactory.cxx deleted file mode 100644 index 2b316e74a2..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPointSetWriterFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPointSetWriterFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PointSetWriterFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(PointSetWriterFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPolyDataGLMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkPolyDataGLMapper2D.cxx deleted file mode 100644 index be627e4048..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPolyDataGLMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPolyDataGLMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PolyDataGLMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(PolyDataGLMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPositionEvent.cxx b/Wrapping/CSwig/Core/wrap_mitkPositionEvent.cxx deleted file mode 100644 index f8811b186c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPositionEvent.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPositionEvent.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PositionEvent"; - namespace wrappers - { - typedef mitk::PositionEvent PositionEvent; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPositionTracker.cxx b/Wrapping/CSwig/Core/wrap_mitkPositionTracker.cxx deleted file mode 100644 index 7baa0c6bac..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPositionTracker.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPositionTracker.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PositionTracker"; - namespace wrappers - { - MITK_WRAP_OBJECT(PositionTracker) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkProgressBar.cxx b/Wrapping/CSwig/Core/wrap_mitkProgressBar.cxx deleted file mode 100644 index b1dbd83ad8..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkProgressBar.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkProgressBar.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ProgressBar"; - namespace wrappers - { - MITK_WRAP_OBJECT(ProgressBar) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkProgressBarImplementation.cxx b/Wrapping/CSwig/Core/wrap_mitkProgressBarImplementation.cxx deleted file mode 100644 index e631cd7c14..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkProgressBarImplementation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkProgressBarImplementation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ProgressBarImplementation"; - namespace wrappers - { - typedef mitk::ProgressBarImplementation ProgressBarImplementation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkProperties.cxx b/Wrapping/CSwig/Core/wrap_mitkProperties.cxx deleted file mode 100644 index 31a91ceb1d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkProperties.cxx +++ /dev/null @@ -1,27 +0,0 @@ -#include "mitkProperties.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Properties"; - namespace wrappers - { - MITK_WRAP_OBJECT(BoolProperty) - MITK_WRAP_OBJECT(IntProperty) - MITK_WRAP_OBJECT(FloatProperty) - MITK_WRAP_OBJECT(DoubleProperty) - MITK_WRAP_OBJECT(Vector3DProperty) - MITK_WRAP_OBJECT(Point3dProperty) - MITK_WRAP_OBJECT(Point4dProperty) - MITK_WRAP_OBJECT(Point3iProperty) - MITK_WRAP_OBJECT(FloatLookupTableProperty) - MITK_WRAP_OBJECT(BoolLookupTableProperty) - MITK_WRAP_OBJECT(IntLookupTableProperty) - MITK_WRAP_OBJECT(StringLookupTableProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkPropertyList.cxx b/Wrapping/CSwig/Core/wrap_mitkPropertyList.cxx deleted file mode 100644 index 5dcb331496..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkPropertyList.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkPropertyList.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="PropertyList"; - namespace wrappers - { - MITK_WRAP_OBJECT(PropertyList) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkRGBToRGBACastImageFilter.cxx b/Wrapping/CSwig/Core/wrap_mitkRGBToRGBACastImageFilter.cxx deleted file mode 100644 index bc840721e8..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkRGBToRGBACastImageFilter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkRGBToRGBACastImageFilter.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="RGBToRGBACastImageFilter"; - namespace wrappers - { - MITK_WRAP_OBJECT(RGBToRGBACastImageFilter) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkRawImageFileReader.cxx b/Wrapping/CSwig/Core/wrap_mitkRawImageFileReader.cxx deleted file mode 100644 index 749112e460..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkRawImageFileReader.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkRawImageFileReader.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="RawImageFileReader"; - namespace wrappers - { - typedef mitk::RawImageFileReader RawImageFileReader; - typedef mitk::RawImageFileReader::Pointer::SmartPointer RawImageFileReader_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkReferenceCountWatcher.cxx b/Wrapping/CSwig/Core/wrap_mitkReferenceCountWatcher.cxx deleted file mode 100644 index f8d4b035cb..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkReferenceCountWatcher.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkReferenceCountWatcher.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ReferenceCountWatcher"; - namespace wrappers - { - typedef mitk::ReferenceCountWatcher ReferenceCountWatcher; - typedef mitk::ReferenceCountWatcher::Pointer::SmartPointer ReferenceCountWatcher_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkRenderingManager.cxx b/Wrapping/CSwig/Core/wrap_mitkRenderingManager.cxx deleted file mode 100644 index dcd09574e9..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkRenderingManager.cxx +++ /dev/null @@ -1,25 +0,0 @@ -#include "mitkRenderingManager.h" -#include "mitkCSwigMacros.h" -#include "vtkRenderWindow.h" -#include "mitkDataStorage.h" -#include "mitkGlobalInteraction.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="RenderingManager"; - namespace wrappers - { - MITK_WRAP_OBJECT(RenderingManager) - typedef std::vector< vtkRenderWindow* > RenderWindowVector; - typedef std::vector< float > FloatVector; - typedef std::vector< bool > BoolVector; - typedef itk::SmartPointer< mitk::DataStorage > DataStoragePointer; - typedef itk::SmartPointer< mitk::GlobalInteraction > GlobalInteractionPointer; - typedef mitk::RenderingManager::RequestType RenderingManager_RequestType; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkRenderingManagerFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkRenderingManagerFactory.cxx deleted file mode 100644 index b21a705974..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkRenderingManagerFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkRenderingManagerFactory.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="RenderingManagerFactory"; - namespace wrappers - { - typedef mitk::RenderingManagerFactory RenderingManagerFactory; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkRenderingPython.cxx b/Wrapping/CSwig/Core/wrap_mitkRenderingPython.cxx deleted file mode 100644 index bcec308f57..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkRenderingPython.cxx +++ /dev/null @@ -1,60 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkRenderingPython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - //"BaseRenderer", - "BaseVtkMapper2D", - "BaseVtkMapper3D", - "ColoredRectangleRendering", - "Geometry2DDataMapper2D", - "Geometry2DDataVtkMapper3D", - "GLMapper2D", - "GradientBackground", - "ImageMapper2D", - "LogoRendering", - "ManufacturerLogo", - "Mapper", - "Mapper2D", - "Mapper3D", - "PointSetMapper2D", - "PointSetVtkMapper3D", - "PolyDataGLMapper2D", - "PolyDataGLMapper2D", - "ShaderRepository", - "SurfaceMapper2D", - "SurfaceVtkMapper3D", - //"VolumeDataVtkMapper3D", - "VtkPropRenderer", - "VtkWidgetRendering", - "vtkMitkRectangleProp", - //"vtkMitkRenderProp", - "vtkMitkThickSlicesFilter" - }; -} -#endif diff --git a/Wrapping/CSwig/Core/wrap_mitkResliceMethodEnumProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkResliceMethodEnumProperty.cxx deleted file mode 100644 index f6cbf37699..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkResliceMethodEnumProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkResliceMethodEnumProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ResliceMethodEnumProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(ResliceMethodEnumProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkResliceMethodProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkResliceMethodProperty.cxx deleted file mode 100644 index fa520b303d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkResliceMethodProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkResliceMethodProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ResliceMethodProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(ResliceMethodProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkRotationOperation.cxx b/Wrapping/CSwig/Core/wrap_mitkRotationOperation.cxx deleted file mode 100644 index c384d41202..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkRotationOperation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkRotationOperation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="RotationOperation"; - namespace wrappers - { - typedef mitk::RotationOperation RotationOperation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSTLFileIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkSTLFileIOFactory.cxx deleted file mode 100644 index bfa1b515fd..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSTLFileIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSTLFileIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="STLFileIOFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(STLFileIOFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSTLFileReader.cxx b/Wrapping/CSwig/Core/wrap_mitkSTLFileReader.cxx deleted file mode 100644 index f5b4e3a939..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSTLFileReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSTLFileReader.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="STLFileReader"; - namespace wrappers - { - MITK_WRAP_OBJECT(STLFileReader) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkShaderEnumProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkShaderEnumProperty.cxx deleted file mode 100644 index f0a5c5d7f0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkShaderEnumProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkShaderEnumProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ShaderEnumProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(ShaderEnumProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkShaderProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkShaderProperty.cxx deleted file mode 100644 index 34a674e9f0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkShaderProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkShaderProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ShaderProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(ShaderProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkShaderRepository.cxx b/Wrapping/CSwig/Core/wrap_mitkShaderRepository.cxx deleted file mode 100644 index 27a8452f2b..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkShaderRepository.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkShaderRepository.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ShaderRepository"; - namespace wrappers - { - MITK_WRAP_OBJECT(ShaderRepository) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSliceNavigationController.cxx b/Wrapping/CSwig/Core/wrap_mitkSliceNavigationController.cxx deleted file mode 100644 index 1146d59fe6..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSliceNavigationController.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSliceNavigationController.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SliceNavigationController"; - namespace wrappers - { - MITK_WRAP_OBJECT(SliceNavigationController) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSlicedData.cxx b/Wrapping/CSwig/Core/wrap_mitkSlicedData.cxx deleted file mode 100644 index d11f5ce5ac..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSlicedData.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSlicedData.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SlicedData"; - namespace wrappers - { - MITK_WRAP_OBJECT(SlicedData) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSlicedGeometry3D.cxx b/Wrapping/CSwig/Core/wrap_mitkSlicedGeometry3D.cxx deleted file mode 100644 index fc849f0ee1..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSlicedGeometry3D.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkSlicedGeometry3D.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SlicedGeometry3D"; - namespace wrappers - { - typedef mitk::SlicedGeometry3D SlicedGeometry3D; - typedef mitk::SlicedGeometry3D::Pointer::SmartPointer SlicedGeometry3D_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSlicesCoordinator.cxx b/Wrapping/CSwig/Core/wrap_mitkSlicesCoordinator.cxx deleted file mode 100644 index 9451f4bae7..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSlicesCoordinator.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSlicesCoordinator.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SlicesCoordinator"; - namespace wrappers - { - MITK_WRAP_OBJECT(SlicesCoordinator) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSlicesRotator.cxx b/Wrapping/CSwig/Core/wrap_mitkSlicesRotator.cxx deleted file mode 100644 index fd330cf4b0..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSlicesRotator.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSlicesRotator.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SlicesRotator"; - namespace wrappers - { - MITK_WRAP_OBJECT(SlicesRotator) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSlicesSwiveller.cxx b/Wrapping/CSwig/Core/wrap_mitkSlicesSwiveller.cxx deleted file mode 100644 index 283b850873..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSlicesSwiveller.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSlicesSwiveller.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SlicesSwiveller"; - namespace wrappers - { - MITK_WRAP_OBJECT(SlicesSwiveller) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSmartPointerProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkSmartPointerProperty.cxx deleted file mode 100644 index d0926f4dcd..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSmartPointerProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSmartPointerProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SmartPointerProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(SmartPointerProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStandaloneDataStorage.cxx b/Wrapping/CSwig/Core/wrap_mitkStandaloneDataStorage.cxx deleted file mode 100644 index fbc1dfe01c..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStandaloneDataStorage.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStandaloneDataStorage.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StandaloneDataStorage"; - namespace wrappers - { - MITK_WRAP_OBJECT(StandaloneDataStorage) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStandardFileLocations.cxx b/Wrapping/CSwig/Core/wrap_mitkStandardFileLocations.cxx deleted file mode 100644 index 12404b561a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStandardFileLocations.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStandardFileLocations.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StandardFileLocations"; - namespace wrappers - { - MITK_WRAP_OBJECT(StandardFileLocations) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkState.cxx b/Wrapping/CSwig/Core/wrap_mitkState.cxx deleted file mode 100644 index 830a6c9f54..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkState.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkState.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="State"; - namespace wrappers - { - MITK_WRAP_OBJECT(State) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStateEvent.cxx b/Wrapping/CSwig/Core/wrap_mitkStateEvent.cxx deleted file mode 100644 index fce28229aa..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStateEvent.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStateEvent.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StateEvent"; - namespace wrappers - { - typedef mitk::StateEvent StateEvent; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStateMachine.cxx b/Wrapping/CSwig/Core/wrap_mitkStateMachine.cxx deleted file mode 100644 index 4f7f9483e4..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStateMachine.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStateMachine.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StateMachine"; - namespace wrappers - { - MITK_WRAP_OBJECT(StateMachine) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStateMachineFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkStateMachineFactory.cxx deleted file mode 100644 index baa60aadcc..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStateMachineFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStateMachineFactory.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StateMachineFactory"; - namespace wrappers - { - typedef mitk::StateMachineFactory StateMachineFactory; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStateTransitionOperation.cxx b/Wrapping/CSwig/Core/wrap_mitkStateTransitionOperation.cxx deleted file mode 100644 index d2515df27a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStateTransitionOperation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStateTransitionOperation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StateTransitionOperation"; - namespace wrappers - { - typedef mitk::StateTransitionOperation StateTransitionOperation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStatusBar.cxx b/Wrapping/CSwig/Core/wrap_mitkStatusBar.cxx deleted file mode 100644 index 0e0c4f31b4..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStatusBar.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStatusBar.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StatusBar"; - namespace wrappers - { - MITK_WRAP_OBJECT(StatusBar) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStatusBarImplementation.cxx b/Wrapping/CSwig/Core/wrap_mitkStatusBarImplementation.cxx deleted file mode 100644 index d976d0fdd7..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStatusBarImplementation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStatusBarImplementation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StatusBarImplementation"; - namespace wrappers - { - typedef mitk::StatusBarImplementation StatusBarImplementation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStepper.cxx b/Wrapping/CSwig/Core/wrap_mitkStepper.cxx deleted file mode 100644 index 3c0de709de..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStepper.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStepper.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Stepper"; - namespace wrappers - { - MITK_WRAP_OBJECT(Stepper) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkStringProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkStringProperty.cxx deleted file mode 100644 index 613296cd5a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkStringProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkStringProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="StringProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(StringProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSubImageSelector.cxx b/Wrapping/CSwig/Core/wrap_mitkSubImageSelector.cxx deleted file mode 100644 index a6a9b6e0cd..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSubImageSelector.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSubImageSelector.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SubImageSelector"; - namespace wrappers - { - MITK_WRAP_OBJECT(SubImageSelector) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurface.cxx b/Wrapping/CSwig/Core/wrap_mitkSurface.cxx deleted file mode 100644 index 0483a8df34..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurface.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSurface.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Surface"; - namespace wrappers - { - MITK_WRAP_OBJECT(Surface) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurfaceGLMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkSurfaceGLMapper2D.cxx deleted file mode 100644 index 3e466d84f4..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurfaceGLMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSurfaceGLMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SurfaceGLMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(SurfaceGLMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurfaceMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkSurfaceMapper2D.cxx deleted file mode 100644 index 16584ab194..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurfaceMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSurfaceMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SurfaceMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(SurfaceMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurfaceOperation.cxx b/Wrapping/CSwig/Core/wrap_mitkSurfaceOperation.cxx deleted file mode 100644 index 3f84d51eb7..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurfaceOperation.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSurfaceOperation.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SurfaceOperation"; - namespace wrappers - { - typedef mitk::SurfaceOperation SurfaceOperation; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurfaceSource.cxx b/Wrapping/CSwig/Core/wrap_mitkSurfaceSource.cxx deleted file mode 100644 index bb2c0e052a..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurfaceSource.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSurfaceSource.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SurfaceSource"; - namespace wrappers - { - MITK_WRAP_OBJECT(SurfaceSource) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurfaceToSurfaceFilter.cxx b/Wrapping/CSwig/Core/wrap_mitkSurfaceToSurfaceFilter.cxx deleted file mode 100644 index 32b469d301..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurfaceToSurfaceFilter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSurfaceToSurfaceFilter.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SurfaceToSurfaceFilter"; - namespace wrappers - { - MITK_WRAP_OBJECT(SurfaceToSurfaceFilter) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkMapper3D.cxx b/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkMapper3D.cxx deleted file mode 100644 index 58db2f671d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkMapper3D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSurfaceVtkMapper3D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SurfaceVtkMapper3D"; - namespace wrappers - { - MITK_WRAP_OBJECT(SurfaceVtkMapper3D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkWriter.cxx b/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkWriter.cxx deleted file mode 100644 index 3846dce3c2..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkWriter.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkSurfaceVtkWriter.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SurfaceVtkWriter"; - namespace wrappers - { - typedef mitk::SurfaceVtkWriter SurfaceVtkWriter; - typedef mitk::SurfaceVtkWriter::Pointer::SmartPointer SurfaceVtkWriter_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkWriterFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkWriterFactory.cxx deleted file mode 100644 index 1412c16269..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkSurfaceVtkWriterFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkSurfaceVtkWriterFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="SurfaceVtkWriterFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(SurfaceVtkWriterFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkTestManager.cxx b/Wrapping/CSwig/Core/wrap_mitkTestManager.cxx deleted file mode 100644 index 55ccc98ad5..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkTestManager.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkTestManager.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="TestManager"; - namespace wrappers - { - typedef mitk::TestManager TestManager; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkThinPlateSplineCurvedGeometry.cxx b/Wrapping/CSwig/Core/wrap_mitkThinPlateSplineCurvedGeometry.cxx deleted file mode 100644 index 2871cf1542..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkThinPlateSplineCurvedGeometry.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkThinPlateSplineCurvedGeometry.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="ThinPlateSplineCurvedGeometry"; - namespace wrappers - { - MITK_WRAP_OBJECT(ThinPlateSplineCurvedGeometry) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkTimeSlicedGeometry.cxx b/Wrapping/CSwig/Core/wrap_mitkTimeSlicedGeometry.cxx deleted file mode 100644 index 363080e359..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkTimeSlicedGeometry.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkTimeSlicedGeometry.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="TimeSlicedGeometry"; - namespace wrappers - { - MITK_WRAP_OBJECT(TimeSlicedGeometry) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkTransferFunction.cxx b/Wrapping/CSwig/Core/wrap_mitkTransferFunction.cxx deleted file mode 100644 index 2f7bdb4895..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkTransferFunction.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkTransferFunction.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="TransferFunction"; - namespace wrappers - { - MITK_WRAP_OBJECT(TransferFunction) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkTransferFunctionProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkTransferFunctionProperty.cxx deleted file mode 100644 index 311c4d38db..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkTransferFunctionProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkTransferFunctionProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="TransferFunctionProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(TransferFunctionProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkTransition.cxx b/Wrapping/CSwig/Core/wrap_mitkTransition.cxx deleted file mode 100644 index f4f72e4bc8..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkTransition.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkTransition.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Transition"; - namespace wrappers - { - typedef mitk::Transition Transition; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkUIDGenerator.cxx b/Wrapping/CSwig/Core/wrap_mitkUIDGenerator.cxx deleted file mode 100644 index 5d9d8a5593..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkUIDGenerator.cxx +++ /dev/null @@ -1,15 +0,0 @@ -#include "mitkUIDGenerator.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="UIDGenerator"; - namespace wrappers - { - typedef mitk::UIDGenerator::UIDGenerator UIDGenerator; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkUndoController.cxx b/Wrapping/CSwig/Core/wrap_mitkUndoController.cxx deleted file mode 100644 index adfef27eb1..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkUndoController.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkUndoController.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="UndoController"; - namespace wrappers - { - typedef mitk::UndoController UndoController; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkUndoModel.cxx b/Wrapping/CSwig/Core/wrap_mitkUndoModel.cxx deleted file mode 100644 index 700cf160cf..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkUndoModel.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkUndoModel.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="UndoModel"; - namespace wrappers - { - MITK_WRAP_OBJECT(UndoModel) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVector.cxx b/Wrapping/CSwig/Core/wrap_mitkVector.cxx deleted file mode 100644 index 4d3ce47f10..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVector.cxx +++ /dev/null @@ -1,59 +0,0 @@ -#include "mitkVector.h" -#include -#include -#include -#include -#include -#include -#include -#include "mitkCommon.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="Vector"; - namespace wrappers - { - typedef float ScalarType; - typedef itk::Matrix Matrix3D; - typedef itk::Matrix Matrix4D; - typedef vnl_matrix_fixed VnlMatrix3D; - typedef itk::Transform Transform3D; - typedef vnl_vector VnlVector; - typedef vnl_vector_ref VnlVectorRef; - - typedef itk::Point Point2D; - typedef itk::Point Point3D; - typedef itk::Point Point4D; - typedef itk::Point Point2I; - typedef itk::Point Point3I; - typedef itk::Point Point4I; - typedef itk::Vector Vector2D; - typedef itk::Vector Vector3D; - typedef vnl_quaternion Quaternion; - - typedef mitk::VectorTraits VectorTraitsVnl; - typedef mitk::VectorTraits VectorTraitsD4; - typedef mitk::VectorTraits> VectorTraitsIndex5; - typedef mitk::VectorTraits> VectorTraitsIndex3; - typedef mitk::VectorTraits VectorTraitsLI3; - typedef mitk::VectorTraits VectorTraitsF3; - typedef mitk::VectorTraits VectorTraitsD3; - typedef mitk::VectorTraits> VectorTraitsVnlFixed; - typedef mitk::VectorTraits VectorTraitsLUI3; - typedef mitk::VectorTraits VectorTraitsUI; - typedef mitk::VectorTraits VectorTraitsScalarType4; - typedef mitk::VectorTraits> VectorTraitsVectorTraitsF3; - typedef mitk::VectorTraits> VectorTraitsPointF3; - typedef mitk::VectorTraits> VectorTraitsPointF4; - typedef mitk::VectorTraits> VectorTraitsVectorTraitsD3; - typedef mitk::VectorTraits> VectorTraitsPointD3; - typedef mitk::VectorTraits> VectorTraitsVectorTraitsI3; - typedef mitk::VectorTraits> VectorTraitsPointI3; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVerboseLimitedLinearUndo.cxx b/Wrapping/CSwig/Core/wrap_mitkVerboseLimitedLinearUndo.cxx deleted file mode 100644 index 0531231f7d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVerboseLimitedLinearUndo.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVerboseLimitedLinearUndo.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VerboseLimitedLinearUndo"; - namespace wrappers - { - MITK_WRAP_OBJECT(VerboseLimitedLinearUndo) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVolumeCalculator.cxx b/Wrapping/CSwig/Core/wrap_mitkVolumeCalculator.cxx deleted file mode 100644 index 036055bd51..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVolumeCalculator.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVolumeCalculator.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VolumeCalculator"; - namespace wrappers - { - MITK_WRAP_OBJECT(VolumeCalculator) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVolumeDataVtkMapper3D.cxx b/Wrapping/CSwig/Core/wrap_mitkVolumeDataVtkMapper3D.cxx deleted file mode 100644 index 68eb298cfa..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVolumeDataVtkMapper3D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVolumeDataVtkMapper3D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VolumeDataVtkMapper3D"; - namespace wrappers - { - MITK_WRAP_OBJECT(VolumeDataVtkMapper3D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtiFileIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkVtiFileIOFactory.cxx deleted file mode 100644 index f8121253f8..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtiFileIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtiFileIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtiFileIOFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtiFileIOFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtiFileReader.cxx b/Wrapping/CSwig/Core/wrap_mitkVtiFileReader.cxx deleted file mode 100644 index 9f50bbf4ec..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtiFileReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtiFileReader.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtiFileReader"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtiFileReader) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkImageIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkImageIOFactory.cxx deleted file mode 100644 index 49819787f2..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkImageIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkImageIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkImageIOFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkImageIOFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkImageReader.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkImageReader.cxx deleted file mode 100644 index 1c950de009..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkImageReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkImageReader.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkImageReader"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkImageReader) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkInteractorCameraController.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkInteractorCameraController.cxx deleted file mode 100644 index 16c683fffb..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkInteractorCameraController.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkInteractorCameraController.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkInteractorCameraController"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkInteractorCameraController) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkInterpolationProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkInterpolationProperty.cxx deleted file mode 100644 index a1b3e79961..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkInterpolationProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkInterpolationProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkInterpolationProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkInterpolationProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkLayerController.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkLayerController.cxx deleted file mode 100644 index 1bda029d22..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkLayerController.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkLayerController.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkLayerController"; - namespace wrappers - { - typedef mitk::VtkLayerController VtkLayerController; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkMapper2D.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkMapper2D.cxx deleted file mode 100644 index f7757e0af1..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkMapper2D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkMapper2D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkMapper2D"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkMapper2D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkMapper3D.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkMapper3D.cxx deleted file mode 100644 index 9ea89f2e72..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkMapper3D.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkMapper3D.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkMapper3D"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkMapper3D) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkPropRenderer.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkPropRenderer.cxx deleted file mode 100644 index ae301463ea..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkPropRenderer.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkPropRenderer.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkPropRenderer"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkPropRenderer) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkRepresentationProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkRepresentationProperty.cxx deleted file mode 100644 index 16559fe311..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkRepresentationProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkRepresentationProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkRepresentationProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkRepresentationProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkResliceInterpolationProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkResliceInterpolationProperty.cxx deleted file mode 100644 index f005b144d9..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkResliceInterpolationProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkResliceInterpolationProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkResliceInterpolationProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkResliceInterpolationProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkScalarModeProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkScalarModeProperty.cxx deleted file mode 100644 index c7eb7986cc..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkScalarModeProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkScalarModeProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkScalarModeProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkScalarModeProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkSurfaceIOFactory.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkSurfaceIOFactory.cxx deleted file mode 100644 index bfd8103816..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkSurfaceIOFactory.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkSurfaceIOFactory.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkSurfaceIOFactory"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkSurfaceIOFactory) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkSurfaceReader.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkSurfaceReader.cxx deleted file mode 100644 index a95611d70e..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkSurfaceReader.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkSurfaceReader.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkSurfaceReader"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkSurfaceReader) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkVolumeRenderingProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkVolumeRenderingProperty.cxx deleted file mode 100644 index cccc812154..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkVolumeRenderingProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkVolumeRenderingProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkVolumeRenderingProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkVolumeRenderingProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkVtkWidgetRendering.cxx b/Wrapping/CSwig/Core/wrap_mitkVtkWidgetRendering.cxx deleted file mode 100644 index a423516360..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkVtkWidgetRendering.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkVtkWidgetRendering.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="VtkWidgetRendering"; - namespace wrappers - { - MITK_WRAP_OBJECT(VtkWidgetRendering) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkWeakPointer.cxx b/Wrapping/CSwig/Core/wrap_mitkWeakPointer.cxx deleted file mode 100644 index 70556a147d..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkWeakPointer.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "mitkWeakPointer.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="WeakPointer"; - namespace wrappers - { - typedef mitk::WeakPointer WeakPointer; - typedef mitk::WeakPointer::Pointer::SmartPointer WeakPointer_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkWeakPointerProperty.cxx b/Wrapping/CSwig/Core/wrap_mitkWeakPointerProperty.cxx deleted file mode 100644 index b682b9ea44..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkWeakPointerProperty.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkWeakPointerProperty.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="WeakPointerProperty"; - namespace wrappers - { - MITK_WRAP_OBJECT(WeakPointerProperty) - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_mitkWheelEvent.cxx b/Wrapping/CSwig/Core/wrap_mitkWheelEvent.cxx deleted file mode 100644 index 45b4db2962..0000000000 --- a/Wrapping/CSwig/Core/wrap_mitkWheelEvent.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "mitkWheelEvent.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="WheelEvent"; - namespace wrappers - { - typedef mitk::WheelEvent WheelEvent; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_qmitkFunctionality.cxx b/Wrapping/CSwig/Core/wrap_qmitkFunctionality.cxx deleted file mode 100644 index e3a9af06dd..0000000000 --- a/Wrapping/CSwig/Core/wrap_qmitkFunctionality.cxx +++ /dev/null @@ -1,21 +0,0 @@ -//#define _MT - -//#include "QmitkFunctionality.h" -#include "mitkDataStorageReference.h" -#include "mitkCSwigMacros.h" - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="DataStorageReference"; - namespace wrappers - { - //MITK_WRAP_OBJECT(Test) - typedef mitk::DataStorageReference DataStorageReference; - //typedef berry::SmartPointer QmitkFunctionality_Pointer; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_vtkMitkRectangleProp.cxx b/Wrapping/CSwig/Core/wrap_vtkMitkRectangleProp.cxx deleted file mode 100644 index 6a8a774afe..0000000000 --- a/Wrapping/CSwig/Core/wrap_vtkMitkRectangleProp.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "vtkMitkRectangleProp.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="vtkMitkRectangleProp"; - namespace wrappers - { - typedef vtkMitkRectangleProp vtkMitkRectangleProp; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_vtkMitkRenderProp.cxx b/Wrapping/CSwig/Core/wrap_vtkMitkRenderProp.cxx deleted file mode 100644 index ccc1508f81..0000000000 --- a/Wrapping/CSwig/Core/wrap_vtkMitkRenderProp.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "vtkMitkRenderProp.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="vtkMitkRenderProp"; - namespace wrappers - { - typedef vtkMitkRenderProp vtkMitkRenderProp; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_vtkMitkThickSlicesFilter.cxx b/Wrapping/CSwig/Core/wrap_vtkMitkThickSlicesFilter.cxx deleted file mode 100644 index 16e079083b..0000000000 --- a/Wrapping/CSwig/Core/wrap_vtkMitkThickSlicesFilter.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "vtkMitkThickSlicesFilter.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="vtkMitkThickSlicesFilter"; - namespace wrappers - { - typedef vtkMitkThickSlicesFilter vtkMitkThickSlicesFilter; - } -} - -#endif - diff --git a/Wrapping/CSwig/Core/wrap_vtkPointSetXMLParser.cxx b/Wrapping/CSwig/Core/wrap_vtkPointSetXMLParser.cxx deleted file mode 100644 index f96ba58c50..0000000000 --- a/Wrapping/CSwig/Core/wrap_vtkPointSetXMLParser.cxx +++ /dev/null @@ -1,16 +0,0 @@ -#include "vtkPointSetXMLParser.h" - - -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="vtkPointSetXMLParser"; - namespace wrappers - { - typedef mitk::vtkPointSetXMLParser vtkPointSetXMLParser; - } -} - -#endif - diff --git a/Wrapping/CSwig/Master.mdx.in b/Wrapping/CSwig/Master.mdx.in deleted file mode 100644 index 4dd4f5e4c1..0000000000 --- a/Wrapping/CSwig/Master.mdx.in +++ /dev/null @@ -1 +0,0 @@ -${INDEX_FILE_CONTENT} diff --git a/Wrapping/CSwig/Python/CMakeLists.txt b/Wrapping/CSwig/Python/CMakeLists.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Wrapping/CSwig/Python/mitk.OpenCV.py.in b/Wrapping/CSwig/Python/mitk.OpenCV.py.in deleted file mode 100644 index 63a56fde54..0000000000 --- a/Wrapping/CSwig/Python/mitk.OpenCV.py.in +++ /dev/null @@ -1,6 +0,0 @@ -import sys -sys.path.append('@ITK_LIBRARY_DIRS@') -sys.path.append('@ITK_DIR@/Wrapping/WrapITK/Python') -sys.path.append('@VTK_LIBRARY_DIRS@') -sys.path.append('@VTK_DIR@/Wrapping/Python') -sys.path.append('@OpenCV_LIBRARY_DIRS@') diff --git a/Wrapping/CSwig/Python/mitk.py.in b/Wrapping/CSwig/Python/mitk.py.in deleted file mode 100644 index 95b5c4a4e6..0000000000 --- a/Wrapping/CSwig/Python/mitk.py.in +++ /dev/null @@ -1,5 +0,0 @@ -import sys -sys.path.append('@ITK_LIBRARY_DIRS@') -sys.path.append('@ITK_DIR@/Wrapping/WrapITK/Python') -sys.path.append('@VTK_LIBRARY_DIRS@') -sys.path.append('@VTK_DIR@/Wrapping/Python') diff --git a/Wrapping/CSwig/Python/mitkCast.py b/Wrapping/CSwig/Python/mitkCast.py deleted file mode 100755 index b4929d1271..0000000000 --- a/Wrapping/CSwig/Python/mitkCast.py +++ /dev/null @@ -1,45 +0,0 @@ -import mitk -import itk - -def base2mitk(baseData): - mitkImage = mitk.Image_New() - mitk.ImageCaster.CastBaseData(baseData, mitkImage) - return mitkImage - -def mitk2itk(mitkImage,itkType): - itkImage = itkType.New() - mitk.ImageCaster.CastToItkImage(mitkImage.GetPointer(),itkImage) - return itkImage - -def base2itk(baseData,itkType): - mitkImage = base2mitk(baseData) - itkImage = mitk2itk(mitkImage,itkType) - return itkImage - -def node2itk(node,itkType): - itkImage = base2itk(node.GetData(),itkType) - return itkImage - -def itk2mitk(itkImage): - mitkImage = mitk.Image_New() - mitk.ImageCaster.CastToMitkImage( itkImage.GetPointer(), mitkImage ) - return mitkImage - -def mitk2node(mitkImage, name): - newNode = mitk.DataNode_New() - newNode.SetData( mitkImage.GetPointer() ) - newNode.SetName(name) - return newNode - -def itk2node(itkImage,name): - mitkImage = itk2mitk(itkImage) - newNode = mitk2node(mitkImage, name) - return newNode - -def threshold(node,min,max): - itkImage = node2itk(node,itk.Image.F3) - filter = itk.BinaryThresholdImageFilter[itkImage,itkImage].New(itkImage,LowerThreshold=min,UpperThreshold=max) - filter.Update() - itkImage = filter.GetOutput() - node = itk2node(itkImage) - return node diff --git a/Wrapping/CSwig/Python/mitkbase.py.in b/Wrapping/CSwig/Python/mitkbase.py.in deleted file mode 100644 index 33bbbaa7db..0000000000 --- a/Wrapping/CSwig/Python/mitkbase.py.in +++ /dev/null @@ -1,76 +0,0 @@ -"""InsightToolkit support module to help load its packages.""" -import sys,os - -# Get the path to the directory containing this script. It may be -# used to set pkgdir below, depending on how this script is -# configured. -if __name__ == '__main__': - selfpath = os.path.abspath(sys.path[0] or os.curdir) -else: - selfpath = os.path.abspath(os.path.dirname(__file__)) - -# The directory containing the binary ITK python wrapper libraries. -pkgdir = @MITK_CSWIG_PACKAGE_DIR@ - -# Python "help(sys.setdlopenflags)" states: -# -# setdlopenflags(...) -# setdlopenflags(n) -> None -# -# Set the flags that will be used for dlopen() calls. Among other -# things, this will enable a lazy resolving of symbols when -# importing a module, if called as sys.setdlopenflags(0) To share -# symbols across extension modules, call as -# -# sys.setdlopenflags(dl.RTLD_NOW|dl.RTLD_GLOBAL) -# -# GCC 3.x depends on proper merging of symbols for RTTI: -# http://gcc.gnu.org/faq.html#dso -# -# The Python setup.py states that the "dl" module -# requires "sizeof(int) == sizeof(long) == sizeof(char*)". -# Therefore the dl module is missing on 64-bit platforms. -# Since RTLD_NOW==0x002 and RTLD_GLOBAL==0x100 very commonly -# we will just guess that the proper flags are 0x102 when there -# is no dl module. - -def preimport(): - """Called by InsightToolkit packages before loading a C module.""" - # Save the current dlopen flags and set the ones we need. - try: - import dl - newflags = dl.RTLD_NOW|dl.RTLD_GLOBAL - except: - newflags = 0x102 # No dl module, so guess (see above). - try: - oldflags = sys.getdlopenflags() - sys.setdlopenflags(newflags) - except: - oldflags = None - # Save the current working directory and change to that containing - # the python wrapper libraries. They have '.' in their rpaths, so - # they will find the libraries on which they depend. - cwd = os.getcwd() - os.chdir(pkgdir) - # Add the binary package directory to the python module search path. - sys.path.insert(1, pkgdir) - return [cwd, oldflags] - -def postimport(data): - """Called by InsightToolkit packages after loading a C module.""" - # Remove the binary package directory to the python module search path. - sys.path.remove(pkgdir) - # Restore the original working directory. - os.chdir(data[0]) - # Restore the original dlopen flags. - try: - sys.setdlopenflags(data[1]) - except: - pass - -# Default location for test output -defaultTestRoot = @MITK_CSWIG_TEST_ROOT@ - -# Default location for test input -defaultDataRoot = @MITK_CSWIG_DATA_ROOT@ - diff --git a/Wrapping/CSwig/PythonMITKModules.cmake b/Wrapping/CSwig/PythonMITKModules.cmake deleted file mode 100644 index a4f3e34cd5..0000000000 --- a/Wrapping/CSwig/PythonMITKModules.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(MITK_PYTHON_MODULES_DIRS Core) - -subdirs(${MITK_PYTHON_MODULES_DIRS}) \ No newline at end of file diff --git a/Wrapping/CSwig/SwigInc.txt.in b/Wrapping/CSwig/SwigInc.txt.in deleted file mode 100644 index 3fc1a405f9..0000000000 --- a/Wrapping/CSwig/SwigInc.txt.in +++ /dev/null @@ -1 +0,0 @@ -@SWIG_INC_CONTENTS@ diff --git a/Wrapping/CSwig/SwigRuntime/CMakeLists.txt b/Wrapping/CSwig/SwigRuntime/CMakeLists.txt deleted file mode 100644 index 20bff587db..0000000000 --- a/Wrapping/CSwig/SwigRuntime/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - -macro(CREATE_SWIG_RUNTIME lang_option lang_postfix lang_link_libs) - set(source_file "${CMAKE_CURRENT_BINARY_DIR}/swigrun${lang_postfix}.cxx") - set(lib_name "SwigRuntime${lang_postfix}") - - add_library(${lib_name} SHARED "${source_file}") - target_link_libraries(${lib_name} ${lang_link_libs}) - - # work around linkage problem on some solaris systems - if(CMAKE_SYSTEM MATCHES "SunOS-." AND CMAKE_COMPILER_IS_GNUCXX AND CMAKE_COMPILER_IS_GNUCC) - target_link_libraries(${lib_name} stdc++) - endif(CMAKE_SYSTEM MATCHES "SunOS-." AND CMAKE_COMPILER_IS_GNUCXX AND CMAKE_COMPILER_IS_GNUCC) - - install_targets("${WRAP_ITK_INSTALL_PREFIX}/lib" ${lib_name}) - set_target_properties(${lib_name} PROPERTIES LINK_FLAGS "${CSWIG_EXTRA_LINKFLAGS}") - - add_custom_command( - SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/swigrun.h - COMMAND ${GCCXML} - ARGS -fxml-start=_cable_ -DCABLE_CONFIGURATION ${CMAKE_CURRENT_SOURCE_DIR}/swigrun.h - -fxml=${CMAKE_CURRENT_BINARY_DIR}/swigrun.xml - TARGET ${lib_name} - OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/swigrun.xml - DEPENDS ${GCCXML}) - - add_custom_command( - SOURCE ${CMAKE_CURRENT_BINARY_DIR}/swigrun.xml - COMMAND ${CSWIG} - ARGS -o "${source_file}" - ${lang_option} - -c++ ${CMAKE_CURRENT_BINARY_DIR}/swigrun.xml - TARGET ${lib_name} - OUTPUTS "${source_file}" - DEPENDS ${CSWIG}) -endmacro(CREATE_SWIG_RUNTIME) - -if(MITK_USE_Python) - set(PYLIBS ${PYTHON_LIBRARY}) - if(PYTHON_DEBUG_LIBRARY) - set(PYLIBS debug ${PYTHON_DEBUG_LIBRARY} optimized ${PYTHON_LIBRARY}) - endif() - #message(warning "PYLIBS: ${PYLIBS}") - CREATE_SWIG_RUNTIME(-python Python "${PYLIBS}") -endif(MITK_USE_Python) - diff --git a/Wrapping/CSwig/SwigRuntime/swigrun.h b/Wrapping/CSwig/SwigRuntime/swigrun.h deleted file mode 100644 index 64bea55378..0000000000 --- a/Wrapping/CSwig/SwigRuntime/swigrun.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifdef CABLE_CONFIGURATION -namespace _cable_ -{ - const char* const group="SwigRunTime"; -} -#endif diff --git a/Wrapping/CSwig/empty.depend.in b/Wrapping/CSwig/empty.depend.in deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Wrapping/CSwig/mitk.swg b/Wrapping/CSwig/mitk.swg deleted file mode 100644 index c80ee68d15..0000000000 --- a/Wrapping/CSwig/mitk.swg +++ /dev/null @@ -1,58 +0,0 @@ -/* This is an itk-specific typemap used by CableSwig. Also see comments - * and "throws" code in CableSwig.cxx. - * -- Charl P. Botha - */ - -#ifdef SWIGPYTHON - -/* ------------------------------------------------------------ - * PyObject * - Just pass straight through unmodified - * This is default behaviour for python.swg, but Cable passes - * a PyObject * through as a "p._object", so we redo the typemap - * ------------------------------------------------------------ */ - -%typemap(in) p._object "$1 = $input;"; -%typemap(out) p._object "$result = $1;"; - -#define %runtime %insert("runtime") - -%insert(runtime) %{ -#if defined(MITK_WINDOWS_PYTHON_DEBUGGABLE) -# include "Python.h" -#else -# ifdef _DEBUG -# undef _DEBUG -# if defined(_MSC_VER) && _MSC_VER >= 1400 -# define _CRT_NOFORCE_MANIFEST 1 -# endif -# include "Python.h" -# define _DEBUG -# else -# include "Python.h" -# endif -#endif -%} - -#endif - -%include exception.i - -/* A "throws" attribute with the "std::exception" type is added synthetically - * to each method node by CableSwig.cxx. When gcc_xml starts passing through - * correct throws types, this typemap could be optionally extended to - * account for more different types. For now this is sufficient though. - */ - -%typemap(throws) std::exception { - SWIG_exception(SWIG_RuntimeError, const_cast(_e.what())); -} - -%include std_string.i - -/* disable this c linkage warning on windows */ -%{ -#ifdef _WIN32 -#pragma warning ( disable : 4190 ) -#pragma warning ( disable : 4049 ) -#endif -%} diff --git a/Wrapping/CSwig/mitkCSwigMacros.h b/Wrapping/CSwig/mitkCSwigMacros.h deleted file mode 100644 index ff7fe3193b..0000000000 --- a/Wrapping/CSwig/mitkCSwigMacros.h +++ /dev/null @@ -1,26 +0,0 @@ -#define MITK_WRAP_OBJECT(name) \ -typedef mitk::name::name name; \ -typedef mitk::name::Pointer::SmartPointer name##_Pointer; - -#define MITK_WRAP_OBJECT_WITH_SUPERCLASS(name) \ -MITK_WRAP_OBJECT(name); \ -typedef mitk::name::Superclass::Self name##_Superclass; \ -typedef mitk::name::Superclass::Pointer::SmartPointer name##_Superclass_Pointer; - -#define MITK_WRAP_OBJECT1(name, wrapname) \ -typedef mitk::name::name wrapname; \ -typedef mitk::name::Pointer::SmartPointer wrapname##_Pointer; - -#define MITK_WRAP_OBJECT_WITH_SUPERCLASS1(name, wrapname) \ -MITK_WRAP_OBJECT1(name, wrapname); \ -typedef mitk::name::Superclass::Self wrapname##_Superclass; \ -typedef mitk::name::Superclass::Pointer::SmartPointer wrapname##_Superclass_Pointer; - - -#define ITK_WRAP_OBJECT(name) \ -typedef itk::name::name name; \ -typedef itk::name::Pointer::SmartPointer name##_Pointer; - -#define ITK_WRAP_OBJECT1(name, arg1, wrapname) \ -typedef itk::name::name wrapname; \ -typedef itk::name::Pointer::SmartPointer wrapname##_Pointer diff --git a/Wrapping/CSwig/mitkvtk.swg b/Wrapping/CSwig/mitkvtk.swg deleted file mode 100644 index 52ab3c003b..0000000000 --- a/Wrapping/CSwig/mitkvtk.swg +++ /dev/null @@ -1,59 +0,0 @@ -%include exception.i - -%{ -#include "vtkImageImport.h" -#include "vtkImageExport.h" -#include "vtkImageData.h" -#include "vtkRenderWindow.h" -#include "vtkRenderer.h" -%} - -#ifdef SWIGPYTHON -%{ -#include "vtkPythonUtil.h" -%} - -%typemap(out) vtkImageExport* { - PyImport_ImportModule("vtk"); - $result = vtkPythonGetObjectFromPointer ( (vtkImageExport*)$1 ); -} - -%typemap(out) vtkImageImport* { - PyImport_ImportModule("vtk"); - $result = vtkPythonGetObjectFromPointer ( (vtkImageImport*)$1 ); -} - -%typemap(out) vtkImageData* { - PyImport_ImportModule("vtk"); - $result = vtkPythonGetObjectFromPointer ( (vtkImageData*)$1 ); -} - -%typemap(in) vtkImageData* { - $1 = NULL; - $1 = (vtkImageData*) vtkPythonGetPointerFromObject ( $input, "vtkImageData" ); - if ( $1 == NULL ) { SWIG_fail; } -} - -%typemap(out) vtkRenderWindow* { - PyImport_ImportModule("vtk"); - $result = vtkPythonGetObjectFromPointer ( (vtkRenderWindow*)$1 ); -} - -%typemap(in) vtkRenderWindow* { - $1 = NULL; - $1 = (vtkRenderWindow*) vtkPythonGetPointerFromObject ( $input, "vtkRenderWindow" ); - if ( $1 == NULL ) { SWIG_fail; } -} - -%typemap(out) vtkRenderer* { - PyImport_ImportModule("vtk"); - $result = vtkPythonGetObjectFromPointer ( (vtkRenderer*)$1 ); -} - -%typemap(in) vtkRenderer* { - $1 = NULL; - $1 = (vtkRenderer*) vtkPythonGetPointerFromObject ( $input, "vtkRenderer" ); - if ( $1 == NULL ) { SWIG_fail; } -} - -#endif diff --git a/Wrapping/CSwig/wrapCore.cmake b/Wrapping/CSwig/wrapCore.cmake deleted file mode 100644 index 5d55ee2868..0000000000 --- a/Wrapping/CSwig/wrapCore.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# create the mitkCorePython libraries -include(Controllers/wrapSources.cmake) -set(WRAP_SOURCES_TEST - ${WRAP_SOURCES_TEST} - wrap_mitkCorePython) - -set(MASTER_INDEX_FILES "${CMAKE_CURRENT_BINARY_DIR}/Mitk.mdx" -) -foreach(source ${WRAP_SOURCES_TEST}) - message("${source}") -endforeach(source) - -MITK_WRAP_LIBRARY("${WRAP_SOURCES_TEST}" Mitk Core - "" "" Mitk) - diff --git a/Wrapping/CSwig/wrap_mitkCorePython.cxx b/Wrapping/CSwig/wrap_mitkCorePython.cxx deleted file mode 100644 index f4328bca44..0000000000 --- a/Wrapping/CSwig/wrap_mitkCorePython.cxx +++ /dev/null @@ -1,59 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkCorePython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - "BaseController", - "CallbackFromGUIThread", - "CameraController", - "CameraRotationController", - "FocusManager", - "LimitedLinearUndo", - "OperationEvent", - "ProgressBar", - "ProgressBarImplementation", - //"ReferenceCountWatcher", - "RenderingManager", - "RenderingManagerFactory", - "SliceNavigationController", - "SlicesCoordinator", - "SlicesRotator", - "SlicesSwiveller", - "StatusBar", - "StatusBarImplementation", - "Stepper", - //"TestingMacros", - "TestManager", - "UndoController", - "UndoModel", - "VerboseLimitedLinearUndo", - "VtkInteractorCameraController", - "VtkLayerController" - }; -} -#endif diff --git a/Wrapping/mitkWrapMacros.cmake b/Wrapping/mitkWrapMacros.cmake deleted file mode 100644 index 300b3c22dc..0000000000 --- a/Wrapping/mitkWrapMacros.cmake +++ /dev/null @@ -1,18 +0,0 @@ -macro(MITK_WRAP_OBJECT HEADERFILES CLASSNAME WRAPPERNAME DIRECTORY) -file(WRITE ${DIRECTORY}/wrap_${CLASSNAME}.cxx "#include "mitkCSwigMacros.h"\n") -foreach(f ${HEADERFILES}) - file(APPEND ${DIRECTORY}/wrap_${CLASSNAME}.cxx "#include "${f}"\n") -endforeach() -file(APPEND ${DIRECTORY}/wrap_${CLASSNAME}.cxx "#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const group="${CLASSNAME}"; - namespace wrappers - { - MITK_WRAP_OBJECT(${CLASSNAME}) - } -} - -#endif") -endmacro() diff --git a/Wrapping/mitkWrapSetup.cmake b/Wrapping/mitkWrapSetup.cmake deleted file mode 100644 index 8638932021..0000000000 --- a/Wrapping/mitkWrapSetup.cmake +++ /dev/null @@ -1,44 +0,0 @@ -#----------------------------------------------------------------------------- -# wrapper config -option(MITK_USE_Python "Build cswig Python wrapper support (requires CableSwig)." OFF) - -#----------------------------------------------------------------------------- -# Do we need CableSwig? -set(MITK_NEED_CableSwig 0) - -if(MITK_USE_Python) - set(MITK_NEED_CableSwig 1) -endif(MITK_USE_Python) - -if(MITK_NEED_CableSwig) - - if(NOT BUILD_SHARED_LIBS) - message(FATAL_ERROR "Wrapping requires a shared build, change BUILD_SHARED_LIBS to ON") - endif(NOT BUILD_SHARED_LIBS) - - # Search first if CableSwig is in the MITK source tree - if(EXISTS ${MITK_SOURCE_DIR}/Utilities/CableSwig) - set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/Utilities/CableSwig/SWIG/CMake) - - # CableSwig is included in the source distribution. - set(MITK_BUILD_CABLESWIG 1) - set(CableSwig_DIR ${MITK_BINARY_DIR}/Utilities/CableSwig CACHE PATH "CableSwig_DIR: The directory containing CableSwigConfig.cmake.") - set(CableSwig_FOUND 1) - set(CableSwig_INSTALL_ROOT ${MITK_INSTALL_LIB_DIR}/CSwig) - include(${CableSwig_DIR}/CableSwigConfig.cmake OPTIONAL) - subdirs(Utilities/CableSwig) - else(EXISTS ${MITK_SOURCE_DIR}/Utilities/CableSwig) - # If CableSwig is not in the source tree, - # then try to find a binary build of CableSwig - find_package(CableSwig) - set(CMAKE_MODULE_PATH ${CableSwig_DIR}/SWIG/CMake) - endif(EXISTS ${MITK_SOURCE_DIR}/Utilities/CableSwig) - - if(NOT CableSwig_FOUND) - # We have not found CableSwig. Complain. - message(FATAL_ERROR "CableSwig is required for CSwig Wrapping.") - endif(NOT CableSwig_FOUND) - -endif(MITK_NEED_CableSwig) - - diff --git a/Wrapping/wrap_mitkCorePython.cxx b/Wrapping/wrap_mitkCorePython.cxx deleted file mode 100644 index f4328bca44..0000000000 --- a/Wrapping/wrap_mitkCorePython.cxx +++ /dev/null @@ -1,59 +0,0 @@ -#define MITK_WRAP_PACKAGE "mitkCorePython" -//#include "wrap_MITKAlgorithms.cxx" -/*=================================================================== - -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. - -===================================================================*/ - -/*=================================================================== - -This file is based heavily on a corresponding ITK filter. - -===================================================================*/ -#ifdef CABLE_CONFIGURATION - -namespace _cable_ -{ - const char* const package = MITK_WRAP_PACKAGE; - const char* const groups[] = - { - "BaseController", - "CallbackFromGUIThread", - "CameraController", - "CameraRotationController", - "FocusManager", - "LimitedLinearUndo", - "OperationEvent", - "ProgressBar", - "ProgressBarImplementation", - //"ReferenceCountWatcher", - "RenderingManager", - "RenderingManagerFactory", - "SliceNavigationController", - "SlicesCoordinator", - "SlicesRotator", - "SlicesSwiveller", - "StatusBar", - "StatusBarImplementation", - "Stepper", - //"TestingMacros", - "TestManager", - "UndoController", - "UndoModel", - "VerboseLimitedLinearUndo", - "VtkInteractorCameraController", - "VtkLayerController" - }; -} -#endif